📄 apr_pools.c
字号:
/* Node list management helper macros; list_insert() inserts 'node' * before 'point'. */#define list_insert(node, point) do { \ node->ref = point->ref; \ *node->ref = node; \ node->next = point; \ point->ref = &node->next; \} while (0)/* list_remove() removes 'node' from its list. */#define list_remove(node) do { \ *node->ref = node->next; \ node->next->ref = node->ref; \} while (0)/* * Memory allocation */APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size){ apr_memnode_t *active, *node; void *mem; apr_size_t free_index; size = APR_ALIGN_DEFAULT(size); active = pool->active; /* If the active node has enough bytes left, use it. */ if (size < (apr_size_t)(active->endp - active->first_avail)) { mem = active->first_avail; active->first_avail += size; return mem; } node = active->next; if (size < (apr_size_t)(node->endp - node->first_avail)) { list_remove(node); } else { if ((node = allocator_alloc(pool->allocator, size)) == NULL) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } } node->free_index = 0; mem = node->first_avail; node->first_avail += size; list_insert(node, active); pool->active = node; free_index = (APR_ALIGN(active->endp - active->first_avail + 1, BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; active->free_index = (APR_UINT32_TRUNC_CAST)free_index; node = active->next; if (free_index >= node->free_index) return mem; do { node = node->next; } while (free_index < node->free_index); list_remove(active); list_insert(active, node); return mem;}/* Provide an implementation of apr_pcalloc for backward compatibility * with code built before apr_pcalloc was a macro */#ifdef apr_pcalloc#undef apr_pcalloc#endifAPR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size);APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size){ void *mem; size = APR_ALIGN_DEFAULT(size); if ((mem = apr_palloc(pool, size)) != NULL) { memset(mem, 0, size); } return mem;}/* * Pool creation/destruction */APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool){ apr_memnode_t *active; /* Destroy the subpools. The subpools will detach themselves from * this pool thus this loop is safe and easy. */ while (pool->child) apr_pool_destroy(pool->child); /* Run cleanups */ run_cleanups(&pool->cleanups); pool->cleanups = NULL; pool->free_cleanups = NULL; /* Free subprocesses */ free_proc_chain(pool->subprocesses); pool->subprocesses = NULL; /* Clear the user data. */ pool->user_data = NULL; /* Find the node attached to the pool structure, reset it, make * it the active node and free the rest of the nodes. */ active = pool->active = pool->self; active->first_avail = pool->self_first_avail; if (active->next == active) return; *active->ref = NULL; allocator_free(pool->allocator, active->next); active->next = active; active->ref = &active->next;}APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool){ apr_memnode_t *active; apr_allocator_t *allocator; /* Destroy the subpools. The subpools will detach themselve from * this pool thus this loop is safe and easy. */ while (pool->child) apr_pool_destroy(pool->child); /* Run cleanups */ run_cleanups(&pool->cleanups); /* Free subprocesses */ free_proc_chain(pool->subprocesses); /* Remove the pool from the parents child list */ if (pool->parent) {#if APR_HAS_THREADS apr_thread_mutex_t *mutex; if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL) apr_thread_mutex_lock(mutex);#endif /* APR_HAS_THREADS */ if ((*pool->ref = pool->sibling) != NULL) pool->sibling->ref = pool->ref;#if APR_HAS_THREADS if (mutex) apr_thread_mutex_unlock(mutex);#endif /* APR_HAS_THREADS */ } /* Find the block attached to the pool structure. Save a copy of the * allocator pointer, because the pool struct soon will be no more. */ allocator = pool->allocator; active = pool->self; *active->ref = NULL;#if APR_HAS_THREADS if (apr_allocator_owner_get(allocator) == pool) { /* Make sure to remove the lock, since it is highly likely to * be invalid now. */ apr_allocator_mutex_set(allocator, NULL); }#endif /* APR_HAS_THREADS */ /* Free all the nodes in the pool (including the node holding the * pool struct), by giving them back to the allocator. */ allocator_free(allocator, active); /* If this pool happens to be the owner of the allocator, free * everything in the allocator (that includes the pool struct * and the allocator). Don't worry about destroying the optional mutex * in the allocator, it will have been destroyed by the cleanup function. */ if (apr_allocator_owner_get(allocator) == pool) { apr_allocator_destroy(allocator); }}APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator){ apr_pool_t *pool; apr_memnode_t *node; *newpool = NULL; if (!parent) parent = global_pool; if (!abort_fn && parent) abort_fn = parent->abort_fn; if (allocator == NULL) allocator = parent->allocator; if ((node = allocator_alloc(allocator, MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) { if (abort_fn) abort_fn(APR_ENOMEM); return APR_ENOMEM; } node->next = node; node->ref = &node->next; pool = (apr_pool_t *)node->first_avail; node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T; pool->allocator = allocator; pool->active = pool->self = node; pool->abort_fn = abort_fn; pool->child = NULL; pool->cleanups = NULL; pool->free_cleanups = NULL; pool->subprocesses = NULL; pool->user_data = NULL; pool->tag = NULL;#ifdef NETWARE pool->owner_proc = (apr_os_proc_t)getnlmhandle();#endif /* defined(NETWARE) */ if ((pool->parent = parent) != NULL) {#if APR_HAS_THREADS apr_thread_mutex_t *mutex; if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL) apr_thread_mutex_lock(mutex);#endif /* APR_HAS_THREADS */ if ((pool->sibling = parent->child) != NULL) pool->sibling->ref = &pool->sibling; parent->child = pool; pool->ref = &parent->child;#if APR_HAS_THREADS if (mutex) apr_thread_mutex_unlock(mutex);#endif /* APR_HAS_THREADS */ } else { pool->sibling = NULL; pool->ref = NULL; } *newpool = pool; 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 apr_pools.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; apr_memnode_t *node; apr_pool_t *pool; apr_byte_t got_a_new_node; apr_memnode_t *free;};#define APR_PSPRINTF_MIN_STRINGSIZE 32static int psprintf_flush(apr_vformatter_buff_t *vbuff){ struct psprintf_data *ps = (struct psprintf_data *)vbuff; apr_memnode_t *node, *active; apr_size_t cur_len, size; char *strp; apr_pool_t *pool; apr_size_t free_index; pool = ps->pool; active = ps->node; strp = ps->vbuff.curpos; cur_len = strp - active->first_avail; size = cur_len << 1; /* Make sure that we don't try to use a block that has less * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it. This * also catches the case where size == 0, which would result * in reusing a block that can't even hold the NUL byte. */ if (size < APR_PSPRINTF_MIN_STRINGSIZE) size = APR_PSPRINTF_MIN_STRINGSIZE; node = active->next; if (!ps->got_a_new_node && size < (apr_size_t)(node->endp - node->first_avail)) { list_remove(node); list_insert(node, active); node->free_index = 0; pool->active = node; free_index = (APR_ALIGN(active->endp - active->first_avail + 1, BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; active->free_index = (APR_UINT32_TRUNC_CAST)free_index; node = active->next; if (free_index < node->free_index) { do { node = node->next; } while (free_index < node->free_index); list_remove(active); list_insert(active, node); } node = pool->active; } else { if ((node = allocator_alloc(pool->allocator, size)) == NULL) return -1; if (ps->got_a_new_node) { active->next = ps->free; ps->free = active; } ps->got_a_new_node = 1; } memcpy(node->first_avail, active->first_avail, cur_len); ps->node = node; ps->vbuff.curpos = node->first_avail + cur_len; ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */ return 0;}APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap){ struct psprintf_data ps; char *strp; apr_size_t size; apr_memnode_t *active, *node; apr_size_t free_index; ps.node = active = pool->active; ps.pool = pool; ps.vbuff.curpos = ps.node->first_avail; /* Save a byte for the NUL terminator */ ps.vbuff.endpos = ps.node->endp - 1; ps.got_a_new_node = 0; ps.free = NULL; /* Make sure that the first node passed to apr_vformatter has at least * room to hold the NUL terminator. */ if (ps.node->first_avail == ps.node->endp) { if (psprintf_flush(&ps.vbuff) == -1) { if (pool->abort_fn) { pool->abort_fn(APR_ENOMEM); } return NULL; } } if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } strp = ps.vbuff.curpos; *strp++ = '\0'; size = strp - ps.node->first_avail; size = APR_ALIGN_DEFAULT(size); strp = ps.node->first_avail; ps.node->first_avail += size; if (ps.free) allocator_free(pool->allocator, ps.free); /* * Link the node in if it's a new one */ if (!ps.got_a_new_node) return strp; active = pool->active; node = ps.node; node->free_index = 0; list_insert(node, active); pool->active = node; free_index = (APR_ALIGN(active->endp - active->first_avail + 1, BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; active->free_index = (APR_UINT32_TRUNC_CAST)free_index; node = active->next; if (free_index >= node->free_index) return strp; do { node = node->next; } while (free_index < node->free_index); list_remove(active); list_insert(active, node); return strp;}#else /* APR_POOL_DEBUG *//* * Debug helper functions *//* * Walk the pool tree rooted at pool, depth first. When fn returns * anything other than 0, abort the traversal and return the value * returned by fn. */static int apr_pool_walk_tree(apr_pool_t *pool, int (*fn)(apr_pool_t *pool, void *data), void *data){ int rv; apr_pool_t *child; rv = fn(pool, data); if (rv) return rv;#if APR_HAS_THREADS if (pool->mutex) { apr_thread_mutex_lock(pool->mutex); }#endif /* APR_HAS_THREADS */ child = pool->child; while (child) { rv = apr_pool_walk_tree(child, fn, data); if (rv) break; child = child->sibling; }#if APR_HAS_THREADS if (pool->mutex) { apr_thread_mutex_unlock(pool->mutex); }#endif /* APR_HAS_THREADS */ return rv;}#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)static void apr_pool_log_event(apr_pool_t *pool, const char *event, const char *file_line, int deref){ if (file_stderr) { if (deref) { apr_file_printf(file_stderr, "POOL DEBUG: " "[%lu"#if APR_HAS_THREADS "/%lu"#endif /* APR_HAS_THREADS */ "] " "%7s " "(%10lu/%10lu/%10lu) " "0x%08X \"%s\" " "<%s> " "(%u/%u/%u) " "\n", (unsigned long)getpid(),#if APR_HAS_THREADS (unsigned long)apr_os_thread_current(),#endif /* APR_HAS_THREADS */ event, (unsigned long)apr_pool_num_bytes(pool, 0), (unsigned long)apr_pool_num_bytes(pool, 1), (unsigned long)apr_pool_num_bytes(global_pool, 1), (unsigned int)pool, pool->tag, file_line, pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear); } else { apr_file_printf(file_stderr, "POOL DEBUG: " "[%lu"#if APR_HAS_THREADS "/%lu"#endif /* APR_HAS_THREADS */ "] " "%7s " " " "0x%08X " "<%s> " "\n", (unsigned long)getpid(),#if APR_HAS_THREADS (unsigned long)apr_os_thread_current(),#endif /* APR_HAS_THREADS */ event, (unsigned int)pool, file_line); } }}#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -