apr_pools.c
来自「Apache 2.0.63 is the current stable vers」· C语言 代码 · 共 2,297 行 · 第 1/5 页
C
2,297 行
apr_memnode_t *node, *active;
apr_size_t cur_len, size;
char *strp;
apr_pool_t *pool;
apr_uint32_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 = 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_uint32_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 = 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)
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_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)
apr_file_open_stderr(&file_stderr, global_pool);
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;
apr_pools_initialized = 0;
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) */
return mem;
}
APR_DECLARE(void *) apr_pcalloc_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);
memset(mem, 0, size);
#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC)
apr_pool_log_event(pool, "PCALLOC", file_line, 1);
#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
return mem;
}
/*
* Pool creation/destruction (debug)
*/
#define POOL_POISON_BYTE 'A'
static void pool_clear_debug(apr_pool_t *pool, const char *file_line)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?