📄 apr_pools.c
字号:
/* ==================================================================== * 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 apache@apache.org. * * 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/>. *//* * Resource allocation code... the code here is responsible for making * sure that nothing leaks. * * rst --- 4/95 --- 6/95 */#include "apr.h"#include "apr_private.h"#include "apr_portable.h" /* for get_os_proc */#include "apr_strings.h"#include "apr_general.h"#include "apr_pools.h"#include "apr_lib.h"#include "apr_lock.h"#include "apr_hash.h"#if APR_HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#if APR_HAVE_SYS_SIGNAL_H#include <sys/signal.h>#endif#if APR_HAVE_SIGNAL_H#include <signal.h>#endif#if APR_HAVE_SYS_WAIT_H#include <sys/wait.h>#endif#if APR_HAVE_SYS_TYPES_H#include <sys/types.h>#endif#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if APR_HAVE_FCNTL_H#include <fcntl.h>#endif#if APR_HAVE_STRING_H#include <string.h>#endif#if APR_HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_MALLOC_H#include <malloc.h>#endif/* Details of the debugging options can now be found in the developer * section of the documentaion. *//* magic numbers --- min free bytes to consider a free apr_pool_t block useable, * and the min amount to allocate if we have to go to malloc() */#ifndef BLOCK_MINFREE#define BLOCK_MINFREE 4096#endif#ifndef BLOCK_MINALLOC#define BLOCK_MINALLOC 8192#endif #ifdef APR_POOL_DEBUG/* first do some option checking... */#ifdef ALLOC_USE_MALLOC#error "sorry, no support for ALLOC_USE_MALLOC and APR_POOL_DEBUG at the same time"#endif /* ALLOC_USE_MALLOC */#ifdef MULTITHREAD# error "sorry, no support for MULTITHREAD and APR_POOL_DEBUG at the same time"#endif /* MULTITHREAD */#endif /* APR_POOL_DEBUG */#ifdef ALLOC_USE_MALLOC#undef BLOCK_MINFREE#undef BLOCK_MINALLOC#define BLOCK_MINFREE 0#define BLOCK_MINALLOC 0#endif /* ALLOC_USE_MALLOC */#define APR_SLACK_LOW 1#define APR_SLACK_HIGH 2/***************************************************************** * * Managing free storage blocks... */union align { /* * Types which are likely to have the longest RELEVANT alignment * restrictions... */ char *cp; void (*f) (void); long l; FILE *fp; double d;};#define CLICK_SZ (sizeof(union align))union block_hdr { union align a; /* Actual header... */ struct { char *endp; union block_hdr *next; char *first_avail;#ifdef APR_POOL_DEBUG union block_hdr *global_next; apr_pool_t *owning_pool;#endif /* APR_POOL_DEBUG */ } h;};#define APR_ABORT(conditional, retcode, func, str) \ if (conditional) { \ if ((func) == NULL) { \ return NULL; \ } \ else { \ fprintf(stderr, "%s", str); \ (*(func))(retcode); \ } \ }/* * Static cells for managing our internal synchronisation. */static union block_hdr *block_freelist = NULL;#if APR_HAS_THREADSstatic apr_lock_t *alloc_mutex;static apr_lock_t *spawn_mutex;#endif#ifdef APR_POOL_DEBUGstatic char *known_stack_point;static int stack_direction;static union block_hdr *global_block_list;#define FREE_POOL ((apr_pool_t *)(-1))#endif /* APR_POOL_DEBUG */#ifdef ALLOC_STATSstatic unsigned long long num_free_blocks_calls;static unsigned long long num_blocks_freed;static unsigned max_blocks_in_one_free;static unsigned num_malloc_calls;static unsigned num_malloc_bytes;#endif /* ALLOC_STATS */#ifdef ALLOC_DEBUG#define FILL_BYTE ((char)(0xa5))#define debug_fill(ptr,size) ((void)memset((ptr), FILL_BYTE, (size)))static APR_INLINE void debug_verify_filled(const char *ptr, const char *endp, const char *error_msg){ for ( ; ptr < endp; ++ptr) { if (*ptr != FILL_BYTE) { fputs(error_msg, stderr); abort(); exit(1); } }}#else /* ALLOC_DEBUG */#define debug_fill(a,b)#define debug_verify_filled(a,b,c)#endif /* ALLOC_DEBUG *//* * Get a completely new block from the system pool. Note that we rely on * malloc() to provide aligned memory. */static union block_hdr *malloc_block(int size, int (*apr_abort)(int retcode)){ union block_hdr *blok;#ifdef ALLOC_DEBUG /* make some room at the end which we'll fill and expect to be * always filled */ size += CLICK_SZ;#endif /* ALLOC_DEBUG */#ifdef ALLOC_STATS ++num_malloc_calls; num_malloc_bytes += size + sizeof(union block_hdr);#endif /* ALLOC_STATS */ blok = (union block_hdr *) malloc(size + sizeof(union block_hdr)); APR_ABORT(blok == NULL, APR_ENOMEM, apr_abort, "Ouch! malloc failed in malloc_block()\n"); debug_fill(blok, size + sizeof(union block_hdr)); blok->h.next = NULL; blok->h.first_avail = (char *) (blok + 1); blok->h.endp = size + blok->h.first_avail;#ifdef ALLOC_DEBUG blok->h.endp -= CLICK_SZ;#endif /* ALLOC_DEBUG */#ifdef APR_POOL_DEBUG blok->h.global_next = global_block_list; global_block_list = blok; blok->h.owning_pool = NULL;#endif /* APR_POOL_DEBUG */ return blok;}#if defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC)static void chk_on_blk_list(union block_hdr *blok, union block_hdr *free_blk){ debug_verify_filled(blok->h.endp, blok->h.endp + CLICK_SZ, "[chk_on_blk_list] Ouch! Someone trounced the padding " "at the end of a block!\n"); while (free_blk) { if (free_blk == blok) { fprintf(stderr, "Ouch! Freeing free block\n"); abort(); exit(1); } free_blk = free_blk->h.next; }}#else /* defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) */#define chk_on_blk_list(_x, _y)#endif /* defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) *//* Free a chain of blocks --- must be called with alarms blocked. */static void free_blocks(union block_hdr *blok){#ifdef ALLOC_USE_MALLOC union block_hdr *next; for ( ; blok; blok = next) { next = blok->h.next; free(blok); }#else /* ALLOC_USE_MALLOC */#ifdef ALLOC_STATS unsigned num_blocks;#endif /* ALLOC_STATS */ /* * First, put new blocks at the head of the free list --- * we'll eventually bash the 'next' pointer of the last block * in the chain to point to the free blocks we already had. */ union block_hdr *old_free_list; if (blok == NULL) { return; /* Sanity check --- freeing empty pool? */ }#if APR_HAS_THREADS if (alloc_mutex) { apr_lock_acquire(alloc_mutex); }#endif old_free_list = block_freelist; block_freelist = blok; /* * Next, adjust first_avail pointers of each block --- have to do it * sooner or later, and it simplifies the search in new_block to do it * now. */#ifdef ALLOC_STATS num_blocks = 1;#endif /* ALLOC_STATS */ while (blok->h.next != NULL) {#ifdef ALLOC_STATS ++num_blocks;#endif /* ALLOC_STATS */ chk_on_blk_list(blok, old_free_list); blok->h.first_avail = (char *) (blok + 1); debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);#ifdef APR_POOL_DEBUG blok->h.owning_pool = FREE_POOL;#endif /* APR_POOL_DEBUG */ blok = blok->h.next; } chk_on_blk_list(blok, old_free_list); blok->h.first_avail = (char *) (blok + 1); debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);#ifdef APR_POOL_DEBUG blok->h.owning_pool = FREE_POOL;#endif /* APR_POOL_DEBUG */ /* Finally, reset next pointer to get the old free blocks back */ blok->h.next = old_free_list;#ifdef ALLOC_STATS if (num_blocks > max_blocks_in_one_free) { max_blocks_in_one_free = num_blocks; } ++num_free_blocks_calls; num_blocks_freed += num_blocks;#endif /* ALLOC_STATS */#if APR_HAS_THREADS if (alloc_mutex) { apr_lock_release(alloc_mutex); }#endif /* APR_HAS_THREADS */#endif /* ALLOC_USE_MALLOC */}/* * Get a new block, from our own free list if possible, from the system * if necessary. Must be called with alarms blocked. */static union block_hdr *new_block(int min_size, int (*apr_abort)(int retcode)){ union block_hdr **lastptr = &block_freelist; union block_hdr *blok = block_freelist; /* First, see if we have anything of the required size * on the free list... */ while (blok != NULL) { if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) { *lastptr = blok->h.next; blok->h.next = NULL; debug_verify_filled(blok->h.first_avail, blok->h.endp, "[new_block] Ouch! Someone trounced a block " "on the free list!\n"); return blok; } else { lastptr = &blok->h.next; blok = blok->h.next; } } /* Nope. */ min_size += BLOCK_MINFREE; blok = malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC, apr_abort); return blok;}/* Accounting */static apr_size_t bytes_in_block_list(union block_hdr *blok){ apr_size_t size = 0; while (blok) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -