summaryrefslogtreecommitdiff
path: root/src/daemon/memorypool.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/memorypool.c')
-rw-r--r--src/daemon/memorypool.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/daemon/memorypool.c b/src/daemon/memorypool.c
new file mode 100644
index 00000000..5b54cd2e
--- /dev/null
+++ b/src/daemon/memorypool.c
@@ -0,0 +1,180 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2007 Daniel Pittman
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file memorypool.c
+ * @brief memory pool
+ * @author Christian Grothoff
+ */
+
+#include "memorypool.h"
+
+struct MemoryPool {
+
+ /**
+ * Pointer to the pool's memory
+ */
+ char * memory;
+
+ /**
+ * Size of the pool.
+ */
+ unsigned int size;
+
+ /**
+ * Offset of the first unallocated byte.
+ */
+ unsigned int pos;
+
+ /**
+ * Offset of the last unallocated byte.
+ */
+ unsigned int end;
+
+ /**
+ * 0 if pool was malloc'ed, 1 if mmapped.
+ */
+ int is_mmap;
+};
+
+/**
+ * Create a memory pool.
+ *
+ * @param max maximum size of the pool
+ */
+struct MemoryPool * MHD_pool_create(unsigned int max) {
+ struct MemoryPool * pool;
+
+ pool = malloc(sizeof(struct MemoryPool));
+ if (pool == NULL)
+ return NULL;
+ pool->memory = MMAP(NULL, max, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS, -1, 0);
+ if ( (pool->memory == MAP_FAILED) ||
+ (pool->memory == NULL) ) {
+ pool->memory = malloc(max);
+ if (pool->memory == NULL) {
+ free(pool);
+ return NULL;
+ }
+ pool->is_mmap = 0;
+ } else {
+ pool->is_mmap = 1;
+ }
+ pool->pos = 0;
+ pool->end = max;
+ pool->size = max;
+ return pool;
+}
+
+/**
+ * Destroy a memory pool.
+ */
+void MHD_pool_destroy(struct MemoryPool * pool) {
+ if (pool == NULL)
+ return;
+ if (pool->is_mmap == 0)
+ free(pool->memory);
+ else
+ MUNMAP(pool->memory, pool->size);
+ free(pool);
+}
+
+/**
+ * Allocate size bytes from the pool.
+ * @return NULL if the pool cannot support size more
+ * bytes
+ */
+void * MHD_pool_allocate(struct MemoryPool * pool,
+ unsigned int size,
+ int from_end) {
+ void * ret;
+
+ if ( (pool->pos + size > pool->end) ||
+ (pool->pos + size < pool->pos) )
+ return NULL;
+ if (from_end == MHD_YES) {
+ ret = &pool->memory[pool->end - size];
+ pool->end -= size;
+ } else {
+ ret = &pool->memory[pool->pos];
+ pool->pos += size;
+ }
+ return ret;
+}
+
+/**
+ * Reallocate a block of memory obtained from the pool.
+ * This is particularly efficient when growing or
+ * shrinking the block that was last (re)allocated.
+ * If the given block is not the most recenlty
+ * (re)allocated block, the memory of the previous
+ * allocation may be leaked until the pool is
+ * destroyed (and copying the data maybe required).
+ *
+ * @param old the existing block
+ * @param old_size the size of the existing block
+ * @param new_size the new size of the block
+ * @return new address of the block, or
+ * NULL if the pool cannot support new_size
+ * bytes (old continues to be valid for old_size)
+ */
+void * MHD_pool_reallocate(struct MemoryPool * pool,
+ void * old,
+ unsigned int old_size,
+ unsigned int new_size) {
+ void * ret;
+
+ if ( (pool->end < old_size) ||
+ (pool->end < new_size) )
+ return NULL; /* unsatisfiable or bogus request */
+
+ if ( (pool->pos >= old_size) &&
+ (&pool->memory[pool->pos - old_size] == old) ) {
+ /* was the previous allocation - optimize! */
+ if (pool->pos + new_size - old_size <= pool->end) {
+ /* fits */
+ pool->pos += new_size - old_size;
+ if (new_size < old_size) /* shrinking - zero again! */
+ memset(&pool->memory[pool->pos],
+ 0,
+ old_size - new_size);
+ return old;
+ }
+ /* does not fit */
+ return NULL;
+ }
+ if (new_size <= old_size)
+ return old; /* cannot shrink, no need to move */
+ if ( (pool->pos + new_size >= pool->pos) &&
+ (pool->pos + new_size <= pool->end) ) {
+ /* fits */
+ ret = &pool->memory[pool->pos];
+ memcpy(ret,
+ old,
+ old_size);
+ pool->pos += new_size;
+ return ret;
+ }
+ /* does not fit */
+ return NULL;
+}
+
+/* end of memorypool.c */