--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 <gopalv@yahoo-inc.com> |
+ +----------------------------------------------------------------------+
+
+ 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 <assert.h>
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#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
+ */