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