Main Page | Modules | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages | Examples

apr_pools.c

Go to the documentation of this file.
00001 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
00002  * applicable.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "apr.h"
00018 #include "apr_private.h"
00019 
00020 #include "apr_atomic.h"
00021 #include "apr_portable.h" /* for get_os_proc */
00022 #include "apr_strings.h"
00023 #include "apr_general.h"
00024 #include "apr_pools.h"
00025 #include "apr_allocator.h"
00026 #include "apr_lib.h"
00027 #include "apr_thread_mutex.h"
00028 #include "apr_hash.h"
00029 #include "apr_time.h"
00030 #define APR_WANT_MEMFUNC
00031 #include "apr_want.h"
00032 
00033 #if APR_HAVE_STDLIB_H
00034 #include <stdlib.h>     /* for malloc, free and abort */
00035 #endif
00036 
00037 #if APR_HAVE_UNISTD_H
00038 #include <unistd.h>     /* for getpid */
00039 #endif
00040 
00041 
00042 /*
00043  * Magic numbers
00044  */
00045 
00046 #define MIN_ALLOC 8192
00047 #define MAX_INDEX   20
00048 
00049 #define BOUNDARY_INDEX 12
00050 #define BOUNDARY_SIZE (1 << BOUNDARY_INDEX)
00051 
00052 /* 
00053  * Timing constants for killing subprocesses
00054  * There is a total 3-second delay between sending a SIGINT 
00055  * and sending of the final SIGKILL.
00056  * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64
00057  * for the exponetial timeout alogrithm.
00058  */
00059 #define TIMEOUT_USECS    3000000
00060 #define TIMEOUT_INTERVAL   46875
00061 
00062 /*
00063  * Allocator
00064  */
00065 
00066 struct apr_allocator_t {
00067     apr_uint32_t        max_index;
00068     apr_uint32_t        max_free_index;
00069     apr_uint32_t        current_free_index;
00070 #if APR_HAS_THREADS
00071     apr_thread_mutex_t *mutex;
00072 #endif /* APR_HAS_THREADS */
00073     apr_pool_t         *owner;
00074     apr_memnode_t      *free[MAX_INDEX];
00075 };
00076 
00077 #define SIZEOF_ALLOCATOR_T  APR_ALIGN_DEFAULT(sizeof(apr_allocator_t))
00078 
00079 
00080 /*
00081  * Allocator
00082  */
00083 
00084 APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator)
00085 {
00086     apr_allocator_t *new_allocator;
00087 
00088     *allocator = NULL;
00089 
00090     if ((new_allocator = malloc(SIZEOF_ALLOCATOR_T)) == NULL)
00091         return APR_ENOMEM;
00092 
00093     memset(new_allocator, 0, SIZEOF_ALLOCATOR_T);
00094     new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
00095 
00096     *allocator = new_allocator;
00097 
00098     return APR_SUCCESS;
00099 }
00100 
00101 APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator)
00102 {
00103     apr_uint32_t index;
00104     apr_memnode_t *node, **ref;
00105 
00106     for (index = 0; index < MAX_INDEX; index++) {
00107         ref = &allocator->free[index];
00108         while ((node = *ref) != NULL) {
00109             *ref = node->next;
00110             free(node);
00111         }
00112     }
00113 
00114     free(allocator);
00115 }
00116 
00117 #if APR_HAS_THREADS
00118 APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator,
00119                                           apr_thread_mutex_t *mutex)
00120 {
00121     allocator->mutex = mutex;
00122 }
00123 
00124 APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get(
00125                                       apr_allocator_t *allocator)
00126 {
00127     return allocator->mutex;
00128 }
00129 #endif /* APR_HAS_THREADS */
00130 
00131 APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator,
00132                                           apr_pool_t *pool)
00133 {
00134     allocator->owner = pool;
00135 }
00136 
00137 APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator)
00138 {
00139     return allocator->owner;
00140 }
00141 
00142 APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator,
00143                                              apr_size_t size)
00144 {
00145     apr_uint32_t max_free_index;
00146 
00147 #if APR_HAS_THREADS
00148     apr_thread_mutex_t *mutex;
00149 
00150     mutex = apr_allocator_mutex_get(allocator);
00151     if (mutex != NULL)
00152         apr_thread_mutex_lock(mutex);
00153 #endif /* APR_HAS_THREADS */
00154 
00155     max_free_index = APR_ALIGN(size, BOUNDARY_SIZE) >> BOUNDARY_INDEX;
00156     allocator->current_free_index += max_free_index;
00157     allocator->current_free_index -= allocator->max_free_index;
00158     allocator->max_free_index = max_free_index;
00159     if (allocator->current_free_index > max_free_index)
00160         allocator->current_free_index = max_free_index;
00161 
00162 #if APR_HAS_THREADS
00163     if (mutex != NULL)
00164         apr_thread_mutex_unlock(mutex);
00165 #endif
00166 }
00167 
00168 static APR_INLINE
00169 apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t size)
00170 {
00171     apr_memnode_t *node, **ref;
00172     apr_uint32_t i, index, max_index;
00173 
00174     /* Round up the block size to the next boundary, but always
00175      * allocate at least a certain size (MIN_ALLOC).
00176      */
00177     size = APR_ALIGN(size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE);
00178     if (size < MIN_ALLOC)
00179         size = MIN_ALLOC;
00180 
00181     /* Find the index for this node size by
00182      * dividing its size by the boundary size
00183      */
00184     index = (size >> BOUNDARY_INDEX) - 1;
00185 
00186     /* First see if there are any nodes in the area we know
00187      * our node will fit into.
00188      */
00189     if (index <= allocator->max_index) {
00190 #if APR_HAS_THREADS
00191         if (allocator->mutex)
00192             apr_thread_mutex_lock(allocator->mutex);
00193 #endif /* APR_HAS_THREADS */
00194 
00195         /* Walk the free list to see if there are
00196          * any nodes on it of the requested size
00197          *
00198          * NOTE: an optimization would be to check
00199          * allocator->free[index] first and if no
00200          * node is present, directly use
00201          * allocator->free[max_index].  This seems
00202          * like overkill though and could cause
00203          * memory waste.
00204          */
00205         max_index = allocator->max_index;
00206         ref = &allocator->free[index];
00207         i = index;
00208         while (*ref == NULL && i < max_index) {
00209            ref++;
00210            i++;
00211         }
00212 
00213         if ((node = *ref) != NULL) {
00214             /* If we have found a node and it doesn't have any
00215              * nodes waiting in line behind it _and_ we are on
00216              * the highest available index, find the new highest
00217              * available index
00218              */
00219             if ((*ref = node->next) == NULL && i >= max_index) {
00220                 do {
00221                     ref--;
00222                     max_index--;
00223                 }
00224                 while (*ref == NULL && max_index > 0);
00225 
00226                 allocator->max_index = max_index;
00227             }
00228 
00229             allocator->current_free_index += node->index;
00230             if (allocator->current_free_index > allocator->max_free_index)
00231                 allocator->current_free_index = allocator->max_free_index;
00232 
00233 #if APR_HAS_THREADS
00234             if (allocator->mutex)
00235                 apr_thread_mutex_unlock(allocator->mutex);
00236 #endif /* APR_HAS_THREADS */
00237 
00238             node->next = NULL;
00239             node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
00240 
00241             return node;
00242         }
00243 
00244 #if APR_HAS_THREADS
00245         if (allocator->mutex)
00246             apr_thread_mutex_unlock(allocator->mutex);
00247 #endif /* APR_HAS_THREADS */
00248     }
00249 
00250     /* If we found nothing, seek the sink (at index 0), if
00251      * it is not empty.
00252      */
00253     else if (allocator->free[0]) {
00254 #if APR_HAS_THREADS
00255         if (allocator->mutex)
00256             apr_thread_mutex_lock(allocator->mutex);
00257 #endif /* APR_HAS_THREADS */
00258 
00259         /* Walk the free list to see if there are
00260          * any nodes on it of the requested size
00261          */
00262         ref = &allocator->free[0];
00263         while ((node = *ref) != NULL && index > node->index)
00264             ref = &node->next;
00265 
00266         if (node) {
00267             *ref = node->next;
00268 
00269             allocator->current_free_index += node->index;
00270             if (allocator->current_free_index > allocator->max_free_index)
00271                 allocator->current_free_index = allocator->max_free_index;
00272 
00273 #if APR_HAS_THREADS
00274             if (allocator->mutex)
00275                 apr_thread_mutex_unlock(allocator->mutex);
00276 #endif /* APR_HAS_THREADS */
00277 
00278             node->next = NULL;
00279             node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
00280 
00281             return node;
00282         }
00283 
00284 #if APR_HAS_THREADS
00285         if (allocator->mutex)
00286             apr_thread_mutex_unlock(allocator->mutex);
00287 #endif /* APR_HAS_THREADS */
00288     }
00289 
00290     /* If we haven't got a suitable node, malloc a new one
00291      * and initialize it.
00292      */
00293     if ((node = malloc(size)) == NULL)
00294         return NULL;
00295 
00296     node->next = NULL;
00297     node->index = index;
00298     node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
00299     node->endp = (char *)node + size;
00300 
00301     return node;
00302 }
00303 
00304 static APR_INLINE
00305 void allocator_free(apr_allocator_t *allocator, apr_memnode_t *node)
00306 {
00307     apr_memnode_t *next, *freelist = NULL;
00308     apr_uint32_t index, max_index;
00309     apr_uint32_t max_free_index, current_free_index;
00310 
00311 #if APR_HAS_THREADS
00312     if (allocator->mutex)
00313         apr_thread_mutex_lock(allocator->mutex);
00314 #endif /* APR_HAS_THREADS */
00315 
00316     max_index = allocator->max_index;
00317     max_free_index = allocator->max_free_index;
00318     current_free_index = allocator->current_free_index;
00319 
00320     /* Walk the list of submitted nodes and free them one by one,
00321      * shoving them in the right 'size' buckets as we go.
00322      */
00323     do {
00324         next = node->next;
00325         index = node->index;
00326 
00327         if (max_free_index != APR_ALLOCATOR_MAX_FREE_UNLIMITED
00328             && index > current_free_index) {
00329             node->next = freelist;
00330             freelist = node;
00331         }
00332         else if (index < MAX_INDEX) {
00333             /* Add the node to the appropiate 'size' bucket.  Adjust
00334              * the max_index when appropiate.
00335              */
00336             if ((node->next = allocator->free[index]) == NULL
00337                 && index > max_index) {
00338                 max_index = index;
00339             }
00340             allocator->free[index] = node;
00341             current_free_index -= index;
00342         }
00343         else {
00344             /* This node is too large to keep in a specific size bucket,
00345              * just add it to the sink (at index 0).
00346              */
00347             node->next = allocator->free[0];
00348             allocator->free[0] = node;
00349             current_free_index -= index;
00350         }
00351     } while ((node = next) != NULL);
00352 
00353     allocator->max_index = max_index;
00354     allocator->current_free_index = current_free_index;
00355 
00356 #if APR_HAS_THREADS
00357     if (allocator->mutex)
00358         apr_thread_mutex_unlock(allocator->mutex);
00359 #endif /* APR_HAS_THREADS */
00360 
00361     while (freelist != NULL) {
00362         node = freelist;
00363         freelist = node->next;
00364         free(node);
00365     }
00366 }
00367 
00368 APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator,
00369                                                  apr_size_t size)
00370 {
00371     return allocator_alloc(allocator, size);
00372 }
00373 
00374 APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator,
00375                                      apr_memnode_t *node)
00376 {
00377     allocator_free(allocator, node);
00378 }
00379 
00380 
00381 
00382 /*
00383  * Debug level
00384  */
00385 
00386 #define APR_POOL_DEBUG_GENERAL  0x01
00387 #define APR_POOL_DEBUG_VERBOSE  0x02
00388 #define APR_POOL_DEBUG_LIFETIME 0x04
00389 #define APR_POOL_DEBUG_OWNER    0x08
00390 #define APR_POOL_DEBUG_VERBOSE_ALLOC 0x10
00391 
00392 #define APR_POOL_DEBUG_VERBOSE_ALL (APR_POOL_DEBUG_VERBOSE \
00393                                     | APR_POOL_DEBUG_VERBOSE_ALLOC)
00394 
00395 
00396 /*
00397  * Structures
00398  */
00399 
00400 typedef struct cleanup_t cleanup_t;
00401 
00402 /** A list of processes */
00403 struct process_chain {
00404     /** The process ID */
00405     apr_proc_t *proc;
00406     apr_kill_conditions_e kill_how;
00407     /** The next process in the list */
00408     struct process_chain *next;
00409 };
00410 
00411 
00412 #if APR_POOL_DEBUG
00413 
00414 typedef struct debug_node_t debug_node_t;
00415 
00416 struct debug_node_t {
00417     debug_node_t *next;
00418     apr_uint32_t  index;
00419     void         *beginp[64];
00420     void         *endp[64];
00421 };
00422 
00423 #define SIZEOF_DEBUG_NODE_T APR_ALIGN_DEFAULT(sizeof(debug_node_t))
00424 
00425 #endif /* APR_POOL_DEBUG */
00426 
00427 /* The ref field in the apr_pool_t struct holds a
00428  * pointer to the pointer referencing this pool.
00429  * It is used for parent, child, sibling management.
00430  * Look at apr_pool_create_ex() and apr_pool_destroy()
00431  * to see how it is used.
00432  */
00433 struct apr_pool_t {
00434     apr_pool_t           *parent;
00435     apr_pool_t           *child;
00436     apr_pool_t           *sibling;
00437     apr_pool_t          **ref;
00438     cleanup_t            *cleanups;
00439     apr_allocator_t      *allocator;
00440     struct process_chain *subprocesses;
00441     apr_abortfunc_t       abort_fn;
00442     apr_hash_t           *user_data;
00443     const char           *tag;
00444 
00445 #if !APR_POOL_DEBUG
00446     apr_memnode_t        *active;
00447     apr_memnode_t        *self; /* The node containing the pool itself */
00448     char                 *self_first_avail;
00449 
00450 #else /* APR_POOL_DEBUG */
00451     debug_node_t         *nodes;
00452     const char           *file_line;
00453     apr_uint32_t          creation_flags;
00454     unsigned int          stat_alloc;
00455     unsigned int          stat_total_alloc;
00456     unsigned int          stat_clear;
00457 #if APR_HAS_THREADS
00458     apr_os_thread_t       owner;
00459     apr_thread_mutex_t   *mutex;
00460 #endif /* APR_HAS_THREADS */
00461 #endif /* APR_POOL_DEBUG */
00462 #ifdef NETWARE
00463     apr_os_proc_t         owner_proc;
00464 #endif /* defined(NETWARE) */
00465 };
00466 
00467 #define SIZEOF_POOL_T       APR_ALIGN_DEFAULT(sizeof(apr_pool_t))
00468 
00469 
00470 /*
00471  * Variables
00472  */
00473 
00474 static apr_byte_t   apr_pools_initialized = 0;
00475 static apr_pool_t  *global_pool = NULL;
00476 
00477 #if !APR_POOL_DEBUG
00478 static apr_allocator_t *global_allocator = NULL;
00479 #endif /* !APR_POOL_DEBUG */
00480 
00481 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
00482 static apr_file_t *file_stderr = NULL;
00483 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
00484 
00485 /*
00486  * Local functions
00487  */
00488 
00489 static void run_cleanups(cleanup_t **c);
00490 static void run_child_cleanups(cleanup_t **c);
00491 static void free_proc_chain(struct process_chain *procs);
00492 
00493 
00494 #if !APR_POOL_DEBUG
00495 /*
00496  * Initialization
00497  */
00498 
00499 APR_DECLARE(apr_status_t) apr_pool_initialize(void)
00500 {
00501     apr_status_t rv;
00502 
00503     if (apr_pools_initialized++)
00504         return APR_SUCCESS;
00505 
00506     if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) {
00507         apr_pools_initialized = 0;
00508         return rv;
00509     }
00510 
00511     if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL,
00512                                  global_allocator)) != APR_SUCCESS) {
00513         apr_allocator_destroy(global_allocator);
00514         global_allocator = NULL;
00515         apr_pools_initialized = 0;
00516         return rv;
00517     }
00518 
00519     apr_pool_tag(global_pool, "apr_global_pool");
00520 
00521     /* This has to happen here because mutexes might be backed by
00522      * atomics.  It used to be snug and safe in apr_initialize().
00523      */
00524     if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) {
00525         return rv;
00526     }
00527 
00528 #if APR_HAS_THREADS
00529     {
00530         apr_thread_mutex_t *mutex;
00531 
00532         if ((rv = apr_thread_mutex_create(&mutex,
00533                                           APR_THREAD_MUTEX_DEFAULT,
00534                                           global_pool)) != APR_SUCCESS) {
00535             return rv;
00536         }
00537 
00538         apr_allocator_mutex_set(global_allocator, mutex);
00539     }
00540 #endif /* APR_HAS_THREADS */
00541 
00542     apr_allocator_owner_set(global_allocator, global_pool);
00543 
00544     return APR_SUCCESS;
00545 }
00546 
00547 APR_DECLARE(void) apr_pool_terminate(void)
00548 {
00549     if (!apr_pools_initialized)
00550         return;
00551 
00552     if (--apr_pools_initialized)
00553         return;
00554 
00555     apr_pool_destroy(global_pool); /* This will also destroy the mutex */
00556     global_pool = NULL;
00557 
00558     global_allocator = NULL;
00559 }
00560 
00561 #ifdef NETWARE
00562 void netware_pool_proc_cleanup ()
00563 {
00564     apr_pool_t *pool = global_pool->child;
00565     apr_os_proc_t owner_proc = (apr_os_proc_t)getnlmhandle();
00566 
00567     while (pool) {
00568         if (pool->owner_proc == owner_proc) {
00569             apr_pool_destroy (pool);
00570             pool = global_pool->child;
00571         }
00572         else {
00573             pool = pool->sibling;
00574         }
00575     }
00576     return;
00577 }
00578 #endif /* defined(NETWARE) */
00579 
00580 /* Node list management helper macros; list_insert() inserts 'node'
00581  * before 'point'. */
00582 #define list_insert(node, point) do {           \
00583     node->ref = point->ref;                     \
00584     *node->ref = node;                          \
00585     node->next = point;                         \
00586     point->ref = &node->next;                   \
00587 } while (0)
00588 
00589 /* list_remove() removes 'node' from its list. */
00590 #define list_remove(node) do {                  \
00591     *node->ref = node->next;                    \
00592     node->next->ref = node->ref;                \
00593 } while (0)
00594 
00595 /*
00596  * Memory allocation
00597  */
00598 
00599 APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size)
00600 {
00601     apr_memnode_t *active, *node;
00602     void *mem;
00603     apr_uint32_t free_index;
00604 
00605     size = APR_ALIGN_DEFAULT(size);
00606     active = pool->active;
00607 
00608     /* If the active node has enough bytes left, use it. */
00609     if (size < (apr_size_t)(active->endp - active->first_avail)) {
00610         mem = active->first_avail;
00611         active->first_avail += size;
00612 
00613         return mem;
00614     }
00615 
00616     node = active->next;
00617     if (size < (apr_size_t)(node->endp - node->first_avail)) {
00618         list_remove(node);
00619     }
00620     else {
00621         if ((node = allocator_alloc(pool->allocator, size)) == NULL) {
00622             if (pool->abort_fn)
00623                 pool->abort_fn(APR_ENOMEM);
00624 
00625             return NULL;
00626         }
00627     }
00628 
00629     node->free_index = 0;
00630 
00631     mem = node->first_avail;
00632     node->first_avail += size;
00633 
00634     list_insert(node, active);
00635 
00636     pool->active = node;
00637 
00638     free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
00639                             BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
00640 
00641     active->free_index = free_index;
00642     node = active->next;
00643     if (free_index >= node->free_index)
00644         return mem;
00645 
00646     do {
00647         node = node->next;
00648     }
00649     while (free_index < node->free_index);
00650 
00651     list_remove(active);
00652     list_insert(active, node);
00653 
00654     return mem;
00655 }
00656 
00657 /* Provide an implementation of apr_pcalloc for backward compatibility
00658  * with code built before apr_pcalloc was a macro
00659  */
00660 
00661 #ifdef apr_pcalloc
00662 #undef apr_pcalloc
00663 #endif
00664 
00665 APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size);
00666 APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size)
00667 {
00668     void *mem;
00669 
00670     size = APR_ALIGN_DEFAULT(size);
00671     if ((mem = apr_palloc(pool, size)) != NULL) {
00672         memset(mem, 0, size);
00673     }
00674 
00675     return mem;
00676 }
00677 
00678 
00679 /*
00680  * Pool creation/destruction
00681  */
00682 
00683 APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool)
00684 {
00685     apr_memnode_t *active;
00686 
00687     /* Destroy the subpools.  The subpools will detach themselves from
00688      * this pool thus this loop is safe and easy.
00689      */
00690     while (pool->child)
00691         apr_pool_destroy(pool->child);
00692 
00693     /* Run cleanups */
00694     run_cleanups(&pool->cleanups);
00695     pool->cleanups = NULL;
00696 
00697     /* Free subprocesses */
00698     free_proc_chain(pool->subprocesses);
00699     pool->subprocesses = NULL;
00700 
00701     /* Clear the user data. */
00702     pool->user_data = NULL;
00703 
00704     /* Find the node attached to the pool structure, reset it, make
00705      * it the active node and free the rest of the nodes.
00706      */
00707     active = pool->active = pool->self;
00708     active->first_avail = pool->self_first_avail;
00709 
00710     if (active->next == active)
00711         return;
00712 
00713     *active->ref = NULL;
00714     allocator_free(pool->allocator, active->next);
00715     active->next = active;
00716     active->ref = &active->next;
00717 }
00718 
00719 APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool)
00720 {
00721     apr_memnode_t *active;
00722     apr_allocator_t *allocator;
00723 
00724     /* Destroy the subpools.  The subpools will detach themselve from
00725      * this pool thus this loop is safe and easy.
00726      */
00727     while (pool->child)
00728         apr_pool_destroy(pool->child);
00729 
00730     /* Run cleanups */
00731     run_cleanups(&pool->cleanups);
00732 
00733     /* Free subprocesses */
00734     free_proc_chain(pool->subprocesses);
00735 
00736     /* Remove the pool from the parents child list */
00737     if (pool->parent) {
00738 #if APR_HAS_THREADS
00739         apr_thread_mutex_t *mutex;
00740 
00741         if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL)
00742             apr_thread_mutex_lock(mutex);
00743 #endif /* APR_HAS_THREADS */
00744 
00745         if ((*pool->ref = pool->sibling) != NULL)
00746             pool->sibling->ref = pool->ref;
00747 
00748 #if APR_HAS_THREADS
00749         if (mutex)
00750             apr_thread_mutex_unlock(mutex);
00751 #endif /* APR_HAS_THREADS */
00752     }
00753 
00754     /* Find the block attached to the pool structure.  Save a copy of the
00755      * allocator pointer, because the pool struct soon will be no more.
00756      */
00757     allocator = pool->allocator;
00758     active = pool->self;
00759     *active->ref = NULL;
00760 
00761 #if APR_HAS_THREADS
00762     if (apr_allocator_owner_get(allocator) == pool) {
00763         /* Make sure to remove the lock, since it is highly likely to
00764          * be invalid now.
00765          */
00766         apr_allocator_mutex_set(allocator, NULL);
00767     }
00768 #endif /* APR_HAS_THREADS */
00769 
00770     /* Free all the nodes in the pool (including the node holding the
00771      * pool struct), by giving them back to the allocator.
00772      */
00773     allocator_free(allocator, active);
00774 
00775     /* If this pool happens to be the owner of the allocator, free
00776      * everything in the allocator (that includes the pool struct
00777      * and the allocator).  Don't worry about destroying the optional mutex
00778      * in the allocator, it will have been destroyed by the cleanup function.
00779      */
00780     if (apr_allocator_owner_get(allocator) == pool) {
00781         apr_allocator_destroy(allocator);
00782     }
00783 }
00784 
00785 APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
00786                                              apr_pool_t *parent,
00787                                              apr_abortfunc_t abort_fn,
00788                                              apr_allocator_t *allocator)
00789 {
00790     apr_pool_t *pool;
00791     apr_memnode_t *node;
00792 
00793     *newpool = NULL;
00794 
00795     if (!parent)
00796         parent = global_pool;
00797 
00798     if (!abort_fn && parent)
00799         abort_fn = parent->abort_fn;
00800 
00801     if (allocator == NULL)
00802         allocator = parent->allocator;
00803 
00804     if ((node = allocator_alloc(allocator,
00805                                 MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
00806         if (abort_fn)
00807             abort_fn(APR_ENOMEM);
00808 
00809         return APR_ENOMEM;
00810     }
00811 
00812     node->next = node;
00813     node->ref = &node->next;
00814 
00815     pool = (apr_pool_t *)node->first_avail;
00816     node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T;
00817 
00818     pool->allocator = allocator;
00819     pool->active = pool->self = node;
00820     pool->abort_fn = abort_fn;
00821     pool->child = NULL;
00822     pool->cleanups = NULL;
00823     pool->subprocesses = NULL;
00824     pool->user_data = NULL;
00825     pool->tag = NULL;
00826 
00827 #ifdef NETWARE
00828     pool->owner_proc = (apr_os_proc_t)getnlmhandle();
00829 #endif /* defined(NETWARE) */
00830 
00831     if ((pool->parent = parent) != NULL) {
00832 #if APR_HAS_THREADS
00833         apr_thread_mutex_t *mutex;
00834 
00835         if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL)
00836             apr_thread_mutex_lock(mutex);
00837 #endif /* APR_HAS_THREADS */
00838 
00839         if ((pool->sibling = parent->child) != NULL)
00840             pool->sibling->ref = &pool->sibling;
00841 
00842         parent->child = pool;
00843         pool->ref = &parent->child;
00844 
00845 #if APR_HAS_THREADS
00846         if (mutex)
00847             apr_thread_mutex_unlock(mutex);
00848 #endif /* APR_HAS_THREADS */
00849     }
00850     else {
00851         pool->sibling = NULL;
00852         pool->ref = NULL;
00853     }
00854 
00855     *newpool = pool;
00856 
00857     return APR_SUCCESS;
00858 }
00859 
00860 
00861 /*
00862  * "Print" functions
00863  */
00864 
00865 /*
00866  * apr_psprintf is implemented by writing directly into the current
00867  * block of the pool, starting right at first_avail.  If there's
00868  * insufficient room, then a new block is allocated and the earlier
00869  * output is copied over.  The new block isn't linked into the pool
00870  * until all the output is done.
00871  *
00872  * Note that this is completely safe because nothing else can
00873  * allocate in this apr_pool_t while apr_psprintf is running.  alarms are
00874  * blocked, and the only thing outside of apr_pools.c that's invoked
00875  * is apr_vformatter -- which was purposefully written to be
00876  * self-contained with no callouts.
00877  */
00878 
00879 struct psprintf_data {
00880     apr_vformatter_buff_t vbuff;
00881     apr_memnode_t   *node;
00882     apr_pool_t      *pool;
00883     apr_byte_t       got_a_new_node;
00884     apr_memnode_t   *free;
00885 };
00886 
00887 #define APR_PSPRINTF_MIN_STRINGSIZE 32
00888 
00889 static int psprintf_flush(apr_vformatter_buff_t *vbuff)
00890 {
00891     struct psprintf_data *ps = (struct psprintf_data *)vbuff;
00892     apr_memnode_t *node, *active;
00893     apr_size_t cur_len, size;
00894     char *strp;
00895     apr_pool_t *pool;
00896     apr_uint32_t free_index;
00897 
00898     pool = ps->pool;
00899     active = ps->node;
00900     strp = ps->vbuff.curpos;
00901     cur_len = strp - active->first_avail;
00902     size = cur_len << 1;
00903 
00904     /* Make sure that we don't try to use a block that has less
00905      * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it.  This
00906      * also catches the case where size == 0, which would result
00907      * in reusing a block that can't even hold the NUL byte.
00908      */
00909     if (size < APR_PSPRINTF_MIN_STRINGSIZE)
00910         size = APR_PSPRINTF_MIN_STRINGSIZE;
00911 
00912     node = active->next;
00913     if (!ps->got_a_new_node
00914         && size < (apr_size_t)(node->endp - node->first_avail)) {
00915 
00916         list_remove(node);
00917         list_insert(node, active);
00918 
00919         node->free_index = 0;
00920 
00921         pool->active = node;
00922 
00923         free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
00924                                 BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
00925 
00926         active->free_index = free_index;
00927         node = active->next;
00928         if (free_index < node->free_index) {
00929             do {
00930                 node = node->next;
00931             }
00932             while (free_index < node->free_index);
00933 
00934             list_remove(active);
00935             list_insert(active, node);
00936         }
00937 
00938         node = pool->active;
00939     }
00940     else {
00941         if ((node = allocator_alloc(pool->allocator, size)) == NULL)
00942             return -1;
00943 
00944         if (ps->got_a_new_node) {
00945             active->next = ps->free;
00946             ps->free = active;
00947         }
00948 
00949         ps->got_a_new_node = 1;
00950     }
00951 
00952     memcpy(node->first_avail, active->first_avail, cur_len);
00953 
00954     ps->node = node;
00955     ps->vbuff.curpos = node->first_avail + cur_len;
00956     ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */
00957 
00958     return 0;
00959 }
00960 
00961 APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap)
00962 {
00963     struct psprintf_data ps;
00964     char *strp;
00965     apr_size_t size;
00966     apr_memnode_t *active, *node;
00967     apr_uint32_t free_index;
00968 
00969     ps.node = active = pool->active;
00970     ps.pool = pool;
00971     ps.vbuff.curpos  = ps.node->first_avail;
00972 
00973     /* Save a byte for the NUL terminator */
00974     ps.vbuff.endpos = ps.node->endp - 1;
00975     ps.got_a_new_node = 0;
00976     ps.free = NULL;
00977 
00978     /* Make sure that the first node passed to apr_vformatter has at least
00979      * room to hold the NUL terminator.
00980      */
00981     if (ps.node->first_avail == ps.node->endp) {
00982         if (psprintf_flush(&ps.vbuff) == -1) {
00983             if (pool->abort_fn) {
00984                 pool->abort_fn(APR_ENOMEM);
00985             }
00986 
00987             return NULL;
00988         }
00989     }
00990 
00991     if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) {
00992         if (pool->abort_fn)
00993             pool->abort_fn(APR_ENOMEM);
00994 
00995         return NULL;
00996     }
00997 
00998     strp = ps.vbuff.curpos;
00999     *strp++ = '\0';
01000 
01001     size = strp - ps.node->first_avail;
01002     size = APR_ALIGN_DEFAULT(size);
01003     strp = ps.node->first_avail;
01004     ps.node->first_avail += size;
01005 
01006     if (ps.free)
01007         allocator_free(pool->allocator, ps.free);
01008 
01009     /*
01010      * Link the node in if it's a new one
01011      */
01012     if (!ps.got_a_new_node)
01013         return strp;
01014 
01015     active = pool->active;
01016     node = ps.node;
01017 
01018     node->free_index = 0;
01019 
01020     list_insert(node, active);
01021 
01022     pool->active = node;
01023 
01024     free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
01025                             BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
01026 
01027     active->free_index = free_index;
01028     node = active->next;
01029 
01030     if (free_index >= node->free_index)
01031         return strp;
01032 
01033     do {
01034         node = node->next;
01035     }
01036     while (free_index < node->free_index);
01037 
01038     list_remove(active);
01039     list_insert(active, node);
01040 
01041     return strp;
01042 }
01043 
01044 
01045 #else /* APR_POOL_DEBUG */
01046 /*
01047  * Debug helper functions
01048  */
01049 
01050 
01051 /*
01052  * Walk the pool tree rooted at pool, depth first.  When fn returns
01053  * anything other than 0, abort the traversal and return the value
01054  * returned by fn.
01055  */
01056 static int apr_pool_walk_tree(apr_pool_t *pool,
01057                               int (*fn)(apr_pool_t *pool, void *data),
01058                               void *data)
01059 {
01060     int rv;
01061     apr_pool_t *child;
01062 
01063     rv = fn(pool, data);
01064     if (rv)
01065         return rv;
01066 
01067 #if APR_HAS_THREADS
01068     if (pool->mutex) {
01069         apr_thread_mutex_lock(pool->mutex);
01070                         }
01071 #endif /* APR_HAS_THREADS */
01072 
01073     child = pool->child;
01074     while (child) {
01075         rv = apr_pool_walk_tree(child, fn, data);
01076         if (rv)
01077             break;
01078 
01079         child = child->sibling;
01080     }
01081 
01082 #if APR_HAS_THREADS
01083     if (pool->mutex) {
01084         apr_thread_mutex_unlock(pool->mutex);
01085     }
01086 #endif /* APR_HAS_THREADS */
01087 
01088     return rv;
01089 }
01090 
01091 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
01092 static void apr_pool_log_event(apr_pool_t *pool, const char *event,
01093                                const char *file_line, int deref)
01094 {
01095     if (file_stderr) {
01096         if (deref) {
01097             apr_file_printf(file_stderr,
01098                 "POOL DEBUG: "
01099                 "[%lu"
01100 #if APR_HAS_THREADS
01101                 "/%lu"
01102 #endif /* APR_HAS_THREADS */
01103                 "] "
01104                 "%7s "
01105                 "(%10lu/%10lu/%10lu) "
01106                 "0x%08X \"%s\" "
01107                 "<%s> "
01108                 "(%u/%u/%u) "
01109                 "\n",
01110                 (unsigned long)getpid(),
01111 #if APR_HAS_THREADS
01112                 (unsigned long)apr_os_thread_current(),
01113 #endif /* APR_HAS_THREADS */
01114                 event,
01115                 (unsigned long)apr_pool_num_bytes(pool, 0),
01116                 (unsigned long)apr_pool_num_bytes(pool, 1),
01117                 (unsigned long)apr_pool_num_bytes(global_pool, 1),
01118                 (unsigned int)pool, pool->tag,
01119                 file_line,
01120                 pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear);
01121         }
01122         else {
01123             apr_file_printf(file_stderr,
01124                 "POOL DEBUG: "
01125                 "[%lu"
01126 #if APR_HAS_THREADS
01127                 "/%lu"
01128 #endif /* APR_HAS_THREADS */
01129                 "] "
01130                 "%7s "
01131                 "                                   "
01132                 "0x%08X "
01133                 "<%s> "
01134                 "\n",
01135                 (unsigned long)getpid(),
01136 #if APR_HAS_THREADS
01137                 (unsigned long)apr_os_thread_current(),
01138 #endif /* APR_HAS_THREADS */
01139                 event,
01140                 (unsigned int)pool,
01141                 file_line);
01142         }
01143     }
01144 }
01145 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
01146 
01147 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)
01148 static int pool_is_child_of(apr_pool_t *parent, void *data)
01149 {
01150     apr_pool_t *pool = (apr_pool_t *)data;
01151 
01152     return (pool == parent);
01153 }
01154 
01155 static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent)
01156 {
01157     if (parent == NULL)
01158         return 0;
01159 
01160     return apr_pool_walk_tree(parent, pool_is_child_of, pool);
01161 }
01162 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */
01163 
01164 static void apr_pool_check_integrity(apr_pool_t *pool)
01165 {
01166     /* Rule of thumb: use of the global pool is always
01167      * ok, since the only user is apr_pools.c.  Unless
01168      * people have searched for the top level parent and
01169      * started to use that...
01170      */
01171     if (pool == global_pool || global_pool == NULL)
01172         return;
01173 
01174     /* Lifetime
01175      * This basically checks to see if the pool being used is still
01176      * a relative to the global pool.  If not it was previously
01177      * destroyed, in which case we abort().
01178      */
01179 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)
01180     if (!apr_pool_is_child_of(pool, global_pool)) {
01181 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
01182         apr_pool_log_event(pool, "LIFE",
01183                            __FILE__ ":apr_pool_integrity check", 0);
01184 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
01185         abort();
01186     }
01187 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */
01188 
01189 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER)
01190 #if APR_HAS_THREADS
01191     if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) {
01192 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
01193         apr_pool_log_event(pool, "THREAD",
01194                            __FILE__ ":apr_pool_integrity check", 0);
01195 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
01196         abort();
01197     }
01198 #endif /* APR_HAS_THREADS */
01199 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */
01200 }
01201 
01202 
01203 /*
01204  * Initialization (debug)
01205  */
01206 
01207 APR_DECLARE(apr_status_t) apr_pool_initialize(void)
01208 {
01209     apr_status_t rv;
01210 
01211     if (apr_pools_initialized++)
01212         return APR_SUCCESS;
01213 
01214     /* Since the debug code works a bit differently then the
01215      * regular pools code, we ask for a lock here.  The regular
01216      * pools code has got this lock embedded in the global
01217      * allocator, a concept unknown to debug mode.
01218      */
01219     if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL,
01220                                  NULL)) != APR_SUCCESS) {
01221         return rv;
01222     }
01223 
01224     apr_pool_tag(global_pool, "APR global pool");
01225 
01226     apr_pools_initialized = 1;
01227 
01228     /* This has to happen here because mutexes might be backed by
01229      * atomics.  It used to be snug and safe in apr_initialize().
01230      */
01231     if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) {
01232         return rv;
01233     }
01234 
01235 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
01236     apr_file_open_stderr(&file_stderr, global_pool);
01237     if (file_stderr) {
01238         apr_file_printf(file_stderr,
01239             "POOL DEBUG: [PID"
01240 #if APR_HAS_THREADS
01241             "/TID"
01242 #endif /* APR_HAS_THREADS */
01243             "] ACTION  (SIZE      /POOL SIZE /TOTAL SIZE) "
01244             "POOL       \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n");
01245 
01246         apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0);
01247     }
01248 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
01249 
01250     return APR_SUCCESS;
01251 }
01252 
01253 APR_DECLARE(void) apr_pool_terminate(void)
01254 {
01255     if (!apr_pools_initialized)
01256         return;
01257 
01258     apr_pools_initialized = 0;
01259 
01260     apr_pool_destroy(global_pool); /* This will also destroy the mutex */
01261     global_pool = NULL;
01262 
01263 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
01264     file_stderr = NULL;
01265 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
01266 }
01267 
01268 
01269 /*
01270  * Memory allocation (debug)
01271  */
01272 
01273 static void *pool_alloc(apr_pool_t *pool, apr_size_t size)
01274 {
01275     debug_node_t *node;
01276     void *mem;
01277 
01278     if ((mem = malloc(size)) == NULL) {
01279         if (pool->abort_fn)
01280             pool->abort_fn(APR_ENOMEM);
01281 
01282         return NULL;
01283     }
01284 
01285     node = pool->nodes;
01286     if (node == NULL || node->index == 64) {
01287         if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) {
01288             if (pool->abort_fn)
01289                 pool->abort_fn(APR_ENOMEM);
01290 
01291             return NULL;
01292         }
01293 
01294         memset(node, 0, SIZEOF_DEBUG_NODE_T);
01295 
01296         node->next = pool->nodes;
01297         pool->nodes = node;
01298         node->index = 0;
01299     }
01300 
01301     node->beginp[node->index] = mem;
01302     node->endp[node->index] = (char *)mem + size;
01303     node->index++;
01304 
01305     pool->stat_alloc++;
01306     pool->stat_total_alloc++;
01307 
01308     return mem;
01309 }
01310 
01311 APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size,
01312                                      const char *file_line)
01313 {
01314     void *mem;
01315 
01316     apr_pool_check_integrity(pool);
01317 
01318     mem = pool_alloc(pool, size);
01319 
01320 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC)
01321     apr_pool_log_event(pool, "PALLOC", file_line, 1);
01322 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
01323 
01324     return mem;
01325 }
01326 
01327 APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size,
01328                                       const char *file_line)
01329 {
01330     void *mem;
01331 
01332     apr_pool_check_integrity(pool);
01333 
01334     mem = pool_alloc(pool, size);
01335     memset(mem, 0, size);
01336 
01337 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC)
01338     apr_pool_log_event(pool, "PCALLOC", file_line, 1);
01339 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
01340 
01341     return mem;
01342 }
01343 
01344 
01345 /*
01346  * Pool creation/destruction (debug)
01347  */
01348 
01349 static void pool_clear_debug(apr_pool_t *pool, const char *file_line)
01350 {
01351     debug_node_t *node;
01352     apr_uint32_t index;
01353 
01354     /* Destroy the subpools.  The subpools will detach themselves from
01355      * this pool thus this loop is safe and easy.
01356      */
01357     while (pool->child)
01358         apr_pool_destroy_debug(pool->child, file_line);
01359 
01360     /* Run cleanups */
01361     run_cleanups(&pool->cleanups);
01362     pool->cleanups = NULL;
01363 
01364     /* Free subprocesses */
01365     free_proc_chain(pool->subprocesses);
01366     pool->subprocesses = NULL;
01367 
01368     /* Clear the user data. */
01369     pool->user_data = NULL;
01370 
01371     /* Free the blocks */
01372     while ((node = pool->nodes) != NULL) {
01373         pool->nodes = node->next;
01374 
01375         for (index = 0; index < node->index; index++)
01376             free(node->beginp[index]);
01377 
01378         free(node);
01379     }
01380 
01381     pool->stat_alloc = 0;
01382     pool->stat_clear++;
01383 }
01384 
01385 APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool,
01386                                        const char *file_line)
01387 {
01388 #if APR_HAS_THREADS
01389     apr_thread_mutex_t *mutex = NULL;
01390 #endif
01391 
01392     apr_pool_check_integrity(pool);
01393 
01394 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
01395     apr_pool_log_event(pool, "CLEAR", file_line, 1);
01396 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
01397 
01398 #if APR_HAS_THREADS
01399     if (pool->parent != NULL)
01400         mutex = pool->parent->mutex;
01401 
01402     /* Lock the parent mutex before clearing so that if we have our
01403      * own mutex it won't be accessed by apr_pool_walk_tree after
01404      * it has been destroyed.
01405      */
01406     if (mutex != NULL && mutex != pool->mutex) {
01407         apr_thread_mutex_lock(mutex);
01408     }
01409 #endif
01410 
01411     pool_clear_debug(pool, file_line);
01412 
01413 #if APR_HAS_THREADS
01414     /* If we had our own mutex, it will have been destroyed by
01415      * the registered cleanups.  Recreate the mutex.  Unlock
01416      * the mutex we obtained above.
01417      */
01418     if (mutex != pool->mutex) {
01419         (void)apr_thread_mutex_create(&pool->mutex,
01420                                       APR_THREAD_MUTEX_NESTED, pool);
01421 
01422         if (mutex != NULL)
01423             (void)apr_thread_mutex_unlock(mutex);
01424     }
01425 #endif /* APR_HAS_THREADS */
01426 }
01427 
01428 APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool,
01429                                          const char *file_line)
01430 {
01431     apr_pool_check_integrity(pool);
01432 
01433 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
01434     apr_pool_log_event(pool, "DESTROY", file_line, 1);
01435 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
01436 
01437     pool_clear_debug(pool, file_line);
01438 
01439     /* Remove the pool from the parents child list */
01440     if (pool->parent) {
01441 #if APR_HAS_THREADS
01442         apr_thread_mutex_t *mutex;
01443 
01444         if ((mutex = pool->parent->mutex) != NULL)
01445             apr_thread_mutex_lock(mutex);
01446 #endif /* APR_HAS_THREADS */
01447 
01448         if ((*pool->ref = pool->sibling) != NULL)
01449             pool->sibling->ref = pool->ref;
01450 
01451 #if APR_HAS_THREADS
01452         if (mutex)
01453             apr_thread_mutex_unlock(mutex);
01454 #endif /* APR_HAS_THREADS */
01455     }
01456 
01457     if (pool->allocator != NULL
01458         && apr_allocator_owner_get(pool->allocator) == pool) {
01459         apr_allocator_destroy(pool->allocator);
01460     }
01461 
01462     /* Free the pool itself */
01463     free(pool);
01464 }
01465 
01466 APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool,
01467                                                    apr_pool_t *parent,
01468                                                    apr_abortfunc_t abort_fn,
01469                                                    apr_allocator_t *allocator,
01470                                                    const char *file_line)
01471 {
01472     apr_pool_t *pool;
01473 
01474     *newpool = NULL;
01475 
01476     if (!parent) {
01477         parent = global_pool;
01478     }
01479     else {
01480        apr_pool_check_integrity(parent);
01481 
01482        if (!allocator)
01483            allocator = parent->allocator;
01484     }
01485 
01486     if (!abort_fn && parent)
01487         abort_fn = parent->abort_fn;
01488 
01489     if ((pool = malloc(SIZEOF_POOL_T)) == NULL) {
01490         if (abort_fn)
01491             abort_fn(APR_ENOMEM);
01492 
01493          return APR_ENOMEM;
01494     }
01495 
01496     memset(pool, 0, SIZEOF_POOL_T);
01497 
01498     pool->allocator = allocator;
01499     pool->abort_fn = abort_fn;
01500     pool->tag = file_line;
01501     pool->file_line = file_line;
01502 
01503     if ((pool->parent = parent) != NULL) {
01504 #if APR_HAS_THREADS
01505         if (parent->mutex)
01506             apr_thread_mutex_lock(parent->mutex);
01507 #endif /* APR_HAS_THREADS */
01508         if ((pool->sibling = parent->child) != NULL)
01509             pool->sibling->ref = &pool->sibling;
01510 
01511         parent->child = pool;
01512         pool->ref = &parent->child;
01513 
01514 #if APR_HAS_THREADS
01515         if (parent->mutex)
01516             apr_thread_mutex_unlock(parent->mutex);
01517 #endif /* APR_HAS_THREADS */
01518     }
01519     else {
01520         pool->sibling = NULL;
01521         pool->ref = NULL;
01522     }
01523 
01524 #if APR_HAS_THREADS
01525     pool->owner = apr_os_thread_current();
01526 #endif /* APR_HAS_THREADS */
01527 
01528     if (parent == NULL || parent->allocator != allocator) {
01529 #if APR_HAS_THREADS
01530         apr_status_t rv;
01531 
01532         /* No matter what the creation flags say, always create
01533          * a lock.  Without it integrity_check and apr_pool_num_bytes
01534          * blow up (because they traverse pools child lists that
01535          * possibly belong to another thread, in combination with
01536          * the pool having no lock).  However, this might actually
01537          * hide problems like creating a child pool of a pool
01538          * belonging to another thread.
01539          */
01540         if ((rv = apr_thread_mutex_create(&pool->mutex,
01541                 APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) {
01542             free(pool);
01543             return rv;
01544         }
01545 #endif /* APR_HAS_THREADS */
01546     }
01547     else {
01548 #if APR_HAS_THREADS
01549         if (parent)
01550             pool->mutex = parent->mutex;
01551 #endif /* APR_HAS_THREADS */
01552     }
01553 
01554     *newpool = pool;
01555 
01556 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
01557     apr_pool_log_event(pool, "CREATE", file_line, 1);
01558 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
01559 
01560     return APR_SUCCESS;
01561 }
01562 
01563 
01564 /*
01565  * "Print" functions (debug)
01566  */
01567 
01568 struct psprintf_data {
01569     apr_vformatter_buff_t vbuff;
01570     char      *mem;
01571     apr_size_t size;
01572 };
01573 
01574 static int psprintf_flush(apr_vformatter_buff_t *vbuff)
01575 {
01576     struct psprintf_data *ps = (struct psprintf_data *)vbuff;
01577     apr_size_t size;
01578 
01579     size = ps->vbuff.curpos - ps->mem;
01580 
01581     ps->size <<= 1;
01582     if ((ps->mem = realloc(ps->mem, ps->size)) == NULL)
01583         return -1;
01584 
01585     ps->vbuff.curpos = ps->mem + size;
01586     ps->vbuff.endpos = ps->mem + ps->size - 1;
01587 
01588     return 0;
01589 }
01590 
01591 APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap)
01592 {
01593     struct psprintf_data ps;
01594     debug_node_t *node;
01595 
01596     apr_pool_check_integrity(pool);
01597 
01598     ps.size = 64;
01599     ps.mem = malloc(ps.size);
01600     ps.vbuff.curpos  = ps.mem;
01601 
01602     /* Save a byte for the NUL terminator */
01603     ps.vbuff.endpos = ps.mem + ps.size - 1;
01604 
01605     if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) {
01606         if (pool->abort_fn)
01607             pool->abort_fn(APR_ENOMEM);
01608 
01609         return NULL;
01610     }
01611 
01612     *ps.vbuff.curpos++ = '\0';
01613 
01614     /*
01615      * Link the node in
01616      */
01617     node = pool->nodes;
01618     if (node == NULL || node->index == 64) {
01619         if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) {
01620             if (pool->abort_fn)
01621                 pool->abort_fn(APR_ENOMEM);
01622 
01623             return NULL;
01624         }
01625 
01626         node->next = pool->nodes;
01627         pool->nodes = node;
01628         node->index = 0;
01629     }
01630 
01631     node->beginp[node->index] = ps.mem;
01632     node->endp[node->index] = ps.mem + ps.size;
01633     node->index++;
01634 
01635     return ps.mem;
01636 }
01637 
01638 
01639 /*
01640  * Debug functions
01641  */
01642 
01643 APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub)
01644 {
01645 }
01646 
01647 static int pool_find(apr_pool_t *pool, void *data)
01648 {
01649     void **pmem = (void **)data;
01650     debug_node_t *node;
01651     apr_uint32_t index;
01652 
01653     node = pool->nodes;
01654 
01655     while (node) {
01656         for (index = 0; index < node->index; index++) {
01657              if (node->beginp[index] <= *pmem
01658                  && node->endp[index] > *pmem) {
01659                  *pmem = pool;
01660                  return 1;
01661              }
01662         }
01663 
01664         node = node->next;
01665     }
01666 
01667     return 0;
01668 }
01669 
01670 APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem)
01671 {
01672     void *pool = (void *)mem;
01673 
01674     if (apr_pool_walk_tree(global_pool, pool_find, &pool))
01675         return pool;
01676 
01677     return NULL;
01678 }
01679 
01680 static int pool_num_bytes(apr_pool_t *pool, void *data)
01681 {
01682     apr_size_t *psize = (apr_size_t *)data;
01683     debug_node_t *node;
01684     apr_uint32_t index;
01685 
01686     node = pool->nodes;
01687 
01688     while (node) {
01689         for (index = 0; index < node->index; index++) {
01690             *psize += (char *)node->endp[index] - (char *)node->beginp[index];
01691         }
01692 
01693         node = node->next;
01694     }
01695 
01696