On Sun, Jul 08, 2001 at 10:11:11AM -0700, Justin Erenkrantz wrote: > In the effort to place my code where my mouth is, I'm implementing this. > Patch posting shortly. -- justin
memory/unix/apr_sms_replay.c and a new apr_sms_pool.c that cleans up things slightly (create_sms function centralizes which SMS we are using - not sure if that is helpful) and define APR_POOL_REPLAY to do your output format. I didn't bother to clean up the apr_instrument function, but if I would actually commit this, I'd clean it up slightly. =) It's a hack. You'll need David's other patches to do the POOLS_ARE_SMS. -- justin
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ #include "apr.h" #include "apr_general.h" #include "apr_private.h" #include "apr_sms.h" #include "apr_sms_replay.h" #include "apr_lock.h" #include <stddef.h> /* for NULL */ #include <stdarg.h> /* for va_list */ #include <unistd.h> /* for getpid */ #include "sms_private.h" static const char *module_identity = "REPLAY"; /* * A SMS that will write debugging information to a file. This will work * with the testpool code to allow the allocation to be replayed. */ /* INTERNALLY USED STRUCTURES */ typedef struct block_t { struct block_t *next; struct block_t **ref; } block_t; typedef struct apr_sms_replay_t { apr_sms_t sms_hdr; block_t *blocks; apr_lock_t *lock; } apr_sms_replay_t; #define SIZEOF_BLOCK_T APR_ALIGN_DEFAULT(sizeof(block_t)) #define SIZEOF_SMS_REPLAY_T APR_ALIGN_DEFAULT(sizeof(apr_sms_replay_t)) #define BLOCK_T(mem) ((block_t *)(mem)) #define SMS_REPLAY_T(sms) ((apr_sms_replay_t *)(sms)) #define INSERT_BLOCK(block, tms) \ if (tms->lock) \ apr_lock_acquire(tms->lock); \ \ block->ref = &tms->blocks; \ if ((block->next = tms->blocks) != NULL) \ block->next->ref = &block->next; \ tms->blocks = block; \ \ if (tms->lock) \ apr_lock_release(tms->lock); #define REMOVE_BLOCK(block, tms) \ if (tms->lock) \ apr_lock_acquire(tms->lock); \ \ if (block->next) \ block->next->ref = block->ref; \ \ if (tms->lock) \ apr_lock_release(tms->lock); static void apr_sms_instrument(const char*fn, apr_sms_t *sms, const char*format,... ) { static volatile int bfirst=1; char buffer[1000]; char buffer2[1000]; va_list ap; apr_os_thread_t pthread = apr_os_thread_current(); pid_t pid = getpid(); struct timeval tv; gettimeofday(&tv, NULL); if (bfirst==1) { bfirst=0; fprintf(stderr, "#APR_INSTRUMENT:PID,THREAD,SECS,USEC,POOL,FN,ARGS\n"); } va_start(ap, format); vsnprintf(buffer, sizeof(buffer), format, ap); va_end(ap); snprintf(buffer2, sizeof(buffer2), "APR_INSTRUMENT:POOL,%lu,%lu,%ld,%ld,%lu,%s,%s\n", pid, pthread, tv.tv_sec, tv.tv_usec, sms, fn, buffer); fputs(buffer2,stderr); } static void *apr_sms_replay_malloc(apr_sms_t *sms, apr_size_t size) { void *mem; apr_sms_instrument("apr_palloc", sms, "%lu", size); size = APR_ALIGN_DEFAULT(size) + SIZEOF_BLOCK_T; mem = apr_sms_malloc(sms->parent, size); if (!mem) return NULL; INSERT_BLOCK(BLOCK_T(mem), SMS_REPLAY_T(sms)) mem = (char *)mem + SIZEOF_BLOCK_T; return mem; } static void *apr_sms_replay_calloc(apr_sms_t *sms, apr_size_t size) { void *mem; apr_sms_instrument("apr_pcalloc", sms, "%lu", size); size = APR_ALIGN_DEFAULT(size) + SIZEOF_BLOCK_T; mem = apr_sms_calloc(sms->parent, size); if (!mem) return NULL; INSERT_BLOCK(BLOCK_T(mem), SMS_REPLAY_T(sms)) mem = (char *)mem + SIZEOF_BLOCK_T; return mem; } static void *apr_sms_replay_realloc(apr_sms_t *sms, void *mem, apr_size_t size) { block_t *block; block = BLOCK_T(mem - SIZEOF_BLOCK_T); REMOVE_BLOCK(block, SMS_REPLAY_T(sms)) size = APR_ALIGN_DEFAULT(size) + SIZEOF_BLOCK_T; mem = apr_sms_realloc(sms->parent, block, size); if (!mem) return NULL; INSERT_BLOCK(BLOCK_T(mem), SMS_REPLAY_T(sms)) mem = (char *)mem + SIZEOF_BLOCK_T; return mem; } static apr_status_t apr_sms_replay_free(apr_sms_t *sms, void *mem) { mem = (char *)mem - SIZEOF_BLOCK_T; REMOVE_BLOCK(BLOCK_T(mem), SMS_REPLAY_T(sms)); return apr_sms_free(sms->parent, mem); } static apr_status_t apr_sms_replay_reset(apr_sms_t *sms) { block_t *block; apr_status_t rv = APR_SUCCESS; apr_sms_instrument("apr_pool_clear", sms, "-"); if (SMS_REPLAY_T(sms)->lock) apr_lock_acquire(SMS_REPLAY_T(sms)->lock); while ((block = SMS_REPLAY_T(sms)->blocks) != NULL) { if ((*block->ref = block->next) != NULL) block->next->ref = block->ref; if ((rv = apr_sms_free(sms->parent, block)) != APR_SUCCESS) break; } if (SMS_REPLAY_T(sms)->lock) apr_lock_release(SMS_REPLAY_T(sms)->lock); return rv; } static apr_status_t apr_sms_replay_pre_destroy(apr_sms_t *sms) { /* This function WILL alwways be called. However, be aware that the * main sms destroy function knows that it's not wise to try and destroy * the same piece of memory twice, so the destroy function in a child won't * neccesarily be called. To guarantee we destroy the lock it's therefore * destroyed here. */ if (SMS_REPLAY_T(sms)->lock) { apr_lock_acquire(SMS_REPLAY_T(sms)->lock); apr_lock_destroy(SMS_REPLAY_T(sms)->lock); SMS_REPLAY_T(sms)->lock = NULL; } return APR_SUCCESS; } static apr_status_t apr_sms_replay_destroy(apr_sms_t *sms) { apr_status_t rv; if ((rv = apr_sms_reset(sms)) != APR_SUCCESS) return rv; return apr_sms_free(sms->parent, sms); } #if APR_HAS_THREADS static apr_status_t apr_sms_replay_thread_register(apr_sms_t *sms, apr_os_thread_t thread) { if (!SMS_REPLAY_T(sms)->lock && sms->threads > 1) return apr_lock_create(&SMS_REPLAY_T(sms)->lock, APR_MUTEX, APR_LOCKALL, NULL, sms->pool); return APR_SUCCESS; } static apr_status_t apr_sms_replay_thread_unregister(apr_sms_t *sms, apr_os_thread_t thread) { return APR_SUCCESS; } #endif /* APR_HAS_THREADS */ APR_DECLARE(apr_status_t) apr_sms_replay_create(apr_sms_t **sms, apr_sms_t *pms) { apr_sms_t *new_sms; apr_status_t rv; *sms = NULL; /* We're not a top level module, ie we have a parent, so * we allocate the memory for the structure from our parent. * This is safe as we shouldn't outlive our parent... */ new_sms = apr_sms_calloc(pms, SIZEOF_SMS_REPLAY_T); if (!new_sms) return APR_ENOMEM; if ((rv = apr_sms_init(new_sms, pms)) != APR_SUCCESS) return rv; new_sms->malloc_fn = apr_sms_replay_malloc; new_sms->calloc_fn = apr_sms_replay_calloc; new_sms->realloc_fn = apr_sms_replay_realloc; new_sms->free_fn = apr_sms_replay_free; new_sms->reset_fn = apr_sms_replay_reset; new_sms->pre_destroy_fn = apr_sms_replay_pre_destroy; new_sms->destroy_fn = apr_sms_replay_destroy; #if APR_HAS_THREADS new_sms->thread_register_fn = apr_sms_replay_thread_register; new_sms->thread_unregister_fn = apr_sms_replay_thread_unregister; #endif /* APR_HAS_THREADS */ new_sms->identity = module_identity; apr_sms_post_init(new_sms); apr_sms_instrument("apr_pool_create", pms, "%lu", new_sms); *sms = new_sms; return APR_SUCCESS; }
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ #define APR_POOL_REPLAY #include "apr.h" #include "apr_pools.h" /* includes apr_sms.h" */ #include "apr_sms_trivial.h" #ifdef APR_POOL_REPLAY #include "apr_sms_replay.h" #endif #include "apr_errno.h" #include "apr_lock.h" #include "apr_portable.h" #include "apr_lib.h" /* for apr_vformatter */ #include "sms_private.h" static int initialized = 0; static apr_pool_t *permanent_pool = NULL; static apr_status_t create_pool(apr_pool_t **newpool, apr_pool_t *p) { #ifdef APR_POOL_REPLAY apr_pool_t *temppool; apr_sms_trivial_create(&temppool, p); return apr_sms_replay_create(newpool, temppool); #else return apr_sms_trivial_create(newpool, p); #endif } APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, apr_pool_t *p) { if (!initialized) /* Hmm, if we are given a parent here, is this correct? * It should never happen, so we're probably OK.... */ return apr_sms_std_create(newpool); return create_pool(newpool, p ? p : permanent_pool); } APR_DECLARE(apr_pool_t *) apr_pool_sub_make(apr_pool_t * p, apr_abortfunc_t abort) { apr_pool_t *np; if (create_pool(&np, p) != APR_SUCCESS) return NULL; apr_sms_set_abort(abort, np); return np; } APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *pool, const void *data, apr_status_t (*plain_cleanup)(void*), apr_status_t (*child_cleanup)(void*)) { if (plain_cleanup == child_cleanup) { /* we only need to register one as an ALL_CLEANUP */ apr_sms_cleanup_register(pool, APR_ALL_CLEANUPS, data, plain_cleanup); return; } if (plain_cleanup) apr_sms_cleanup_register(pool, APR_GENERAL_CLEANUP, data, plain_cleanup); if (child_cleanup) apr_sms_cleanup_register(pool, APR_CHILD_CLEANUP, data, child_cleanup); } APR_DECLARE(void) apr_pool_cleanup_for_exec(void) { #if !defined(WIN32) && !defined(OS2) /* See note in apr_pools.c for why we do this :) */ apr_sms_cleanup_run_type(permanent_pool, APR_CHILD_CLEANUP); #endif } APR_DECLARE(apr_status_t) apr_pool_alloc_init(apr_pool_t *gp) { initialized = 1; return create_pool(&permanent_pool, gp); } APR_DECLARE(void) apr_pool_alloc_term(apr_pool_t *gp) { apr_sms_destroy(permanent_pool); /* so, are we still initialized after this???? */ } APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b) { while (b && b != a) b = b->parent; return b == a; } /* This stuff needs to be reviewed, but here it is :) */ struct psprintf_data { apr_vformatter_buff_t vbuff; char *base; apr_sms_t *sms; }; static int psprintf_flush(apr_vformatter_buff_t *vbuff) { struct psprintf_data *ps = (struct psprintf_data*)vbuff; apr_size_t size; char *ptr; size = (char*) ps->vbuff.curpos - ps->base; ptr = apr_sms_realloc(ps->sms, ps->base, 2*size); if (ptr == NULL) { fputs("[psprintf_flush] Ouch! Out of memory!\n", stderr); exit(1); } ps->base = ptr; ps->vbuff.curpos = ptr + size; ps->vbuff.endpos = ptr + 2 * size - 1; return 0; } APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *p, const char *fmt, va_list ap) { struct psprintf_data ps; void *ptr; ps.sms = (apr_sms_t*)p; ps.base = apr_sms_malloc(ps.sms, 512); if (ps.base == NULL) { fputs("[apr_pvsprintf] Ouch! Out of memory!\n", stderr); exit(1); } ps.vbuff.curpos = ps.base; ps.vbuff.endpos = ps.base + 511; apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap); *ps.vbuff.curpos++ = '\0'; ptr = ps.base; ptr = apr_sms_realloc(ps.sms, ptr, (char*)ps.vbuff.curpos - (char*)ptr); if (ptr == NULL) { fputs("[apr_pvsprintf #2] Ouch! Out of memory!\n", stderr); exit(1); } return (char*)ptr; } APR_DECLARE_NONSTD(char*) apr_psprintf(apr_pool_t *p, const char *fmt, ...) { va_list ap; char *res; va_start(ap,fmt); res = apr_pvsprintf(p, fmt, ap); va_end(ap); return res; } APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *a, apr_proc_t *pid, enum kill_conditions how) { struct process_chain *newpc = (struct process_chain*) apr_sms_malloc(a, sizeof(struct process_chain)); newpc->pid = pid; newpc->kill_how = how; newpc->next = a -> subprocesses; a->subprocesses = newpc; }
