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