bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / memory / unix / apr_pools.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr.h"
18 #include "apr_private.h"
19
20 #include "apr_atomic.h"
21 #include "apr_portable.h" /* for get_os_proc */
22 #include "apr_strings.h"
23 #include "apr_general.h"
24 #include "apr_pools.h"
25 #include "apr_allocator.h"
26 #include "apr_lib.h"
27 #include "apr_thread_mutex.h"
28 #include "apr_hash.h"
29 #include "apr_time.h"
30 #define APR_WANT_MEMFUNC
31 #include "apr_want.h"
32
33 #if APR_HAVE_STDLIB_H
34 #include <stdlib.h>     /* for malloc, free and abort */
35 #endif
36
37 #if APR_HAVE_UNISTD_H
38 #include <unistd.h>     /* for getpid */
39 #endif
40
41
42 /*
43  * Magic numbers
44  */
45
46 #define MIN_ALLOC 8192
47 #define MAX_INDEX   20
48
49 #define BOUNDARY_INDEX 12
50 #define BOUNDARY_SIZE (1 << BOUNDARY_INDEX)
51
52 /* 
53  * Timing constants for killing subprocesses
54  * There is a total 3-second delay between sending a SIGINT 
55  * and sending of the final SIGKILL.
56  * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64
57  * for the exponetial timeout alogrithm.
58  */
59 #define TIMEOUT_USECS    3000000
60 #define TIMEOUT_INTERVAL   46875
61
62 /*
63  * Allocator
64  *
65  * @note The max_free_index and current_free_index fields are not really
66  * indices, but quantities of BOUNDARY_SIZE big memory blocks.
67  */
68
69 struct apr_allocator_t {
70     /** largest used index into free[], always < MAX_INDEX */
71     apr_uint32_t        max_index;
72     /** Total size (in BOUNDARY_SIZE multiples) of unused memory before
73      * blocks are given back. @see apr_allocator_max_free_set().
74      * @note Initialized to APR_ALLOCATOR_MAX_FREE_UNLIMITED,
75      * which means to never give back blocks.
76      */
77     apr_uint32_t        max_free_index;
78     /**
79      * Memory size (in BOUNDARY_SIZE multiples) that currently must be freed
80      * before blocks are given back. Range: 0..max_free_index
81      */
82     apr_uint32_t        current_free_index;
83 #if APR_HAS_THREADS
84     apr_thread_mutex_t *mutex;
85 #endif /* APR_HAS_THREADS */
86     apr_pool_t         *owner;
87     /**
88      * Lists of free nodes. Slot 0 is used for oversized nodes,
89      * and the slots 1..MAX_INDEX-1 contain nodes of sizes
90      * (i+1) * BOUNDARY_SIZE. Example for BOUNDARY_INDEX == 12:
91      * slot  0: nodes larger than 81920
92      * slot  1: size  8192
93      * slot  2: size 12288
94      * ...
95      * slot 19: size 81920
96      */
97     apr_memnode_t      *free[MAX_INDEX];
98 };
99
100 #define SIZEOF_ALLOCATOR_T  APR_ALIGN_DEFAULT(sizeof(apr_allocator_t))
101
102
103 /*
104  * Allocator
105  */
106
107 APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator)
108 {
109     apr_allocator_t *new_allocator;
110
111     *allocator = NULL;
112
113     if ((new_allocator = malloc(SIZEOF_ALLOCATOR_T)) == NULL)
114         return APR_ENOMEM;
115
116     memset(new_allocator, 0, SIZEOF_ALLOCATOR_T);
117     new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
118
119     *allocator = new_allocator;
120
121     return APR_SUCCESS;
122 }
123
124 APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator)
125 {
126     apr_uint32_t index;
127     apr_memnode_t *node, **ref;
128
129     for (index = 0; index < MAX_INDEX; index++) {
130         ref = &allocator->free[index];
131         while ((node = *ref) != NULL) {
132             *ref = node->next;
133             free(node);
134         }
135     }
136
137     free(allocator);
138 }
139
140 #if APR_HAS_THREADS
141 APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator,
142                                           apr_thread_mutex_t *mutex)
143 {
144     allocator->mutex = mutex;
145 }
146
147 APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get(
148                                       apr_allocator_t *allocator)
149 {
150     return allocator->mutex;
151 }
152 #endif /* APR_HAS_THREADS */
153
154 APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator,
155                                           apr_pool_t *pool)
156 {
157     allocator->owner = pool;
158 }
159
160 APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator)
161 {
162     return allocator->owner;
163 }
164
165 APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator,
166                                              apr_size_t size)
167 {
168     apr_uint32_t max_free_index;
169
170 #if APR_HAS_THREADS
171     apr_thread_mutex_t *mutex;
172
173     mutex = apr_allocator_mutex_get(allocator);
174     if (mutex != NULL)
175         apr_thread_mutex_lock(mutex);
176 #endif /* APR_HAS_THREADS */
177
178     max_free_index = APR_ALIGN(size, BOUNDARY_SIZE) >> BOUNDARY_INDEX;
179     allocator->current_free_index += max_free_index;
180     allocator->current_free_index -= allocator->max_free_index;
181     allocator->max_free_index = max_free_index;
182     if (allocator->current_free_index > max_free_index)
183         allocator->current_free_index = max_free_index;
184
185 #if APR_HAS_THREADS
186     if (mutex != NULL)
187         apr_thread_mutex_unlock(mutex);
188 #endif
189 }
190
191 static APR_INLINE
192 apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t in_size)
193 {
194     apr_memnode_t *node, **ref;
195     apr_uint32_t i, index, max_index;
196     apr_size_t size;
197
198     /* Round up the block size to the next boundary, but always
199      * allocate at least a certain size (MIN_ALLOC).
200      */
201     size = APR_ALIGN(in_size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE);
202     if (size < in_size) {
203         return NULL;
204     }
205     if (size < MIN_ALLOC)
206         size = MIN_ALLOC;
207
208     /* Find the index for this node size by
209      * dividing its size by the boundary size
210      */
211     index = (size >> BOUNDARY_INDEX) - 1;
212
213     /* First see if there are any nodes in the area we know
214      * our node will fit into.
215      */
216     if (index <= allocator->max_index) {
217 #if APR_HAS_THREADS
218         if (allocator->mutex)
219             apr_thread_mutex_lock(allocator->mutex);
220 #endif /* APR_HAS_THREADS */
221
222         /* Walk the free list to see if there are
223          * any nodes on it of the requested size
224          *
225          * NOTE: an optimization would be to check
226          * allocator->free[index] first and if no
227          * node is present, directly use
228          * allocator->free[max_index].  This seems
229          * like overkill though and could cause
230          * memory waste.
231          */
232         max_index = allocator->max_index;
233         ref = &allocator->free[index];
234         i = index;
235         while (*ref == NULL && i < max_index) {
236            ref++;
237            i++;
238         }
239
240         if ((node = *ref) != NULL) {
241             /* If we have found a node and it doesn't have any
242              * nodes waiting in line behind it _and_ we are on
243              * the highest available index, find the new highest
244              * available index
245              */
246             if ((*ref = node->next) == NULL && i >= max_index) {
247                 do {
248                     ref--;
249                     max_index--;
250                 }
251                 while (*ref == NULL && max_index > 0);
252
253                 allocator->max_index = max_index;
254             }
255
256             allocator->current_free_index += node->index;
257             if (allocator->current_free_index > allocator->max_free_index)
258                 allocator->current_free_index = allocator->max_free_index;
259
260 #if APR_HAS_THREADS
261             if (allocator->mutex)
262                 apr_thread_mutex_unlock(allocator->mutex);
263 #endif /* APR_HAS_THREADS */
264
265             node->next = NULL;
266             node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
267
268             return node;
269         }
270
271 #if APR_HAS_THREADS
272         if (allocator->mutex)
273             apr_thread_mutex_unlock(allocator->mutex);
274 #endif /* APR_HAS_THREADS */
275     }
276
277     /* If we found nothing, seek the sink (at index 0), if
278      * it is not empty.
279      */
280     else if (allocator->free[0]) {
281 #if APR_HAS_THREADS
282         if (allocator->mutex)
283             apr_thread_mutex_lock(allocator->mutex);
284 #endif /* APR_HAS_THREADS */
285
286         /* Walk the free list to see if there are
287          * any nodes on it of the requested size
288          */
289         ref = &allocator->free[0];
290         while ((node = *ref) != NULL && index > node->index)
291             ref = &node->next;
292
293         if (node) {
294             *ref = node->next;
295
296             allocator->current_free_index += node->index;
297             if (allocator->current_free_index > allocator->max_free_index)
298                 allocator->current_free_index = allocator->max_free_index;
299
300 #if APR_HAS_THREADS
301             if (allocator->mutex)
302                 apr_thread_mutex_unlock(allocator->mutex);
303 #endif /* APR_HAS_THREADS */
304
305             node->next = NULL;
306             node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
307
308             return node;
309         }
310
311 #if APR_HAS_THREADS
312         if (allocator->mutex)
313             apr_thread_mutex_unlock(allocator->mutex);
314 #endif /* APR_HAS_THREADS */
315     }
316
317     /* If we haven't got a suitable node, malloc a new one
318      * and initialize it.
319      */
320     if ((node = malloc(size)) == NULL)
321         return NULL;
322
323     node->next = NULL;
324     node->index = index;
325     node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
326     node->endp = (char *)node + size;
327
328     return node;
329 }
330
331 static APR_INLINE
332 void allocator_free(apr_allocator_t *allocator, apr_memnode_t *node)
333 {
334     apr_memnode_t *next, *freelist = NULL;
335     apr_uint32_t index, max_index;
336     apr_uint32_t max_free_index, current_free_index;
337
338 #if APR_HAS_THREADS
339     if (allocator->mutex)
340         apr_thread_mutex_lock(allocator->mutex);
341 #endif /* APR_HAS_THREADS */
342
343     max_index = allocator->max_index;
344     max_free_index = allocator->max_free_index;
345     current_free_index = allocator->current_free_index;
346
347     /* Walk the list of submitted nodes and free them one by one,
348      * shoving them in the right 'size' buckets as we go.
349      */
350     do {
351         next = node->next;
352         index = node->index;
353
354         if (max_free_index != APR_ALLOCATOR_MAX_FREE_UNLIMITED
355             && index > current_free_index) {
356             node->next = freelist;
357             freelist = node;
358         }
359         else if (index < MAX_INDEX) {
360             /* Add the node to the appropiate 'size' bucket.  Adjust
361              * the max_index when appropiate.
362              */
363             if ((node->next = allocator->free[index]) == NULL
364                 && index > max_index) {
365                 max_index = index;
366             }
367             allocator->free[index] = node;
368             if (current_free_index >= index)
369                 current_free_index -= index;
370             else
371                 current_free_index = 0;
372         }
373         else {
374             /* This node is too large to keep in a specific size bucket,
375              * just add it to the sink (at index 0).
376              */
377             node->next = allocator->free[0];
378             allocator->free[0] = node;
379             if (current_free_index >= index)
380                 current_free_index -= index;
381             else
382                 current_free_index = 0;
383         }
384     } while ((node = next) != NULL);
385
386     allocator->max_index = max_index;
387     allocator->current_free_index = current_free_index;
388
389 #if APR_HAS_THREADS
390     if (allocator->mutex)
391         apr_thread_mutex_unlock(allocator->mutex);
392 #endif /* APR_HAS_THREADS */
393
394     while (freelist != NULL) {
395         node = freelist;
396         freelist = node->next;
397         free(node);
398     }
399 }
400
401 APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator,
402                                                  apr_size_t size)
403 {
404     return allocator_alloc(allocator, size);
405 }
406
407 APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator,
408                                      apr_memnode_t *node)
409 {
410     allocator_free(allocator, node);
411 }
412
413
414
415 /*
416  * Debug level
417  */
418
419 #define APR_POOL_DEBUG_GENERAL  0x01
420 #define APR_POOL_DEBUG_VERBOSE  0x02
421 #define APR_POOL_DEBUG_LIFETIME 0x04
422 #define APR_POOL_DEBUG_OWNER    0x08
423 #define APR_POOL_DEBUG_VERBOSE_ALLOC 0x10
424
425 #define APR_POOL_DEBUG_VERBOSE_ALL (APR_POOL_DEBUG_VERBOSE \
426                                     | APR_POOL_DEBUG_VERBOSE_ALLOC)
427
428
429 /*
430  * Structures
431  */
432
433 typedef struct cleanup_t cleanup_t;
434
435 /** A list of processes */
436 struct process_chain {
437     /** The process ID */
438     apr_proc_t *proc;
439     apr_kill_conditions_e kill_how;
440     /** The next process in the list */
441     struct process_chain *next;
442 };
443
444
445 #if APR_POOL_DEBUG
446
447 typedef struct debug_node_t debug_node_t;
448
449 struct debug_node_t {
450     debug_node_t *next;
451     apr_uint32_t  index;
452     void         *beginp[64];
453     void         *endp[64];
454 };
455
456 #define SIZEOF_DEBUG_NODE_T APR_ALIGN_DEFAULT(sizeof(debug_node_t))
457
458 #endif /* APR_POOL_DEBUG */
459
460 /* The ref field in the apr_pool_t struct holds a
461  * pointer to the pointer referencing this pool.
462  * It is used for parent, child, sibling management.
463  * Look at apr_pool_create_ex() and apr_pool_destroy()
464  * to see how it is used.
465  */
466 struct apr_pool_t {
467     apr_pool_t           *parent;
468     apr_pool_t           *child;
469     apr_pool_t           *sibling;
470     apr_pool_t          **ref;
471     cleanup_t            *cleanups;
472     apr_allocator_t      *allocator;
473     struct process_chain *subprocesses;
474     apr_abortfunc_t       abort_fn;
475     apr_hash_t           *user_data;
476     const char           *tag;
477
478 #if !APR_POOL_DEBUG
479     apr_memnode_t        *active;
480     apr_memnode_t        *self; /* The node containing the pool itself */
481     char                 *self_first_avail;
482
483 #else /* APR_POOL_DEBUG */
484     debug_node_t         *nodes;
485     const char           *file_line;
486     apr_uint32_t          creation_flags;
487     unsigned int          stat_alloc;
488     unsigned int          stat_total_alloc;
489     unsigned int          stat_clear;
490 #if APR_HAS_THREADS
491     apr_os_thread_t       owner;
492     apr_thread_mutex_t   *mutex;
493 #endif /* APR_HAS_THREADS */
494 #endif /* APR_POOL_DEBUG */
495 #ifdef NETWARE
496     apr_os_proc_t         owner_proc;
497 #endif /* defined(NETWARE) */
498 };
499
500 #define SIZEOF_POOL_T       APR_ALIGN_DEFAULT(sizeof(apr_pool_t))
501
502
503 /*
504  * Variables
505  */
506
507 static apr_byte_t   apr_pools_initialized = 0;
508 static apr_pool_t  *global_pool = NULL;
509
510 #if !APR_POOL_DEBUG
511 static apr_allocator_t *global_allocator = NULL;
512 #endif /* !APR_POOL_DEBUG */
513
514 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
515 static apr_file_t *file_stderr = NULL;
516 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
517
518 /*
519  * Local functions
520  */
521
522 static void run_cleanups(cleanup_t **c);
523 static void run_child_cleanups(cleanup_t **c);
524 static void free_proc_chain(struct process_chain *procs);
525
526
527 #if !APR_POOL_DEBUG
528 /*
529  * Initialization
530  */
531
532 APR_DECLARE(apr_status_t) apr_pool_initialize(void)
533 {
534     apr_status_t rv;
535
536     if (apr_pools_initialized++)
537         return APR_SUCCESS;
538
539     if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) {
540         apr_pools_initialized = 0;
541         return rv;
542     }
543
544     if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL,
545                                  global_allocator)) != APR_SUCCESS) {
546         apr_allocator_destroy(global_allocator);
547         global_allocator = NULL;
548         apr_pools_initialized = 0;
549         return rv;
550     }
551
552     apr_pool_tag(global_pool, "apr_global_pool");
553
554     /* This has to happen here because mutexes might be backed by
555      * atomics.  It used to be snug and safe in apr_initialize().
556      */
557     if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) {
558         return rv;
559     }
560
561 #if APR_HAS_THREADS
562     {
563         apr_thread_mutex_t *mutex;
564
565         if ((rv = apr_thread_mutex_create(&mutex,
566                                           APR_THREAD_MUTEX_DEFAULT,
567                                           global_pool)) != APR_SUCCESS) {
568             return rv;
569         }
570
571         apr_allocator_mutex_set(global_allocator, mutex);
572     }
573 #endif /* APR_HAS_THREADS */
574
575     apr_allocator_owner_set(global_allocator, global_pool);
576
577     return APR_SUCCESS;
578 }
579
580 APR_DECLARE(void) apr_pool_terminate(void)
581 {
582     if (!apr_pools_initialized)
583         return;
584
585     if (--apr_pools_initialized)
586         return;
587
588     apr_pool_destroy(global_pool); /* This will also destroy the mutex */
589     global_pool = NULL;
590
591     global_allocator = NULL;
592 }
593
594 #ifdef NETWARE
595 void netware_pool_proc_cleanup ()
596 {
597     apr_pool_t *pool = global_pool->child;
598     apr_os_proc_t owner_proc = (apr_os_proc_t)getnlmhandle();
599
600     while (pool) {
601         if (pool->owner_proc == owner_proc) {
602             apr_pool_destroy (pool);
603             pool = global_pool->child;
604         }
605         else {
606             pool = pool->sibling;
607         }
608     }
609     return;
610 }
611 #endif /* defined(NETWARE) */
612
613 /* Node list management helper macros; list_insert() inserts 'node'
614  * before 'point'. */
615 #define list_insert(node, point) do {           \
616     node->ref = point->ref;                     \
617     *node->ref = node;                          \
618     node->next = point;                         \
619     point->ref = &node->next;                   \
620 } while (0)
621
622 /* list_remove() removes 'node' from its list. */
623 #define list_remove(node) do {                  \
624     *node->ref = node->next;                    \
625     node->next->ref = node->ref;                \
626 } while (0)
627
628 /*
629  * Memory allocation
630  */
631
632 APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t in_size)
633 {
634     apr_memnode_t *active, *node;
635     void *mem;
636     apr_uint32_t free_index;
637     apr_size_t size;
638
639     size = APR_ALIGN_DEFAULT(in_size);
640     if (size < in_size) {
641         if (pool->abort_fn)
642             pool->abort_fn(APR_ENOMEM);
643         return NULL;
644     }
645     active = pool->active;
646
647     /* If the active node has enough bytes left, use it. */
648     if (size < (apr_size_t)(active->endp - active->first_avail)) {
649         mem = active->first_avail;
650         active->first_avail += size;
651
652         return mem;
653     }
654
655     node = active->next;
656     if (size < (apr_size_t)(node->endp - node->first_avail)) {
657         list_remove(node);
658     }
659     else {
660         if ((node = allocator_alloc(pool->allocator, size)) == NULL) {
661             if (pool->abort_fn)
662                 pool->abort_fn(APR_ENOMEM);
663
664             return NULL;
665         }
666     }
667
668     node->free_index = 0;
669
670     mem = node->first_avail;
671     node->first_avail += size;
672
673     list_insert(node, active);
674
675     pool->active = node;
676
677     free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
678                             BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
679
680     active->free_index = free_index;
681     node = active->next;
682     if (free_index >= node->free_index)
683         return mem;
684
685     do {
686         node = node->next;
687     }
688     while (free_index < node->free_index);
689
690     list_remove(active);
691     list_insert(active, node);
692
693     return mem;
694 }
695
696 /* Provide an implementation of apr_pcalloc for backward compatibility
697  * with code built before apr_pcalloc was a macro
698  */
699
700 #ifdef apr_pcalloc
701 #undef apr_pcalloc
702 #endif
703
704 APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size);
705 APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size)
706 {
707     void *mem;
708
709     if ((mem = apr_palloc(pool, size)) != NULL) {
710         memset(mem, 0, size);
711     }
712
713     return mem;
714 }
715
716
717 /*
718  * Pool creation/destruction
719  */
720
721 APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool)
722 {
723     apr_memnode_t *active;
724
725     /* Destroy the subpools.  The subpools will detach themselves from
726      * this pool thus this loop is safe and easy.
727      */
728     while (pool->child)
729         apr_pool_destroy(pool->child);
730
731     /* Run cleanups */
732     run_cleanups(&pool->cleanups);
733     pool->cleanups = NULL;
734
735     /* Free subprocesses */
736     free_proc_chain(pool->subprocesses);
737     pool->subprocesses = NULL;
738
739     /* Clear the user data. */
740     pool->user_data = NULL;
741
742     /* Find the node attached to the pool structure, reset it, make
743      * it the active node and free the rest of the nodes.
744      */
745     active = pool->active = pool->self;
746     active->first_avail = pool->self_first_avail;
747
748     if (active->next == active)
749         return;
750
751     *active->ref = NULL;
752     allocator_free(pool->allocator, active->next);
753     active->next = active;
754     active->ref = &active->next;
755 }
756
757 APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool)
758 {
759     apr_memnode_t *active;
760     apr_allocator_t *allocator;
761
762     /* Destroy the subpools.  The subpools will detach themselve from
763      * this pool thus this loop is safe and easy.
764      */
765     while (pool->child)
766         apr_pool_destroy(pool->child);
767
768     /* Run cleanups */
769     run_cleanups(&pool->cleanups);
770
771     /* Free subprocesses */
772     free_proc_chain(pool->subprocesses);
773
774     /* Remove the pool from the parents child list */
775     if (pool->parent) {
776 #if APR_HAS_THREADS
777         apr_thread_mutex_t *mutex;
778
779         if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL)
780             apr_thread_mutex_lock(mutex);
781 #endif /* APR_HAS_THREADS */
782
783         if ((*pool->ref = pool->sibling) != NULL)
784             pool->sibling->ref = pool->ref;
785
786 #if APR_HAS_THREADS
787         if (mutex)
788             apr_thread_mutex_unlock(mutex);
789 #endif /* APR_HAS_THREADS */
790     }
791
792     /* Find the block attached to the pool structure.  Save a copy of the
793      * allocator pointer, because the pool struct soon will be no more.
794      */
795     allocator = pool->allocator;
796     active = pool->self;
797     *active->ref = NULL;
798
799 #if APR_HAS_THREADS
800     if (apr_allocator_owner_get(allocator) == pool) {
801         /* Make sure to remove the lock, since it is highly likely to
802          * be invalid now.
803          */
804         apr_allocator_mutex_set(allocator, NULL);
805     }
806 #endif /* APR_HAS_THREADS */
807
808     /* Free all the nodes in the pool (including the node holding the
809      * pool struct), by giving them back to the allocator.
810      */
811     allocator_free(allocator, active);
812
813     /* If this pool happens to be the owner of the allocator, free
814      * everything in the allocator (that includes the pool struct
815      * and the allocator).  Don't worry about destroying the optional mutex
816      * in the allocator, it will have been destroyed by the cleanup function.
817      */
818     if (apr_allocator_owner_get(allocator) == pool) {
819         apr_allocator_destroy(allocator);
820     }
821 }
822
823 APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
824                                              apr_pool_t *parent,
825                                              apr_abortfunc_t abort_fn,
826                                              apr_allocator_t *allocator)
827 {
828     apr_pool_t *pool;
829     apr_memnode_t *node;
830
831     *newpool = NULL;
832
833     if (!parent)
834         parent = global_pool;
835
836     if (!abort_fn && parent)
837         abort_fn = parent->abort_fn;
838
839     if (allocator == NULL)
840         allocator = parent->allocator;
841
842     if ((node = allocator_alloc(allocator,
843                                 MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
844         if (abort_fn)
845             abort_fn(APR_ENOMEM);
846
847         return APR_ENOMEM;
848     }
849
850     node->next = node;
851     node->ref = &node->next;
852
853     pool = (apr_pool_t *)node->first_avail;
854     node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T;
855
856     pool->allocator = allocator;
857     pool->active = pool->self = node;
858     pool->abort_fn = abort_fn;
859     pool->child = NULL;
860     pool->cleanups = NULL;
861     pool->subprocesses = NULL;
862     pool->user_data = NULL;
863     pool->tag = NULL;
864
865 #ifdef NETWARE
866     pool->owner_proc = (apr_os_proc_t)getnlmhandle();
867 #endif /* defined(NETWARE) */
868
869     if ((pool->parent = parent) != NULL) {
870 #if APR_HAS_THREADS
871         apr_thread_mutex_t *mutex;
872
873         if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL)
874             apr_thread_mutex_lock(mutex);
875 #endif /* APR_HAS_THREADS */
876
877         if ((pool->sibling = parent->child) != NULL)
878             pool->sibling->ref = &pool->sibling;
879
880         parent->child = pool;
881         pool->ref = &parent->child;
882
883 #if APR_HAS_THREADS
884         if (mutex)
885             apr_thread_mutex_unlock(mutex);
886 #endif /* APR_HAS_THREADS */
887     }
888     else {
889         pool->sibling = NULL;
890         pool->ref = NULL;
891     }
892
893     *newpool = pool;
894
895     return APR_SUCCESS;
896 }
897
898
899 /*
900  * "Print" functions
901  */
902
903 /*
904  * apr_psprintf is implemented by writing directly into the current
905  * block of the pool, starting right at first_avail.  If there's
906  * insufficient room, then a new block is allocated and the earlier
907  * output is copied over.  The new block isn't linked into the pool
908  * until all the output is done.
909  *
910  * Note that this is completely safe because nothing else can
911  * allocate in this apr_pool_t while apr_psprintf is running.  alarms are
912  * blocked, and the only thing outside of apr_pools.c that's invoked
913  * is apr_vformatter -- which was purposefully written to be
914  * self-contained with no callouts.
915  */
916
917 struct psprintf_data {
918     apr_vformatter_buff_t vbuff;
919     apr_memnode_t   *node;
920     apr_pool_t      *pool;
921     apr_byte_t       got_a_new_node;
922     apr_memnode_t   *free;
923 };
924
925 #define APR_PSPRINTF_MIN_STRINGSIZE 32
926
927 static int psprintf_flush(apr_vformatter_buff_t *vbuff)
928 {
929     struct psprintf_data *ps = (struct psprintf_data *)vbuff;
930     apr_memnode_t *node, *active;
931     apr_size_t cur_len, size;
932     char *strp;
933     apr_pool_t *pool;
934     apr_uint32_t free_index;
935
936     pool = ps->pool;
937     active = ps->node;
938     strp = ps->vbuff.curpos;
939     cur_len = strp - active->first_avail;
940     size = cur_len << 1;
941
942     /* Make sure that we don't try to use a block that has less
943      * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it.  This
944      * also catches the case where size == 0, which would result
945      * in reusing a block that can't even hold the NUL byte.
946      */
947     if (size < APR_PSPRINTF_MIN_STRINGSIZE)
948         size = APR_PSPRINTF_MIN_STRINGSIZE;
949
950     node = active->next;
951     if (!ps->got_a_new_node
952         && size < (apr_size_t)(node->endp - node->first_avail)) {
953
954         list_remove(node);
955         list_insert(node, active);
956
957         node->free_index = 0;
958
959         pool->active = node;
960
961         free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
962                                 BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
963
964         active->free_index = free_index;
965         node = active->next;
966         if (free_index < node->free_index) {
967             do {
968                 node = node->next;
969             }
970             while (free_index < node->free_index);
971
972             list_remove(active);
973             list_insert(active, node);
974         }
975
976         node = pool->active;
977     }
978     else {
979         if ((node = allocator_alloc(pool->allocator, size)) == NULL)
980             return -1;
981
982         if (ps->got_a_new_node) {
983             active->next = ps->free;
984             ps->free = active;
985         }
986
987         ps->got_a_new_node = 1;
988     }
989
990     memcpy(node->first_avail, active->first_avail, cur_len);
991
992     ps->node = node;
993     ps->vbuff.curpos = node->first_avail + cur_len;
994     ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */
995
996     return 0;
997 }
998
999 APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap)
1000 {
1001     struct psprintf_data ps;
1002     char *strp;
1003     apr_size_t size;
1004     apr_memnode_t *active, *node;
1005     apr_uint32_t free_index;
1006
1007     ps.node = active = pool->active;
1008     ps.pool = pool;
1009     ps.vbuff.curpos  = ps.node->first_avail;
1010
1011     /* Save a byte for the NUL terminator */
1012     ps.vbuff.endpos = ps.node->endp - 1;
1013     ps.got_a_new_node = 0;
1014     ps.free = NULL;
1015
1016     /* Make sure that the first node passed to apr_vformatter has at least
1017      * room to hold the NUL terminator.
1018      */
1019     if (ps.node->first_avail == ps.node->endp) {
1020         if (psprintf_flush(&ps.vbuff) == -1) {
1021             if (pool->abort_fn) {
1022                 pool->abort_fn(APR_ENOMEM);
1023             }
1024
1025             return NULL;
1026         }
1027     }
1028
1029     if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) {
1030         if (pool->abort_fn)
1031             pool->abort_fn(APR_ENOMEM);
1032
1033         return NULL;
1034     }
1035
1036     strp = ps.vbuff.curpos;
1037     *strp++ = '\0';
1038
1039     size = strp - ps.node->first_avail;
1040     size = APR_ALIGN_DEFAULT(size);
1041     strp = ps.node->first_avail;
1042     ps.node->first_avail += size;
1043
1044     if (ps.free)
1045         allocator_free(pool->allocator, ps.free);
1046
1047     /*
1048      * Link the node in if it's a new one
1049      */
1050     if (!ps.got_a_new_node)
1051         return strp;
1052
1053     active = pool->active;
1054     node = ps.node;
1055
1056     node->free_index = 0;
1057
1058     list_insert(node, active);
1059
1060     pool->active = node;
1061
1062     free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
1063                             BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
1064
1065     active->free_index = free_index;
1066     node = active->next;
1067
1068     if (free_index >= node->free_index)
1069         return strp;
1070
1071     do {
1072         node = node->next;
1073     }
1074     while (free_index < node->free_index);
1075
1076     list_remove(active);
1077     list_insert(active, node);
1078
1079     return strp;
1080 }
1081
1082
1083 #else /* APR_POOL_DEBUG */
1084 /*
1085  * Debug helper functions
1086  */
1087
1088
1089 /*
1090  * Walk the pool tree rooted at pool, depth first.  When fn returns
1091  * anything other than 0, abort the traversal and return the value
1092  * returned by fn.
1093  */
1094 static int apr_pool_walk_tree(apr_pool_t *pool,
1095                               int (*fn)(apr_pool_t *pool, void *data),
1096                               void *data)
1097 {
1098     int rv;
1099     apr_pool_t *child;
1100
1101     rv = fn(pool, data);
1102     if (rv)
1103         return rv;
1104
1105 #if APR_HAS_THREADS
1106     if (pool->mutex) {
1107         apr_thread_mutex_lock(pool->mutex);
1108                         }
1109 #endif /* APR_HAS_THREADS */
1110
1111     child = pool->child;
1112     while (child) {
1113         rv = apr_pool_walk_tree(child, fn, data);
1114         if (rv)
1115             break;
1116
1117         child = child->sibling;
1118     }
1119
1120 #if APR_HAS_THREADS
1121     if (pool->mutex) {
1122         apr_thread_mutex_unlock(pool->mutex);
1123     }
1124 #endif /* APR_HAS_THREADS */
1125
1126     return rv;
1127 }
1128
1129 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1130 static void apr_pool_log_event(apr_pool_t *pool, const char *event,
1131                                const char *file_line, int deref)
1132 {
1133     if (file_stderr) {
1134         if (deref) {
1135             apr_file_printf(file_stderr,
1136                 "POOL DEBUG: "
1137                 "[%lu"
1138 #if APR_HAS_THREADS
1139                 "/%lu"
1140 #endif /* APR_HAS_THREADS */
1141                 "] "
1142                 "%7s "
1143                 "(%10lu/%10lu/%10lu) "
1144                 "0x%08X \"%s\" "
1145                 "<%s> "
1146                 "(%u/%u/%u) "
1147                 "\n",
1148                 (unsigned long)getpid(),
1149 #if APR_HAS_THREADS
1150                 (unsigned long)apr_os_thread_current(),
1151 #endif /* APR_HAS_THREADS */
1152                 event,
1153                 (unsigned long)apr_pool_num_bytes(pool, 0),
1154                 (unsigned long)apr_pool_num_bytes(pool, 1),
1155                 (unsigned long)apr_pool_num_bytes(global_pool, 1),
1156                 (unsigned int)pool, pool->tag,
1157                 file_line,
1158                 pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear);
1159         }
1160         else {
1161             apr_file_printf(file_stderr,
1162                 "POOL DEBUG: "
1163                 "[%lu"
1164 #if APR_HAS_THREADS
1165                 "/%lu"
1166 #endif /* APR_HAS_THREADS */
1167                 "] "
1168                 "%7s "
1169                 "                                   "
1170                 "0x%08X "
1171                 "<%s> "
1172                 "\n",
1173                 (unsigned long)getpid(),
1174 #if APR_HAS_THREADS
1175                 (unsigned long)apr_os_thread_current(),
1176 #endif /* APR_HAS_THREADS */
1177                 event,
1178                 (unsigned int)pool,
1179                 file_line);
1180         }
1181     }
1182 }
1183 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1184
1185 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)
1186 static int pool_is_child_of(apr_pool_t *parent, void *data)
1187 {
1188     apr_pool_t *pool = (apr_pool_t *)data;
1189
1190     return (pool == parent);
1191 }
1192
1193 static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent)
1194 {
1195     if (parent == NULL)
1196         return 0;
1197
1198     return apr_pool_walk_tree(parent, pool_is_child_of, pool);
1199 }
1200 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */
1201
1202 static void apr_pool_check_integrity(apr_pool_t *pool)
1203 {
1204     /* Rule of thumb: use of the global pool is always
1205      * ok, since the only user is apr_pools.c.  Unless
1206      * people have searched for the top level parent and
1207      * started to use that...
1208      */
1209     if (pool == global_pool || global_pool == NULL)
1210         return;
1211
1212     /* Lifetime
1213      * This basically checks to see if the pool being used is still
1214      * a relative to the global pool.  If not it was previously
1215      * destroyed, in which case we abort().
1216      */
1217 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)
1218     if (!apr_pool_is_child_of(pool, global_pool)) {
1219 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1220         apr_pool_log_event(pool, "LIFE",
1221                            __FILE__ ":apr_pool_integrity check", 0);
1222 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1223         abort();
1224     }
1225 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */
1226
1227 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER)
1228 #if APR_HAS_THREADS
1229     if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) {
1230 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1231         apr_pool_log_event(pool, "THREAD",
1232                            __FILE__ ":apr_pool_integrity check", 0);
1233 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1234         abort();
1235     }
1236 #endif /* APR_HAS_THREADS */
1237 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */
1238 }
1239
1240
1241 /*
1242  * Initialization (debug)
1243  */
1244
1245 APR_DECLARE(apr_status_t) apr_pool_initialize(void)
1246 {
1247     apr_status_t rv;
1248
1249     if (apr_pools_initialized++)
1250         return APR_SUCCESS;
1251
1252     /* Since the debug code works a bit differently then the
1253      * regular pools code, we ask for a lock here.  The regular
1254      * pools code has got this lock embedded in the global
1255      * allocator, a concept unknown to debug mode.
1256      */
1257     if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL,
1258                                  NULL)) != APR_SUCCESS) {
1259         return rv;
1260     }
1261
1262     apr_pool_tag(global_pool, "APR global pool");
1263
1264     apr_pools_initialized = 1;
1265
1266     /* This has to happen here because mutexes might be backed by
1267      * atomics.  It used to be snug and safe in apr_initialize().
1268      */
1269     if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) {
1270         return rv;
1271     }
1272
1273 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1274     apr_file_open_stderr(&file_stderr, global_pool);
1275     if (file_stderr) {
1276         apr_file_printf(file_stderr,
1277             "POOL DEBUG: [PID"
1278 #if APR_HAS_THREADS
1279             "/TID"
1280 #endif /* APR_HAS_THREADS */
1281             "] ACTION  (SIZE      /POOL SIZE /TOTAL SIZE) "
1282             "POOL       \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n");
1283
1284         apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0);
1285     }
1286 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1287
1288     return APR_SUCCESS;
1289 }
1290
1291 APR_DECLARE(void) apr_pool_terminate(void)
1292 {
1293     if (!apr_pools_initialized)
1294         return;
1295
1296     apr_pools_initialized = 0;
1297
1298     apr_pool_destroy(global_pool); /* This will also destroy the mutex */
1299     global_pool = NULL;
1300
1301 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1302     file_stderr = NULL;
1303 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1304 }
1305
1306
1307 /*
1308  * Memory allocation (debug)
1309  */
1310
1311 static void *pool_alloc(apr_pool_t *pool, apr_size_t size)
1312 {
1313     debug_node_t *node;
1314     void *mem;
1315
1316     if ((mem = malloc(size)) == NULL) {
1317         if (pool->abort_fn)
1318             pool->abort_fn(APR_ENOMEM);
1319
1320         return NULL;
1321     }
1322
1323     node = pool->nodes;
1324     if (node == NULL || node->index == 64) {
1325         if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) {
1326             if (pool->abort_fn)
1327                 pool->abort_fn(APR_ENOMEM);
1328
1329             return NULL;
1330         }
1331
1332         memset(node, 0, SIZEOF_DEBUG_NODE_T);
1333
1334         node->next = pool->nodes;
1335         pool->nodes = node;
1336         node->index = 0;
1337     }
1338
1339     node->beginp[node->index] = mem;
1340     node->endp[node->index] = (char *)mem + size;
1341     node->index++;
1342
1343     pool->stat_alloc++;
1344     pool->stat_total_alloc++;
1345
1346     return mem;
1347 }
1348
1349 APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size,
1350                                      const char *file_line)
1351 {
1352     void *mem;
1353
1354     apr_pool_check_integrity(pool);
1355
1356     mem = pool_alloc(pool, size);
1357
1358 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC)
1359     apr_pool_log_event(pool, "PALLOC", file_line, 1);
1360 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
1361
1362     return mem;
1363 }
1364
1365 APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size,
1366                                       const char *file_line)
1367 {
1368     void *mem;
1369
1370     apr_pool_check_integrity(pool);
1371
1372     mem = pool_alloc(pool, size);
1373     memset(mem, 0, size);
1374
1375 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC)
1376     apr_pool_log_event(pool, "PCALLOC", file_line, 1);
1377 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
1378
1379     return mem;
1380 }
1381
1382
1383 /*
1384  * Pool creation/destruction (debug)
1385  */
1386
1387 #define POOL_POISON_BYTE 'A'
1388
1389 static void pool_clear_debug(apr_pool_t *pool, const char *file_line)
1390 {
1391     debug_node_t *node;
1392     apr_uint32_t index;
1393
1394     /* Destroy the subpools.  The subpools will detach themselves from
1395      * this pool thus this loop is safe and easy.
1396      */
1397     while (pool->child)
1398         apr_pool_destroy_debug(pool->child, file_line);
1399
1400     /* Run cleanups */
1401     run_cleanups(&pool->cleanups);
1402     pool->cleanups = NULL;
1403
1404     /* Free subprocesses */
1405     free_proc_chain(pool->subprocesses);
1406     pool->subprocesses = NULL;
1407
1408     /* Clear the user data. */
1409     pool->user_data = NULL;
1410
1411     /* Free the blocks, scribbling over them first to help highlight
1412      * use-after-free issues. */
1413     while ((node = pool->nodes) != NULL) {
1414         pool->nodes = node->next;
1415
1416         for (index = 0; index < node->index; index++) {
1417             memset(node->beginp[index], POOL_POISON_BYTE,
1418                    node->endp[index] - node->beginp[index]);
1419             free(node->beginp[index]);
1420         }
1421
1422         memset(node, POOL_POISON_BYTE, SIZEOF_DEBUG_NODE_T);
1423         free(node);
1424     }
1425
1426     pool->stat_alloc = 0;
1427     pool->stat_clear++;
1428 }
1429
1430 APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool,
1431                                        const char *file_line)
1432 {
1433 #if APR_HAS_THREADS
1434     apr_thread_mutex_t *mutex = NULL;
1435 #endif
1436
1437     apr_pool_check_integrity(pool);
1438
1439 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
1440     apr_pool_log_event(pool, "CLEAR", file_line, 1);
1441 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
1442
1443 #if APR_HAS_THREADS
1444     if (pool->parent != NULL)
1445         mutex = pool->parent->mutex;
1446
1447     /* Lock the parent mutex before clearing so that if we have our
1448      * own mutex it won't be accessed by apr_pool_walk_tree after
1449      * it has been destroyed.
1450      */
1451     if (mutex != NULL && mutex != pool->mutex) {
1452         apr_thread_mutex_lock(mutex);
1453     }
1454 #endif
1455
1456     pool_clear_debug(pool, file_line);
1457
1458 #if APR_HAS_THREADS
1459     /* If we had our own mutex, it will have been destroyed by
1460      * the registered cleanups.  Recreate the mutex.  Unlock
1461      * the mutex we obtained above.
1462      */
1463     if (mutex != pool->mutex) {
1464         (void)apr_thread_mutex_create(&pool->mutex,
1465                                       APR_THREAD_MUTEX_NESTED, pool);
1466
1467         if (mutex != NULL)
1468             (void)apr_thread_mutex_unlock(mutex);
1469     }
1470 #endif /* APR_HAS_THREADS */
1471 }
1472
1473 APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool,
1474                                          const char *file_line)
1475 {
1476     apr_pool_check_integrity(pool);
1477
1478 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
1479     apr_pool_log_event(pool, "DESTROY", file_line, 1);
1480 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
1481
1482     pool_clear_debug(pool, file_line);
1483
1484     /* Remove the pool from the parents child list */
1485     if (pool->parent) {
1486 #if APR_HAS_THREADS
1487         apr_thread_mutex_t *mutex;
1488
1489         if ((mutex = pool->parent->mutex) != NULL)
1490             apr_thread_mutex_lock(mutex);
1491 #endif /* APR_HAS_THREADS */
1492
1493         if ((*pool->ref = pool->sibling) != NULL)
1494             pool->sibling->ref = pool->ref;
1495
1496 #if APR_HAS_THREADS
1497         if (mutex)
1498             apr_thread_mutex_unlock(mutex);
1499 #endif /* APR_HAS_THREADS */
1500     }
1501
1502     if (pool->allocator != NULL
1503         && apr_allocator_owner_get(pool->allocator) == pool) {
1504         apr_allocator_destroy(pool->allocator);
1505     }
1506
1507     /* Free the pool itself */
1508     free(pool);
1509 }
1510
1511 APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool,
1512                                                    apr_pool_t *parent,
1513                                                    apr_abortfunc_t abort_fn,
1514                                                    apr_allocator_t *allocator,
1515                                                    const char *file_line)
1516 {
1517     apr_pool_t *pool;
1518
1519     *newpool = NULL;
1520
1521     if (!parent) {
1522         parent = global_pool;
1523     }
1524     else {
1525        apr_pool_check_integrity(parent);
1526
1527        if (!allocator)
1528            allocator = parent->allocator;
1529     }
1530
1531     if (!abort_fn && parent)
1532         abort_fn = parent->abort_fn;
1533
1534     if ((pool = malloc(SIZEOF_POOL_T)) == NULL) {
1535         if (abort_fn)
1536             abort_fn(APR_ENOMEM);
1537
1538          return APR_ENOMEM;
1539     }
1540
1541     memset(pool, 0, SIZEOF_POOL_T);
1542
1543     pool->allocator = allocator;
1544     pool->abort_fn = abort_fn;
1545     pool->tag = file_line;
1546     pool->file_line = file_line;
1547
1548     if ((pool->parent = parent) != NULL) {
1549 #if APR_HAS_THREADS
1550         if (parent->mutex)
1551             apr_thread_mutex_lock(parent->mutex);
1552 #endif /* APR_HAS_THREADS */
1553         if ((pool->sibling = parent->child) != NULL)
1554             pool->sibling->ref = &pool->sibling;
1555
1556         parent->child = pool;
1557         pool->ref = &parent->child;
1558
1559 #if APR_HAS_THREADS
1560         if (parent->mutex)
1561             apr_thread_mutex_unlock(parent->mutex);
1562 #endif /* APR_HAS_THREADS */
1563     }
1564     else {
1565         pool->sibling = NULL;
1566         pool->ref = NULL;
1567     }
1568
1569 #if APR_HAS_THREADS
1570     pool->owner = apr_os_thread_current();
1571 #endif /* APR_HAS_THREADS */
1572
1573     if (parent == NULL || parent->allocator != allocator) {
1574 #if APR_HAS_THREADS
1575         apr_status_t rv;
1576
1577         /* No matter what the creation flags say, always create
1578          * a lock.  Without it integrity_check and apr_pool_num_bytes
1579          * blow up (because they traverse pools child lists that
1580          * possibly belong to another thread, in combination with
1581          * the pool having no lock).  However, this might actually
1582          * hide problems like creating a child pool of a pool
1583          * belonging to another thread.
1584          */
1585         if ((rv = apr_thread_mutex_create(&pool->mutex,
1586                 APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) {
1587             free(pool);
1588             return rv;
1589         }
1590 #endif /* APR_HAS_THREADS */
1591     }
1592     else {
1593 #if APR_HAS_THREADS
1594         if (parent)
1595             pool->mutex = parent->mutex;
1596 #endif /* APR_HAS_THREADS */
1597     }
1598
1599     *newpool = pool;
1600
1601 #if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
1602     apr_pool_log_event(pool, "CREATE", file_line, 1);
1603 #endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
1604
1605     return APR_SUCCESS;
1606 }
1607
1608
1609 /*
1610  * "Print" functions (debug)
1611  */
1612
1613 struct psprintf_data {
1614     apr_vformatter_buff_t vbuff;
1615     char      *mem;
1616     apr_size_t size;
1617 };
1618
1619 static int psprintf_flush(apr_vformatter_buff_t *vbuff)
1620 {
1621     struct psprintf_data *ps = (struct psprintf_data *)vbuff;
1622     apr_size_t size;
1623
1624     size = ps->vbuff.curpos - ps->mem;
1625
1626     ps->size <<= 1;
1627     if ((ps->mem = realloc(ps->mem, ps->size)) == NULL)
1628         return -1;
1629
1630     ps->vbuff.curpos = ps->mem + size;
1631     ps->vbuff.endpos = ps->mem + ps->size - 1;
1632
1633     return 0;
1634 }
1635
1636 APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap)
1637 {
1638     struct psprintf_data ps;
1639     debug_node_t *node;
1640
1641     apr_pool_check_integrity(pool);
1642
1643     ps.size = 64;
1644     ps.mem = malloc(ps.size);
1645     ps.vbuff.curpos  = ps.mem;
1646
1647     /* Save a byte for the NUL terminator */
1648     ps.vbuff.endpos = ps.mem + ps.size - 1;
1649
1650     if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) {
1651         if (pool->abort_fn)
1652             pool->abort_fn(APR_ENOMEM);
1653
1654         return NULL;
1655     }
1656
1657     *ps.vbuff.curpos++ = '\0';
1658
1659     /*
1660      * Link the node in
1661      */
1662     node = pool->nodes;
1663     if (node == NULL || node->index == 64) {
1664         if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) {
1665             if (pool->abort_fn)
1666                 pool->abort_fn(APR_ENOMEM);
1667
1668             return NULL;
1669         }
1670
1671         node->next = pool->nodes;
1672         pool->nodes = node;
1673         node->index = 0;
1674     }
1675
1676     node->beginp[node->index] = ps.mem;
1677     node->endp[node->index] = ps.mem + ps.size;
1678     node->index++;
1679
1680     return ps.mem;
1681 }
1682
1683
1684 /*
1685  * Debug functions
1686  */
1687
1688 APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub)
1689 {
1690 }
1691
1692 static int pool_find(apr_pool_t *pool, void *data)
1693 {
1694     void **pmem = (void **)data;
1695     debug_node_t *node;
1696     apr_uint32_t index;
1697
1698     node = pool->nodes;
1699
1700     while (node) {
1701         for (index = 0; index < node->index; index++) {
1702              if (node->beginp[index] <= *pmem
1703                  && node->endp[index] > *pmem) {
1704                  *pmem = pool;
1705                  return 1;
1706              }
1707         }
1708
1709         node = node->next;
1710     }
1711
1712     return 0;
1713 }
1714
1715 APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem)
1716 {
1717     void *pool = (void *)mem;
1718
1719     if (apr_pool_walk_tree(global_pool, pool_find, &pool))
1720         return pool;
1721
1722     return NULL;
1723 }
1724
1725 static int pool_num_bytes(apr_pool_t *pool, void *data)
1726 {
1727     apr_size_t *psize = (apr_size_t *)data;
1728     debug_node_t *node;
1729     apr_uint32_t index;
1730
1731     node = pool->nodes;
1732
1733     while (node) {
1734         for (index = 0; index < node->index; index++) {
1735             *psize += (char *)node->endp[index] - (char *)node->beginp[index];
1736         }
1737
1738         node = node->next;
1739     }
1740
1741     return 0;
1742 }
1743
1744 APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *pool, int recurse)
1745 {
1746     apr_size_t size = 0;
1747
1748     if (!recurse) {
1749         pool_num_bytes(pool, &size);
1750
1751         return size;
1752     }
1753
1754     apr_pool_walk_tree(pool, pool_num_bytes, &size);
1755
1756     return size;
1757 }
1758
1759 APR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag)
1760 {
1761 }
1762
1763 #endif /* !APR_POOL_DEBUG */
1764
1765
1766 /*
1767  * "Print" functions (common)
1768  */
1769
1770 APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...)
1771 {
1772     va_list ap;
1773     char *res;
1774
1775     va_start(ap, fmt);
1776     res = apr_pvsprintf(p, fmt, ap);
1777     va_end(ap);
1778     return res;
1779 }
1780
1781 /*
1782  * Pool Properties
1783  */
1784
1785 APR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abort_fn,
1786                                      apr_pool_t *pool)
1787 {
1788     pool->abort_fn = abort_fn;
1789 }
1790
1791 APR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool)
1792 {
1793     return pool->abort_fn;
1794 }
1795
1796 APR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool)
1797 {
1798 #ifdef NETWARE
1799     /* On NetWare, don't return the global_pool, return the application pool 
1800        as the top most pool */
1801     if (pool->parent == global_pool)
1802         return NULL;
1803     else
1804 #endif
1805     return pool->parent;
1806 }
1807
1808 APR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool)
1809 {
1810     return pool->allocator;
1811 }
1812
1813 /* return TRUE if a is an ancestor of b
1814  * NULL is considered an ancestor of all pools
1815  */
1816 APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b)
1817 {
1818     if (a == NULL)
1819         return 1;
1820
1821     while (b) {
1822         if (a == b)
1823             return 1;
1824
1825         b = b->parent;
1826     }
1827
1828     return 0;
1829 }
1830
1831 APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag)
1832 {
1833     pool->tag = tag;
1834 }
1835
1836
1837 /*
1838  * User data management
1839  */
1840
1841 APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, const char *key,
1842                                                 apr_status_t (*cleanup) (void *),
1843                                                 apr_pool_t *pool)
1844 {
1845 #if APR_POOL_DEBUG
1846     apr_pool_check_integrity(pool);
1847 #endif /* APR_POOL_DEBUG */
1848
1849     if (pool->user_data == NULL)
1850         pool->user_data = apr_hash_make(pool);
1851
1852     if (apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING) == NULL) {
1853         char *new_key = apr_pstrdup(pool, key);
1854         apr_hash_set(pool->user_data, new_key, APR_HASH_KEY_STRING, data);
1855     }
1856     else {
1857         apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data);
1858     }
1859
1860     if (cleanup)
1861         apr_pool_cleanup_register(pool, data, cleanup, cleanup);
1862
1863     return APR_SUCCESS;
1864 }
1865
1866 APR_DECLARE(apr_status_t) apr_pool_userdata_setn(const void *data,
1867                               const char *key,
1868                               apr_status_t (*cleanup)(void *),
1869                               apr_pool_t *pool)
1870 {
1871 #if APR_POOL_DEBUG
1872     apr_pool_check_integrity(pool);
1873 #endif /* APR_POOL_DEBUG */
1874
1875     if (pool->user_data == NULL)
1876         pool->user_data = apr_hash_make(pool);
1877
1878     apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data);
1879
1880     if (cleanup)
1881         apr_pool_cleanup_register(pool, data, cleanup, cleanup);
1882
1883     return APR_SUCCESS;
1884 }
1885
1886 APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key,
1887                                                 apr_pool_t *pool)
1888 {
1889 #if APR_POOL_DEBUG
1890     apr_pool_check_integrity(pool);
1891 #endif /* APR_POOL_DEBUG */
1892
1893     if (pool->user_data == NULL) {
1894         *data = NULL;
1895     }
1896     else {
1897         *data = apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING);
1898     }
1899
1900     return APR_SUCCESS;
1901 }
1902
1903
1904 /*
1905  * Cleanup
1906  */
1907
1908 struct cleanup_t {
1909     struct cleanup_t *next;
1910     const void *data;
1911     apr_status_t (*plain_cleanup_fn)(void *data);
1912     apr_status_t (*child_cleanup_fn)(void *data);
1913 };
1914
1915 APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void *data,
1916                       apr_status_t (*plain_cleanup_fn)(void *data),
1917                       apr_status_t (*child_cleanup_fn)(void *data))
1918 {
1919     cleanup_t *c;
1920
1921 #if APR_POOL_DEBUG
1922     apr_pool_check_integrity(p);
1923 #endif /* APR_POOL_DEBUG */
1924
1925     if (p != NULL) {
1926         c = (cleanup_t *)apr_palloc(p, sizeof(cleanup_t));
1927         c->data = data;
1928         c->plain_cleanup_fn = plain_cleanup_fn;
1929         c->child_cleanup_fn = child_cleanup_fn;
1930         c->next = p->cleanups;
1931         p->cleanups = c;
1932     }
1933 }
1934
1935 APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data,
1936                       apr_status_t (*cleanup_fn)(void *))
1937 {
1938     cleanup_t *c, **lastp;
1939
1940 #if APR_POOL_DEBUG
1941     apr_pool_check_integrity(p);
1942 #endif /* APR_POOL_DEBUG */
1943
1944     if (p == NULL)
1945         return;
1946
1947     c = p->cleanups;
1948     lastp = &p->cleanups;
1949     while (c) {
1950         if (c->data == data && c->plain_cleanup_fn == cleanup_fn) {
1951             *lastp = c->next;
1952             break;
1953         }
1954
1955         lastp = &c->next;
1956         c = c->next;
1957     }
1958 }
1959
1960 APR_DECLARE(void) apr_pool_child_cleanup_set(apr_pool_t *p, const void *data,
1961                       apr_status_t (*plain_cleanup_fn)(void *),
1962                       apr_status_t (*child_cleanup_fn)(void *))
1963 {
1964     cleanup_t *c;
1965
1966 #if APR_POOL_DEBUG
1967     apr_pool_check_integrity(p);
1968 #endif /* APR_POOL_DEBUG */
1969
1970     if (p == NULL)
1971         return;
1972
1973     c = p->cleanups;
1974     while (c) {
1975         if (c->data == data && c->plain_cleanup_fn == plain_cleanup_fn) {
1976             c->child_cleanup_fn = child_cleanup_fn;
1977             break;
1978         }
1979
1980         c = c->next;
1981     }
1982 }
1983
1984 APR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data,
1985                               apr_status_t (*cleanup_fn)(void *))
1986 {
1987     apr_pool_cleanup_kill(p, data, cleanup_fn);
1988     return (*cleanup_fn)(data);
1989 }
1990
1991 static void run_cleanups(cleanup_t **cref)
1992 {
1993     cleanup_t *c = *cref;
1994
1995     while (c) {
1996         *cref = c->next;
1997         (*c->plain_cleanup_fn)((void *)c->data);
1998         c = *cref;
1999     }
2000 }
2001
2002 static void run_child_cleanups(cleanup_t **cref)
2003 {
2004     cleanup_t *c = *cref;
2005
2006     while (c) {
2007         *cref = c->next;
2008         (*c->child_cleanup_fn)((void *)c->data);
2009         c = *cref;
2010     }
2011 }
2012
2013 static void cleanup_pool_for_exec(apr_pool_t *p)
2014 {
2015     run_child_cleanups(&p->cleanups);
2016
2017     for (p = p->child; p; p = p->sibling)
2018         cleanup_pool_for_exec(p);
2019 }
2020
2021 APR_DECLARE(void) apr_pool_cleanup_for_exec(void)
2022 {
2023 #if !defined(WIN32) && !defined(OS2)
2024     /*
2025      * Don't need to do anything on NT or OS/2, because I
2026      * am actually going to spawn the new process - not
2027      * exec it. All handles that are not inheritable, will
2028      * be automajically closed. The only problem is with
2029      * file handles that are open, but there isn't much
2030      * I can do about that (except if the child decides
2031      * to go out and close them
2032      */
2033     cleanup_pool_for_exec(global_pool);
2034 #endif /* !defined(WIN32) && !defined(OS2) */
2035 }
2036
2037 APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data)
2038 {
2039     /* do nothing cleanup routine */
2040     return APR_SUCCESS;
2041 }
2042
2043 /* Subprocesses don't use the generic cleanup interface because
2044  * we don't want multiple subprocesses to result in multiple
2045  * three-second pauses; the subprocesses have to be "freed" all
2046  * at once.  If other resources are introduced with the same property,
2047  * we might want to fold support for that into the generic interface.
2048  * For now, it's a special case.
2049  */
2050 APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *pool, apr_proc_t *proc,
2051                                            apr_kill_conditions_e how)
2052 {
2053     struct process_chain *pc = apr_palloc(pool, sizeof(struct process_chain));
2054
2055     pc->proc = proc;
2056     pc->kill_how = how;
2057     pc->next = pool->subprocesses;
2058     pool->subprocesses = pc;
2059 }
2060
2061 static void free_proc_chain(struct process_chain *procs)
2062 {
2063     /* Dispose of the subprocesses we've spawned off in the course of
2064      * whatever it was we're cleaning up now.  This may involve killing
2065      * some of them off...
2066      */
2067     struct process_chain *pc;
2068     int need_timeout = 0;
2069     apr_time_t timeout_interval;
2070
2071     if (!procs)
2072         return; /* No work.  Whew! */
2073
2074     /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL
2075      * dance with any of the processes we're cleaning up.  If we've got
2076      * any kill-on-sight subprocesses, ditch them now as well, so they
2077      * don't waste any more cycles doing whatever it is that they shouldn't
2078      * be doing anymore.
2079      */
2080
2081 #ifndef NEED_WAITPID
2082     /* Pick up all defunct processes */
2083     for (pc = procs; pc; pc = pc->next) {
2084         if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) != APR_CHILD_NOTDONE)
2085             pc->kill_how = APR_KILL_NEVER;
2086     }
2087 #endif /* !defined(NEED_WAITPID) */
2088
2089     for (pc = procs; pc; pc = pc->next) {
2090 #ifndef WIN32
2091         if ((pc->kill_how == APR_KILL_AFTER_TIMEOUT)
2092             || (pc->kill_how == APR_KILL_ONLY_ONCE)) {
2093             /*
2094              * Subprocess may be dead already.  Only need the timeout if not.
2095              * Note: apr_proc_kill on Windows is TerminateProcess(), which is
2096              * similar to a SIGKILL, so always give the process a timeout
2097              * under Windows before killing it.
2098              */
2099             if (apr_proc_kill(pc->proc, SIGTERM) == APR_SUCCESS)
2100                 need_timeout = 1;
2101         }
2102         else if (pc->kill_how == APR_KILL_ALWAYS) {
2103 #else /* WIN32 knows only one fast, clean method of killing processes today */
2104         if (pc->kill_how != APR_KILL_NEVER) {
2105             need_timeout = 1;
2106             pc->kill_how = APR_KILL_ALWAYS;
2107 #endif
2108             apr_proc_kill(pc->proc, SIGKILL);
2109         }
2110     }
2111
2112     /* Sleep only if we have to. The sleep algorithm grows
2113      * by a factor of two on each iteration. TIMEOUT_INTERVAL
2114      * is equal to TIMEOUT_USECS / 64.
2115      */
2116     if (need_timeout) {
2117         timeout_interval = TIMEOUT_INTERVAL;
2118         apr_sleep(timeout_interval);
2119
2120         do {
2121             /* check the status of the subprocesses */
2122             need_timeout = 0;
2123             for (pc = procs; pc; pc = pc->next) {
2124                 if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) {
2125                     if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT)
2126                             == APR_CHILD_NOTDONE)
2127                         need_timeout = 1;               /* subprocess is still active */
2128                     else
2129                         pc->kill_how = APR_KILL_NEVER;  /* subprocess has exited */
2130                 }
2131             }
2132             if (need_timeout) {
2133                 if (timeout_interval >= TIMEOUT_USECS) {
2134                     break;
2135                 }
2136                 apr_sleep(timeout_interval);
2137                 timeout_interval *= 2;
2138             }
2139         } while (need_timeout);
2140     }
2141
2142     /* OK, the scripts we just timed out for have had a chance to clean up
2143      * --- now, just get rid of them, and also clean up the system accounting
2144      * goop...
2145      */
2146     for (pc = procs; pc; pc = pc->next) {
2147         if (pc->kill_how == APR_KILL_AFTER_TIMEOUT)
2148             apr_proc_kill(pc->proc, SIGKILL);
2149     }
2150
2151     /* Now wait for all the signaled processes to die */
2152     for (pc = procs; pc; pc = pc->next) {
2153         if (pc->kill_how != APR_KILL_NEVER)
2154             (void)apr_proc_wait(pc->proc, NULL, NULL, APR_WAIT);
2155     }
2156 }
2157
2158
2159 /*
2160  * Pool creation/destruction stubs, for people who are running
2161  * mixed release/debug enviroments.
2162  */
2163
2164 #if !APR_POOL_DEBUG
2165 APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size,
2166                                      const char *file_line)
2167 {
2168     return apr_palloc(pool, size);
2169 }
2170
2171 APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size,
2172                                       const char *file_line)
2173 {
2174     return apr_pcalloc(pool, size);
2175 }
2176
2177 APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool,
2178                                        const char *file_line)
2179 {
2180     apr_pool_clear(pool);
2181 }
2182
2183 APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool,
2184                                          const char *file_line)
2185 {
2186     apr_pool_destroy(pool);
2187 }
2188
2189 APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool,
2190                                                    apr_pool_t *parent,
2191                                                    apr_abortfunc_t abort_fn,
2192                                                    apr_allocator_t *allocator,
2193                                                    const char *file_line)
2194 {
2195     return apr_pool_create_ex(newpool, parent, abort_fn, allocator);
2196 }
2197
2198 #else /* APR_POOL_DEBUG */
2199
2200 #undef apr_palloc
2201 APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size);
2202
2203 APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size)
2204 {
2205     return apr_palloc_debug(pool, size, "undefined");
2206 }
2207
2208 #undef apr_pcalloc
2209 APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size);
2210
2211 APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size)
2212 {
2213     return apr_pcalloc_debug(pool, size, "undefined");
2214 }
2215
2216 #undef apr_pool_clear
2217 APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool);
2218
2219 APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool)
2220 {
2221     apr_pool_clear_debug(pool, "undefined");
2222 }
2223
2224 #undef apr_pool_destroy
2225 APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool);
2226
2227 APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool)
2228 {
2229     apr_pool_destroy_debug(pool, "undefined");
2230 }
2231
2232 #undef apr_pool_create_ex
2233 APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
2234                                              apr_pool_t *parent,
2235                                              apr_abortfunc_t abort_fn,
2236                                              apr_allocator_t *allocator);
2237
2238 APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
2239                                              apr_pool_t *parent,
2240                                              apr_abortfunc_t abort_fn,
2241                                              apr_allocator_t *allocator)
2242 {
2243     return apr_pool_create_ex_debug(newpool, parent,
2244                                     abort_fn, allocator,
2245                                     "undefined");
2246 }
2247
2248 #endif /* APR_POOL_DEBUG */
2249
2250 /* Deprecated */
2251 APR_DECLARE(void) apr_allocator_set_max_free(apr_allocator_t *allocator,
2252                                              apr_size_t size)
2253 {
2254     apr_allocator_max_free_set(allocator, size);
2255 }
2256
2257 /* Deprecated */
2258 APR_DECLARE(void) apr_pool_set_abort(apr_abortfunc_t abort_fn,
2259                                      apr_pool_t *pool)
2260 {
2261     apr_pool_abort_set(abort_fn, pool);
2262 }
2263
2264 /* Deprecated */
2265 APR_DECLARE(apr_abortfunc_t) apr_pool_get_abort(apr_pool_t *pool)
2266 {
2267     return apr_pool_abort_get(pool);
2268 }
2269
2270 /* Deprecated */
2271 APR_DECLARE(apr_pool_t *) apr_pool_get_parent(apr_pool_t *pool)
2272 {
2273     return apr_pool_parent_get(pool);
2274 }
2275
2276 /* Deprecated */
2277 APR_DECLARE(void) apr_allocator_set_owner(apr_allocator_t *allocator,
2278                                           apr_pool_t *pool)
2279 {
2280     apr_allocator_owner_set(allocator, pool);
2281 }
2282
2283 /* Deprecated */
2284 APR_DECLARE(apr_pool_t *) apr_allocator_get_owner(
2285                                   apr_allocator_t *allocator)
2286 {
2287     return apr_allocator_owner_get(allocator);
2288 }
2289
2290 #if APR_HAS_THREADS
2291 /* Deprecated */
2292 APR_DECLARE(apr_thread_mutex_t *) apr_allocator_get_mutex(
2293                                       apr_allocator_t *allocator)
2294 {
2295     return apr_allocator_mutex_get(allocator);
2296 }
2297
2298 /* Deprecated */
2299 APR_DECLARE(void) apr_allocator_set_mutex(apr_allocator_t *allocator,
2300                                           apr_thread_mutex_t *mutex)
2301 {
2302     apr_allocator_mutex_set(allocator, mutex);
2303 }
2304 #endif /* APR_HAS_THREADS */
2305