X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?p=php5-apc.git;a=blobdiff_plain;f=apc_pool.c;fp=apc_pool.c;h=1d122585fb52ef7d3436b7020a7e20f7712e36b7;hp=0000000000000000000000000000000000000000;hb=3682e0a7a26931aabca2b6e54eb08efd7dc0430b;hpb=575ce08215526bb71a967d69d601e77e1afbcd11 diff --git a/apc_pool.c b/apc_pool.c new file mode 100644 index 0000000..1d12258 --- /dev/null +++ b/apc_pool.c @@ -0,0 +1,344 @@ +/* + +----------------------------------------------------------------------+ + | APC | + +----------------------------------------------------------------------+ + | Copyright (c) 2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gopal Vijayaraghavan | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Yahoo! Inc. in 2008. + + Future revisions and derivatives of this source code must acknowledge + Yahoo! Inc. as the original contributor of this module by + leaving this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. + + */ + +/* $Id: apc_pool.c,v 3.3 2008/01/09 12:30:39 gopalv Exp $ */ + + +#include "apc_pool.h" +#include + +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + +/* {{{ typedefs */ +typedef struct _pool_block +{ + size_t avail; + size_t capacity; + unsigned char *mark; + struct _pool_block *next; + unsigned :0; /* this should align to word */ + unsigned char data[0]; +}pool_block; + +/* + parts in ? are optional and turned on for fun, memory loss, + and for something else that I forgot about ... ah, debugging + + |--------> data[0] |<-- non word boundary (too) + +-------------+--------------+-----------+-------------+-------------->>> + | pool_block | ?sizeinfo<1> | block<1> | ?redzone<1> | ?sizeinfo<2> + | | (size_t) | | padded left | + +-------------+--------------+-----------+-------------+-------------->>> + */ + +struct _apc_pool +{ + apc_malloc_t allocate; + apc_free_t deallocate; + + size_t dsize; + void *owner; + + struct + { + unsigned int redzones:1; + unsigned int sizeinfo:1; + } options; + + pool_block *head; +}; +/* }}} */ + +/* {{{ redzone code */ +static const unsigned char decaff[] = { + 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad, + 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad, + 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad, + 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee, 0xba, 0xad +}; + +/* a redzone is at least 4 (0xde,0xca,0xc0,0xff) bytes */ +#define REDZONE_SIZE(size) \ + ((ALIGNWORD((size)) > ((size) + 4)) ? \ + (ALIGNWORD((size)) - (size)) : /* does not change realsize */\ + ALIGNWORD((size)) - (size) + ALIGNWORD((sizeof(char)))) /* adds 1 word to realsize */ + +#define SIZEINFO_SIZE ALIGNWORD(sizeof(size_t)) + +#define MARK_REDZONE(block, redsize) do {\ + memcpy(block, decaff, redsize );\ + } while(0) + +#define CHECK_REDZONE(block, redsize) (memcmp(block, decaff, redsize) == 0) + +/* }}} */ + +#define APC_POOL_OPTION(pool, option) ((pool)->options.option) + +/* {{{ create_pool_block */ +static pool_block* create_pool_block(apc_pool *pool, size_t size) +{ + size_t realsize = sizeof(pool_block) + ALIGNWORD(size); + + pool_block* entry = pool->allocate(realsize); + + entry->avail = entry->capacity = size; + + entry->mark = entry->data; + + entry->next = pool->head; + + pool->head = entry; + + return entry; +} +/* }}} */ + +/* {{{ apc_pool_create */ +apc_pool* apc_pool_create(apc_pool_type pool_type, + apc_malloc_t allocate, + apc_free_t deallocate) +{ + apc_pool* pool = NULL; + size_t dsize = 0; + + /* sanity checks */ + assert(sizeof(decaff) > REDZONE_SIZE(ALIGNWORD(sizeof(char)))); + assert(sizeof(pool_block) == ALIGNWORD(sizeof(pool_block))); + + assert(APC_POOL_SIZE_MASK & (APC_POOL_SIZEINFO | APC_POOL_REDZONES) == 0); + + switch(pool_type & APC_POOL_SIZE_MASK) { + case APC_SMALL_POOL: + dsize = 512; + break; + + case APC_LARGE_POOL: + dsize = 8192; + break; + + case APC_MEDIUM_POOL: + dsize = 4096; + break; + + default: + return NULL; + } + + pool = (apc_pool*)allocate(sizeof(apc_pool)); + + if(!pool) { + return NULL; + } + + pool->allocate = allocate; + pool->deallocate = deallocate; + pool->dsize = dsize; + pool->head = NULL; + + APC_POOL_OPTION(pool, redzones) = (pool_type & APC_POOL_REDZONES) != 0; + APC_POOL_OPTION(pool, sizeinfo) = (pool_type & APC_POOL_SIZEINFO) != 0; + + if(!create_pool_block(pool, dsize)) { + deallocate(pool); + return NULL; + } + + return pool; +} +/* }}} */ + +/* {{{ apc_pool_destroy */ +void apc_pool_destroy(apc_pool *pool) +{ + + apc_free_t deallocate = pool->deallocate; + pool_block *entry; + pool_block *tmp; + + entry = pool->head; + + while(entry != NULL) { + tmp = entry->next; + deallocate(entry); + entry = tmp; + } + + deallocate(pool); +} +/* }}} */ + +/* {{{ apc_pool_alloc */ +void* apc_pool_alloc(apc_pool *pool, size_t size) +{ + unsigned char *p = NULL; + size_t realsize = ALIGNWORD(size); + size_t poolsize; + unsigned char *redzone = NULL; + size_t redsize = 0; + size_t *sizeinfo= NULL; + + pool_block *entry; + + + if(APC_POOL_OPTION(pool, redzones)) { + redsize = REDZONE_SIZE(size); /* redsize might be re-using word size padding */ + realsize = size + redsize; /* recalculating realsize */ + } else { + redsize = realsize - size; /* use padding space */ + } + + if(APC_POOL_OPTION(pool, sizeinfo)) { + realsize += ALIGNWORD(sizeof(size_t)); + } + + + for(entry = pool->head; entry != NULL; entry = entry->next) { + if(entry->avail >= realsize) { + goto found; + } + } + + poolsize = ALIGNSIZE(realsize, pool->dsize); + + entry = create_pool_block(pool, poolsize); + + if(!entry) { + return NULL; + } + +found: + p = entry->mark; + + if(APC_POOL_OPTION(pool, sizeinfo)) { + sizeinfo = (size_t*)p; + p += SIZEINFO_SIZE; + *sizeinfo = size; + } + + redzone = p + size; + + if(APC_POOL_OPTION(pool, redzones)) { + MARK_REDZONE(redzone, redsize); + } + +#ifdef VALGRIND_MAKE_MEM_NOACCESS + if(redsize != 0) { + VALGRIND_MAKE_MEM_NOACCESS(redzone, redsize); + } +#endif + + entry->avail -= realsize; + entry->mark += realsize; + +#ifdef VALGRIND_MAKE_MEM_UNDEFINED + /* need to write before reading data off this */ + VALGRIND_MAKE_MEM_UNDEFINED(p, size); +#endif + + return (void*)p; +} +/* }}} */ + +/* {{{ apc_pool_free */ +/* + * free does not do anything other than + * check for redzone values when free'ing + * data areas. + */ +void apc_pool_free(apc_pool *pool, void *p) +{ + if(!APC_POOL_OPTION(pool, sizeinfo) || + !APC_POOL_OPTION(pool, redzones)) { + } +} +/* }}} */ + +/* {{{ apc_pool_check_integrity */ +/* + * Checking integrity at runtime, does an + * overwrite check only when the sizeinfo + * is set. + */ +int apc_pool_check_integrity(apc_pool *pool) +{ + pool_block *entry; + size_t *sizeinfo = NULL; + unsigned char *start; + size_t realsize; + unsigned char *redzone; + size_t redsize; + + for(entry = pool->head; entry != NULL; entry = entry->next) { + start = (unsigned char *)entry + ALIGNWORD(sizeof(pool_block)); + if((entry->mark - start) != (entry->capacity - entry->avail)) { + return 0; + } + } + + if(!APC_POOL_OPTION(pool, sizeinfo) || + !APC_POOL_OPTION(pool, redzones)) { + return 1; + } + + for(entry = pool->head; entry != NULL; entry = entry->next) { + start = (unsigned char *)entry + ALIGNWORD(sizeof(pool_block)); + + while(start < entry->mark) { + sizeinfo = (size_t*)start; + /* redzone starts where real data ends, in a non-word boundary + * redsize is at least 4 bytes + whatever's needed to make it + * to another word boundary. + */ + redzone = start + SIZEINFO_SIZE + (*sizeinfo); + redsize = REDZONE_SIZE(*sizeinfo); + if(!CHECK_REDZONE(redzone, redsize)) + { + /* + fprintf(stderr, "Redzone check failed for %p\n", + start + ALIGNWORD(sizeof(size_t)));*/ + return 0; + } + realsize = SIZEINFO_SIZE + *sizeinfo + redsize; + start += realsize; + } + } + + return 1; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker + * vim<600: expandtab sw=4 ts=4 sts=4 + */