Return-Path: Delivered-To: apmail-apr-dev-archive@apr.apache.org Received: (qmail 53561 invoked by uid 500); 30 Nov 2001 17:25:50 -0000 Mailing-List: contact dev-help@apr.apache.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Delivered-To: mailing list dev@apr.apache.org Received: (qmail 53446 invoked from network); 30 Nov 2001 17:25:49 -0000 From: "Sander Striker" To: Subject: Pools rewrite [2] Date: Fri, 30 Nov 2001 18:27:14 +0100 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_003D_01C179CC.A22C3520" X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2911.0) X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 In-Reply-To: Importance: Normal X-Rcpt-To: X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N This is a multi-part message in MIME format. ------=_NextPart_000_003D_01C179CC.A22C3520 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi, This is my second go at the pools code. I incorporated some suggestions made by Brian Pane. Please review, Sander PS. The debug code will come back, but in a different incarnation. I need some time to do that without making the code unreadable. ------=_NextPart_000_003D_01C179CC.A22C3520 Content-Type: application/octet-stream; name="apr_pools.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="apr_pools.c" /* = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A= * The Apache Software License, Version 1.1=0A= *=0A= * Copyright (c) 2000-2001 The Apache Software Foundation. All rights=0A= * reserved.=0A= *=0A= * Redistribution and use in source and binary forms, with or without=0A= * modification, are permitted provided that the following conditions=0A= * are met:=0A= *=0A= * 1. Redistributions of source code must retain the above copyright=0A= * notice, this list of conditions and the following disclaimer.=0A= *=0A= * 2. Redistributions in binary form must reproduce the above copyright=0A= * notice, this list of conditions and the following disclaimer in=0A= * the documentation and/or other materials provided with the=0A= * distribution.=0A= *=0A= * 3. The end-user documentation included with the redistribution,=0A= * if any, must include the following acknowledgment:=0A= * "This product includes software developed by the=0A= * Apache Software Foundation (http://www.apache.org/)."=0A= * Alternately, this acknowledgment may appear in the software itself,=0A= * if and wherever such third-party acknowledgments normally appear.=0A= *=0A= * 4. The names "Apache" and "Apache Software Foundation" must=0A= * not be used to endorse or promote products derived from this=0A= * software without prior written permission. For written=0A= * permission, please contact apache@apache.org.=0A= *=0A= * 5. Products derived from this software may not be called "Apache",=0A= * nor may "Apache" appear in their name, without prior written=0A= * permission of the Apache Software Foundation.=0A= *=0A= * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED=0A= * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES=0A= * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE=0A= * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR=0A= * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,=0A= * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT=0A= * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF=0A= * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND=0A= * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,=0A= * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT=0A= * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF=0A= * SUCH DAMAGE.=0A= * = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A= *=0A= * This software consists of voluntary contributions made by many=0A= * individuals on behalf of the Apache Software Foundation. For more=0A= * information on the Apache Software Foundation, please see=0A= * .=0A= */=0A= =0A= #include "apr.h"=0A= #include "apr_private.h"=0A= =0A= /* TODO: Clean out the #includes */=0A= =0A= #include "apr_portable.h" /* for get_os_proc */=0A= #include "apr_strings.h"=0A= #include "apr_general.h"=0A= #include "apr_pools.h"=0A= #include "apr_lib.h"=0A= #include "apr_thread_mutex.h"=0A= #include "apr_hash.h"=0A= #define APR_WANT_MEMFUNC=0A= #include "apr_want.h"=0A= =0A= #if APR_HAVE_STDIO_H=0A= #include =0A= #endif=0A= #ifdef HAVE_SYS_STAT_H=0A= #include =0A= #endif=0A= #if APR_HAVE_SYS_SIGNAL_H=0A= #include =0A= #endif=0A= #if APR_HAVE_SIGNAL_H=0A= #include =0A= #endif=0A= #if APR_HAVE_SYS_WAIT_H=0A= #include =0A= #endif=0A= #if APR_HAVE_SYS_TYPES_H=0A= #include =0A= #endif=0A= #if APR_HAVE_UNISTD_H=0A= #include =0A= #endif=0A= #if APR_HAVE_FCNTL_H=0A= #include =0A= #endif=0A= #if APR_HAVE_STRING_H=0A= #include =0A= #endif=0A= #if APR_HAVE_STDLIB_H=0A= #include =0A= #endif=0A= #ifdef HAVE_MALLOC_H=0A= #include =0A= #endif=0A= =0A= =0A= =0A= /*=0A= * Magic numbers=0A= */=0A= =0A= #define MIN_ALLOC 8192=0A= #define MAX_INDEX 16=0A= =0A= #define BOUNDARY_INDEX 12=0A= #define BOUNDARY_SIZE (1 << BOUNDARY_INDEX)=0A= =0A= /*=0A= * Macros and defines=0A= */=0A= =0A= /* ALIGN() is only to be used to align on a power of 2 boundary */=0A= #define ALIGN(size, boundary) \=0A= (((size) + ((boundary) - 1)) & ~((boundary) - 1))=0A= =0A= #define ALIGN_DEFAULT(size) ALIGN(size, 8)=0A= =0A= #define LOCK(mutex) \=0A= if (mutex) \=0A= apr_thread_mutex_lock(mutex);=0A= =0A= #define UNLOCK(mutex) \=0A= if (mutex) \=0A= apr_thread_mutex_unlock(mutex);=0A= =0A= /*=0A= * Structures=0A= */=0A= =0A= typedef struct cleanup_t cleanup_t;=0A= typedef struct allocator_t allocator_t;=0A= typedef struct node_t node_t;=0A= =0A= struct node_t {=0A= node_t *next;=0A= node_t **ref;=0A= apr_uint32_t index;=0A= char *first_avail;=0A= char *endp;=0A= };=0A= =0A= struct allocator_t {=0A= apr_uint32_t max_index;=0A= apr_thread_mutex_t *mutex;=0A= apr_pool_t *owner;=0A= node_t *free[MAX_INDEX];=0A= };=0A= =0A= /* The ref field in the apr_pool_t struct holds a=0A= * pointer to the pointer referencing this pool.=0A= * It is used for parent, child, sibling management.=0A= * Look at apr_pool_create_ex() and apr_pool_destroy()=0A= * to see how it is used.=0A= */=0A= struct apr_pool_t {=0A= allocator_t *allocator;=0A= node_t *active;=0A= node_t *self; /* The node containing the pool itself */=0A= char *self_first_avail;=0A= apr_pool_t *parent;=0A= apr_pool_t *child;=0A= apr_pool_t *sibling;=0A= apr_pool_t **ref;=0A= cleanup_t *cleanups;=0A= struct process_chain *subprocesses;=0A= apr_abortfunc_t abort_fn;=0A= apr_hash_t *user_data;=0A= #ifdef APR_POOL_DEBUG=0A= const char *tag;=0A= #endif=0A= };=0A= =0A= #define SIZEOF_NODE_T ALIGN_DEFAULT(sizeof(node_t))=0A= #define SIZEOF_ALLOCATOR_T ALIGN_DEFAULT(sizeof(allocator_t))=0A= #define SIZEOF_POOL_T ALIGN_DEFAULT(sizeof(apr_pool_t))=0A= =0A= /*=0A= * Variables=0A= */=0A= =0A= static apr_pool_t *global_pool =3D NULL;=0A= static apr_byte_t global_allocator_initialized =3D 0;=0A= static allocator_t global_allocator =3D { =0A= 0, /* max_index */=0A= NULL, /* mutex */=0A= NULL, /* owner */=0A= { NULL } /* free[0] */=0A= };=0A= =0A= /*=0A= * Memory allocation=0A= */=0A= =0A= static APR_INLINE node_t *node_malloc(allocator_t *allocator, apr_size_t = size)=0A= {=0A= node_t *node, **ref;=0A= apr_uint32_t i, index, max_index; =0A= =0A= /* Round up the block size to the next boundary, but always=0A= * allocate at least a certain size (MIN_ALLOC).=0A= */=0A= size =3D ALIGN(size + SIZEOF_NODE_T, BOUNDARY_SIZE);=0A= if (size < MIN_ALLOC)=0A= size =3D MIN_ALLOC;=0A= =0A= /* Find the index for this node size by=0A= * deviding its size by the boundary size=0A= */=0A= index =3D (size >> BOUNDARY_INDEX) - 1;=0A= =0A= /* First see if there are any nodes in the area we know=0A= * our node will fit into.=0A= */=0A= if (index <=3D allocator->max_index) {=0A= LOCK(allocator->mutex)=0A= =0A= /* Walk the free list to see if there are=0A= * any nodes on it of the requested size=0A= *=0A= * NOTE: an optimization would be to check=0A= * allocator->free[index] first and if no=0A= * node is present, directly use =0A= * allocator->free[max_index]. This seems=0A= * like overkill though and could cause=0A= * memory waste.=0A= */=0A= max_index =3D allocator->max_index;=0A= ref =3D &allocator->free[index];=0A= i =3D index;=0A= while (*ref =3D=3D NULL && i < max_index) {=0A= ref++;=0A= i++;=0A= }=0A= =0A= if ((node =3D *ref) !=3D NULL) {=0A= /* If we have found a node and it doesn't have any=0A= * nodes waiting in line behind it _and_ we are on=0A= * the highest available index, find the new highest=0A= * available index=0A= */=0A= if ((*ref =3D node->next) =3D=3D NULL && i >=3D max_index) {=0A= do {=0A= ref--;=0A= max_index--;=0A= }=0A= while (*ref =3D=3D NULL && max_index > 0);=0A= =0A= allocator->max_index =3D max_index;=0A= }=0A= else=0A= node->next =3D NULL;=0A= =0A= UNLOCK(allocator->mutex)=0A= =0A= return node;=0A= }=0A= =0A= UNLOCK(allocator->mutex)=0A= }=0A= =0A= /* If we found nothing, seek the sink (at index 0), if=0A= * it is not empty.=0A= */=0A= else if (allocator->free[0]) {=0A= LOCK(allocator->mutex)=0A= =0A= /* Walk the free list to see if there are=0A= * any nodes on it of the requested size=0A= */=0A= ref =3D &allocator->free[0];=0A= while ((node =3D *ref) !=3D NULL && index > node->index)=0A= ref =3D &node->next;=0A= =0A= if (node) {=0A= *ref =3D node->next;=0A= node->next =3D NULL;=0A= =0A= UNLOCK(allocator->mutex)=0A= =0A= return node;=0A= }=0A= =0A= UNLOCK(allocator->mutex)=0A= }=0A= =0A= /* If we haven't got a suitable node, malloc a new one=0A= * and initialize it.=0A= */=0A= if ((node =3D malloc(size)) =3D=3D NULL)=0A= return NULL;=0A= =0A= node->next =3D NULL;=0A= node->index =3D index;=0A= node->first_avail =3D (char *)node + SIZEOF_NODE_T;=0A= node->endp =3D (char *)node + size;=0A= =0A= return node;=0A= }=0A= =0A= static APR_INLINE void node_free(allocator_t *allocator, node_t *node)=0A= {=0A= node_t *next;=0A= apr_uint32_t index, max_index;=0A= =0A= LOCK(allocator->mutex)=0A= =0A= max_index =3D allocator->max_index;=0A= =0A= /* Walk the list of submitted nodes and free them one by one,=0A= * shoving them in the right 'size' buckets as we go.=0A= */=0A= do {=0A= next =3D node->next;=0A= index =3D node->index;=0A= =0A= if (index < MAX_INDEX) {=0A= /* Add the node to the appropiate 'size' bucket. Adjust=0A= * the max_index when appropiate.=0A= */=0A= if ((node->next =3D allocator->free[index]) !=3D NULL && = index > max_index) {=0A= max_index =3D index;=0A= }=0A= allocator->free[index] =3D node;=0A= }=0A= else {=0A= /* This node is too large to keep in a specific size bucket,=0A= * just add it to the sink (at index 0).=0A= */=0A= node->next =3D allocator->free[0];=0A= allocator->free[0] =3D node;=0A= }=0A= }=0A= while ((node =3D next) !=3D NULL);=0A= =0A= /* Walk the list of remaining nodes and give them back to the system. */=0A= while (node) {=0A= next =3D node->next;=0A= free(node);=0A= node =3D next;=0A= }=0A= =0A= allocator->max_index =3D max_index;=0A= =0A= UNLOCK(allocator->mutex)=0A= }=0A= =0A= APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size)=0A= {=0A= node_t *active, *node;=0A= void *mem;=0A= char *endp;=0A= =0A= size =3D ALIGN_DEFAULT(size);=0A= active =3D pool->active;=0A= =0A= /* If the active node has enough bytes left, use it. */=0A= endp =3D active->first_avail + size;=0A= if (endp < active->endp) {=0A= mem =3D active->first_avail;=0A= active->first_avail =3D endp;=0A= =0A= return mem;=0A= }=0A= =0A= /* Reset the active node, get ourselves a new one and activate it. */=0A= active->first_avail =3D (char *)active + SIZEOF_NODE_T;=0A= =0A= if ((node =3D node_malloc(pool->allocator, size)) =3D=3D NULL) {=0A= active->first_avail =3D active->endp;=0A= =0A= if (pool->abort_fn)=0A= pool->abort_fn(APR_ENOMEM);=0A= =0A= return NULL;=0A= }=0A= =0A= active->next =3D pool->active =3D node; =0A= node->ref =3D &active->next;=0A= =0A= mem =3D node->first_avail;=0A= node->first_avail +=3D size;=0A= =0A= return mem;=0A= }=0A= =0A= /* apr_pcalloc is almost exactly the same as apr_palloc, except for=0A= * a few memset()s. This saves an extra function call though, which=0A= * is enough justification for this code duplication IMO.=0A= */=0A= APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size)=0A= {=0A= node_t *active, *node;=0A= void *mem;=0A= char *endp;=0A= =0A= size =3D ALIGN_DEFAULT(size);=0A= active =3D pool->active;=0A= =0A= /* If the active node has enough bytes left, use it. */=0A= endp =3D active->first_avail + size;=0A= if (endp < active->endp) {=0A= mem =3D active->first_avail;=0A= active->first_avail =3D endp;=0A= =0A= memset(mem, 0, size);=0A= =0A= return mem;=0A= }=0A= =0A= /* Reset the active node, get ourselves a new one and activate it. */=0A= active->first_avail =3D (char *)active + SIZEOF_NODE_T;=0A= =0A= if ((node =3D node_malloc(pool->allocator, size)) =3D=3D NULL) {=0A= active->first_avail =3D active->endp;=0A= =0A= if (pool->abort_fn)=0A= pool->abort_fn(APR_ENOMEM);=0A= =0A= return NULL;=0A= }=0A= =0A= active->next =3D pool->active =3D node; =0A= node->ref =3D &active->next;=0A= =0A= mem =3D node->first_avail;=0A= node->first_avail +=3D size;=0A= =0A= memset(mem, 0, size);=0A= =0A= return mem;=0A= }=0A= =0A= /*=0A= * Pool management=0A= */=0A= =0A= static void run_cleanups(cleanup_t *c);=0A= static void free_proc_chain(struct process_chain *procs);=0A= =0A= APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool)=0A= {=0A= node_t *active;=0A= =0A= /* Destroy the subpools. The subpools will detach themselve from =0A= * this pool thus this loop is safe and easy.=0A= */=0A= while (pool->child)=0A= apr_pool_destroy(pool->child);=0A= =0A= /* Run cleanups and free any subprocesses. */=0A= run_cleanups(pool->cleanups);=0A= pool->cleanups =3D NULL;=0A= free_proc_chain(pool->subprocesses);=0A= pool->subprocesses =3D NULL;=0A= =0A= /* Reset the active node */=0A= if ((active =3D pool->active) =3D=3D pool->self) {=0A= active->first_avail =3D pool->self_first_avail;=0A= return;=0A= }=0A= =0A= active->first_avail =3D (char *)active + SIZEOF_NODE_T;=0A= =0A= /* Find the node attached to the pool structure, make=0A= * it the active node and free the rest of the nodes.=0A= */=0A= active =3D pool->active =3D pool->self; =0A= active->first_avail =3D pool->self_first_avail;=0A= node_free(pool->allocator, active->next);=0A= active->next =3D NULL;=0A= }=0A= =0A= APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool)=0A= {=0A= node_t *node, *active, **ref;=0A= allocator_t *allocator;=0A= apr_thread_mutex_t *mutex;=0A= apr_uint32_t index;=0A= =0A= /* Destroy the subpools. The subpools will detach themselve from =0A= * this pool thus this loop is safe and easy.=0A= */=0A= while (pool->child)=0A= apr_pool_destroy(pool->child);=0A= =0A= /* Run cleanups and free any subprocesses. */=0A= run_cleanups(pool->cleanups);=0A= free_proc_chain(pool->subprocesses);=0A= =0A= /* Remove the pool from the parents child list */=0A= if (pool->parent) {=0A= mutex =3D pool->parent->allocator->mutex;=0A= =0A= LOCK(mutex)=0A= =0A= if ((*pool->ref =3D pool->sibling) !=3D NULL)=0A= pool->sibling->ref =3D pool->ref;=0A= =0A= UNLOCK(mutex)=0A= }=0A= =0A= /* Reset the active block */=0A= active =3D pool->active;=0A= active->first_avail =3D (char *)active + SIZEOF_NODE_T;=0A= =0A= /* Find the block attached to the pool structure. Save a copy of the=0A= * allocator pointer, because the pool struct soon will be no more.=0A= */=0A= allocator =3D pool->allocator;=0A= active =3D pool->self;=0A= active->first_avail =3D (char *)active + SIZEOF_NODE_T;=0A= =0A= /* If this pool happens to be the owner of the allocator, free =0A= * everything in the allocator (that includes the pool struct=0A= * and the allocator). Don't worry about destroying the optional = mutex=0A= * in the allocator, it will have been destroyed by the cleanup = function.=0A= */=0A= if (allocator->owner =3D=3D pool) {=0A= for (index =3D 0; index < MAX_INDEX; index++) {=0A= ref =3D &allocator->free[index];=0A= while ((node =3D *ref) !=3D NULL) {=0A= *ref =3D node->next;=0A= free(node);=0A= }=0A= }=0A= =0A= ref =3D &active;=0A= while ((node =3D *ref) !=3D NULL) {=0A= *ref =3D node->next;=0A= free(node);=0A= }=0A= =0A= return;=0A= }=0A= =0A= /* Free all the nodes in the pool (including the node holding the=0A= * pool struct), by giving them back to the allocator.=0A= */=0A= node_free(allocator, active);=0A= }=0A= =0A= APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, =0A= apr_pool_t *parent,=0A= apr_abortfunc_t abort_fn,=0A= apr_uint32_t flags)=0A= {=0A= apr_pool_t *pool;=0A= node_t *node;=0A= allocator_t *allocator, *new_allocator;=0A= apr_status_t rv;=0A= =0A= *newpool =3D NULL;=0A= =0A= if (!parent)=0A= parent =3D global_pool;=0A= =0A= allocator =3D parent ? parent->allocator : &global_allocator;=0A= if ((node =3D node_malloc(allocator, MIN_ALLOC - SIZEOF_NODE_T)) = =3D=3D NULL) {=0A= if (abort_fn)=0A= abort_fn(APR_ENOMEM);=0A= =0A= return APR_ENOMEM;=0A= }=0A= =0A= if ((flags & POOL_FNEW_ALLOCATOR) =3D=3D POOL_FNEW_ALLOCATOR) {=0A= new_allocator =3D (allocator_t *)node->first_avail;=0A= pool =3D (apr_pool_t *)((char *)new_allocator + = SIZEOF_ALLOCATOR_T);=0A= node->first_avail =3D pool->self_first_avail =3D (char *)pool + = SIZEOF_POOL_T;=0A= =0A= memset(new_allocator, 0, SIZEOF_ALLOCATOR_T);=0A= new_allocator->max_index =3D 0;=0A= new_allocator->mutex =3D NULL;=0A= new_allocator->owner =3D pool;=0A= new_allocator->free[0] =3D NULL;=0A= =0A= pool->allocator =3D new_allocator;=0A= pool->active =3D pool->self =3D node;=0A= pool->abort_fn =3D abort_fn;=0A= pool->child =3D NULL;=0A= pool->cleanups =3D NULL;=0A= pool->subprocesses =3D NULL;=0A= pool->user_data =3D NULL;=0A= #ifdef APR_POOL_DEBUG=0A= pool->tag =3D NULL;=0A= #endif=0A= =0A= if ((flags & POOL_FLOCK) =3D=3D POOL_FLOCK) {=0A= if ((rv =3D apr_thread_mutex_create(&allocator->mutex, =0A= APR_THREAD_MUTEX_DEFAULT, pool)) !=3D APR_SUCCESS) {=0A= node_free(allocator, node);=0A= return rv;=0A= }=0A= }=0A= }=0A= else {=0A= pool =3D (apr_pool_t *)node->first_avail;=0A= node->first_avail =3D pool->self_first_avail =3D (char *)pool + = SIZEOF_POOL_T;=0A= =0A= pool->allocator =3D allocator;=0A= pool->active =3D pool->self =3D node;=0A= pool->abort_fn =3D abort_fn;=0A= pool->child =3D NULL;=0A= pool->cleanups =3D NULL;=0A= pool->subprocesses =3D NULL;=0A= pool->user_data =3D NULL;=0A= #ifdef APR_POOL_DEBUG=0A= pool->tag =3D NULL;=0A= #endif=0A= }=0A= =0A= if ((pool->parent =3D parent) !=3D NULL) {=0A= LOCK(allocator->mutex)=0A= =0A= if ((pool->sibling =3D parent->child) !=3D NULL)=0A= pool->sibling->ref =3D &pool->sibling;=0A= =0A= parent->child =3D pool;=0A= pool->ref =3D &parent->child;=0A= =0A= UNLOCK(allocator->mutex)=0A= }=0A= else {=0A= pool->sibling =3D NULL;=0A= pool->ref =3D &pool->sibling;=0A= }=0A= =0A= *newpool =3D pool;=0A= =0A= return APR_SUCCESS;=0A= }=0A= =0A= APR_DECLARE(void) apr_pool_set_abort(apr_abortfunc_t abort_fn,=0A= apr_pool_t *pool)=0A= {=0A= pool->abort_fn =3D abort_fn;=0A= }=0A= =0A= APR_DECLARE(apr_abortfunc_t) apr_pool_get_abort(apr_pool_t *pool)=0A= {=0A= return pool->abort_fn;=0A= }=0A= =0A= APR_DECLARE(apr_pool_t *) apr_pool_get_parent(apr_pool_t *pool)=0A= {=0A= return pool->parent;=0A= }=0A= =0A= /* return TRUE if a is an ancestor of b=0A= * NULL is considered an ancestor of all pools=0A= */=0A= APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b)=0A= {=0A= if (a =3D=3D NULL)=0A= return 1;=0A= =0A= while (b) {=0A= if (a =3D=3D b)=0A= return 1;=0A= =0A= b =3D b->parent;=0A= }=0A= =0A= return 0;=0A= }=0A= =0A= /*=0A= * Initialization=0A= */=0A= =0A= APR_DECLARE(apr_status_t) apr_pool_alloc_init(apr_pool_t *global)=0A= {=0A= apr_status_t rv;=0A= =0A= if (global_allocator_initialized)=0A= return APR_SUCCESS; /* Is this correct? */=0A= =0A= memset(&global_allocator, 0, SIZEOF_ALLOCATOR_T);=0A= =0A= if ((rv =3D apr_thread_mutex_create(&global_allocator.mutex, =0A= APR_THREAD_MUTEX_DEFAULT, global)) !=3D APR_SUCCESS) {=0A= return rv;=0A= }=0A= =0A= global_allocator.owner =3D global;=0A= global_pool =3D global;=0A= global_allocator_initialized =3D 1;=0A= =0A= return APR_SUCCESS;=0A= }=0A= =0A= APR_DECLARE(void) apr_pool_alloc_term(apr_pool_t *global)=0A= {=0A= /*=0A= * XXX: What happens when global_pool !=3D global?=0A= * IMHO apr_pool_alloc_term should take void, not an=0A= * apr_pool_t *.=0A= */=0A= if (global_allocator.mutex)=0A= apr_thread_mutex_destroy(global_allocator.mutex);=0A= =0A= apr_pool_destroy(global_pool);=0A= global_pool =3D NULL;=0A= =0A= global_allocator.max_index =3D 0;=0A= global_allocator.mutex =3D NULL;=0A= global_allocator.owner =3D NULL;=0A= global_allocator.free[0] =3D NULL;=0A= =0A= global_allocator_initialized =3D 0;=0A= }=0A= =0A= /*=0A= * Cleanup=0A= */=0A= =0A= struct cleanup_t {=0A= struct cleanup_t *next;=0A= const void *data;=0A= apr_status_t (*plain_cleanup_fn)(void *data);=0A= apr_status_t (*child_cleanup_fn)(void *data);=0A= };=0A= =0A= APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void = *data,=0A= apr_status_t (*plain_cleanup_fn)(void *data),=0A= apr_status_t (*child_cleanup_fn)(void *data))=0A= {=0A= cleanup_t *c;=0A= =0A= if (p !=3D NULL) {=0A= c =3D (cleanup_t *) apr_palloc(p, sizeof(cleanup_t));=0A= c->data =3D data;=0A= c->plain_cleanup_fn =3D plain_cleanup_fn;=0A= c->child_cleanup_fn =3D child_cleanup_fn;=0A= c->next =3D p->cleanups;=0A= p->cleanups =3D c;=0A= }=0A= }=0A= =0A= APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data,=0A= apr_status_t (*cleanup_fn)(void *))=0A= {=0A= cleanup_t *c, **lastp;=0A= =0A= if (p =3D=3D NULL)=0A= return;=0A= =0A= c =3D p->cleanups;=0A= lastp =3D &p->cleanups;=0A= while (c) {=0A= if (c->data =3D=3D data && c->plain_cleanup_fn =3D=3D = cleanup_fn) {=0A= *lastp =3D c->next;=0A= break;=0A= }=0A= =0A= lastp =3D &c->next;=0A= c =3D c->next;=0A= }=0A= }=0A= =0A= APR_DECLARE(void) apr_pool_child_cleanup_set(apr_pool_t *p, const void = *data,=0A= apr_status_t (*plain_cleanup_fn) = (void *),=0A= apr_status_t (*child_cleanup_fn) = (void *))=0A= {=0A= cleanup_t *c;=0A= =0A= if (p =3D=3D NULL)=0A= return;=0A= =0A= c =3D p->cleanups;=0A= while (c) {=0A= if (c->data =3D=3D data && c->plain_cleanup_fn =3D=3D = plain_cleanup_fn) {=0A= c->child_cleanup_fn =3D child_cleanup_fn;=0A= break;=0A= }=0A= =0A= c =3D c->next;=0A= }=0A= }=0A= =0A= APR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data,=0A= apr_status_t (*cleanup_fn) (void = *))=0A= {=0A= apr_pool_cleanup_kill(p, data, cleanup_fn);=0A= return (*cleanup_fn)(data);=0A= }=0A= =0A= static void run_cleanups(cleanup_t *c)=0A= {=0A= while (c) {=0A= (*c->plain_cleanup_fn)((void *)c->data);=0A= c =3D c->next;=0A= }=0A= }=0A= =0A= static void run_child_cleanups(cleanup_t *c)=0A= {=0A= while (c) {=0A= (*c->child_cleanup_fn)((void *)c->data);=0A= c =3D c->next;=0A= }=0A= }=0A= =0A= static void cleanup_pool_for_exec(apr_pool_t *p)=0A= {=0A= run_child_cleanups(p->cleanups);=0A= p->cleanups =3D NULL;=0A= =0A= for (p =3D p->child; p; p =3D p->sibling)=0A= cleanup_pool_for_exec(p);=0A= }=0A= =0A= APR_DECLARE(void) apr_pool_cleanup_for_exec(void)=0A= {=0A= #if !defined(WIN32) && !defined(OS2)=0A= /*=0A= * Don't need to do anything on NT or OS/2, because I=0A= * am actually going to spawn the new process - not=0A= * exec it. All handles that are not inheritable, will=0A= * be automajically closed. The only problem is with=0A= * file handles that are open, but there isn't much=0A= * I can do about that (except if the child decides=0A= * to go out and close them=0A= */=0A= cleanup_pool_for_exec(global_pool);=0A= #endif /* !defined(WIN32) && !defined(OS2) */=0A= }=0A= =0A= APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data)=0A= {=0A= /* do nothing cleanup routine */=0A= return APR_SUCCESS;=0A= }=0A= =0A= /*=0A= * Debug functions=0A= */=0A= =0A= #ifdef APR_POOL_DEBUG=0A= APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag)=0A= {=0A= pool->tag =3D tag;=0A= }=0A= #endif=0A= =0A= /*=0A= * User data management=0A= */=0A= =0A= APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, const = char *key,=0A= apr_status_t (*cleanup) = (void *),=0A= apr_pool_t *pool)=0A= {=0A= if (pool->user_data =3D=3D NULL)=0A= pool->user_data =3D apr_hash_make(pool);=0A= =0A= if (apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING) =3D=3D = NULL){=0A= char *new_key =3D apr_pstrdup(pool, key);=0A= apr_hash_set(pool->user_data, new_key, APR_HASH_KEY_STRING, = data);=0A= } =0A= else {=0A= apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data);=0A= }=0A= =0A= if (cleanup)=0A= apr_pool_cleanup_register(pool, data, cleanup, cleanup);=0A= =0A= return APR_SUCCESS;=0A= }=0A= =0A= APR_DECLARE(apr_status_t) apr_pool_userdata_setn(const void *data, const = char *key,=0A= apr_status_t (*cleanup) = (void *),=0A= apr_pool_t *pool)=0A= {=0A= if (pool->user_data =3D=3D NULL)=0A= pool->user_data =3D apr_hash_make(pool);=0A= =0A= apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data);=0A= =0A= if (cleanup)=0A= apr_pool_cleanup_register(pool, data, cleanup, cleanup);=0A= =0A= return APR_SUCCESS;=0A= }=0A= =0A= APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char = *key, apr_pool_t *pool)=0A= {=0A= if (pool->user_data =3D=3D NULL)=0A= *data =3D NULL;=0A= else=0A= *data =3D apr_hash_get(pool->user_data, key, strlen(key));=0A= =0A= return APR_SUCCESS;=0A= }=0A= =0A= =0A= /*=0A= * "Print" functions=0A= */=0A= =0A= /*=0A= * apr_psprintf is implemented by writing directly into the current=0A= * block of the pool, starting right at first_avail. If there's=0A= * insufficient room, then a new block is allocated and the earlier=0A= * output is copied over. The new block isn't linked into the pool=0A= * until all the output is done.=0A= *=0A= * Note that this is completely safe because nothing else can=0A= * allocate in this apr_pool_t while apr_psprintf is running. alarms are=0A= * blocked, and the only thing outside of alloc.c that's invoked=0A= * is apr_vformatter -- which was purposefully written to be=0A= * self-contained with no callouts.=0A= */=0A= =0A= struct psprintf_data {=0A= apr_vformatter_buff_t vbuff;=0A= node_t *node;=0A= allocator_t *allocator;=0A= apr_byte_t got_a_new_node;=0A= node_t *free;=0A= };=0A= =0A= static int psprintf_flush(apr_vformatter_buff_t *vbuff)=0A= {=0A= struct psprintf_data *ps =3D (struct psprintf_data *)vbuff;=0A= node_t *node, *active;=0A= apr_size_t cur_len;=0A= char *strp;=0A= allocator_t *allocator;=0A= =0A= allocator =3D ps->allocator;=0A= node =3D ps->node;=0A= strp =3D ps->vbuff.curpos;=0A= cur_len =3D strp - node->first_avail;=0A= =0A= if ((active =3D node_malloc(allocator, cur_len << 1)) =3D=3D NULL)=0A= return -1;=0A= =0A= memcpy(active->first_avail, node->first_avail, cur_len);=0A= =0A= if (ps->got_a_new_node) {=0A= node->next =3D ps->free;=0A= ps->free =3D node; =0A= }=0A= =0A= ps->node =3D active;=0A= ps->vbuff.curpos =3D active->first_avail + cur_len;=0A= ps->vbuff.endpos =3D active->endp - 1; /* Save a byte for NUL = terminator */=0A= ps->got_a_new_node =3D 1;=0A= =0A= return 0;=0A= }=0A= =0A= APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, = va_list ap)=0A= {=0A= struct psprintf_data ps;=0A= char *strp;=0A= apr_size_t size;=0A= node_t *active;=0A= =0A= ps.node =3D active =3D pool->active;=0A= ps.allocator =3D pool->allocator;=0A= ps.vbuff.curpos =3D ps.node->first_avail;=0A= /* Save a byte for the NUL terminator */=0A= ps.vbuff.endpos =3D ps.node->endp - 1;=0A= ps.got_a_new_node =3D 0;=0A= ps.free =3D NULL;=0A= =0A= if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) =3D=3D -1) {=0A= if (pool->abort_fn)=0A= pool->abort_fn(APR_ENOMEM);=0A= =0A= return NULL;=0A= }=0A= =0A= strp =3D ps.vbuff.curpos;=0A= *strp++ =3D '\0';=0A= =0A= size =3D strp - ps.node->first_avail;=0A= size =3D ALIGN_DEFAULT(size);=0A= strp =3D ps.node->first_avail;=0A= ps.node->first_avail +=3D size;=0A= =0A= /* =0A= * Link the node in if it's a new one =0A= */=0A= if (ps.got_a_new_node) {=0A= active->next =3D pool->active =3D ps.node;=0A= }=0A= =0A= if (ps.free)=0A= node_free(ps.allocator, ps.free);=0A= =0A= return strp;=0A= }=0A= =0A= APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, = ...)=0A= {=0A= va_list ap;=0A= char *res;=0A= =0A= va_start(ap, fmt);=0A= res =3D apr_pvsprintf(p, fmt, ap);=0A= va_end(ap);=0A= return res;=0A= }=0A= =0A= /*****************************************************************=0A= *=0A= * More grotty system stuff... subprocesses. Frump. These don't use=0A= * the generic cleanup interface because I don't want multiple=0A= * subprocesses to result in multiple three-second pauses; the=0A= * subprocesses have to be "freed" all at once. If someone comes=0A= * along with another resource they want to allocate which has the=0A= * same property, we might want to fold support for that into the=0A= * generic interface, but for now, it's a special case=0A= */=0A= =0A= APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *pool, apr_proc_t = *pid,=0A= enum kill_conditions how)=0A= {=0A= struct process_chain *pc =3D apr_palloc(pool, sizeof(struct = process_chain));=0A= =0A= pc->pid =3D pid;=0A= pc->kill_how =3D how;=0A= pc->next =3D pool->subprocesses;=0A= pool->subprocesses =3D pc;=0A= }=0A= =0A= static void free_proc_chain(struct process_chain *procs)=0A= {=0A= /* Dispose of the subprocesses we've spawned off in the course of=0A= * whatever it was we're cleaning up now. This may involve killing=0A= * some of them off...=0A= */=0A= struct process_chain *pc;=0A= int need_timeout =3D 0;=0A= =0A= if (!procs)=0A= return; /* No work. Whew! */=0A= =0A= /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL=0A= * dance with any of the processes we're cleaning up. If we've got=0A= * any kill-on-sight subprocesses, ditch them now as well, so they=0A= * don't waste any more cycles doing whatever it is that they = shouldn't=0A= * be doing anymore.=0A= */=0A= =0A= #ifndef NEED_WAITPID=0A= /* Pick up all defunct processes */=0A= for (pc =3D procs; pc; pc =3D pc->next) {=0A= if (apr_proc_wait(pc->pid, NULL, NULL, APR_NOWAIT) !=3D = APR_CHILD_NOTDONE)=0A= pc->kill_how =3D kill_never;=0A= }=0A= #endif=0A= =0A= for (pc =3D procs; pc; pc =3D pc->next) {=0A= if ((pc->kill_how =3D=3D kill_after_timeout) ||=0A= (pc->kill_how =3D=3D kill_only_once)) {=0A= /*=0A= * Subprocess may be dead already. Only need the timeout if = not.=0A= * Note: apr_proc_kill on Windows is TerminateProcess(), = which is =0A= * similar to a SIGKILL, so always give the process a timeout=0A= * under Windows before killing it.=0A= */=0A= #ifdef WIN32=0A= need_timeout =3D 1;=0A= #else=0A= if (apr_proc_kill(pc->pid, SIGTERM) =3D=3D APR_SUCCESS)=0A= need_timeout =3D 1;=0A= #endif=0A= }=0A= else if (pc->kill_how =3D=3D kill_always) {=0A= apr_proc_kill(pc->pid, SIGKILL);=0A= }=0A= }=0A= =0A= /* Sleep only if we have to... */=0A= if (need_timeout)=0A= sleep(3);=0A= =0A= /* OK, the scripts we just timed out for have had a chance to clean = up=0A= * --- now, just get rid of them, and also clean up the system = accounting=0A= * goop...=0A= */=0A= for (pc =3D procs; pc; pc =3D pc->next) {=0A= if (pc->kill_how =3D=3D kill_after_timeout)=0A= apr_proc_kill(pc->pid, SIGKILL);=0A= }=0A= =0A= /* Now wait for all the signaled processes to die */=0A= for (pc =3D procs; pc; pc =3D pc->next) {=0A= if (pc->kill_how !=3D kill_never)=0A= (void)apr_proc_wait(pc->pid, NULL, NULL, APR_WAIT);=0A= }=0A= #ifdef WIN32=0A= /* =0A= * XXX: Do we need an APR function to clean-up a proc_t?=0A= * Well ... yeah ... but we can't since it's scope is ill defined.=0A= * We can't dismiss the handle until the apr_proc_wait above is=0A= * finished with the proc_t.=0A= */=0A= {=0A= for (p =3D procs; p; p =3D p->next) {=0A= if (p->pid->hproc) {=0A= CloseHandle(p->pid->hproc);=0A= p->pid->hproc =3D NULL;=0A= }=0A= }=0A= }=0A= =0A= #endif /* WIN32 */=0A= }=0A= =0A= ------=_NextPart_000_003D_01C179CC.A22C3520 Content-Type: application/octet-stream; name="apr_pools.h" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="apr_pools.h" /* = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A= * The Apache Software License, Version 1.1=0A= *=0A= * Copyright (c) 2000-2001 The Apache Software Foundation. All rights=0A= * reserved.=0A= *=0A= * Redistribution and use in source and binary forms, with or without=0A= * modification, are permitted provided that the following conditions=0A= * are met:=0A= *=0A= * 1. Redistributions of source code must retain the above copyright=0A= * notice, this list of conditions and the following disclaimer.=0A= *=0A= * 2. Redistributions in binary form must reproduce the above copyright=0A= * notice, this list of conditions and the following disclaimer in=0A= * the documentation and/or other materials provided with the=0A= * distribution.=0A= *=0A= * 3. The end-user documentation included with the redistribution,=0A= * if any, must include the following acknowledgment:=0A= * "This product includes software developed by the=0A= * Apache Software Foundation (http://www.apache.org/)."=0A= * Alternately, this acknowledgment may appear in the software itself,=0A= * if and wherever such third-party acknowledgments normally appear.=0A= *=0A= * 4. The names "Apache" and "Apache Software Foundation" must=0A= * not be used to endorse or promote products derived from this=0A= * software without prior written permission. For written=0A= * permission, please contact apache@apache.org.=0A= *=0A= * 5. Products derived from this software may not be called "Apache",=0A= * nor may "Apache" appear in their name, without prior written=0A= * permission of the Apache Software Foundation.=0A= *=0A= * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED=0A= * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES=0A= * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE=0A= * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR=0A= * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,=0A= * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT=0A= * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF=0A= * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND=0A= * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,=0A= * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT=0A= * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF=0A= * SUCH DAMAGE.=0A= * = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A= *=0A= * This software consists of voluntary contributions made by many=0A= * individuals on behalf of the Apache Software Foundation. For more=0A= * information on the Apache Software Foundation, please see=0A= * .=0A= */=0A= =0A= #ifndef APR_POOLS_H=0A= #define APR_POOLS_H=0A= =0A= #ifdef __cplusplus=0A= extern "C" {=0A= #endif=0A= =0A= /**=0A= * @file apr_pools.h=0A= * @brief APR memory allocation=0A= *=0A= * Resource allocation routines...=0A= *=0A= * designed so that we don't have to keep track of EVERYTHING so that=0A= * it can be explicitly freed later (a fundamentally unsound strategy ---=0A= * particularly in the presence of die()).=0A= *=0A= * Instead, we maintain pools, and allocate items (both memory and I/O=0A= * handlers) from the pools --- currently there are two, one for per=0A= * transaction info, and one for config info. When a transaction is = over,=0A= * we can delete everything in the per-transaction apr_pool_t without = fear, =0A= * and without thinking too hard about it either.=0A= */=0A= /** =0A= * @defgroup APR_Pool Pool Allocation Functions=0A= * @ingroup APR=0A= * @{ =0A= */=0A= #include "apr.h"=0A= #include "apr_errno.h"=0A= =0A= /* Memory allocation/Pool debugging options... =0A= *=0A= * Look in the developer documentation for details of what these do.=0A= *=0A= * NB These should ALL normally be commented out unless you REALLY=0A= * need them!!=0A= */=0A= =0A= /*=0A= #define APR_POOL_DEBUG=0A= */=0A= =0A= /** The fundamental pool type */=0A= typedef struct apr_pool_t apr_pool_t;=0A= =0A= /** A function that is called when allocation fails. */=0A= typedef int (*apr_abortfunc_t)(int retcode);=0A= =0A= /**=0A= * @defgroup PoolDebug Pool Debugging functions.=0A= *=0A= * pools have nested lifetimes -- sub_pools are destroyed when the=0A= * parent pool is cleared. We allow certain liberties with operations=0A= * on things such as tables (and on other structures in a more general=0A= * sense) where we allow the caller to insert values into a table which=0A= * were not allocated from the table's pool. The table's data will=0A= * remain valid as long as all the pools from which its values are=0A= * allocated remain valid.=0A= *=0A= * For example, if B is a sub pool of A, and you build a table T in=0A= * pool B, then it's safe to insert data allocated in A or B into T=0A= * (because B lives at most as long as A does, and T is destroyed when=0A= * B is cleared/destroyed). On the other hand, if S is a table in=0A= * pool A, it is safe to insert data allocated in A into S, but it=0A= * is *not safe* to insert data allocated from B into S... because=0A= * B can be cleared/destroyed before A is (which would leave dangling=0A= * pointers in T's data structures).=0A= *=0A= * In general we say that it is safe to insert data into a table T=0A= * if the data is allocated in any ancestor of T's pool. This is the=0A= * basis on which the APR_POOL_DEBUG code works -- it tests these = ancestor=0A= * relationships for all data inserted into tables. APR_POOL_DEBUG also=0A= * provides tools (apr_find_pool, and apr_pool_is_ancestor) for other=0A= * folks to implement similar restrictions for their own data=0A= * structures.=0A= *=0A= * However, sometimes this ancestor requirement is inconvenient --=0A= * sometimes we're forced to create a sub pool (such as through=0A= * apr_sub_req_lookup_uri), and the sub pool is guaranteed to have=0A= * the same lifetime as the parent pool. This is a guarantee implemented=0A= * by the *caller*, not by the pool code. That is, the caller guarantees=0A= * they won't destroy the sub pool individually prior to destroying the=0A= * parent pool.=0A= *=0A= * In this case the caller must call apr_pool_join() to indicate this=0A= * guarantee to the APR_POOL_DEBUG code. There are a few examples spread=0A= * through the standard modules.=0A= *=0A= * These functions are only implemented when #APR_POOL_DEBUG is set.=0A= *=0A= * @{=0A= */=0A= #if defined(APR_POOL_DEBUG) || defined(DOXYGEN)=0A= /**=0A= * Guarantee that a subpool has the same lifetime as the parent.=0A= * @param p The parent pool=0A= * @param sub The subpool=0A= */=0A= APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub);=0A= =0A= /**=0A= * Find a pool from something allocated in it.=0A= * @param ts The thing allocated in the pool=0A= * @return The pool it is allocated in=0A= */=0A= APR_DECLARE(apr_pool_t *) apr_find_pool(const void *ts);=0A= =0A= /**=0A= * Report the number of bytes currently in the pool=0A= * @param p The pool to inspect=0A= * @param recurse Recurse/include the subpools' sizes=0A= * @return The number of bytes=0A= */=0A= APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *p, int recurse);=0A= =0A= /**=0A= * Report the number of bytes currently in the list of free blocks=0A= * @return The number of bytes=0A= */=0A= APR_DECLARE(apr_size_t) apr_pool_free_blocks_num_bytes(void);=0A= =0A= /**=0A= * Tag a pool (give it a name)=0A= * @param pool The pool to tag=0A= * @param tag The tag=0A= */=0A= APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag);=0A= =0A= /* @} */=0A= =0A= #else=0A= # ifdef apr_pool_join=0A= # undef apr_pool_join=0A= # endif=0A= # define apr_pool_join(a,b)=0A= =0A= # ifdef apr_pool_tag=0A= # undef apr_pool_tag=0A= # endif=0A= # define apr_pool_tag(pool, tag)=0A= #endif=0A= =0A= /**=0A= * Determine if pool a is an ancestor of pool b=0A= * @param a The pool to search =0A= * @param b The pool to search for=0A= * @return True if a is an ancestor of b, NULL is considered an ancestor=0A= * of all pools.=0A= */=0A= APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b);=0A= =0A= =0A= /*=0A= * APR memory structure manipulators (pools, tables, and arrays).=0A= */=0A= =0A= /**=0A= * Setup all of the internal structures required to use pools=0A= * @param globalp The APR global pool, used to allocate APR structures=0A= * before any other pools are created. This pool should = not=0A= * ever be used outside of APR.=0A= * @remark Programs do NOT need to call this directly. APR will call = this=0A= * automatically from apr_initialize. =0A= * @internal=0A= */=0A= APR_DECLARE(apr_status_t) apr_pool_alloc_init(apr_pool_t *globalp);=0A= =0A= /**=0A= * Tear down all of the internal structures required to use pools=0A= * @param globalp The APR global pool, used to allocate APR structures=0A= * before any other pools are created. This pool should = not=0A= * ever be used outside of APR.=0A= * @remark Programs do NOT need to call this directly. APR will call = this=0A= * automatically from apr_terminate. =0A= * @internal=0A= */=0A= APR_DECLARE(void) apr_pool_alloc_term(apr_pool_t *globalp); =0A= =0A= /* pool functions */=0A= =0A= #define POOL_FNONE 0x0=0A= #define POOL_FNEW_ALLOCATOR 0x1=0A= #define POOL_FLOCK 0x2=0A= =0A= /**=0A= * Create a new pool.=0A= * @param newpool The pool we have just created.=0A= * @param parent The parent pool. If this is NULL, the new pool is a = root=0A= * pool. If it is non-NULL, the new pool will inherit all=0A= * of its parent pool's attributes, except the apr_pool_t will =0A= * be a sub-pool.=0A= * @param apr_abort A function to use if the pool cannot allocate more = memory.=0A= * @param flags Flags indicating how the pool should be created:=0A= * - POOL_FNEW_ALLOCATOR will create a new allocator for the pool=0A= * instead of using the allocator of the parent.=0A= * - POOL_FLOCK will create a mutex for the newly created = allocator=0A= * (this flag only makes sense in combination with = POOL_FNEW_ALLOCATOR)=0A= *=0A= */=0A= APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,=0A= apr_pool_t *parent,=0A= apr_abortfunc_t abort_fn,=0A= apr_uint32_t flags);=0A= =0A= /**=0A= * Create a new pool.=0A= * @param newpool The pool we have just created.=0A= * @param parent The parent pool. If this is NULL, the new pool is a = root=0A= * pool. If it is non-NULL, the new pool will inherit all=0A= * of its parent pool's attributes, except the apr_pool_t will =0A= * be a sub-pool.=0A= */=0A= #if defined(DOXYGEN)=0A= APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool,=0A= apr_pool_t *parent);=0A= #else=0A= #define apr_pool_create(newpool, parent) \=0A= apr_pool_create_ex(newpool, parent, NULL, POOL_FNONE)=0A= #endif=0A= =0A= /**=0A= * @param newpool The new sub-pool=0A= * @param parent The pool to use as a parent pool=0A= * @param apr_abort A function to use if the pool cannot allocate more = memory.=0A= * @deffunc void apr_pool_sub_make(apr_pool_t **p, apr_pool_t *parent, = int (*apr_abort)(int retcode), const char *created)=0A= * @remark The @a apr_abort function provides a way to quit the program = if the=0A= * machine is out of memory. By default, APR will return on error.=0A= */=0A= #if defined(DOXYGEN)=0A= APR_DECLARE(void) apr_pool_sub_make(apr_pool_t **newpool, =0A= apr_pool_t *parent,=0A= int (*apr_abort)(int retcode));=0A= #else=0A= #define apr_pool_sub_make(newpool, parent, abort_fn) \=0A= (void)apr_pool_create_ex(newpool, parent, abort_fn, POOL_FNONE);=0A= #endif=0A= =0A= /**=0A= * Allocate a block of memory from a pool=0A= * @param c The pool to allocate from =0A= * @param reqsize The amount of memory to allocate =0A= * @return The allocated memory=0A= */=0A= APR_DECLARE(void *) apr_palloc(apr_pool_t *c, apr_size_t reqsize);=0A= =0A= /**=0A= * Allocate a block of memory from a pool and set all of the memory to 0=0A= * @param p The pool to allocate from =0A= * @param size The amount of memory to allocate =0A= * @return The allocated memory=0A= */=0A= APR_DECLARE(void *) apr_pcalloc(apr_pool_t *p, apr_size_t size);=0A= =0A= /**=0A= * Clear all memory in the pool and run all the cleanups. This also = clears all=0A= * subpools.=0A= * @param p The pool to clear=0A= * @remark This does not actually free the memory, it just allows the = pool=0A= * to re-use this memory for the next allocation.=0A= * @see apr_pool_destroy()=0A= */=0A= APR_DECLARE(void) apr_pool_clear(apr_pool_t *p);=0A= =0A= /**=0A= * Destroy the pool. This runs apr_pool_clear() and then frees all the = memory.=0A= * @param p The pool to destroy=0A= * @remark This will actually free the memory=0A= */=0A= APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);=0A= =0A= /**=0A= * Set the function to be called when an allocation failure occurs.=0A= * @tip If the program wants APR to exit on a memory allocation error,=0A= * then this function can be called to set the callback to use (for=0A= * performing cleanup and then exiting). If this function is not = called,=0A= * then APR will return an error and expect the calling program to=0A= * deal with the error accordingly.=0A= * @deffunc apr_status_t apr_pool_set_abort(apr_abortfunc_t abortfunc, = apr_pool_t *pool)=0A= */=0A= APR_DECLARE(void) apr_pool_set_abort(apr_abortfunc_t abortfunc,=0A= apr_pool_t *pool);=0A= =0A= /**=0A= * Get the abort function associated with the specified pool.=0A= * @param pool The pool for retrieving the abort function.=0A= * @return The abort function for the given pool.=0A= * @deffunc apr_abortfunc_t apr_pool_get_abort(apr_pool_t *pool)=0A= */=0A= APR_DECLARE(apr_abortfunc_t) apr_pool_get_abort(apr_pool_t *pool);=0A= =0A= /**=0A= * Get the parent pool of the specified pool.=0A= * @param pool The pool for retrieving the parent pool.=0A= * @return The parent of the given pool.=0A= * @deffunc apr_pool_t * apr_pool_get_parent(apr_pool_t *pool)=0A= */=0A= APR_DECLARE(apr_pool_t *) apr_pool_get_parent(apr_pool_t *pool);=0A= =0A= /**=0A= * Set the data associated with the current pool=0A= * @param data The user data associated with the pool.=0A= * @param key The key to use for association=0A= * @param cleanup The cleanup program to use to cleanup the data (NULL = if none)=0A= * @param pool The current pool=0A= * @warning The data to be attached to the pool should have a life span=0A= * at least as long as the pool it is being attached to.=0A= *=0A= * Users of APR must take EXTREME care when choosing a key to=0A= * use for their data. It is possible to accidentally overwrite=0A= * data by choosing a key that another part of the program is using=0A= * It is advised that steps are taken to ensure that a unique=0A= * key is used at all times.=0A= * @bug Specify how to ensure this uniqueness!=0A= */=0A= APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data,=0A= const char *key,=0A= apr_status_t (*cleanup)(void *),=0A= apr_pool_t *pool);=0A= =0A= /**=0A= * Set the data associated with the current pool=0A= * @param data The user data associated with the pool.=0A= * @param key The key to use for association=0A= * @param cleanup The cleanup program to use to cleanup the data (NULL = if none)=0A= * @param pool The current pool=0A= * @note same as apr_pool_userdata_set(), except that this version = doesn't=0A= * make a copy of the key (this function is useful, for example, = when=0A= * the key is a string literal)=0A= * @warning The key and the data to be attached to the pool should have=0A= * a life span at least as long as the pool itself.=0A= *=0A= */=0A= APR_DECLARE(apr_status_t) apr_pool_userdata_setn(const void *data,=0A= const char *key,=0A= apr_status_t = (*cleanup)(void *),=0A= apr_pool_t *pool);=0A= =0A= /**=0A= * Return the data associated with the current pool.=0A= * @param data The user data associated with the pool.=0A= * @param key The key for the data to retrieve=0A= * @param pool The current pool.=0A= */=0A= APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char = *key,=0A= apr_pool_t *pool);=0A= =0A= /**=0A= * Register a function to be called when a pool is cleared or destroyed=0A= * @param p The pool register the cleanup with =0A= * @param data The data to pass to the cleanup function.=0A= * @param plain_cleanup The function to call when the pool is cleared =0A= * or destroyed=0A= * @param child_cleanup The function to call when a child process is = created -=0A= * this function is called in the child, obviously!=0A= */=0A= APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void = *data,=0A= apr_status_t = (*plain_cleanup)(void *),=0A= apr_status_t = (*child_cleanup)(void *));=0A= =0A= /**=0A= * Remove a previously registered cleanup function=0A= * @param p The pool remove the cleanup from =0A= * @param data The data to remove from cleanup=0A= * @param cleanup The function to remove from cleanup=0A= * @remarks For some strange reason only the plain_cleanup is handled by = this=0A= * function=0A= */=0A= APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data,=0A= apr_status_t (*cleanup)(void *));=0A= =0A= /**=0A= * Replace the child cleanup of a previously registered cleanup=0A= * @param p The pool of the registered cleanup=0A= * @param data The data of the registered cleanup=0A= * @param plain_cleanup The plain cleanup function of the registered = cleanup=0A= * @param child_cleanup The function to register as the child cleanup=0A= */=0A= APR_DECLARE(void) apr_pool_child_cleanup_set(apr_pool_t *p, const void = *data,=0A= apr_status_t (*plain_cleanup)(void = *),=0A= apr_status_t (*child_cleanup)(void = *));=0A= =0A= /**=0A= * Run the specified cleanup function immediately and unregister it. Use=0A= * @a data instead of the data that was registered with the cleanup.=0A= * @param p The pool remove the cleanup from =0A= * @param data The data to remove from cleanup=0A= * @param cleanup The function to remove from cleanup=0A= */=0A= APR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data,=0A= apr_status_t (*cleanup)(void = *));=0A= =0A= /**=0A= * An empty cleanup function =0A= * @param data The data to cleanup=0A= */=0A= APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data);=0A= =0A= /* Preparing for exec() --- close files, etc., but *don't* flush I/O=0A= * buffers, *don't* wait for subprocesses, and *don't* free any memory.=0A= */=0A= /**=0A= * Run all of the child_cleanups, so that any unnecessary files are =0A= * closed because we are about to exec a new program=0A= */=0A= APR_DECLARE(void) apr_pool_cleanup_for_exec(void);=0A= =0A= /*=0A= * Pool accessor functions.=0A= *=0A= * These standardized function are used by opaque (APR) data types to = return=0A= * the apr_pool_t that is associated with the data type.=0A= *=0A= * APR_POOL_DECLARE_ACCESSOR() is used in a header file to declare the=0A= * accessor function. A typical usage and result would be:=0A= *=0A= * APR_POOL_DECLARE_ACCESSOR(file);=0A= * becomes:=0A= * APR_DECLARE(apr_pool_t *) apr_file_pool_get(apr_file_t *ob);=0A= *=0A= * In the implementation, the APR_POOL_IMPLEMENT_ACCESSOR() is used to=0A= * actually define the function. It assumes the field is named "pool". = For=0A= * data types with a different field name (e.g. "cont" or "cntxt") the=0A= * APR_POOL_IMPLEMENT_ACCESSOR_X() macro should be used.=0A= *=0A= * Note: the linkage is specified for APR. It would be possible to expand=0A= * the macros to support other linkages.=0A= */=0A= #define APR_POOL_DECLARE_ACCESSOR(typename) \=0A= APR_DECLARE(apr_pool_t *) apr_##typename##_pool_get \=0A= (const apr_##typename##_t *ob)=0A= =0A= #define APR_POOL_IMPLEMENT_ACCESSOR(typename) \=0A= APR_POOL_IMPLEMENT_ACCESSOR_X(typename, pool)=0A= #define APR_POOL_IMPLEMENT_ACCESSOR_X(typename, fieldname) \=0A= APR_DECLARE(apr_pool_t *) apr_##typename##_pool_get \=0A= (const apr_##typename##_t *ob) { return ob->fieldname; }=0A= =0A= /** @} */=0A= #ifdef __cplusplus=0A= }=0A= #endif=0A= =0A= #endif /* !APR_POOLS_H */=0A= ------=_NextPart_000_003D_01C179CC.A22C3520--