📄 apr_pools.c
字号:
b = b->parent; } return 0;}/* * All blocks belonging to sub will be changed to point to p * instead. This is a guarantee by the caller that sub will not * be destroyed before p is. */APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub){ union block_hdr *b; /* We could handle more general cases... but this is it for now. */ if (sub->parent != p) { fprintf(stderr, "pool_join: p is not parent of sub\n"); abort(); } while (p->joined) { p = p->joined; } sub->joined = p; for (b = global_block_list; b; b = b->h.global_next) { if (b->h.owning_pool == sub) { b->h.owning_pool = p; } } return 0;}#endif/***************************************************************** * * Allocating stuff... */APR_DECLARE(void*) apr_palloc(apr_pool_t *a, apr_size_t reqsize){#ifdef ALLOC_USE_MALLOC apr_size_t size = reqsize + CLICK_SZ; void *ptr; ptr = malloc(size); if (ptr == NULL) { fputs("Ouch! Out of memory!\n", stderr); exit(1); } debug_fill(ptr, size); /* might as well get uninitialized protection */ *(void **)ptr = a->allocation_list; a->allocation_list = ptr; return (char *)ptr + CLICK_SZ;#else /* * Round up requested size to an even number of alignment units * (core clicks) */ apr_size_t nclicks; apr_size_t size; /* First, see if we have space in the block most recently * allocated to this pool */ union block_hdr *blok; char *first_avail; char *new_first_avail; nclicks = 1 + ((reqsize - 1) / CLICK_SZ); size = nclicks * CLICK_SZ; /* First, see if we have space in the block most recently * allocated to this pool */ blok = a->last; first_avail = blok->h.first_avail; if (reqsize <= 0) { return NULL; } new_first_avail = first_avail + size; if (new_first_avail <= blok->h.endp) { debug_verify_filled(first_avail, blok->h.endp, "[apr_palloc] Ouch! Someone trounced past the end " "of their allocation!\n"); blok->h.first_avail = new_first_avail; return (void *) first_avail; } /* Nope --- get a new one that's guaranteed to be big enough */#if APR_HAS_THREADS if (alloc_mutex) { apr_lock_acquire(alloc_mutex); }#endif blok = new_block(size, a->apr_abort); a->last->h.next = blok; a->last = blok;#ifdef APR_POOL_DEBUG blok->h.owning_pool = a;#endif#if APR_HAS_THREADS if (alloc_mutex) { apr_lock_release(alloc_mutex); }#endif first_avail = blok->h.first_avail; blok->h.first_avail += size; return (void *) first_avail;#endif}APR_DECLARE(void *) apr_pcalloc(apr_pool_t *a, apr_size_t size){ void *res = apr_palloc(a, size); memset(res, '\0', size); return res;}/***************************************************************** * * User data management functions */APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, const char *key, apr_status_t (*cleanup) (void *), apr_pool_t *cont){ int keylen = strlen(key); if (cont->prog_data == NULL) cont->prog_data = apr_hash_make(cont); if (apr_hash_get(cont->prog_data, key, keylen) == NULL){ char *new_key = apr_pstrdup(cont, key); apr_hash_set(cont->prog_data, new_key, keylen, data); } else { apr_hash_set(cont->prog_data, key, keylen, data); } apr_pool_cleanup_register(cont, data, cleanup, cleanup); return APR_SUCCESS;}APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key, apr_pool_t *cont){ if (cont->prog_data == NULL) *data = NULL; else *data = apr_hash_get(cont->prog_data, key, strlen(key)); return APR_SUCCESS;}/***************************************************************** * * "Print" functions *//* * apr_psprintf is implemented by writing directly into the current * block of the pool, starting right at first_avail. If there's * insufficient room, then a new block is allocated and the earlier * output is copied over. The new block isn't linked into the pool * until all the output is done. * * Note that this is completely safe because nothing else can * allocate in this apr_pool_t while apr_psprintf is running. alarms are * blocked, and the only thing outside of alloc.c that's invoked * is apr_vformatter -- which was purposefully written to be * self-contained with no callouts. */struct psprintf_data { apr_vformatter_buff_t vbuff;#ifdef ALLOC_USE_MALLOC char *base;#else union block_hdr *blok; int got_a_new_block;#endif};static int psprintf_flush(apr_vformatter_buff_t *vbuff){ struct psprintf_data *ps = (struct psprintf_data *)vbuff;#ifdef ALLOC_USE_MALLOC apr_size_t size; char *ptr; size = (char *)ps->vbuff.curpos - ps->base; ptr = realloc(ps->base, 2*size); if (ptr == NULL) { fputs("Ouch! Out of memory!\n", stderr); exit(1); } ps->base = ptr; ps->vbuff.curpos = ptr + size; ps->vbuff.endpos = ptr + 2*size - 1; return 0;#else union block_hdr *blok; union block_hdr *nblok; apr_size_t cur_len; char *strp; blok = ps->blok; strp = ps->vbuff.curpos; cur_len = strp - blok->h.first_avail; /* must try another blok */#if APR_HAS_THREADS apr_lock_acquire(alloc_mutex);#endif nblok = new_block(2 * cur_len, NULL);#if APR_HAS_THREADS apr_lock_release(alloc_mutex);#endif memcpy(nblok->h.first_avail, blok->h.first_avail, cur_len); ps->vbuff.curpos = nblok->h.first_avail + cur_len; /* save a byte for the NUL terminator */ ps->vbuff.endpos = nblok->h.endp - 1; /* did we allocate the current blok? if so free it up */ if (ps->got_a_new_block) { debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);#if APR_HAS_THREADS apr_lock_acquire(alloc_mutex);#endif blok->h.next = block_freelist; block_freelist = blok;#if APR_HAS_THREADS apr_lock_release(alloc_mutex);#endif } ps->blok = nblok; ps->got_a_new_block = 1; /* note that we've deliberately not linked the new block onto * the pool yet... because we may need to flush again later, and * we'd have to spend more effort trying to unlink the block. */ return 0;#endif}APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *p, const char *fmt, va_list ap){#ifdef ALLOC_USE_MALLOC struct psprintf_data ps; void *ptr; ps.base = malloc(512); if (ps.base == NULL) { fputs("Ouch! Out of memory!\n", stderr); exit(1); } /* need room at beginning for allocation_list */ ps.vbuff.curpos = ps.base + CLICK_SZ; ps.vbuff.endpos = ps.base + 511; apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap); *ps.vbuff.curpos++ = '\0'; ptr = ps.base; /* shrink */ ptr = realloc(ptr, (char *)ps.vbuff.curpos - (char *)ptr); if (ptr == NULL) { fputs("Ouch! Out of memory!\n", stderr); exit(1); } *(void **)ptr = p->allocation_list; p->allocation_list = ptr; return (char *)ptr + CLICK_SZ;#else struct psprintf_data ps; char *strp; apr_size_t size; ps.blok = p->last; ps.vbuff.curpos = ps.blok->h.first_avail; ps.vbuff.endpos = ps.blok->h.endp - 1; /* save one for NUL */ ps.got_a_new_block = 0; apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap); strp = ps.vbuff.curpos; *strp++ = '\0'; size = strp - ps.blok->h.first_avail; size = (1 + ((size - 1) / CLICK_SZ)) * CLICK_SZ; strp = ps.blok->h.first_avail; /* save away result pointer */ ps.blok->h.first_avail += size; /* have to link the block in if it's a new one */ if (ps.got_a_new_block) { p->last->h.next = ps.blok; p->last = ps.blok;#ifdef APR_POOL_DEBUG ps.blok->h.owning_pool = p;#endif } return strp;#endif}APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...){ va_list ap; char *res; va_start(ap, fmt); res = apr_pvsprintf(p, fmt, ap); va_end(ap); return res;}/***************************************************************** * * More grotty system stuff... subprocesses. Frump. These don't use * the generic cleanup interface because I don't want multiple * subprocesses to result in multiple three-second pauses; the * subprocesses have to be "freed" all at once. If someone comes * along with another resource they want to allocate which has the * same property, we might want to fold support for that into the * generic interface, but for now, it's a special case */APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *a, apr_proc_t *pid, enum kill_conditions how){ struct process_chain *new = (struct process_chain *) apr_palloc(a, sizeof(struct process_chain)); new->pid = pid; new->kill_how = how; new->next = a->subprocesses; a->subprocesses = new;}static void free_proc_chain(struct process_chain *procs){ /* Dispose of the subprocesses we've spawned off in the course of * whatever it was we're cleaning up now. This may involve killing * some of them off... */ struct process_chain *p; int need_timeout = 0; if (procs == NULL) { return; /* No work. Whew! */ } /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL * dance with any of the processes we're cleaning up. If we've got * any kill-on-sight subprocesses, ditch them now as well, so they * don't waste any more cycles doing whatever it is that they shouldn't * be doing anymore. */#ifndef NEED_WAITPID /* Pick up all defunct processes */ for (p = procs; p; p = p->next) { if (apr_proc_wait(p->pid, APR_NOWAIT) == APR_CHILD_DONE) { p->kill_how = kill_never; } }#endif for (p = procs; p; p = p->next) { if ((p->kill_how == kill_after_timeout) || (p->kill_how == kill_only_once)) { /* * Subprocess may be dead already. Only need the timeout if not. * Note: apr_proc_kill on Windows is TerminateProcess(), which is * similar to a SIGKILL, so always give the process a timeout * under Windows before killing it. */#ifdef WIN32 need_timeout = 1;#else if (apr_proc_kill(p->pid, SIGTERM) == APR_SUCCESS) { need_timeout = 1; }#endif } else if (p->kill_how == kill_always) { apr_proc_kill(p->pid, SIGKILL); } } /* Sleep only if we have to... */ if (need_timeout) { sleep(3); } /* OK, the scripts we just timed out for have had a chance to clean up * --- now, just get rid of them, and also clean up the system accounting * goop... */ for (p = procs; p; p = p->next) { if (p->kill_how == kill_after_timeout) { apr_proc_kill(p->pid, SIGKILL); } }#ifdef WIN32 /* * Do we need an APR function to clean-up a proc_t? */ { for (p = procs; p; p = p->next) { CloseHandle((HANDLE)p->pid->pid); } }#endif /* WIN32 */ /* Now wait for all the signaled processes to die */ for (p = procs; p; p = p->next) { if (p->kill_how != kill_never) { (void) apr_proc_wait(p->pid, APR_WAIT); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -