1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr.h"
18251875Speter#include "apr_private.h"
19251875Speter
20251875Speter#include "apr_atomic.h"
21251875Speter#include "apr_portable.h" /* for get_os_proc */
22251875Speter#include "apr_strings.h"
23251875Speter#include "apr_general.h"
24251875Speter#include "apr_pools.h"
25251875Speter#include "apr_allocator.h"
26251875Speter#include "apr_lib.h"
27251875Speter#include "apr_thread_mutex.h"
28251875Speter#include "apr_hash.h"
29251875Speter#include "apr_time.h"
30251875Speter#define APR_WANT_MEMFUNC
31251875Speter#include "apr_want.h"
32251875Speter#include "apr_env.h"
33251875Speter
34251875Speter#if APR_HAVE_STDLIB_H
35251875Speter#include <stdlib.h>     /* for malloc, free and abort */
36251875Speter#endif
37251875Speter
38251875Speter#if APR_HAVE_UNISTD_H
39251875Speter#include <unistd.h>     /* for getpid and sysconf */
40251875Speter#endif
41251875Speter
42251875Speter#if APR_ALLOCATOR_USES_MMAP
43251875Speter#include <sys/mman.h>
44251875Speter#endif
45251875Speter
46251875Speter/*
47251875Speter * Magic numbers
48251875Speter */
49251875Speter
50251875Speter/*
51251875Speter * XXX: This is not optimal when using --enable-allocator-uses-mmap on
52251875Speter * XXX: machines with large pagesize, but currently the sink is assumed
53251875Speter * XXX: to be index 0, so MIN_ALLOC must be at least two pages.
54251875Speter */
55251875Speter#define MIN_ALLOC (2 * BOUNDARY_SIZE)
56251875Speter#define MAX_INDEX   20
57251875Speter
58251875Speter#if APR_ALLOCATOR_USES_MMAP && defined(_SC_PAGESIZE)
59251875Speterstatic unsigned int boundary_index;
60251875Speterstatic unsigned int boundary_size;
61251875Speter#define BOUNDARY_INDEX  boundary_index
62251875Speter#define BOUNDARY_SIZE   boundary_size
63251875Speter#else
64251875Speter#define BOUNDARY_INDEX 12
65251875Speter#define BOUNDARY_SIZE (1 << BOUNDARY_INDEX)
66251875Speter#endif
67251875Speter
68251875Speter/*
69251875Speter * Timing constants for killing subprocesses
70251875Speter * There is a total 3-second delay between sending a SIGINT
71251875Speter * and sending of the final SIGKILL.
72251875Speter * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64
73251875Speter * for the exponetial timeout alogrithm.
74251875Speter */
75251875Speter#define TIMEOUT_USECS    3000000
76251875Speter#define TIMEOUT_INTERVAL   46875
77251875Speter
78251875Speter/*
79251875Speter * Allocator
80251875Speter *
81251875Speter * @note The max_free_index and current_free_index fields are not really
82251875Speter * indices, but quantities of BOUNDARY_SIZE big memory blocks.
83251875Speter */
84251875Speter
85251875Speterstruct apr_allocator_t {
86251875Speter    /** largest used index into free[], always < MAX_INDEX */
87251875Speter    apr_uint32_t        max_index;
88251875Speter    /** Total size (in BOUNDARY_SIZE multiples) of unused memory before
89251875Speter     * blocks are given back. @see apr_allocator_max_free_set().
90251875Speter     * @note Initialized to APR_ALLOCATOR_MAX_FREE_UNLIMITED,
91251875Speter     * which means to never give back blocks.
92251875Speter     */
93251875Speter    apr_uint32_t        max_free_index;
94251875Speter    /**
95251875Speter     * Memory size (in BOUNDARY_SIZE multiples) that currently must be freed
96251875Speter     * before blocks are given back. Range: 0..max_free_index
97251875Speter     */
98251875Speter    apr_uint32_t        current_free_index;
99251875Speter#if APR_HAS_THREADS
100251875Speter    apr_thread_mutex_t *mutex;
101251875Speter#endif /* APR_HAS_THREADS */
102251875Speter    apr_pool_t         *owner;
103251875Speter    /**
104251875Speter     * Lists of free nodes. Slot 0 is used for oversized nodes,
105251875Speter     * and the slots 1..MAX_INDEX-1 contain nodes of sizes
106251875Speter     * (i+1) * BOUNDARY_SIZE. Example for BOUNDARY_INDEX == 12:
107251875Speter     * slot  0: nodes larger than 81920
108251875Speter     * slot  1: size  8192
109251875Speter     * slot  2: size 12288
110251875Speter     * ...
111251875Speter     * slot 19: size 81920
112251875Speter     */
113251875Speter    apr_memnode_t      *free[MAX_INDEX];
114251875Speter};
115251875Speter
116251875Speter#define SIZEOF_ALLOCATOR_T  APR_ALIGN_DEFAULT(sizeof(apr_allocator_t))
117251875Speter
118251875Speter
119251875Speter/*
120251875Speter * Allocator
121251875Speter */
122251875Speter
123251875SpeterAPR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator)
124251875Speter{
125251875Speter    apr_allocator_t *new_allocator;
126251875Speter
127251875Speter    *allocator = NULL;
128251875Speter
129251875Speter    if ((new_allocator = malloc(SIZEOF_ALLOCATOR_T)) == NULL)
130251875Speter        return APR_ENOMEM;
131251875Speter
132251875Speter    memset(new_allocator, 0, SIZEOF_ALLOCATOR_T);
133251875Speter    new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
134251875Speter
135251875Speter    *allocator = new_allocator;
136251875Speter
137251875Speter    return APR_SUCCESS;
138251875Speter}
139251875Speter
140251875SpeterAPR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator)
141251875Speter{
142251875Speter    apr_uint32_t index;
143251875Speter    apr_memnode_t *node, **ref;
144251875Speter
145251875Speter    for (index = 0; index < MAX_INDEX; index++) {
146251875Speter        ref = &allocator->free[index];
147251875Speter        while ((node = *ref) != NULL) {
148251875Speter            *ref = node->next;
149251875Speter#if APR_ALLOCATOR_USES_MMAP
150251875Speter            munmap(node, (node->index+1) << BOUNDARY_INDEX);
151251875Speter#else
152251875Speter            free(node);
153251875Speter#endif
154251875Speter        }
155251875Speter    }
156251875Speter
157251875Speter    free(allocator);
158251875Speter}
159251875Speter
160251875Speter#if APR_HAS_THREADS
161251875SpeterAPR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator,
162251875Speter                                          apr_thread_mutex_t *mutex)
163251875Speter{
164251875Speter    allocator->mutex = mutex;
165251875Speter}
166251875Speter
167251875SpeterAPR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get(
168251875Speter                                      apr_allocator_t *allocator)
169251875Speter{
170251875Speter    return allocator->mutex;
171251875Speter}
172251875Speter#endif /* APR_HAS_THREADS */
173251875Speter
174251875SpeterAPR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator,
175251875Speter                                          apr_pool_t *pool)
176251875Speter{
177251875Speter    allocator->owner = pool;
178251875Speter}
179251875Speter
180251875SpeterAPR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator)
181251875Speter{
182251875Speter    return allocator->owner;
183251875Speter}
184251875Speter
185251875SpeterAPR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator,
186251875Speter                                             apr_size_t in_size)
187251875Speter{
188251875Speter    apr_uint32_t max_free_index;
189251875Speter    apr_uint32_t size = (APR_UINT32_TRUNC_CAST)in_size;
190251875Speter
191251875Speter#if APR_HAS_THREADS
192251875Speter    apr_thread_mutex_t *mutex;
193251875Speter
194251875Speter    mutex = apr_allocator_mutex_get(allocator);
195251875Speter    if (mutex != NULL)
196251875Speter        apr_thread_mutex_lock(mutex);
197251875Speter#endif /* APR_HAS_THREADS */
198251875Speter
199251875Speter    max_free_index = APR_ALIGN(size, BOUNDARY_SIZE) >> BOUNDARY_INDEX;
200251875Speter    allocator->current_free_index += max_free_index;
201251875Speter    allocator->current_free_index -= allocator->max_free_index;
202251875Speter    allocator->max_free_index = max_free_index;
203251875Speter    if (allocator->current_free_index > max_free_index)
204251875Speter        allocator->current_free_index = max_free_index;
205251875Speter
206251875Speter#if APR_HAS_THREADS
207251875Speter    if (mutex != NULL)
208251875Speter        apr_thread_mutex_unlock(mutex);
209251875Speter#endif
210251875Speter}
211251875Speter
212251875Speterstatic APR_INLINE
213251875Speterapr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t in_size)
214251875Speter{
215251875Speter    apr_memnode_t *node, **ref;
216251875Speter    apr_uint32_t max_index;
217251875Speter    apr_size_t size, i, index;
218251875Speter
219251875Speter    /* Round up the block size to the next boundary, but always
220251875Speter     * allocate at least a certain size (MIN_ALLOC).
221251875Speter     */
222251875Speter    size = APR_ALIGN(in_size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE);
223251875Speter    if (size < in_size) {
224251875Speter        return NULL;
225251875Speter    }
226251875Speter    if (size < MIN_ALLOC)
227251875Speter        size = MIN_ALLOC;
228251875Speter
229251875Speter    /* Find the index for this node size by
230251875Speter     * dividing its size by the boundary size
231251875Speter     */
232251875Speter    index = (size >> BOUNDARY_INDEX) - 1;
233251875Speter
234251875Speter    if (index > APR_UINT32_MAX) {
235251875Speter        return NULL;
236251875Speter    }
237251875Speter
238251875Speter    /* First see if there are any nodes in the area we know
239251875Speter     * our node will fit into.
240251875Speter     */
241251875Speter    if (index <= allocator->max_index) {
242251875Speter#if APR_HAS_THREADS
243251875Speter        if (allocator->mutex)
244251875Speter            apr_thread_mutex_lock(allocator->mutex);
245251875Speter#endif /* APR_HAS_THREADS */
246251875Speter
247251875Speter        /* Walk the free list to see if there are
248251875Speter         * any nodes on it of the requested size
249251875Speter         *
250251875Speter         * NOTE: an optimization would be to check
251251875Speter         * allocator->free[index] first and if no
252251875Speter         * node is present, directly use
253251875Speter         * allocator->free[max_index].  This seems
254251875Speter         * like overkill though and could cause
255251875Speter         * memory waste.
256251875Speter         */
257251875Speter        max_index = allocator->max_index;
258251875Speter        ref = &allocator->free[index];
259251875Speter        i = index;
260251875Speter        while (*ref == NULL && i < max_index) {
261251875Speter           ref++;
262251875Speter           i++;
263251875Speter        }
264251875Speter
265251875Speter        if ((node = *ref) != NULL) {
266251875Speter            /* If we have found a node and it doesn't have any
267251875Speter             * nodes waiting in line behind it _and_ we are on
268251875Speter             * the highest available index, find the new highest
269251875Speter             * available index
270251875Speter             */
271251875Speter            if ((*ref = node->next) == NULL && i >= max_index) {
272251875Speter                do {
273251875Speter                    ref--;
274251875Speter                    max_index--;
275251875Speter                }
276251875Speter                while (*ref == NULL && max_index > 0);
277251875Speter
278251875Speter                allocator->max_index = max_index;
279251875Speter            }
280251875Speter
281251875Speter            allocator->current_free_index += node->index + 1;
282251875Speter            if (allocator->current_free_index > allocator->max_free_index)
283251875Speter                allocator->current_free_index = allocator->max_free_index;
284251875Speter
285251875Speter#if APR_HAS_THREADS
286251875Speter            if (allocator->mutex)
287251875Speter                apr_thread_mutex_unlock(allocator->mutex);
288251875Speter#endif /* APR_HAS_THREADS */
289251875Speter
290251875Speter            node->next = NULL;
291251875Speter            node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
292251875Speter
293251875Speter            return node;
294251875Speter        }
295251875Speter
296251875Speter#if APR_HAS_THREADS
297251875Speter        if (allocator->mutex)
298251875Speter            apr_thread_mutex_unlock(allocator->mutex);
299251875Speter#endif /* APR_HAS_THREADS */
300251875Speter    }
301251875Speter
302251875Speter    /* If we found nothing, seek the sink (at index 0), if
303251875Speter     * it is not empty.
304251875Speter     */
305251875Speter    else if (allocator->free[0]) {
306251875Speter#if APR_HAS_THREADS
307251875Speter        if (allocator->mutex)
308251875Speter            apr_thread_mutex_lock(allocator->mutex);
309251875Speter#endif /* APR_HAS_THREADS */
310251875Speter
311251875Speter        /* Walk the free list to see if there are
312251875Speter         * any nodes on it of the requested size
313251875Speter         */
314251875Speter        ref = &allocator->free[0];
315251875Speter        while ((node = *ref) != NULL && index > node->index)
316251875Speter            ref = &node->next;
317251875Speter
318251875Speter        if (node) {
319251875Speter            *ref = node->next;
320251875Speter
321251875Speter            allocator->current_free_index += node->index + 1;
322251875Speter            if (allocator->current_free_index > allocator->max_free_index)
323251875Speter                allocator->current_free_index = allocator->max_free_index;
324251875Speter
325251875Speter#if APR_HAS_THREADS
326251875Speter            if (allocator->mutex)
327251875Speter                apr_thread_mutex_unlock(allocator->mutex);
328251875Speter#endif /* APR_HAS_THREADS */
329251875Speter
330251875Speter            node->next = NULL;
331251875Speter            node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
332251875Speter
333251875Speter            return node;
334251875Speter        }
335251875Speter
336251875Speter#if APR_HAS_THREADS
337251875Speter        if (allocator->mutex)
338251875Speter            apr_thread_mutex_unlock(allocator->mutex);
339251875Speter#endif /* APR_HAS_THREADS */
340251875Speter    }
341251875Speter
342251875Speter    /* If we haven't got a suitable node, malloc a new one
343251875Speter     * and initialize it.
344251875Speter     */
345251875Speter#if APR_ALLOCATOR_USES_MMAP
346251875Speter    if ((node = mmap(NULL, size, PROT_READ|PROT_WRITE,
347251875Speter                     MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED)
348251875Speter#else
349251875Speter    if ((node = malloc(size)) == NULL)
350251875Speter#endif
351251875Speter        return NULL;
352251875Speter
353251875Speter    node->next = NULL;
354251875Speter    node->index = (APR_UINT32_TRUNC_CAST)index;
355251875Speter    node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
356251875Speter    node->endp = (char *)node + size;
357251875Speter
358251875Speter    return node;
359251875Speter}
360251875Speter
361251875Speterstatic APR_INLINE
362251875Spetervoid allocator_free(apr_allocator_t *allocator, apr_memnode_t *node)
363251875Speter{
364251875Speter    apr_memnode_t *next, *freelist = NULL;
365251875Speter    apr_uint32_t index, max_index;
366251875Speter    apr_uint32_t max_free_index, current_free_index;
367251875Speter
368251875Speter#if APR_HAS_THREADS
369251875Speter    if (allocator->mutex)
370251875Speter        apr_thread_mutex_lock(allocator->mutex);
371251875Speter#endif /* APR_HAS_THREADS */
372251875Speter
373251875Speter    max_index = allocator->max_index;
374251875Speter    max_free_index = allocator->max_free_index;
375251875Speter    current_free_index = allocator->current_free_index;
376251875Speter
377251875Speter    /* Walk the list of submitted nodes and free them one by one,
378251875Speter     * shoving them in the right 'size' buckets as we go.
379251875Speter     */
380251875Speter    do {
381251875Speter        next = node->next;
382251875Speter        index = node->index;
383251875Speter
384251875Speter        if (max_free_index != APR_ALLOCATOR_MAX_FREE_UNLIMITED
385251875Speter            && index + 1 > current_free_index) {
386251875Speter            node->next = freelist;
387251875Speter            freelist = node;
388251875Speter        }
389251875Speter        else if (index < MAX_INDEX) {
390251875Speter            /* Add the node to the appropiate 'size' bucket.  Adjust
391251875Speter             * the max_index when appropiate.
392251875Speter             */
393251875Speter            if ((node->next = allocator->free[index]) == NULL
394251875Speter                && index > max_index) {
395251875Speter                max_index = index;
396251875Speter            }
397251875Speter            allocator->free[index] = node;
398251875Speter            if (current_free_index >= index + 1)
399251875Speter                current_free_index -= index + 1;
400251875Speter            else
401251875Speter                current_free_index = 0;
402251875Speter        }
403251875Speter        else {
404251875Speter            /* This node is too large to keep in a specific size bucket,
405251875Speter             * just add it to the sink (at index 0).
406251875Speter             */
407251875Speter            node->next = allocator->free[0];
408251875Speter            allocator->free[0] = node;
409251875Speter            if (current_free_index >= index + 1)
410251875Speter                current_free_index -= index + 1;
411251875Speter            else
412251875Speter                current_free_index = 0;
413251875Speter        }
414251875Speter    } while ((node = next) != NULL);
415251875Speter
416251875Speter    allocator->max_index = max_index;
417251875Speter    allocator->current_free_index = current_free_index;
418251875Speter
419251875Speter#if APR_HAS_THREADS
420251875Speter    if (allocator->mutex)
421251875Speter        apr_thread_mutex_unlock(allocator->mutex);
422251875Speter#endif /* APR_HAS_THREADS */
423251875Speter
424251875Speter    while (freelist != NULL) {
425251875Speter        node = freelist;
426251875Speter        freelist = node->next;
427251875Speter#if APR_ALLOCATOR_USES_MMAP
428251875Speter        munmap(node, (node->index+1) << BOUNDARY_INDEX);
429251875Speter#else
430251875Speter        free(node);
431251875Speter#endif
432251875Speter    }
433251875Speter}
434251875Speter
435251875SpeterAPR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator,
436251875Speter                                                 apr_size_t size)
437251875Speter{
438251875Speter    return allocator_alloc(allocator, size);
439251875Speter}
440251875Speter
441251875SpeterAPR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator,
442251875Speter                                     apr_memnode_t *node)
443251875Speter{
444251875Speter    allocator_free(allocator, node);
445251875Speter}
446251875Speter
447251875Speter
448251875Speter
449251875Speter/*
450251875Speter * Debug level
451251875Speter */
452251875Speter
453251875Speter#define APR_POOL_DEBUG_GENERAL  0x01
454251875Speter#define APR_POOL_DEBUG_VERBOSE  0x02
455251875Speter#define APR_POOL_DEBUG_LIFETIME 0x04
456251875Speter#define APR_POOL_DEBUG_OWNER    0x08
457251875Speter#define APR_POOL_DEBUG_VERBOSE_ALLOC 0x10
458251875Speter
459251875Speter#define APR_POOL_DEBUG_VERBOSE_ALL (APR_POOL_DEBUG_VERBOSE \
460251875Speter                                    | APR_POOL_DEBUG_VERBOSE_ALLOC)
461251875Speter
462251875Speter
463251875Speter/*
464251875Speter * Structures
465251875Speter */
466251875Speter
467251875Spetertypedef struct cleanup_t cleanup_t;
468251875Speter
469251875Speter/** A list of processes */
470251875Speterstruct process_chain {
471251875Speter    /** The process ID */
472251875Speter    apr_proc_t *proc;
473251875Speter    apr_kill_conditions_e kill_how;
474251875Speter    /** The next process in the list */
475251875Speter    struct process_chain *next;
476251875Speter};
477251875Speter
478251875Speter
479251875Speter#if APR_POOL_DEBUG
480251875Speter
481251875Spetertypedef struct debug_node_t debug_node_t;
482251875Speter
483251875Speterstruct debug_node_t {
484251875Speter    debug_node_t *next;
485251875Speter    apr_uint32_t  index;
486251875Speter    void         *beginp[64];
487251875Speter    void         *endp[64];
488251875Speter};
489251875Speter
490251875Speter#define SIZEOF_DEBUG_NODE_T APR_ALIGN_DEFAULT(sizeof(debug_node_t))
491251875Speter
492251875Speter#endif /* APR_POOL_DEBUG */
493251875Speter
494251875Speter/* The ref field in the apr_pool_t struct holds a
495251875Speter * pointer to the pointer referencing this pool.
496251875Speter * It is used for parent, child, sibling management.
497251875Speter * Look at apr_pool_create_ex() and apr_pool_destroy()
498251875Speter * to see how it is used.
499251875Speter */
500251875Speterstruct apr_pool_t {
501251875Speter    apr_pool_t           *parent;
502251875Speter    apr_pool_t           *child;
503251875Speter    apr_pool_t           *sibling;
504251875Speter    apr_pool_t          **ref;
505251875Speter    cleanup_t            *cleanups;
506251875Speter    cleanup_t            *free_cleanups;
507251875Speter    apr_allocator_t      *allocator;
508251875Speter    struct process_chain *subprocesses;
509251875Speter    apr_abortfunc_t       abort_fn;
510251875Speter    apr_hash_t           *user_data;
511251875Speter    const char           *tag;
512251875Speter
513251875Speter#if !APR_POOL_DEBUG
514251875Speter    apr_memnode_t        *active;
515251875Speter    apr_memnode_t        *self; /* The node containing the pool itself */
516251875Speter    char                 *self_first_avail;
517251875Speter
518251875Speter#else /* APR_POOL_DEBUG */
519251875Speter    apr_pool_t           *joined; /* the caller has guaranteed that this pool
520251875Speter                                   * will survive as long as ->joined */
521251875Speter    debug_node_t         *nodes;
522251875Speter    const char           *file_line;
523251875Speter    apr_uint32_t          creation_flags;
524251875Speter    unsigned int          stat_alloc;
525251875Speter    unsigned int          stat_total_alloc;
526251875Speter    unsigned int          stat_clear;
527251875Speter#if APR_HAS_THREADS
528251875Speter    apr_os_thread_t       owner;
529251875Speter    apr_thread_mutex_t   *mutex;
530251875Speter#endif /* APR_HAS_THREADS */
531251875Speter#endif /* APR_POOL_DEBUG */
532251875Speter#ifdef NETWARE
533251875Speter    apr_os_proc_t         owner_proc;
534251875Speter#endif /* defined(NETWARE) */
535251875Speter    cleanup_t            *pre_cleanups;
536251875Speter};
537251875Speter
538251875Speter#define SIZEOF_POOL_T       APR_ALIGN_DEFAULT(sizeof(apr_pool_t))
539251875Speter
540251875Speter
541251875Speter/*
542251875Speter * Variables
543251875Speter */
544251875Speter
545251875Speterstatic apr_byte_t   apr_pools_initialized = 0;
546251875Speterstatic apr_pool_t  *global_pool = NULL;
547251875Speter
548251875Speter#if !APR_POOL_DEBUG
549251875Speterstatic apr_allocator_t *global_allocator = NULL;
550251875Speter#endif /* !APR_POOL_DEBUG */
551251875Speter
552251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
553251875Speterstatic apr_file_t *file_stderr = NULL;
554251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
555251875Speter
556251875Speter/*
557251875Speter * Local functions
558251875Speter */
559251875Speter
560251875Speterstatic void run_cleanups(cleanup_t **c);
561251875Speterstatic void free_proc_chain(struct process_chain *procs);
562251875Speter
563251875Speter#if APR_POOL_DEBUG
564251875Speterstatic void pool_destroy_debug(apr_pool_t *pool, const char *file_line);
565251875Speter#endif
566251875Speter
567251875Speter#if !APR_POOL_DEBUG
568251875Speter/*
569251875Speter * Initialization
570251875Speter */
571251875Speter
572251875SpeterAPR_DECLARE(apr_status_t) apr_pool_initialize(void)
573251875Speter{
574251875Speter    apr_status_t rv;
575251875Speter
576251875Speter    if (apr_pools_initialized++)
577251875Speter        return APR_SUCCESS;
578251875Speter
579251875Speter#if APR_ALLOCATOR_USES_MMAP && defined(_SC_PAGESIZE)
580251875Speter    boundary_size = sysconf(_SC_PAGESIZE);
581251875Speter    boundary_index = 12;
582251875Speter    while ( (1 << boundary_index) < boundary_size)
583251875Speter        boundary_index++;
584251875Speter    boundary_size = (1 << boundary_index);
585251875Speter#endif
586251875Speter
587251875Speter    if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) {
588251875Speter        apr_pools_initialized = 0;
589251875Speter        return rv;
590251875Speter    }
591251875Speter
592251875Speter    if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL,
593251875Speter                                 global_allocator)) != APR_SUCCESS) {
594251875Speter        apr_allocator_destroy(global_allocator);
595251875Speter        global_allocator = NULL;
596251875Speter        apr_pools_initialized = 0;
597251875Speter        return rv;
598251875Speter    }
599251875Speter
600251875Speter    apr_pool_tag(global_pool, "apr_global_pool");
601251875Speter
602251875Speter    /* This has to happen here because mutexes might be backed by
603251875Speter     * atomics.  It used to be snug and safe in apr_initialize().
604251875Speter     *
605251875Speter     * Warning: apr_atomic_init() must always be called, by any
606251875Speter     * means possible, from apr_initialize().
607251875Speter     */
608251875Speter    if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) {
609251875Speter        return rv;
610251875Speter    }
611251875Speter
612251875Speter#if APR_HAS_THREADS
613251875Speter    {
614251875Speter        apr_thread_mutex_t *mutex;
615251875Speter
616251875Speter        if ((rv = apr_thread_mutex_create(&mutex,
617251875Speter                                          APR_THREAD_MUTEX_DEFAULT,
618251875Speter                                          global_pool)) != APR_SUCCESS) {
619251875Speter            return rv;
620251875Speter        }
621251875Speter
622251875Speter        apr_allocator_mutex_set(global_allocator, mutex);
623251875Speter    }
624251875Speter#endif /* APR_HAS_THREADS */
625251875Speter
626251875Speter    apr_allocator_owner_set(global_allocator, global_pool);
627251875Speter
628251875Speter    return APR_SUCCESS;
629251875Speter}
630251875Speter
631251875SpeterAPR_DECLARE(void) apr_pool_terminate(void)
632251875Speter{
633251875Speter    if (!apr_pools_initialized)
634251875Speter        return;
635251875Speter
636251875Speter    if (--apr_pools_initialized)
637251875Speter        return;
638251875Speter
639251875Speter    apr_pool_destroy(global_pool); /* This will also destroy the mutex */
640251875Speter    global_pool = NULL;
641251875Speter
642251875Speter    global_allocator = NULL;
643251875Speter}
644251875Speter
645251875Speter
646251875Speter/* Node list management helper macros; list_insert() inserts 'node'
647251875Speter * before 'point'. */
648251875Speter#define list_insert(node, point) do {           \
649251875Speter    node->ref = point->ref;                     \
650251875Speter    *node->ref = node;                          \
651251875Speter    node->next = point;                         \
652251875Speter    point->ref = &node->next;                   \
653251875Speter} while (0)
654251875Speter
655251875Speter/* list_remove() removes 'node' from its list. */
656251875Speter#define list_remove(node) do {                  \
657251875Speter    *node->ref = node->next;                    \
658251875Speter    node->next->ref = node->ref;                \
659251875Speter} while (0)
660251875Speter
661251875Speter/* Returns the amount of free space in the given node. */
662251875Speter#define node_free_space(node_) ((apr_size_t)(node_->endp - node_->first_avail))
663251875Speter
664251875Speter/*
665251875Speter * Memory allocation
666251875Speter */
667251875Speter
668251875SpeterAPR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t in_size)
669251875Speter{
670251875Speter    apr_memnode_t *active, *node;
671251875Speter    void *mem;
672251875Speter    apr_size_t size, free_index;
673251875Speter
674251875Speter    size = APR_ALIGN_DEFAULT(in_size);
675251875Speter    if (size < in_size) {
676251875Speter        if (pool->abort_fn)
677251875Speter            pool->abort_fn(APR_ENOMEM);
678251875Speter
679251875Speter        return NULL;
680251875Speter    }
681251875Speter    active = pool->active;
682251875Speter
683251875Speter    /* If the active node has enough bytes left, use it. */
684251875Speter    if (size <= node_free_space(active)) {
685251875Speter        mem = active->first_avail;
686251875Speter        active->first_avail += size;
687251875Speter
688251875Speter        return mem;
689251875Speter    }
690251875Speter
691251875Speter    node = active->next;
692251875Speter    if (size <= node_free_space(node)) {
693251875Speter        list_remove(node);
694251875Speter    }
695251875Speter    else {
696251875Speter        if ((node = allocator_alloc(pool->allocator, size)) == NULL) {
697251875Speter            if (pool->abort_fn)
698251875Speter                pool->abort_fn(APR_ENOMEM);
699251875Speter
700251875Speter            return NULL;
701251875Speter        }
702251875Speter    }
703251875Speter
704251875Speter    node->free_index = 0;
705251875Speter
706251875Speter    mem = node->first_avail;
707251875Speter    node->first_avail += size;
708251875Speter
709251875Speter    list_insert(node, active);
710251875Speter
711251875Speter    pool->active = node;
712251875Speter
713251875Speter    free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
714251875Speter                            BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
715251875Speter
716251875Speter    active->free_index = (APR_UINT32_TRUNC_CAST)free_index;
717251875Speter    node = active->next;
718251875Speter    if (free_index >= node->free_index)
719251875Speter        return mem;
720251875Speter
721251875Speter    do {
722251875Speter        node = node->next;
723251875Speter    }
724251875Speter    while (free_index < node->free_index);
725251875Speter
726251875Speter    list_remove(active);
727251875Speter    list_insert(active, node);
728251875Speter
729251875Speter    return mem;
730251875Speter}
731251875Speter
732251875Speter/* Provide an implementation of apr_pcalloc for backward compatibility
733251875Speter * with code built before apr_pcalloc was a macro
734251875Speter */
735251875Speter
736251875Speter#ifdef apr_pcalloc
737251875Speter#undef apr_pcalloc
738251875Speter#endif
739251875Speter
740251875SpeterAPR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size);
741251875SpeterAPR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size)
742251875Speter{
743251875Speter    void *mem;
744251875Speter
745251875Speter    if ((mem = apr_palloc(pool, size)) != NULL) {
746251875Speter        memset(mem, 0, size);
747251875Speter    }
748251875Speter
749251875Speter    return mem;
750251875Speter}
751251875Speter
752251875Speter
753251875Speter/*
754251875Speter * Pool creation/destruction
755251875Speter */
756251875Speter
757251875SpeterAPR_DECLARE(void) apr_pool_clear(apr_pool_t *pool)
758251875Speter{
759251875Speter    apr_memnode_t *active;
760251875Speter
761251875Speter    /* Run pre destroy cleanups */
762251875Speter    run_cleanups(&pool->pre_cleanups);
763251875Speter    pool->pre_cleanups = NULL;
764251875Speter
765251875Speter    /* Destroy the subpools.  The subpools will detach themselves from
766251875Speter     * this pool thus this loop is safe and easy.
767251875Speter     */
768251875Speter    while (pool->child)
769251875Speter        apr_pool_destroy(pool->child);
770251875Speter
771251875Speter    /* Run cleanups */
772251875Speter    run_cleanups(&pool->cleanups);
773251875Speter    pool->cleanups = NULL;
774251875Speter    pool->free_cleanups = NULL;
775251875Speter
776251875Speter    /* Free subprocesses */
777251875Speter    free_proc_chain(pool->subprocesses);
778251875Speter    pool->subprocesses = NULL;
779251875Speter
780251875Speter    /* Clear the user data. */
781251875Speter    pool->user_data = NULL;
782251875Speter
783251875Speter    /* Find the node attached to the pool structure, reset it, make
784251875Speter     * it the active node and free the rest of the nodes.
785251875Speter     */
786251875Speter    active = pool->active = pool->self;
787251875Speter    active->first_avail = pool->self_first_avail;
788251875Speter
789251875Speter    if (active->next == active)
790251875Speter        return;
791251875Speter
792251875Speter    *active->ref = NULL;
793251875Speter    allocator_free(pool->allocator, active->next);
794251875Speter    active->next = active;
795251875Speter    active->ref = &active->next;
796251875Speter}
797251875Speter
798251875SpeterAPR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool)
799251875Speter{
800251875Speter    apr_memnode_t *active;
801251875Speter    apr_allocator_t *allocator;
802251875Speter
803251875Speter    /* Run pre destroy cleanups */
804251875Speter    run_cleanups(&pool->pre_cleanups);
805251875Speter    pool->pre_cleanups = NULL;
806251875Speter
807251875Speter    /* Destroy the subpools.  The subpools will detach themselve from
808251875Speter     * this pool thus this loop is safe and easy.
809251875Speter     */
810251875Speter    while (pool->child)
811251875Speter        apr_pool_destroy(pool->child);
812251875Speter
813251875Speter    /* Run cleanups */
814251875Speter    run_cleanups(&pool->cleanups);
815251875Speter
816251875Speter    /* Free subprocesses */
817251875Speter    free_proc_chain(pool->subprocesses);
818251875Speter
819251875Speter    /* Remove the pool from the parents child list */
820251875Speter    if (pool->parent) {
821251875Speter#if APR_HAS_THREADS
822251875Speter        apr_thread_mutex_t *mutex;
823251875Speter
824251875Speter        if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL)
825251875Speter            apr_thread_mutex_lock(mutex);
826251875Speter#endif /* APR_HAS_THREADS */
827251875Speter
828251875Speter        if ((*pool->ref = pool->sibling) != NULL)
829251875Speter            pool->sibling->ref = pool->ref;
830251875Speter
831251875Speter#if APR_HAS_THREADS
832251875Speter        if (mutex)
833251875Speter            apr_thread_mutex_unlock(mutex);
834251875Speter#endif /* APR_HAS_THREADS */
835251875Speter    }
836251875Speter
837251875Speter    /* Find the block attached to the pool structure.  Save a copy of the
838251875Speter     * allocator pointer, because the pool struct soon will be no more.
839251875Speter     */
840251875Speter    allocator = pool->allocator;
841251875Speter    active = pool->self;
842251875Speter    *active->ref = NULL;
843251875Speter
844251875Speter#if APR_HAS_THREADS
845251875Speter    if (apr_allocator_owner_get(allocator) == pool) {
846251875Speter        /* Make sure to remove the lock, since it is highly likely to
847251875Speter         * be invalid now.
848251875Speter         */
849251875Speter        apr_allocator_mutex_set(allocator, NULL);
850251875Speter    }
851251875Speter#endif /* APR_HAS_THREADS */
852251875Speter
853251875Speter    /* Free all the nodes in the pool (including the node holding the
854251875Speter     * pool struct), by giving them back to the allocator.
855251875Speter     */
856251875Speter    allocator_free(allocator, active);
857251875Speter
858251875Speter    /* If this pool happens to be the owner of the allocator, free
859251875Speter     * everything in the allocator (that includes the pool struct
860251875Speter     * and the allocator).  Don't worry about destroying the optional mutex
861251875Speter     * in the allocator, it will have been destroyed by the cleanup function.
862251875Speter     */
863251875Speter    if (apr_allocator_owner_get(allocator) == pool) {
864251875Speter        apr_allocator_destroy(allocator);
865251875Speter    }
866251875Speter}
867251875Speter
868251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
869251875Speter                                             apr_pool_t *parent,
870251875Speter                                             apr_abortfunc_t abort_fn,
871251875Speter                                             apr_allocator_t *allocator)
872251875Speter{
873251875Speter    apr_pool_t *pool;
874251875Speter    apr_memnode_t *node;
875251875Speter
876251875Speter    *newpool = NULL;
877251875Speter
878251875Speter    if (!parent)
879251875Speter        parent = global_pool;
880251875Speter
881251875Speter    /* parent will always be non-NULL here except the first time a
882251875Speter     * pool is created, in which case allocator is guaranteed to be
883251875Speter     * non-NULL. */
884251875Speter
885251875Speter    if (!abort_fn && parent)
886251875Speter        abort_fn = parent->abort_fn;
887251875Speter
888251875Speter    if (allocator == NULL)
889251875Speter        allocator = parent->allocator;
890251875Speter
891251875Speter    if ((node = allocator_alloc(allocator,
892251875Speter                                MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
893251875Speter        if (abort_fn)
894251875Speter            abort_fn(APR_ENOMEM);
895251875Speter
896251875Speter        return APR_ENOMEM;
897251875Speter    }
898251875Speter
899251875Speter    node->next = node;
900251875Speter    node->ref = &node->next;
901251875Speter
902251875Speter    pool = (apr_pool_t *)node->first_avail;
903251875Speter    node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T;
904251875Speter
905251875Speter    pool->allocator = allocator;
906251875Speter    pool->active = pool->self = node;
907251875Speter    pool->abort_fn = abort_fn;
908251875Speter    pool->child = NULL;
909251875Speter    pool->cleanups = NULL;
910251875Speter    pool->free_cleanups = NULL;
911251875Speter    pool->pre_cleanups = NULL;
912251875Speter    pool->subprocesses = NULL;
913251875Speter    pool->user_data = NULL;
914251875Speter    pool->tag = NULL;
915251875Speter
916251875Speter#ifdef NETWARE
917251875Speter    pool->owner_proc = (apr_os_proc_t)getnlmhandle();
918251875Speter#endif /* defined(NETWARE) */
919251875Speter
920251875Speter    if ((pool->parent = parent) != NULL) {
921251875Speter#if APR_HAS_THREADS
922251875Speter        apr_thread_mutex_t *mutex;
923251875Speter
924251875Speter        if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL)
925251875Speter            apr_thread_mutex_lock(mutex);
926251875Speter#endif /* APR_HAS_THREADS */
927251875Speter
928251875Speter        if ((pool->sibling = parent->child) != NULL)
929251875Speter            pool->sibling->ref = &pool->sibling;
930251875Speter
931251875Speter        parent->child = pool;
932251875Speter        pool->ref = &parent->child;
933251875Speter
934251875Speter#if APR_HAS_THREADS
935251875Speter        if (mutex)
936251875Speter            apr_thread_mutex_unlock(mutex);
937251875Speter#endif /* APR_HAS_THREADS */
938251875Speter    }
939251875Speter    else {
940251875Speter        pool->sibling = NULL;
941251875Speter        pool->ref = NULL;
942251875Speter    }
943251875Speter
944251875Speter    *newpool = pool;
945251875Speter
946251875Speter    return APR_SUCCESS;
947251875Speter}
948251875Speter
949251875Speter/* Deprecated. Renamed to apr_pool_create_unmanaged_ex
950251875Speter */
951251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_core_ex(apr_pool_t **newpool,
952251875Speter                                                  apr_abortfunc_t abort_fn,
953251875Speter                                                  apr_allocator_t *allocator)
954251875Speter{
955251875Speter    return apr_pool_create_unmanaged_ex(newpool, abort_fn, allocator);
956251875Speter}
957251875Speter
958251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex(apr_pool_t **newpool,
959251875Speter                                                  apr_abortfunc_t abort_fn,
960251875Speter                                                  apr_allocator_t *allocator)
961251875Speter{
962251875Speter    apr_pool_t *pool;
963251875Speter    apr_memnode_t *node;
964251875Speter    apr_allocator_t *pool_allocator;
965251875Speter
966251875Speter    *newpool = NULL;
967251875Speter
968251875Speter    if (!apr_pools_initialized)
969251875Speter        return APR_ENOPOOL;
970251875Speter    if ((pool_allocator = allocator) == NULL) {
971251875Speter        if ((pool_allocator = malloc(SIZEOF_ALLOCATOR_T)) == NULL) {
972251875Speter            if (abort_fn)
973251875Speter                abort_fn(APR_ENOMEM);
974251875Speter
975251875Speter            return APR_ENOMEM;
976251875Speter        }
977251875Speter        memset(pool_allocator, 0, SIZEOF_ALLOCATOR_T);
978251875Speter        pool_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
979251875Speter    }
980251875Speter    if ((node = allocator_alloc(pool_allocator,
981251875Speter                                MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
982251875Speter        if (abort_fn)
983251875Speter            abort_fn(APR_ENOMEM);
984251875Speter
985251875Speter        return APR_ENOMEM;
986251875Speter    }
987251875Speter
988251875Speter    node->next = node;
989251875Speter    node->ref = &node->next;
990251875Speter
991251875Speter    pool = (apr_pool_t *)node->first_avail;
992251875Speter    node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T;
993251875Speter
994251875Speter    pool->allocator = pool_allocator;
995251875Speter    pool->active = pool->self = node;
996251875Speter    pool->abort_fn = abort_fn;
997251875Speter    pool->child = NULL;
998251875Speter    pool->cleanups = NULL;
999251875Speter    pool->free_cleanups = NULL;
1000251875Speter    pool->pre_cleanups = NULL;
1001251875Speter    pool->subprocesses = NULL;
1002251875Speter    pool->user_data = NULL;
1003251875Speter    pool->tag = NULL;
1004251875Speter    pool->parent = NULL;
1005251875Speter    pool->sibling = NULL;
1006251875Speter    pool->ref = NULL;
1007251875Speter
1008251875Speter#ifdef NETWARE
1009251875Speter    pool->owner_proc = (apr_os_proc_t)getnlmhandle();
1010251875Speter#endif /* defined(NETWARE) */
1011251875Speter    if (!allocator)
1012251875Speter        pool_allocator->owner = pool;
1013251875Speter    *newpool = pool;
1014251875Speter
1015251875Speter    return APR_SUCCESS;
1016251875Speter}
1017251875Speter
1018251875Speter/*
1019251875Speter * "Print" functions
1020251875Speter */
1021251875Speter
1022251875Speter/*
1023251875Speter * apr_psprintf is implemented by writing directly into the current
1024251875Speter * block of the pool, starting right at first_avail.  If there's
1025251875Speter * insufficient room, then a new block is allocated and the earlier
1026251875Speter * output is copied over.  The new block isn't linked into the pool
1027251875Speter * until all the output is done.
1028251875Speter *
1029251875Speter * Note that this is completely safe because nothing else can
1030251875Speter * allocate in this apr_pool_t while apr_psprintf is running.  alarms are
1031251875Speter * blocked, and the only thing outside of apr_pools.c that's invoked
1032251875Speter * is apr_vformatter -- which was purposefully written to be
1033251875Speter * self-contained with no callouts.
1034251875Speter */
1035251875Speter
1036251875Speterstruct psprintf_data {
1037251875Speter    apr_vformatter_buff_t vbuff;
1038251875Speter    apr_memnode_t   *node;
1039251875Speter    apr_pool_t      *pool;
1040251875Speter    apr_byte_t       got_a_new_node;
1041251875Speter    apr_memnode_t   *free;
1042251875Speter};
1043251875Speter
1044251875Speter#define APR_PSPRINTF_MIN_STRINGSIZE 32
1045251875Speter
1046251875Speterstatic int psprintf_flush(apr_vformatter_buff_t *vbuff)
1047251875Speter{
1048251875Speter    struct psprintf_data *ps = (struct psprintf_data *)vbuff;
1049251875Speter    apr_memnode_t *node, *active;
1050251875Speter    apr_size_t cur_len, size;
1051251875Speter    char *strp;
1052251875Speter    apr_pool_t *pool;
1053251875Speter    apr_size_t free_index;
1054251875Speter
1055251875Speter    pool = ps->pool;
1056251875Speter    active = ps->node;
1057251875Speter    strp = ps->vbuff.curpos;
1058251875Speter    cur_len = strp - active->first_avail;
1059251875Speter    size = cur_len << 1;
1060251875Speter
1061251875Speter    /* Make sure that we don't try to use a block that has less
1062251875Speter     * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it.  This
1063251875Speter     * also catches the case where size == 0, which would result
1064251875Speter     * in reusing a block that can't even hold the NUL byte.
1065251875Speter     */
1066251875Speter    if (size < APR_PSPRINTF_MIN_STRINGSIZE)
1067251875Speter        size = APR_PSPRINTF_MIN_STRINGSIZE;
1068251875Speter
1069251875Speter    node = active->next;
1070251875Speter    if (!ps->got_a_new_node && size <= node_free_space(node)) {
1071251875Speter
1072251875Speter        list_remove(node);
1073251875Speter        list_insert(node, active);
1074251875Speter
1075251875Speter        node->free_index = 0;
1076251875Speter
1077251875Speter        pool->active = node;
1078251875Speter
1079251875Speter        free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
1080251875Speter                                BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
1081251875Speter
1082251875Speter        active->free_index = (APR_UINT32_TRUNC_CAST)free_index;
1083251875Speter        node = active->next;
1084251875Speter        if (free_index < node->free_index) {
1085251875Speter            do {
1086251875Speter                node = node->next;
1087251875Speter            }
1088251875Speter            while (free_index < node->free_index);
1089251875Speter
1090251875Speter            list_remove(active);
1091251875Speter            list_insert(active, node);
1092251875Speter        }
1093251875Speter
1094251875Speter        node = pool->active;
1095251875Speter    }
1096251875Speter    else {
1097251875Speter        if ((node = allocator_alloc(pool->allocator, size)) == NULL)
1098251875Speter            return -1;
1099251875Speter
1100251875Speter        if (ps->got_a_new_node) {
1101251875Speter            active->next = ps->free;
1102251875Speter            ps->free = active;
1103251875Speter        }
1104251875Speter
1105251875Speter        ps->got_a_new_node = 1;
1106251875Speter    }
1107251875Speter
1108251875Speter    memcpy(node->first_avail, active->first_avail, cur_len);
1109251875Speter
1110251875Speter    ps->node = node;
1111251875Speter    ps->vbuff.curpos = node->first_avail + cur_len;
1112251875Speter    ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */
1113251875Speter
1114251875Speter    return 0;
1115251875Speter}
1116251875Speter
1117251875SpeterAPR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap)
1118251875Speter{
1119251875Speter    struct psprintf_data ps;
1120251875Speter    char *strp;
1121251875Speter    apr_size_t size;
1122251875Speter    apr_memnode_t *active, *node;
1123251875Speter    apr_size_t free_index;
1124251875Speter
1125251875Speter    ps.node = active = pool->active;
1126251875Speter    ps.pool = pool;
1127251875Speter    ps.vbuff.curpos  = ps.node->first_avail;
1128251875Speter
1129251875Speter    /* Save a byte for the NUL terminator */
1130251875Speter    ps.vbuff.endpos = ps.node->endp - 1;
1131251875Speter    ps.got_a_new_node = 0;
1132251875Speter    ps.free = NULL;
1133251875Speter
1134251875Speter    /* Make sure that the first node passed to apr_vformatter has at least
1135251875Speter     * room to hold the NUL terminator.
1136251875Speter     */
1137251875Speter    if (ps.node->first_avail == ps.node->endp) {
1138251875Speter        if (psprintf_flush(&ps.vbuff) == -1) {
1139251875Speter            if (pool->abort_fn) {
1140251875Speter                pool->abort_fn(APR_ENOMEM);
1141251875Speter            }
1142251875Speter
1143251875Speter            return NULL;
1144251875Speter        }
1145251875Speter    }
1146251875Speter
1147251875Speter    if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) {
1148251875Speter        if (pool->abort_fn)
1149251875Speter            pool->abort_fn(APR_ENOMEM);
1150251875Speter
1151251875Speter        return NULL;
1152251875Speter    }
1153251875Speter
1154251875Speter    strp = ps.vbuff.curpos;
1155251875Speter    *strp++ = '\0';
1156251875Speter
1157251875Speter    size = strp - ps.node->first_avail;
1158251875Speter    size = APR_ALIGN_DEFAULT(size);
1159251875Speter    strp = ps.node->first_avail;
1160251875Speter    ps.node->first_avail += size;
1161251875Speter
1162251875Speter    if (ps.free)
1163251875Speter        allocator_free(pool->allocator, ps.free);
1164251875Speter
1165251875Speter    /*
1166251875Speter     * Link the node in if it's a new one
1167251875Speter     */
1168251875Speter    if (!ps.got_a_new_node)
1169251875Speter        return strp;
1170251875Speter
1171251875Speter    active = pool->active;
1172251875Speter    node = ps.node;
1173251875Speter
1174251875Speter    node->free_index = 0;
1175251875Speter
1176251875Speter    list_insert(node, active);
1177251875Speter
1178251875Speter    pool->active = node;
1179251875Speter
1180251875Speter    free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
1181251875Speter                            BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
1182251875Speter
1183251875Speter    active->free_index = (APR_UINT32_TRUNC_CAST)free_index;
1184251875Speter    node = active->next;
1185251875Speter
1186251875Speter    if (free_index >= node->free_index)
1187251875Speter        return strp;
1188251875Speter
1189251875Speter    do {
1190251875Speter        node = node->next;
1191251875Speter    }
1192251875Speter    while (free_index < node->free_index);
1193251875Speter
1194251875Speter    list_remove(active);
1195251875Speter    list_insert(active, node);
1196251875Speter
1197251875Speter    return strp;
1198251875Speter}
1199251875Speter
1200251875Speter
1201251875Speter#else /* APR_POOL_DEBUG */
1202251875Speter/*
1203251875Speter * Debug helper functions
1204251875Speter */
1205251875Speter
1206251875Speter
1207251875Speter/*
1208251875Speter * Walk the pool tree rooted at pool, depth first.  When fn returns
1209251875Speter * anything other than 0, abort the traversal and return the value
1210251875Speter * returned by fn.
1211251875Speter */
1212251875Speterstatic int apr_pool_walk_tree(apr_pool_t *pool,
1213251875Speter                              int (*fn)(apr_pool_t *pool, void *data),
1214251875Speter                              void *data)
1215251875Speter{
1216251875Speter    int rv;
1217251875Speter    apr_pool_t *child;
1218251875Speter
1219251875Speter    rv = fn(pool, data);
1220251875Speter    if (rv)
1221251875Speter        return rv;
1222251875Speter
1223251875Speter#if APR_HAS_THREADS
1224251875Speter    if (pool->mutex) {
1225251875Speter        apr_thread_mutex_lock(pool->mutex);
1226251875Speter                        }
1227251875Speter#endif /* APR_HAS_THREADS */
1228251875Speter
1229251875Speter    child = pool->child;
1230251875Speter    while (child) {
1231251875Speter        rv = apr_pool_walk_tree(child, fn, data);
1232251875Speter        if (rv)
1233251875Speter            break;
1234251875Speter
1235251875Speter        child = child->sibling;
1236251875Speter    }
1237251875Speter
1238251875Speter#if APR_HAS_THREADS
1239251875Speter    if (pool->mutex) {
1240251875Speter        apr_thread_mutex_unlock(pool->mutex);
1241251875Speter    }
1242251875Speter#endif /* APR_HAS_THREADS */
1243251875Speter
1244251875Speter    return rv;
1245251875Speter}
1246251875Speter
1247251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1248251875Speterstatic void apr_pool_log_event(apr_pool_t *pool, const char *event,
1249251875Speter                               const char *file_line, int deref)
1250251875Speter{
1251251875Speter    if (file_stderr) {
1252251875Speter        if (deref) {
1253251875Speter            apr_file_printf(file_stderr,
1254251875Speter                "POOL DEBUG: "
1255251875Speter                "[%lu"
1256251875Speter#if APR_HAS_THREADS
1257251875Speter                "/%lu"
1258251875Speter#endif /* APR_HAS_THREADS */
1259251875Speter                "] "
1260251875Speter                "%7s "
1261251875Speter                "(%10lu/%10lu/%10lu) "
1262251875Speter                "0x%pp \"%s\" "
1263251875Speter                "<%s> "
1264251875Speter                "(%u/%u/%u) "
1265251875Speter                "\n",
1266251875Speter                (unsigned long)getpid(),
1267251875Speter#if APR_HAS_THREADS
1268251875Speter                (unsigned long)apr_os_thread_current(),
1269251875Speter#endif /* APR_HAS_THREADS */
1270251875Speter                event,
1271251875Speter                (unsigned long)apr_pool_num_bytes(pool, 0),
1272251875Speter                (unsigned long)apr_pool_num_bytes(pool, 1),
1273251875Speter                (unsigned long)apr_pool_num_bytes(global_pool, 1),
1274251875Speter                pool, pool->tag,
1275251875Speter                file_line,
1276251875Speter                pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear);
1277251875Speter        }
1278251875Speter        else {
1279251875Speter            apr_file_printf(file_stderr,
1280251875Speter                "POOL DEBUG: "
1281251875Speter                "[%lu"
1282251875Speter#if APR_HAS_THREADS
1283251875Speter                "/%lu"
1284251875Speter#endif /* APR_HAS_THREADS */
1285251875Speter                "] "
1286251875Speter                "%7s "
1287251875Speter                "                                   "
1288251875Speter                "0x%pp "
1289251875Speter                "<%s> "
1290251875Speter                "\n",
1291251875Speter                (unsigned long)getpid(),
1292251875Speter#if APR_HAS_THREADS
1293251875Speter                (unsigned long)apr_os_thread_current(),
1294251875Speter#endif /* APR_HAS_THREADS */
1295251875Speter                event,
1296251875Speter                pool,
1297251875Speter                file_line);
1298251875Speter        }
1299251875Speter    }
1300251875Speter}
1301251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1302251875Speter
1303251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)
1304251875Speterstatic int pool_is_child_of(apr_pool_t *parent, void *data)
1305251875Speter{
1306251875Speter    apr_pool_t *pool = (apr_pool_t *)data;
1307251875Speter
1308251875Speter    return (pool == parent);
1309251875Speter}
1310251875Speter
1311251875Speterstatic int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent)
1312251875Speter{
1313251875Speter    if (parent == NULL)
1314251875Speter        return 0;
1315251875Speter
1316251875Speter    return apr_pool_walk_tree(parent, pool_is_child_of, pool);
1317251875Speter}
1318251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */
1319251875Speter
1320251875Speterstatic void apr_pool_check_integrity(apr_pool_t *pool)
1321251875Speter{
1322251875Speter    /* Rule of thumb: use of the global pool is always
1323251875Speter     * ok, since the only user is apr_pools.c.  Unless
1324251875Speter     * people have searched for the top level parent and
1325251875Speter     * started to use that...
1326251875Speter     */
1327251875Speter    if (pool == global_pool || global_pool == NULL)
1328251875Speter        return;
1329251875Speter
1330251875Speter    /* Lifetime
1331251875Speter     * This basically checks to see if the pool being used is still
1332251875Speter     * a relative to the global pool.  If not it was previously
1333251875Speter     * destroyed, in which case we abort().
1334251875Speter     */
1335251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME)
1336251875Speter    if (!apr_pool_is_child_of(pool, global_pool)) {
1337251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1338251875Speter        apr_pool_log_event(pool, "LIFE",
1339251875Speter                           __FILE__ ":apr_pool_integrity check", 0);
1340251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1341251875Speter        abort();
1342251875Speter    }
1343251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */
1344251875Speter
1345251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER)
1346251875Speter#if APR_HAS_THREADS
1347251875Speter    if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) {
1348251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1349251875Speter        apr_pool_log_event(pool, "THREAD",
1350251875Speter                           __FILE__ ":apr_pool_integrity check", 0);
1351251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1352251875Speter        abort();
1353251875Speter    }
1354251875Speter#endif /* APR_HAS_THREADS */
1355251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */
1356251875Speter}
1357251875Speter
1358251875Speter
1359251875Speter/*
1360251875Speter * Initialization (debug)
1361251875Speter */
1362251875Speter
1363251875SpeterAPR_DECLARE(apr_status_t) apr_pool_initialize(void)
1364251875Speter{
1365251875Speter    apr_status_t rv;
1366251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1367251875Speter    char *logpath;
1368251875Speter    apr_file_t *debug_log = NULL;
1369251875Speter#endif
1370251875Speter
1371251875Speter    if (apr_pools_initialized++)
1372251875Speter        return APR_SUCCESS;
1373251875Speter
1374251875Speter#if APR_ALLOCATOR_USES_MMAP && defined(_SC_PAGESIZE)
1375251875Speter    boundary_size = sysconf(_SC_PAGESIZE);
1376251875Speter    boundary_index = 12;
1377251875Speter    while ( (1 << boundary_index) < boundary_size)
1378251875Speter        boundary_index++;
1379251875Speter    boundary_size = (1 << boundary_index);
1380251875Speter#endif
1381251875Speter
1382251875Speter    /* Since the debug code works a bit differently then the
1383251875Speter     * regular pools code, we ask for a lock here.  The regular
1384251875Speter     * pools code has got this lock embedded in the global
1385251875Speter     * allocator, a concept unknown to debug mode.
1386251875Speter     */
1387251875Speter    if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL,
1388251875Speter                                 NULL)) != APR_SUCCESS) {
1389251875Speter        return rv;
1390251875Speter    }
1391251875Speter
1392251875Speter    apr_pool_tag(global_pool, "APR global pool");
1393251875Speter
1394251875Speter    apr_pools_initialized = 1;
1395251875Speter
1396251875Speter    /* This has to happen here because mutexes might be backed by
1397251875Speter     * atomics.  It used to be snug and safe in apr_initialize().
1398251875Speter     */
1399251875Speter    if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) {
1400251875Speter        return rv;
1401251875Speter    }
1402251875Speter
1403251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1404251875Speter    rv = apr_env_get(&logpath, "APR_POOL_DEBUG_LOG", global_pool);
1405251875Speter
1406251875Speter    /* Don't pass file_stderr directly to apr_file_open() here, since
1407251875Speter     * apr_file_open() can call back to apr_pool_log_event() and that
1408251875Speter     * may attempt to use then then non-NULL but partially set up file
1409251875Speter     * object. */
1410251875Speter    if (rv == APR_SUCCESS) {
1411251875Speter        apr_file_open(&debug_log, logpath, APR_APPEND|APR_WRITE|APR_CREATE,
1412251875Speter                      APR_OS_DEFAULT, global_pool);
1413251875Speter    }
1414251875Speter    else {
1415251875Speter        apr_file_open_stderr(&debug_log, global_pool);
1416251875Speter    }
1417251875Speter
1418251875Speter    /* debug_log is now a file handle. */
1419251875Speter    file_stderr = debug_log;
1420251875Speter
1421251875Speter    if (file_stderr) {
1422251875Speter        apr_file_printf(file_stderr,
1423251875Speter            "POOL DEBUG: [PID"
1424251875Speter#if APR_HAS_THREADS
1425251875Speter            "/TID"
1426251875Speter#endif /* APR_HAS_THREADS */
1427251875Speter            "] ACTION  (SIZE      /POOL SIZE /TOTAL SIZE) "
1428251875Speter            "POOL       \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n");
1429251875Speter
1430251875Speter        apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0);
1431251875Speter    }
1432251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1433251875Speter
1434251875Speter    return APR_SUCCESS;
1435251875Speter}
1436251875Speter
1437251875SpeterAPR_DECLARE(void) apr_pool_terminate(void)
1438251875Speter{
1439251875Speter    if (!apr_pools_initialized)
1440251875Speter        return;
1441251875Speter
1442251875Speter    if (--apr_pools_initialized)
1443251875Speter        return;
1444251875Speter
1445251875Speter    apr_pool_destroy(global_pool); /* This will also destroy the mutex */
1446251875Speter    global_pool = NULL;
1447251875Speter
1448251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1449251875Speter    file_stderr = NULL;
1450251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1451251875Speter}
1452251875Speter
1453251875Speter
1454251875Speter/*
1455251875Speter * Memory allocation (debug)
1456251875Speter */
1457251875Speter
1458251875Speterstatic void *pool_alloc(apr_pool_t *pool, apr_size_t size)
1459251875Speter{
1460251875Speter    debug_node_t *node;
1461251875Speter    void *mem;
1462251875Speter
1463251875Speter    if ((mem = malloc(size)) == NULL) {
1464251875Speter        if (pool->abort_fn)
1465251875Speter            pool->abort_fn(APR_ENOMEM);
1466251875Speter
1467251875Speter        return NULL;
1468251875Speter    }
1469251875Speter
1470251875Speter    node = pool->nodes;
1471251875Speter    if (node == NULL || node->index == 64) {
1472251875Speter        if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) {
1473251875Speter            free(mem);
1474251875Speter            if (pool->abort_fn)
1475251875Speter                pool->abort_fn(APR_ENOMEM);
1476251875Speter
1477251875Speter            return NULL;
1478251875Speter        }
1479251875Speter
1480251875Speter        memset(node, 0, SIZEOF_DEBUG_NODE_T);
1481251875Speter
1482251875Speter        node->next = pool->nodes;
1483251875Speter        pool->nodes = node;
1484251875Speter        node->index = 0;
1485251875Speter    }
1486251875Speter
1487251875Speter    node->beginp[node->index] = mem;
1488251875Speter    node->endp[node->index] = (char *)mem + size;
1489251875Speter    node->index++;
1490251875Speter
1491251875Speter    pool->stat_alloc++;
1492251875Speter    pool->stat_total_alloc++;
1493251875Speter
1494251875Speter    return mem;
1495251875Speter}
1496251875Speter
1497251875SpeterAPR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size,
1498251875Speter                                     const char *file_line)
1499251875Speter{
1500251875Speter    void *mem;
1501251875Speter
1502251875Speter    apr_pool_check_integrity(pool);
1503251875Speter
1504251875Speter    mem = pool_alloc(pool, size);
1505251875Speter
1506251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC)
1507251875Speter    apr_pool_log_event(pool, "PALLOC", file_line, 1);
1508251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
1509251875Speter
1510251875Speter    return mem;
1511251875Speter}
1512251875Speter
1513251875SpeterAPR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size,
1514251875Speter                                      const char *file_line)
1515251875Speter{
1516251875Speter    void *mem;
1517251875Speter
1518251875Speter    apr_pool_check_integrity(pool);
1519251875Speter
1520251875Speter    mem = pool_alloc(pool, size);
1521251875Speter    memset(mem, 0, size);
1522251875Speter
1523251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC)
1524251875Speter    apr_pool_log_event(pool, "PCALLOC", file_line, 1);
1525251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */
1526251875Speter
1527251875Speter    return mem;
1528251875Speter}
1529251875Speter
1530251875Speter
1531251875Speter/*
1532251875Speter * Pool creation/destruction (debug)
1533251875Speter */
1534251875Speter
1535251875Speter#define POOL_POISON_BYTE 'A'
1536251875Speter
1537251875Speterstatic void pool_clear_debug(apr_pool_t *pool, const char *file_line)
1538251875Speter{
1539251875Speter    debug_node_t *node;
1540251875Speter    apr_uint32_t index;
1541251875Speter
1542251875Speter    /* Run pre destroy cleanups */
1543251875Speter    run_cleanups(&pool->pre_cleanups);
1544251875Speter    pool->pre_cleanups = NULL;
1545251875Speter
1546251875Speter    /* Destroy the subpools.  The subpools will detach themselves from
1547251875Speter     * this pool thus this loop is safe and easy.
1548251875Speter     */
1549251875Speter    while (pool->child)
1550251875Speter        pool_destroy_debug(pool->child, file_line);
1551251875Speter
1552251875Speter    /* Run cleanups */
1553251875Speter    run_cleanups(&pool->cleanups);
1554251875Speter    pool->free_cleanups = NULL;
1555251875Speter    pool->cleanups = NULL;
1556251875Speter
1557251875Speter    /* If new child pools showed up, this is a reason to raise a flag */
1558251875Speter    if (pool->child)
1559251875Speter        abort();
1560251875Speter
1561251875Speter    /* Free subprocesses */
1562251875Speter    free_proc_chain(pool->subprocesses);
1563251875Speter    pool->subprocesses = NULL;
1564251875Speter
1565251875Speter    /* Clear the user data. */
1566251875Speter    pool->user_data = NULL;
1567251875Speter
1568251875Speter    /* Free the blocks, scribbling over them first to help highlight
1569251875Speter     * use-after-free issues. */
1570251875Speter    while ((node = pool->nodes) != NULL) {
1571251875Speter        pool->nodes = node->next;
1572251875Speter
1573251875Speter        for (index = 0; index < node->index; index++) {
1574251875Speter            memset(node->beginp[index], POOL_POISON_BYTE,
1575251875Speter                   (char *)node->endp[index] - (char *)node->beginp[index]);
1576251875Speter            free(node->beginp[index]);
1577251875Speter        }
1578251875Speter
1579251875Speter        memset(node, POOL_POISON_BYTE, SIZEOF_DEBUG_NODE_T);
1580251875Speter        free(node);
1581251875Speter    }
1582251875Speter
1583251875Speter    pool->stat_alloc = 0;
1584251875Speter    pool->stat_clear++;
1585251875Speter}
1586251875Speter
1587251875SpeterAPR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool,
1588251875Speter                                       const char *file_line)
1589251875Speter{
1590251875Speter#if APR_HAS_THREADS
1591251875Speter    apr_thread_mutex_t *mutex = NULL;
1592251875Speter#endif
1593251875Speter
1594251875Speter    apr_pool_check_integrity(pool);
1595251875Speter
1596251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
1597251875Speter    apr_pool_log_event(pool, "CLEAR", file_line, 1);
1598251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
1599251875Speter
1600251875Speter#if APR_HAS_THREADS
1601251875Speter    if (pool->parent != NULL)
1602251875Speter        mutex = pool->parent->mutex;
1603251875Speter
1604251875Speter    /* Lock the parent mutex before clearing so that if we have our
1605251875Speter     * own mutex it won't be accessed by apr_pool_walk_tree after
1606251875Speter     * it has been destroyed.
1607251875Speter     */
1608251875Speter    if (mutex != NULL && mutex != pool->mutex) {
1609251875Speter        apr_thread_mutex_lock(mutex);
1610251875Speter    }
1611251875Speter#endif
1612251875Speter
1613251875Speter    pool_clear_debug(pool, file_line);
1614251875Speter
1615251875Speter#if APR_HAS_THREADS
1616251875Speter    /* If we had our own mutex, it will have been destroyed by
1617251875Speter     * the registered cleanups.  Recreate the mutex.  Unlock
1618251875Speter     * the mutex we obtained above.
1619251875Speter     */
1620251875Speter    if (mutex != pool->mutex) {
1621251875Speter        (void)apr_thread_mutex_create(&pool->mutex,
1622251875Speter                                      APR_THREAD_MUTEX_NESTED, pool);
1623251875Speter
1624251875Speter        if (mutex != NULL)
1625251875Speter            (void)apr_thread_mutex_unlock(mutex);
1626251875Speter    }
1627251875Speter#endif /* APR_HAS_THREADS */
1628251875Speter}
1629251875Speter
1630251875Speterstatic void pool_destroy_debug(apr_pool_t *pool, const char *file_line)
1631251875Speter{
1632251875Speter    apr_pool_check_integrity(pool);
1633251875Speter
1634251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
1635251875Speter    apr_pool_log_event(pool, "DESTROY", file_line, 1);
1636251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
1637251875Speter
1638251875Speter    pool_clear_debug(pool, file_line);
1639251875Speter
1640251875Speter    /* Remove the pool from the parents child list */
1641251875Speter    if (pool->parent) {
1642251875Speter#if APR_HAS_THREADS
1643251875Speter        apr_thread_mutex_t *mutex;
1644251875Speter
1645251875Speter        if ((mutex = pool->parent->mutex) != NULL)
1646251875Speter            apr_thread_mutex_lock(mutex);
1647251875Speter#endif /* APR_HAS_THREADS */
1648251875Speter
1649251875Speter        if ((*pool->ref = pool->sibling) != NULL)
1650251875Speter            pool->sibling->ref = pool->ref;
1651251875Speter
1652251875Speter#if APR_HAS_THREADS
1653251875Speter        if (mutex)
1654251875Speter            apr_thread_mutex_unlock(mutex);
1655251875Speter#endif /* APR_HAS_THREADS */
1656251875Speter    }
1657251875Speter
1658251875Speter    if (pool->allocator != NULL
1659251875Speter        && apr_allocator_owner_get(pool->allocator) == pool) {
1660251875Speter        apr_allocator_destroy(pool->allocator);
1661251875Speter    }
1662251875Speter
1663251875Speter    /* Free the pool itself */
1664251875Speter    free(pool);
1665251875Speter}
1666251875Speter
1667251875SpeterAPR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool,
1668251875Speter                                         const char *file_line)
1669251875Speter{
1670251875Speter    if (pool->joined) {
1671251875Speter        /* Joined pools must not be explicitly destroyed; the caller
1672251875Speter         * has broken the guarantee. */
1673251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL)
1674251875Speter        apr_pool_log_event(pool, "LIFE",
1675251875Speter                           __FILE__ ":apr_pool_destroy abort on joined", 0);
1676251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */
1677251875Speter
1678251875Speter        abort();
1679251875Speter    }
1680251875Speter    pool_destroy_debug(pool, file_line);
1681251875Speter}
1682251875Speter
1683251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool,
1684251875Speter                                                   apr_pool_t *parent,
1685251875Speter                                                   apr_abortfunc_t abort_fn,
1686251875Speter                                                   apr_allocator_t *allocator,
1687251875Speter                                                   const char *file_line)
1688251875Speter{
1689251875Speter    apr_pool_t *pool;
1690251875Speter
1691251875Speter    *newpool = NULL;
1692251875Speter
1693251875Speter    if (!parent) {
1694251875Speter        parent = global_pool;
1695251875Speter    }
1696251875Speter    else {
1697251875Speter       apr_pool_check_integrity(parent);
1698251875Speter
1699251875Speter       if (!allocator)
1700251875Speter           allocator = parent->allocator;
1701251875Speter    }
1702251875Speter
1703251875Speter    if (!abort_fn && parent)
1704251875Speter        abort_fn = parent->abort_fn;
1705251875Speter
1706251875Speter    if ((pool = malloc(SIZEOF_POOL_T)) == NULL) {
1707251875Speter        if (abort_fn)
1708251875Speter            abort_fn(APR_ENOMEM);
1709251875Speter
1710251875Speter         return APR_ENOMEM;
1711251875Speter    }
1712251875Speter
1713251875Speter    memset(pool, 0, SIZEOF_POOL_T);
1714251875Speter
1715251875Speter    pool->allocator = allocator;
1716251875Speter    pool->abort_fn = abort_fn;
1717251875Speter    pool->tag = file_line;
1718251875Speter    pool->file_line = file_line;
1719251875Speter
1720251875Speter    if ((pool->parent = parent) != NULL) {
1721251875Speter#if APR_HAS_THREADS
1722251875Speter        if (parent->mutex)
1723251875Speter            apr_thread_mutex_lock(parent->mutex);
1724251875Speter#endif /* APR_HAS_THREADS */
1725251875Speter        if ((pool->sibling = parent->child) != NULL)
1726251875Speter            pool->sibling->ref = &pool->sibling;
1727251875Speter
1728251875Speter        parent->child = pool;
1729251875Speter        pool->ref = &parent->child;
1730251875Speter
1731251875Speter#if APR_HAS_THREADS
1732251875Speter        if (parent->mutex)
1733251875Speter            apr_thread_mutex_unlock(parent->mutex);
1734251875Speter#endif /* APR_HAS_THREADS */
1735251875Speter    }
1736251875Speter    else {
1737251875Speter        pool->sibling = NULL;
1738251875Speter        pool->ref = NULL;
1739251875Speter    }
1740251875Speter
1741251875Speter#if APR_HAS_THREADS
1742251875Speter    pool->owner = apr_os_thread_current();
1743251875Speter#endif /* APR_HAS_THREADS */
1744251875Speter#ifdef NETWARE
1745251875Speter    pool->owner_proc = (apr_os_proc_t)getnlmhandle();
1746251875Speter#endif /* defined(NETWARE) */
1747251875Speter
1748251875Speter
1749251875Speter    if (parent == NULL || parent->allocator != allocator) {
1750251875Speter#if APR_HAS_THREADS
1751251875Speter        apr_status_t rv;
1752251875Speter
1753251875Speter        /* No matter what the creation flags say, always create
1754251875Speter         * a lock.  Without it integrity_check and apr_pool_num_bytes
1755251875Speter         * blow up (because they traverse pools child lists that
1756251875Speter         * possibly belong to another thread, in combination with
1757251875Speter         * the pool having no lock).  However, this might actually
1758251875Speter         * hide problems like creating a child pool of a pool
1759251875Speter         * belonging to another thread.
1760251875Speter         */
1761251875Speter        if ((rv = apr_thread_mutex_create(&pool->mutex,
1762251875Speter                APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) {
1763251875Speter            free(pool);
1764251875Speter            return rv;
1765251875Speter        }
1766251875Speter#endif /* APR_HAS_THREADS */
1767251875Speter    }
1768251875Speter    else {
1769251875Speter#if APR_HAS_THREADS
1770251875Speter        if (parent)
1771251875Speter            pool->mutex = parent->mutex;
1772251875Speter#endif /* APR_HAS_THREADS */
1773251875Speter    }
1774251875Speter
1775251875Speter    *newpool = pool;
1776251875Speter
1777251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
1778251875Speter    apr_pool_log_event(pool, "CREATE", file_line, 1);
1779251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
1780251875Speter
1781251875Speter    return APR_SUCCESS;
1782251875Speter}
1783251875Speter
1784251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_core_ex_debug(apr_pool_t **newpool,
1785251875Speter                                                   apr_abortfunc_t abort_fn,
1786251875Speter                                                   apr_allocator_t *allocator,
1787251875Speter                                                   const char *file_line)
1788251875Speter{
1789251875Speter    return apr_pool_create_unmanaged_ex_debug(newpool, abort_fn, allocator,
1790251875Speter                                              file_line);
1791251875Speter}
1792251875Speter
1793251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex_debug(apr_pool_t **newpool,
1794251875Speter                                                   apr_abortfunc_t abort_fn,
1795251875Speter                                                   apr_allocator_t *allocator,
1796251875Speter                                                   const char *file_line)
1797251875Speter{
1798251875Speter    apr_pool_t *pool;
1799251875Speter    apr_allocator_t *pool_allocator;
1800251875Speter
1801251875Speter    *newpool = NULL;
1802251875Speter
1803251875Speter    if ((pool = malloc(SIZEOF_POOL_T)) == NULL) {
1804251875Speter        if (abort_fn)
1805251875Speter            abort_fn(APR_ENOMEM);
1806251875Speter
1807251875Speter         return APR_ENOMEM;
1808251875Speter    }
1809251875Speter
1810251875Speter    memset(pool, 0, SIZEOF_POOL_T);
1811251875Speter
1812251875Speter    pool->abort_fn = abort_fn;
1813251875Speter    pool->tag = file_line;
1814251875Speter    pool->file_line = file_line;
1815251875Speter
1816251875Speter#if APR_HAS_THREADS
1817251875Speter    pool->owner = apr_os_thread_current();
1818251875Speter#endif /* APR_HAS_THREADS */
1819251875Speter#ifdef NETWARE
1820251875Speter    pool->owner_proc = (apr_os_proc_t)getnlmhandle();
1821251875Speter#endif /* defined(NETWARE) */
1822251875Speter
1823251875Speter    if ((pool_allocator = allocator) == NULL) {
1824251875Speter        apr_status_t rv;
1825251875Speter        if ((rv = apr_allocator_create(&pool_allocator)) != APR_SUCCESS) {
1826251875Speter            if (abort_fn)
1827251875Speter                abort_fn(rv);
1828251875Speter            return rv;
1829251875Speter        }
1830251875Speter        pool_allocator->owner = pool;
1831251875Speter    }
1832251875Speter    pool->allocator = pool_allocator;
1833251875Speter
1834251875Speter    if (pool->allocator != allocator) {
1835251875Speter#if APR_HAS_THREADS
1836251875Speter        apr_status_t rv;
1837251875Speter
1838251875Speter        /* No matter what the creation flags say, always create
1839251875Speter         * a lock.  Without it integrity_check and apr_pool_num_bytes
1840251875Speter         * blow up (because they traverse pools child lists that
1841251875Speter         * possibly belong to another thread, in combination with
1842251875Speter         * the pool having no lock).  However, this might actually
1843251875Speter         * hide problems like creating a child pool of a pool
1844251875Speter         * belonging to another thread.
1845251875Speter         */
1846251875Speter        if ((rv = apr_thread_mutex_create(&pool->mutex,
1847251875Speter                APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) {
1848251875Speter            free(pool);
1849251875Speter            return rv;
1850251875Speter        }
1851251875Speter#endif /* APR_HAS_THREADS */
1852251875Speter    }
1853251875Speter
1854251875Speter    *newpool = pool;
1855251875Speter
1856251875Speter#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE)
1857251875Speter    apr_pool_log_event(pool, "CREATE", file_line, 1);
1858251875Speter#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */
1859251875Speter
1860251875Speter    return APR_SUCCESS;
1861251875Speter}
1862251875Speter
1863251875Speter/*
1864251875Speter * "Print" functions (debug)
1865251875Speter */
1866251875Speter
1867251875Speterstruct psprintf_data {
1868251875Speter    apr_vformatter_buff_t vbuff;
1869251875Speter    char      *mem;
1870251875Speter    apr_size_t size;
1871251875Speter};
1872251875Speter
1873251875Speterstatic int psprintf_flush(apr_vformatter_buff_t *vbuff)
1874251875Speter{
1875251875Speter    struct psprintf_data *ps = (struct psprintf_data *)vbuff;
1876251875Speter    apr_size_t size;
1877251875Speter
1878251875Speter    size = ps->vbuff.curpos - ps->mem;
1879251875Speter
1880251875Speter    ps->size <<= 1;
1881251875Speter    if ((ps->mem = realloc(ps->mem, ps->size)) == NULL)
1882251875Speter        return -1;
1883251875Speter
1884251875Speter    ps->vbuff.curpos = ps->mem + size;
1885251875Speter    ps->vbuff.endpos = ps->mem + ps->size - 1;
1886251875Speter
1887251875Speter    return 0;
1888251875Speter}
1889251875Speter
1890251875SpeterAPR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap)
1891251875Speter{
1892251875Speter    struct psprintf_data ps;
1893251875Speter    debug_node_t *node;
1894251875Speter
1895251875Speter    apr_pool_check_integrity(pool);
1896251875Speter
1897251875Speter    ps.size = 64;
1898251875Speter    ps.mem = malloc(ps.size);
1899251875Speter    ps.vbuff.curpos  = ps.mem;
1900251875Speter
1901251875Speter    /* Save a byte for the NUL terminator */
1902251875Speter    ps.vbuff.endpos = ps.mem + ps.size - 1;
1903251875Speter
1904251875Speter    if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) {
1905251875Speter        if (pool->abort_fn)
1906251875Speter            pool->abort_fn(APR_ENOMEM);
1907251875Speter
1908251875Speter        return NULL;
1909251875Speter    }
1910251875Speter
1911251875Speter    *ps.vbuff.curpos++ = '\0';
1912251875Speter
1913251875Speter    /*
1914251875Speter     * Link the node in
1915251875Speter     */
1916251875Speter    node = pool->nodes;
1917251875Speter    if (node == NULL || node->index == 64) {
1918251875Speter        if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) {
1919251875Speter            if (pool->abort_fn)
1920251875Speter                pool->abort_fn(APR_ENOMEM);
1921251875Speter
1922251875Speter            return NULL;
1923251875Speter        }
1924251875Speter
1925251875Speter        node->next = pool->nodes;
1926251875Speter        pool->nodes = node;
1927251875Speter        node->index = 0;
1928251875Speter    }
1929251875Speter
1930251875Speter    node->beginp[node->index] = ps.mem;
1931251875Speter    node->endp[node->index] = ps.mem + ps.size;
1932251875Speter    node->index++;
1933251875Speter
1934251875Speter    return ps.mem;
1935251875Speter}
1936251875Speter
1937251875Speter
1938251875Speter/*
1939251875Speter * Debug functions
1940251875Speter */
1941251875Speter
1942251875SpeterAPR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub)
1943251875Speter{
1944251875Speter#if APR_POOL_DEBUG
1945251875Speter    if (sub->parent != p) {
1946251875Speter        abort();
1947251875Speter    }
1948251875Speter    sub->joined = p;
1949251875Speter#endif
1950251875Speter}
1951251875Speter
1952251875Speterstatic int pool_find(apr_pool_t *pool, void *data)
1953251875Speter{
1954251875Speter    void **pmem = (void **)data;
1955251875Speter    debug_node_t *node;
1956251875Speter    apr_uint32_t index;
1957251875Speter
1958251875Speter    node = pool->nodes;
1959251875Speter
1960251875Speter    while (node) {
1961251875Speter        for (index = 0; index < node->index; index++) {
1962251875Speter             if (node->beginp[index] <= *pmem
1963251875Speter                 && node->endp[index] > *pmem) {
1964251875Speter                 *pmem = pool;
1965251875Speter                 return 1;
1966251875Speter             }
1967251875Speter        }
1968251875Speter
1969251875Speter        node = node->next;
1970251875Speter    }
1971251875Speter
1972251875Speter    return 0;
1973251875Speter}
1974251875Speter
1975251875SpeterAPR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem)
1976251875Speter{
1977251875Speter    void *pool = (void *)mem;
1978251875Speter
1979251875Speter    if (apr_pool_walk_tree(global_pool, pool_find, &pool))
1980251875Speter        return pool;
1981251875Speter
1982251875Speter    return NULL;
1983251875Speter}
1984251875Speter
1985251875Speterstatic int pool_num_bytes(apr_pool_t *pool, void *data)
1986251875Speter{
1987251875Speter    apr_size_t *psize = (apr_size_t *)data;
1988251875Speter    debug_node_t *node;
1989251875Speter    apr_uint32_t index;
1990251875Speter
1991251875Speter    node = pool->nodes;
1992251875Speter
1993251875Speter    while (node) {
1994251875Speter        for (index = 0; index < node->index; index++) {
1995251875Speter            *psize += (char *)node->endp[index] - (char *)node->beginp[index];
1996251875Speter        }
1997251875Speter
1998251875Speter        node = node->next;
1999251875Speter    }
2000251875Speter
2001251875Speter    return 0;
2002251875Speter}
2003251875Speter
2004251875SpeterAPR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *pool, int recurse)
2005251875Speter{
2006251875Speter    apr_size_t size = 0;
2007251875Speter
2008251875Speter    if (!recurse) {
2009251875Speter        pool_num_bytes(pool, &size);
2010251875Speter
2011251875Speter        return size;
2012251875Speter    }
2013251875Speter
2014251875Speter    apr_pool_walk_tree(pool, pool_num_bytes, &size);
2015251875Speter
2016251875Speter    return size;
2017251875Speter}
2018251875Speter
2019251875SpeterAPR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag)
2020251875Speter{
2021251875Speter}
2022251875Speter
2023251875Speter#endif /* !APR_POOL_DEBUG */
2024251875Speter
2025251875Speter#ifdef NETWARE
2026251875Spetervoid netware_pool_proc_cleanup ()
2027251875Speter{
2028251875Speter    apr_pool_t *pool = global_pool->child;
2029251875Speter    apr_os_proc_t owner_proc = (apr_os_proc_t)getnlmhandle();
2030251875Speter
2031251875Speter    while (pool) {
2032251875Speter        if (pool->owner_proc == owner_proc) {
2033251875Speter            apr_pool_destroy (pool);
2034251875Speter            pool = global_pool->child;
2035251875Speter        }
2036251875Speter        else {
2037251875Speter            pool = pool->sibling;
2038251875Speter        }
2039251875Speter    }
2040251875Speter    return;
2041251875Speter}
2042251875Speter#endif /* defined(NETWARE) */
2043251875Speter
2044251875Speter
2045251875Speter/*
2046251875Speter * "Print" functions (common)
2047251875Speter */
2048251875Speter
2049251875SpeterAPR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...)
2050251875Speter{
2051251875Speter    va_list ap;
2052251875Speter    char *res;
2053251875Speter
2054251875Speter    va_start(ap, fmt);
2055251875Speter    res = apr_pvsprintf(p, fmt, ap);
2056251875Speter    va_end(ap);
2057251875Speter    return res;
2058251875Speter}
2059251875Speter
2060251875Speter/*
2061251875Speter * Pool Properties
2062251875Speter */
2063251875Speter
2064251875SpeterAPR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abort_fn,
2065251875Speter                                     apr_pool_t *pool)
2066251875Speter{
2067251875Speter    pool->abort_fn = abort_fn;
2068251875Speter}
2069251875Speter
2070251875SpeterAPR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool)
2071251875Speter{
2072251875Speter    return pool->abort_fn;
2073251875Speter}
2074251875Speter
2075251875SpeterAPR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool)
2076251875Speter{
2077251875Speter#ifdef NETWARE
2078251875Speter    /* On NetWare, don't return the global_pool, return the application pool
2079251875Speter       as the top most pool */
2080251875Speter    if (pool->parent == global_pool)
2081251875Speter        return pool;
2082251875Speter    else
2083251875Speter#endif
2084251875Speter    return pool->parent;
2085251875Speter}
2086251875Speter
2087251875SpeterAPR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool)
2088251875Speter{
2089251875Speter    return pool->allocator;
2090251875Speter}
2091251875Speter
2092251875Speter/* return TRUE if a is an ancestor of b
2093251875Speter * NULL is considered an ancestor of all pools
2094251875Speter */
2095251875SpeterAPR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b)
2096251875Speter{
2097251875Speter    if (a == NULL)
2098251875Speter        return 1;
2099251875Speter
2100251875Speter#if APR_POOL_DEBUG
2101251875Speter    /* Find the pool with the longest lifetime guaranteed by the
2102251875Speter     * caller: */
2103251875Speter    while (a->joined) {
2104251875Speter        a = a->joined;
2105251875Speter    }
2106251875Speter#endif
2107251875Speter
2108251875Speter    while (b) {
2109251875Speter        if (a == b)
2110251875Speter            return 1;
2111251875Speter
2112251875Speter        b = b->parent;
2113251875Speter    }
2114251875Speter
2115251875Speter    return 0;
2116251875Speter}
2117251875Speter
2118251875SpeterAPR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag)
2119251875Speter{
2120251875Speter    pool->tag = tag;
2121251875Speter}
2122251875Speter
2123251875Speter
2124251875Speter/*
2125251875Speter * User data management
2126251875Speter */
2127251875Speter
2128251875SpeterAPR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, const char *key,
2129251875Speter                                                apr_status_t (*cleanup) (void *),
2130251875Speter                                                apr_pool_t *pool)
2131251875Speter{
2132251875Speter#if APR_POOL_DEBUG
2133251875Speter    apr_pool_check_integrity(pool);
2134251875Speter#endif /* APR_POOL_DEBUG */
2135251875Speter
2136251875Speter    if (pool->user_data == NULL)
2137251875Speter        pool->user_data = apr_hash_make(pool);
2138251875Speter
2139251875Speter    if (apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING) == NULL) {
2140251875Speter        char *new_key = apr_pstrdup(pool, key);
2141251875Speter        apr_hash_set(pool->user_data, new_key, APR_HASH_KEY_STRING, data);
2142251875Speter    }
2143251875Speter    else {
2144251875Speter        apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data);
2145251875Speter    }
2146251875Speter
2147251875Speter    if (cleanup)
2148251875Speter        apr_pool_cleanup_register(pool, data, cleanup, cleanup);
2149251875Speter
2150251875Speter    return APR_SUCCESS;
2151251875Speter}
2152251875Speter
2153251875SpeterAPR_DECLARE(apr_status_t) apr_pool_userdata_setn(const void *data,
2154251875Speter                              const char *key,
2155251875Speter                              apr_status_t (*cleanup)(void *),
2156251875Speter                              apr_pool_t *pool)
2157251875Speter{
2158251875Speter#if APR_POOL_DEBUG
2159251875Speter    apr_pool_check_integrity(pool);
2160251875Speter#endif /* APR_POOL_DEBUG */
2161251875Speter
2162251875Speter    if (pool->user_data == NULL)
2163251875Speter        pool->user_data = apr_hash_make(pool);
2164251875Speter
2165251875Speter    apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data);
2166251875Speter
2167251875Speter    if (cleanup)
2168251875Speter        apr_pool_cleanup_register(pool, data, cleanup, cleanup);
2169251875Speter
2170251875Speter    return APR_SUCCESS;
2171251875Speter}
2172251875Speter
2173251875SpeterAPR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key,
2174251875Speter                                                apr_pool_t *pool)
2175251875Speter{
2176251875Speter#if APR_POOL_DEBUG
2177251875Speter    apr_pool_check_integrity(pool);
2178251875Speter#endif /* APR_POOL_DEBUG */
2179251875Speter
2180251875Speter    if (pool->user_data == NULL) {
2181251875Speter        *data = NULL;
2182251875Speter    }
2183251875Speter    else {
2184251875Speter        *data = apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING);
2185251875Speter    }
2186251875Speter
2187251875Speter    return APR_SUCCESS;
2188251875Speter}
2189251875Speter
2190251875Speter
2191251875Speter/*
2192251875Speter * Cleanup
2193251875Speter */
2194251875Speter
2195251875Speterstruct cleanup_t {
2196251875Speter    struct cleanup_t *next;
2197251875Speter    const void *data;
2198251875Speter    apr_status_t (*plain_cleanup_fn)(void *data);
2199251875Speter    apr_status_t (*child_cleanup_fn)(void *data);
2200251875Speter};
2201251875Speter
2202251875SpeterAPR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void *data,
2203251875Speter                      apr_status_t (*plain_cleanup_fn)(void *data),
2204251875Speter                      apr_status_t (*child_cleanup_fn)(void *data))
2205251875Speter{
2206251875Speter    cleanup_t *c;
2207251875Speter
2208251875Speter#if APR_POOL_DEBUG
2209251875Speter    apr_pool_check_integrity(p);
2210251875Speter#endif /* APR_POOL_DEBUG */
2211251875Speter
2212251875Speter    if (p != NULL) {
2213251875Speter        if (p->free_cleanups) {
2214251875Speter            /* reuse a cleanup structure */
2215251875Speter            c = p->free_cleanups;
2216251875Speter            p->free_cleanups = c->next;
2217251875Speter        } else {
2218251875Speter            c = apr_palloc(p, sizeof(cleanup_t));
2219251875Speter        }
2220251875Speter        c->data = data;
2221251875Speter        c->plain_cleanup_fn = plain_cleanup_fn;
2222251875Speter        c->child_cleanup_fn = child_cleanup_fn;
2223251875Speter        c->next = p->cleanups;
2224251875Speter        p->cleanups = c;
2225251875Speter    }
2226251875Speter}
2227251875Speter
2228251875SpeterAPR_DECLARE(void) apr_pool_pre_cleanup_register(apr_pool_t *p, const void *data,
2229251875Speter                      apr_status_t (*plain_cleanup_fn)(void *data))
2230251875Speter{
2231251875Speter    cleanup_t *c;
2232251875Speter
2233251875Speter#if APR_POOL_DEBUG
2234251875Speter    apr_pool_check_integrity(p);
2235251875Speter#endif /* APR_POOL_DEBUG */
2236251875Speter
2237251875Speter    if (p != NULL) {
2238251875Speter        if (p->free_cleanups) {
2239251875Speter            /* reuse a cleanup structure */
2240251875Speter            c = p->free_cleanups;
2241251875Speter            p->free_cleanups = c->next;
2242251875Speter        } else {
2243251875Speter            c = apr_palloc(p, sizeof(cleanup_t));
2244251875Speter        }
2245251875Speter        c->data = data;
2246251875Speter        c->plain_cleanup_fn = plain_cleanup_fn;
2247251875Speter        c->next = p->pre_cleanups;
2248251875Speter        p->pre_cleanups = c;
2249251875Speter    }
2250251875Speter}
2251251875Speter
2252251875SpeterAPR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data,
2253251875Speter                      apr_status_t (*cleanup_fn)(void *))
2254251875Speter{
2255251875Speter    cleanup_t *c, **lastp;
2256251875Speter
2257251875Speter#if APR_POOL_DEBUG
2258251875Speter    apr_pool_check_integrity(p);
2259251875Speter#endif /* APR_POOL_DEBUG */
2260251875Speter
2261251875Speter    if (p == NULL)
2262251875Speter        return;
2263251875Speter
2264251875Speter    c = p->cleanups;
2265251875Speter    lastp = &p->cleanups;
2266251875Speter    while (c) {
2267251875Speter#if APR_POOL_DEBUG
2268251875Speter        /* Some cheap loop detection to catch a corrupt list: */
2269251875Speter        if (c == c->next
2270251875Speter            || (c->next && c == c->next->next)
2271251875Speter            || (c->next && c->next->next && c == c->next->next->next)) {
2272251875Speter            abort();
2273251875Speter        }
2274251875Speter#endif
2275251875Speter
2276251875Speter        if (c->data == data && c->plain_cleanup_fn == cleanup_fn) {
2277251875Speter            *lastp = c->next;
2278251875Speter            /* move to freelist */
2279251875Speter            c->next = p->free_cleanups;
2280251875Speter            p->free_cleanups = c;
2281251875Speter            break;
2282251875Speter        }
2283251875Speter
2284251875Speter        lastp = &c->next;
2285251875Speter        c = c->next;
2286251875Speter    }
2287251875Speter
2288251875Speter    /* Remove any pre-cleanup as well */
2289251875Speter    c = p->pre_cleanups;
2290251875Speter    lastp = &p->pre_cleanups;
2291251875Speter    while (c) {
2292251875Speter#if APR_POOL_DEBUG
2293251875Speter        /* Some cheap loop detection to catch a corrupt list: */
2294251875Speter        if (c == c->next
2295251875Speter            || (c->next && c == c->next->next)
2296251875Speter            || (c->next && c->next->next && c == c->next->next->next)) {
2297251875Speter            abort();
2298251875Speter        }
2299251875Speter#endif
2300251875Speter
2301251875Speter        if (c->data == data && c->plain_cleanup_fn == cleanup_fn) {
2302251875Speter            *lastp = c->next;
2303251875Speter            /* move to freelist */
2304251875Speter            c->next = p->free_cleanups;
2305251875Speter            p->free_cleanups = c;
2306251875Speter            break;
2307251875Speter        }
2308251875Speter
2309251875Speter        lastp = &c->next;
2310251875Speter        c = c->next;
2311251875Speter    }
2312251875Speter
2313251875Speter}
2314251875Speter
2315251875SpeterAPR_DECLARE(void) apr_pool_child_cleanup_set(apr_pool_t *p, const void *data,
2316251875Speter                      apr_status_t (*plain_cleanup_fn)(void *),
2317251875Speter                      apr_status_t (*child_cleanup_fn)(void *))
2318251875Speter{
2319251875Speter    cleanup_t *c;
2320251875Speter
2321251875Speter#if APR_POOL_DEBUG
2322251875Speter    apr_pool_check_integrity(p);
2323251875Speter#endif /* APR_POOL_DEBUG */
2324251875Speter
2325251875Speter    if (p == NULL)
2326251875Speter        return;
2327251875Speter
2328251875Speter    c = p->cleanups;
2329251875Speter    while (c) {
2330251875Speter        if (c->data == data && c->plain_cleanup_fn == plain_cleanup_fn) {
2331251875Speter            c->child_cleanup_fn = child_cleanup_fn;
2332251875Speter            break;
2333251875Speter        }
2334251875Speter
2335251875Speter        c = c->next;
2336251875Speter    }
2337251875Speter}
2338251875Speter
2339251875SpeterAPR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data,
2340251875Speter                              apr_status_t (*cleanup_fn)(void *))
2341251875Speter{
2342251875Speter    apr_pool_cleanup_kill(p, data, cleanup_fn);
2343251875Speter    return (*cleanup_fn)(data);
2344251875Speter}
2345251875Speter
2346251875Speterstatic void run_cleanups(cleanup_t **cref)
2347251875Speter{
2348251875Speter    cleanup_t *c = *cref;
2349251875Speter
2350251875Speter    while (c) {
2351251875Speter        *cref = c->next;
2352251875Speter        (*c->plain_cleanup_fn)((void *)c->data);
2353251875Speter        c = *cref;
2354251875Speter    }
2355251875Speter}
2356251875Speter
2357251875Speter#if !defined(WIN32) && !defined(OS2)
2358251875Speter
2359251875Speterstatic void run_child_cleanups(cleanup_t **cref)
2360251875Speter{
2361251875Speter    cleanup_t *c = *cref;
2362251875Speter
2363251875Speter    while (c) {
2364251875Speter        *cref = c->next;
2365251875Speter        (*c->child_cleanup_fn)((void *)c->data);
2366251875Speter        c = *cref;
2367251875Speter    }
2368251875Speter}
2369251875Speter
2370251875Speterstatic void cleanup_pool_for_exec(apr_pool_t *p)
2371251875Speter{
2372251875Speter    run_child_cleanups(&p->cleanups);
2373251875Speter
2374251875Speter    for (p = p->child; p; p = p->sibling)
2375251875Speter        cleanup_pool_for_exec(p);
2376251875Speter}
2377251875Speter
2378251875SpeterAPR_DECLARE(void) apr_pool_cleanup_for_exec(void)
2379251875Speter{
2380251875Speter    cleanup_pool_for_exec(global_pool);
2381251875Speter}
2382251875Speter
2383251875Speter#else /* !defined(WIN32) && !defined(OS2) */
2384251875Speter
2385251875SpeterAPR_DECLARE(void) apr_pool_cleanup_for_exec(void)
2386251875Speter{
2387251875Speter    /*
2388251875Speter     * Don't need to do anything on NT or OS/2, because
2389251875Speter     * these platforms will spawn the new process - not
2390251875Speter     * fork for exec. All handles that are not inheritable,
2391251875Speter     * will be automajically closed. The only problem is
2392251875Speter     * with file handles that are open, but there isn't
2393251875Speter     * much that can be done about that (except if the
2394251875Speter     * child decides to go out and close them, or the
2395251875Speter     * developer quits opening them shared)
2396251875Speter     */
2397251875Speter    return;
2398251875Speter}
2399251875Speter
2400251875Speter#endif /* !defined(WIN32) && !defined(OS2) */
2401251875Speter
2402251875SpeterAPR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data)
2403251875Speter{
2404251875Speter    /* do nothing cleanup routine */
2405251875Speter    return APR_SUCCESS;
2406251875Speter}
2407251875Speter
2408251875Speter/* Subprocesses don't use the generic cleanup interface because
2409251875Speter * we don't want multiple subprocesses to result in multiple
2410251875Speter * three-second pauses; the subprocesses have to be "freed" all
2411251875Speter * at once.  If other resources are introduced with the same property,
2412251875Speter * we might want to fold support for that into the generic interface.
2413251875Speter * For now, it's a special case.
2414251875Speter */
2415251875SpeterAPR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *pool, apr_proc_t *proc,
2416251875Speter                                           apr_kill_conditions_e how)
2417251875Speter{
2418251875Speter    struct process_chain *pc = apr_palloc(pool, sizeof(struct process_chain));
2419251875Speter
2420251875Speter    pc->proc = proc;
2421251875Speter    pc->kill_how = how;
2422251875Speter    pc->next = pool->subprocesses;
2423251875Speter    pool->subprocesses = pc;
2424251875Speter}
2425251875Speter
2426251875Speterstatic void free_proc_chain(struct process_chain *procs)
2427251875Speter{
2428251875Speter    /* Dispose of the subprocesses we've spawned off in the course of
2429251875Speter     * whatever it was we're cleaning up now.  This may involve killing
2430251875Speter     * some of them off...
2431251875Speter     */
2432251875Speter    struct process_chain *pc;
2433251875Speter    int need_timeout = 0;
2434251875Speter    apr_time_t timeout_interval;
2435251875Speter
2436251875Speter    if (!procs)
2437251875Speter        return; /* No work.  Whew! */
2438251875Speter
2439251875Speter    /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL
2440251875Speter     * dance with any of the processes we're cleaning up.  If we've got
2441251875Speter     * any kill-on-sight subprocesses, ditch them now as well, so they
2442251875Speter     * don't waste any more cycles doing whatever it is that they shouldn't
2443251875Speter     * be doing anymore.
2444251875Speter     */
2445251875Speter
2446251875Speter#ifndef NEED_WAITPID
2447251875Speter    /* Pick up all defunct processes */
2448251875Speter    for (pc = procs; pc; pc = pc->next) {
2449251875Speter        if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) != APR_CHILD_NOTDONE)
2450251875Speter            pc->kill_how = APR_KILL_NEVER;
2451251875Speter    }
2452251875Speter#endif /* !defined(NEED_WAITPID) */
2453251875Speter
2454251875Speter    for (pc = procs; pc; pc = pc->next) {
2455251875Speter#ifndef WIN32
2456251875Speter        if ((pc->kill_how == APR_KILL_AFTER_TIMEOUT)
2457251875Speter            || (pc->kill_how == APR_KILL_ONLY_ONCE)) {
2458251875Speter            /*
2459251875Speter             * Subprocess may be dead already.  Only need the timeout if not.
2460251875Speter             * Note: apr_proc_kill on Windows is TerminateProcess(), which is
2461251875Speter             * similar to a SIGKILL, so always give the process a timeout
2462251875Speter             * under Windows before killing it.
2463251875Speter             */
2464251875Speter            if (apr_proc_kill(pc->proc, SIGTERM) == APR_SUCCESS)
2465251875Speter                need_timeout = 1;
2466251875Speter        }
2467251875Speter        else if (pc->kill_how == APR_KILL_ALWAYS) {
2468251875Speter#else /* WIN32 knows only one fast, clean method of killing processes today */
2469251875Speter        if (pc->kill_how != APR_KILL_NEVER) {
2470251875Speter            need_timeout = 1;
2471251875Speter            pc->kill_how = APR_KILL_ALWAYS;
2472251875Speter#endif
2473251875Speter            apr_proc_kill(pc->proc, SIGKILL);
2474251875Speter        }
2475251875Speter    }
2476251875Speter
2477251875Speter    /* Sleep only if we have to. The sleep algorithm grows
2478251875Speter     * by a factor of two on each iteration. TIMEOUT_INTERVAL
2479251875Speter     * is equal to TIMEOUT_USECS / 64.
2480251875Speter     */
2481251875Speter    if (need_timeout) {
2482251875Speter        timeout_interval = TIMEOUT_INTERVAL;
2483251875Speter        apr_sleep(timeout_interval);
2484251875Speter
2485251875Speter        do {
2486251875Speter            /* check the status of the subprocesses */
2487251875Speter            need_timeout = 0;
2488251875Speter            for (pc = procs; pc; pc = pc->next) {
2489251875Speter                if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) {
2490251875Speter                    if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT)
2491251875Speter                            == APR_CHILD_NOTDONE)
2492251875Speter                        need_timeout = 1;		/* subprocess is still active */
2493251875Speter                    else
2494251875Speter                        pc->kill_how = APR_KILL_NEVER;	/* subprocess has exited */
2495251875Speter                }
2496251875Speter            }
2497251875Speter            if (need_timeout) {
2498251875Speter                if (timeout_interval >= TIMEOUT_USECS) {
2499251875Speter                    break;
2500251875Speter                }
2501251875Speter                apr_sleep(timeout_interval);
2502251875Speter                timeout_interval *= 2;
2503251875Speter            }
2504251875Speter        } while (need_timeout);
2505251875Speter    }
2506251875Speter
2507251875Speter    /* OK, the scripts we just timed out for have had a chance to clean up
2508251875Speter     * --- now, just get rid of them, and also clean up the system accounting
2509251875Speter     * goop...
2510251875Speter     */
2511251875Speter    for (pc = procs; pc; pc = pc->next) {
2512251875Speter        if (pc->kill_how == APR_KILL_AFTER_TIMEOUT)
2513251875Speter            apr_proc_kill(pc->proc, SIGKILL);
2514251875Speter    }
2515251875Speter
2516251875Speter    /* Now wait for all the signaled processes to die */
2517251875Speter    for (pc = procs; pc; pc = pc->next) {
2518251875Speter        if (pc->kill_how != APR_KILL_NEVER)
2519251875Speter            (void)apr_proc_wait(pc->proc, NULL, NULL, APR_WAIT);
2520251875Speter    }
2521251875Speter}
2522251875Speter
2523251875Speter
2524251875Speter/*
2525251875Speter * Pool creation/destruction stubs, for people who are running
2526251875Speter * mixed release/debug enviroments.
2527251875Speter */
2528251875Speter
2529251875Speter#if !APR_POOL_DEBUG
2530251875SpeterAPR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size,
2531251875Speter                                     const char *file_line)
2532251875Speter{
2533251875Speter    return apr_palloc(pool, size);
2534251875Speter}
2535251875Speter
2536251875SpeterAPR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size,
2537251875Speter                                      const char *file_line)
2538251875Speter{
2539251875Speter    return apr_pcalloc(pool, size);
2540251875Speter}
2541251875Speter
2542251875SpeterAPR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool,
2543251875Speter                                       const char *file_line)
2544251875Speter{
2545251875Speter    apr_pool_clear(pool);
2546251875Speter}
2547251875Speter
2548251875SpeterAPR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool,
2549251875Speter                                         const char *file_line)
2550251875Speter{
2551251875Speter    apr_pool_destroy(pool);
2552251875Speter}
2553251875Speter
2554251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool,
2555251875Speter                                                   apr_pool_t *parent,
2556251875Speter                                                   apr_abortfunc_t abort_fn,
2557251875Speter                                                   apr_allocator_t *allocator,
2558251875Speter                                                   const char *file_line)
2559251875Speter{
2560251875Speter    return apr_pool_create_ex(newpool, parent, abort_fn, allocator);
2561251875Speter}
2562251875Speter
2563251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_core_ex_debug(apr_pool_t **newpool,
2564251875Speter                                                   apr_abortfunc_t abort_fn,
2565251875Speter                                                   apr_allocator_t *allocator,
2566251875Speter                                                   const char *file_line)
2567251875Speter{
2568251875Speter    return apr_pool_create_unmanaged_ex(newpool, abort_fn, allocator);
2569251875Speter}
2570251875Speter
2571251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex_debug(apr_pool_t **newpool,
2572251875Speter                                                   apr_abortfunc_t abort_fn,
2573251875Speter                                                   apr_allocator_t *allocator,
2574251875Speter                                                   const char *file_line)
2575251875Speter{
2576251875Speter    return apr_pool_create_unmanaged_ex(newpool, abort_fn, allocator);
2577251875Speter}
2578251875Speter
2579251875Speter#else /* APR_POOL_DEBUG */
2580251875Speter
2581251875Speter#undef apr_palloc
2582251875SpeterAPR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size);
2583251875Speter
2584251875SpeterAPR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size)
2585251875Speter{
2586251875Speter    return apr_palloc_debug(pool, size, "undefined");
2587251875Speter}
2588251875Speter
2589251875Speter#undef apr_pcalloc
2590251875SpeterAPR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size);
2591251875Speter
2592251875SpeterAPR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size)
2593251875Speter{
2594251875Speter    return apr_pcalloc_debug(pool, size, "undefined");
2595251875Speter}
2596251875Speter
2597251875Speter#undef apr_pool_clear
2598251875SpeterAPR_DECLARE(void) apr_pool_clear(apr_pool_t *pool);
2599251875Speter
2600251875SpeterAPR_DECLARE(void) apr_pool_clear(apr_pool_t *pool)
2601251875Speter{
2602251875Speter    apr_pool_clear_debug(pool, "undefined");
2603251875Speter}
2604251875Speter
2605251875Speter#undef apr_pool_destroy
2606251875SpeterAPR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool);
2607251875Speter
2608251875SpeterAPR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool)
2609251875Speter{
2610251875Speter    apr_pool_destroy_debug(pool, "undefined");
2611251875Speter}
2612251875Speter
2613251875Speter#undef apr_pool_create_ex
2614251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
2615251875Speter                                             apr_pool_t *parent,
2616251875Speter                                             apr_abortfunc_t abort_fn,
2617251875Speter                                             apr_allocator_t *allocator);
2618251875Speter
2619251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
2620251875Speter                                             apr_pool_t *parent,
2621251875Speter                                             apr_abortfunc_t abort_fn,
2622251875Speter                                             apr_allocator_t *allocator)
2623251875Speter{
2624251875Speter    return apr_pool_create_ex_debug(newpool, parent,
2625251875Speter                                    abort_fn, allocator,
2626251875Speter                                    "undefined");
2627251875Speter}
2628251875Speter
2629251875Speter#undef apr_pool_create_core_ex
2630251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_core_ex(apr_pool_t **newpool,
2631251875Speter                                                  apr_abortfunc_t abort_fn,
2632251875Speter                                                  apr_allocator_t *allocator);
2633251875Speter
2634251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_core_ex(apr_pool_t **newpool,
2635251875Speter                                                  apr_abortfunc_t abort_fn,
2636251875Speter                                                  apr_allocator_t *allocator)
2637251875Speter{
2638251875Speter    return apr_pool_create_unmanaged_ex_debug(newpool, abort_fn,
2639251875Speter                                         allocator, "undefined");
2640251875Speter}
2641251875Speter
2642251875Speter#undef apr_pool_create_unmanaged_ex
2643251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex(apr_pool_t **newpool,
2644251875Speter                                                  apr_abortfunc_t abort_fn,
2645251875Speter                                                  apr_allocator_t *allocator);
2646251875Speter
2647251875SpeterAPR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex(apr_pool_t **newpool,
2648251875Speter                                                  apr_abortfunc_t abort_fn,
2649251875Speter                                                  apr_allocator_t *allocator)
2650251875Speter{
2651251875Speter    return apr_pool_create_unmanaged_ex_debug(newpool, abort_fn,
2652251875Speter                                         allocator, "undefined");
2653251875Speter}
2654251875Speter
2655251875Speter#endif /* APR_POOL_DEBUG */
2656