~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/memory/unix/apr_pools.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

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