📄 apr_pools.c
字号:
*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 <= node_free_space(node)) { 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%pp \"%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), 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%pp " "<%s> " "\n", (unsigned long)getpid(),#if APR_HAS_THREADS (unsigned long)apr_os_thread_current(),#endif /* APR_HAS_THREADS */ event, pool, file_line); } }}#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)static int pool_is_child_of(apr_pool_t *parent, void *data){ apr_pool_t *pool = (apr_pool_t *)data; return (pool == parent);}static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent){ if (parent == NULL) return 0; return apr_pool_walk_tree(parent, pool_is_child_of, pool);}#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */static void apr_pool_check_integrity(apr_pool_t *pool){ /* Rule of thumb: use of the global pool is always * ok, since the only user is apr_pools.c. Unless * people have searched for the top level parent and * started to use that... */ if (pool == global_pool || global_pool == NULL) return; /* Lifetime * This basically checks to see if the pool being used is still * a relative to the global pool. If not it was previously * destroyed, in which case we abort(). */#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) if (!apr_pool_is_child_of(pool, global_pool)) {#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) apr_pool_log_event(pool, "LIFE", __FILE__ ":apr_pool_integrity check", 0);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ abort(); }#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */#if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER)#if APR_HAS_THREADS if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) {#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) apr_pool_log_event(pool, "THREAD", __FILE__ ":apr_pool_integrity check", 0);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ abort(); }#endif /* APR_HAS_THREADS */#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */}/* * Initialization (debug) */APR_DECLARE(apr_status_t) apr_pool_initialize(void){ apr_status_t rv;#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) char *logpath; apr_file_t *debug_log = NULL;#endif if (apr_pools_initialized++) return APR_SUCCESS; /* Since the debug code works a bit differently then the * regular pools code, we ask for a lock here. The regular * pools code has got this lock embedded in the global * allocator, a concept unknown to debug mode. */ if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, NULL)) != APR_SUCCESS) { return rv; } apr_pool_tag(global_pool, "APR global pool"); apr_pools_initialized = 1; /* This has to happen here because mutexes might be backed by * atomics. It used to be snug and safe in apr_initialize(). */ if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { return rv; }#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) rv = apr_env_get(&logpath, "APR_POOL_DEBUG_LOG", global_pool); /* Don't pass file_stderr directly to apr_file_open() here, since * apr_file_open() can call back to apr_pool_log_event() and that * may attempt to use then then non-NULL but partially set up file * object. */ if (rv == APR_SUCCESS) { apr_file_open(&debug_log, logpath, APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, global_pool); } else { apr_file_open_stderr(&debug_log, global_pool); } /* debug_log is now a file handle. */ file_stderr = debug_log; if (file_stderr) { apr_file_printf(file_stderr, "POOL DEBUG: [PID"#if APR_HAS_THREADS "/TID"#endif /* APR_HAS_THREADS */ "] ACTION (SIZE /POOL SIZE /TOTAL SIZE) " "POOL \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n"); apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0); }#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ return APR_SUCCESS;}APR_DECLARE(void) apr_pool_terminate(void){ if (!apr_pools_initialized) return; if (--apr_pools_initialized) return; apr_pool_destroy(global_pool); /* This will also destroy the mutex */ global_pool = NULL;#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) file_stderr = NULL;#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */}/* * Memory allocation (debug) */static void *pool_alloc(apr_pool_t *pool, apr_size_t size){ debug_node_t *node; void *mem; if ((mem = malloc(size)) == NULL) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } node = pool->nodes; if (node == NULL || node->index == 64) { if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { if (pool->abort_fn) pool->abort_fn(APR_ENOMEM); return NULL; } memset(node, 0, SIZEOF_DEBUG_NODE_T); node->next = pool->nodes; pool->nodes = node; node->index = 0; } node->beginp[node->index] = mem; node->endp[node->index] = (char *)mem + size; node->index++; pool->stat_alloc++; pool->stat_total_alloc++; return mem;}APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, const char *file_line){ void *mem; apr_pool_check_integrity(pool); mem = pool_alloc(pool, size);#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) apr_pool_log_event(pool, "PALLOC", file_line, 1);#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -