enable_static
with_openssl
enable_examples
+enable_heap_allocator
'
ac_precious_vars='build_alias
host_alias
--disable-shared do not build shared library
--enable-static build static library
--enable-examples build examples
+ --disable-heap-allocator
+ Disable the heap allocator
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+# Check whether --enable-heap-allocator was given.
+if test "${enable_heap_allocator+set}" = set; then :
+ enableval=$enable_heap_allocator; if test x"$enable_heap_allocator" = x"no"; then :
+
+
+$as_echo "#define DISABLE_HEAP_ALLOCATOR 1" >>confdefs.h
+
+fi
+
+else
+ enable_heap_allocator="yes"
+fi
+
+
# Extract the first word of "tput", so it can be a program name with args.
set dummy tput; ac_word=$2
Configuration:
OpenSSL support: ${OPENSSL}
+ Heap allocator: ${enable_heap_allocator}
Examples: ${EXAMPLES}
Now type "make" to build, and "make install" to install.
AC_SUBST(EXAMPLES_BUILD)
+AC_ARG_ENABLE([heap-allocator],
+ [AS_HELP_STRING([--disable-heap-allocator], [Disable the heap allocator])],
+ [AS_IF([test x"$enable_heap_allocator" = x"no"], [
+ AC_DEFINE([DISABLE_HEAP_ALLOCATOR], [1], [Disable the heap allocator])])
+ ], [enable_heap_allocator="yes"])
+
BUILDSYS_INIT
BUILDSYS_TOUCH_DEPS
Configuration:
OpenSSL support: ${OPENSSL}
+ Heap allocator: ${enable_heap_allocator}
Examples: ${EXAMPLES}
Now type "make" to build, and "make install" to install.
#include "mowgli.h"
-#ifdef HAVE_MMAP
-# include <sys/mman.h>
-# if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
-# define MAP_ANON MAP_ANONYMOUS
-# endif
-#endif
-
-/* A block of memory allocated to the allocator */
-struct mowgli_block_
-{
- mowgli_node_t node;
-
- /* link back to our heap */
- mowgli_heap_t *heap;
-
- /* pointer to the first item */
- void *data;
-
- /* singly linked list of free items */
- void *first_free;
-
- unsigned int num_allocated;
-};
-
-/* A pile of blocks */
-struct mowgli_heap_
-{
- unsigned int elem_size;
- unsigned int mowgli_heap_elems;
- unsigned int free_elems;
-
- unsigned int alloc_size;
-
- unsigned int flags;
-
- mowgli_list_t blocks; /* list of non-empty blocks */
-
- mowgli_allocation_policy_t *allocator;
- mowgli_boolean_t use_mmap;
-
- mowgli_mutex_t mutex;
-
- mowgli_block_t *empty_block; /* a single entirely free block, or NULL */
-};
-
-typedef struct mowgli_heap_elem_header_ mowgli_heap_elem_header_t;
-
-struct mowgli_heap_elem_header_
-{
- union
- {
- mowgli_block_t *block; /* for allocated elems: block ptr */
- mowgli_heap_elem_header_t *next;/* for free elems: next free */
- } un;
-};
-
-/* expands a mowgli_heap_t by 1 block */
-static void
-mowgli_heap_expand(mowgli_heap_t *bh)
-{
- mowgli_block_t *block = NULL;
- void *blp = NULL;
- mowgli_heap_elem_header_t *node, *prev;
- char *offset;
- unsigned int a;
- size_t blp_size;
-
- blp_size = sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems);
-
- if (bh->empty_block != NULL)
- return;
-
-#if defined(HAVE_MMAP) && defined(MAP_ANON)
-
- if (bh->use_mmap)
- blp = mmap(NULL, sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems),
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
- else
-#elif defined(_WIN32)
-
- if (bh->use_mmap)
- blp = VirtualAlloc(NULL, sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems),
- MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- else
-#endif
- blp = mowgli_alloc_using_policy(bh->allocator, blp_size);
-
- block = (mowgli_block_t *) blp;
-
- offset = (char *) blp + sizeof(mowgli_block_t);
- block->data = offset;
- block->heap = bh;
-
- prev = NULL;
-
- for (a = 0; a < bh->mowgli_heap_elems; a++)
- {
- node = (mowgli_heap_elem_header_t *) offset;
- node->un.next = prev;
- offset += bh->alloc_size;
- prev = node;
- }
-
- block->first_free = prev;
-
- bh->empty_block = block;
- bh->free_elems += bh->mowgli_heap_elems;
-}
-
-/* shrinks a mowgli_heap_t by 1 block. */
-static void
-mowgli_heap_shrink(mowgli_heap_t *heap, mowgli_block_t *b)
-{
- return_if_fail(b != NULL);
-
- if (b == heap->empty_block)
- heap->empty_block = NULL;
- else
- mowgli_node_delete(&b->node, &heap->blocks);
-
-#if defined(HAVE_MMAP) && defined(MAP_ANON)
-
- if (heap->use_mmap)
- munmap(b, sizeof(mowgli_block_t) + (heap->alloc_size * heap->mowgli_heap_elems));
- else
-#elif defined(_WIN32)
-
- if (heap->use_mmap)
- VirtualFree(b, 0, MEM_RELEASE);
- else
-#endif
- mowgli_free(b);
-
- heap->free_elems -= heap->mowgli_heap_elems;
-}
-
-/* creates a new mowgli_heap_t */
-mowgli_heap_t *
-mowgli_heap_create_full(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags, mowgli_allocation_policy_t *allocator)
-{
- mowgli_allocation_policy_t *bhallocator = allocator;
-
- if (bhallocator == NULL)
- bhallocator = mowgli_allocator_get_policy();
-
- mowgli_heap_t *bh = mowgli_alloc_using_policy(bhallocator, sizeof *bh);
- int numpages, pagesize;
-
- bh->elem_size = elem_size;
- bh->mowgli_heap_elems = mowgli_heap_elems;
-
- /* at least 2, this avoids some silly special cases */
- if (bh->mowgli_heap_elems < 2)
- bh->mowgli_heap_elems = 2;
-
- bh->free_elems = 0;
-
- bh->alloc_size = bh->elem_size + sizeof(mowgli_heap_elem_header_t);
-
- /* don't waste part of a page */
- if (allocator == NULL)
- {
-#ifdef HAVE_MMAP
- pagesize = getpagesize();
+#ifndef DISABLE_HEAP_ALLOCATOR
+# include "heap.enabled.c"
#else
- pagesize = 4096;
-#endif
- numpages = (sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems) + pagesize - 1) / pagesize;
- bh->mowgli_heap_elems = (numpages * pagesize - sizeof(mowgli_block_t)) / bh->alloc_size;
- }
-
- bh->flags = flags;
- bh->allocator = bhallocator;
-
-#if (defined(HAVE_MMAP) && defined(MAP_ANON)) || defined(_WIN32)
- bh->use_mmap = allocator != NULL ? FALSE : TRUE;
-#endif
-
- if (mowgli_mutex_init(&bh->mutex) != 0)
- mowgli_log_fatal("heap mutex can't be created");
-
- if (flags & BH_NOW)
- {
- mowgli_mutex_lock(&bh->mutex);
- mowgli_heap_expand(bh);
- mowgli_mutex_unlock(&bh->mutex);
- }
-
- return bh;
-}
-
-mowgli_heap_t *
-mowgli_heap_create(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags)
-{
- return mowgli_heap_create_full(elem_size, mowgli_heap_elems, flags, NULL);
-}
-
-/* completely frees a mowgli_heap_t and all blocks */
-void
-mowgli_heap_destroy(mowgli_heap_t *heap)
-{
- mowgli_node_t *n, *tn;
-
- MOWGLI_LIST_FOREACH_SAFE(n, tn, heap->blocks.head)
- {
- mowgli_heap_shrink(heap, n->data);
- }
-
- if (heap->empty_block)
- mowgli_heap_shrink(heap, heap->empty_block);
-
- mowgli_mutex_uninit(&heap->mutex);
-
- /* everything related to heap has gone, time for itself */
- mowgli_free(heap);
-}
-
-/* allocates a new item from a mowgli_heap_t */
-void *
-mowgli_heap_alloc(mowgli_heap_t *heap)
-{
- mowgli_node_t *n;
- mowgli_block_t *b;
- mowgli_heap_elem_header_t *h;
-
- if (mowgli_mutex_lock(&heap->mutex) != 0)
- mowgli_log_fatal("heap mutex can't be locked");
-
- /* no free space? */
- if (heap->free_elems == 0)
- {
- mowgli_heap_expand(heap);
-
- if (heap->free_elems == 0)
- {
- mowgli_mutex_unlock(&heap->mutex);
- return NULL;
- }
- }
-
- /* try a partially used block before using a fully free block */
- n = heap->blocks.head;
- b = n != NULL ? n->data : NULL;
-
- if ((b == NULL) || (b->first_free == NULL))
- b = heap->empty_block;
-
- /* due to above check */
- return_val_if_fail(b != NULL, NULL);
-
- /* pull the first free node from the list */
- h = b->first_free;
- return_val_if_fail(h != NULL, NULL);
-
- /* mark it as used */
- b->first_free = h->un.next;
- h->un.block = b;
-
- /* keep count */
- heap->free_elems--;
- b->num_allocated++;
-
- /* move it between the lists if needed */
-
- /* note that a block has at least two items in it, so these cases
- * cannot both occur in the same allocation */
- if (b->num_allocated == 1)
- {
- heap->empty_block = NULL;
- mowgli_node_add_head(b, &b->node, &heap->blocks);
- }
- else if (b->first_free == NULL)
- {
- /* move full blocks to the end of the list */
- mowgli_node_delete(&b->node, &heap->blocks);
- mowgli_node_add(b, &b->node, &heap->blocks);
- }
-
-#ifdef HEAP_DEBUG
-
- /* debug */
- mowgli_log("mowgli_heap_alloc(heap = @%p) -> %p", heap, (char*) h + sizeof(mowgli_heap_elem_header_t));
+# include "heap.disabled.c"
#endif
-
- mowgli_mutex_unlock(&heap->mutex);
-
- /* return pointer to it */
- return (char *) h + sizeof(mowgli_heap_elem_header_t);
-}
-
-/* frees an item back to the mowgli_heap_t */
-void
-mowgli_heap_free(mowgli_heap_t *heap, void *data)
-{
- mowgli_block_t *b;
- mowgli_heap_elem_header_t *h;
-
- if (mowgli_mutex_lock(&heap->mutex) != 0)
- mowgli_log_fatal("heap mutex can't be locked");
-
- h = (mowgli_heap_elem_header_t *) ((char *) data - sizeof(mowgli_heap_elem_header_t));
- b = h->un.block;
-
- return_if_fail(b->heap == heap);
- return_if_fail(b->num_allocated > 0);
-
- /* memset the element before returning it to the heap. */
- memset(data, 0, b->heap->elem_size);
-
- /* mark it as free */
- h->un.next = b->first_free;
- b->first_free = h;
-
- /* keep count */
- heap->free_elems++;
- b->num_allocated--;
-#ifdef HEAP_DEBUG
-
- /* debug */
- mowgli_log("mowgli_heap_free(heap = @%p, data = %p)", heap, data);
-#endif
-
- /* move it between the lists if needed */
- if (b->num_allocated == 0)
- {
- if (heap->empty_block != NULL)
- mowgli_heap_shrink(heap, heap->empty_block);
-
- mowgli_node_delete(&b->node, &heap->blocks);
- heap->empty_block = b;
- }
- else if (b->num_allocated == heap->mowgli_heap_elems - 1)
- {
- mowgli_node_delete(&b->node, &heap->blocks);
- mowgli_node_add_head(b, &b->node, &heap->blocks);
- }
-
- mowgli_mutex_unlock(&heap->mutex);
-}
--- /dev/null
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * heap.c: Heap allocation.
+ *
+ * Copyright (c) 2019 Aaron M. D. Jones <aaronmdjones@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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 AUTHOR 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.
+ */
+
+#include "mowgli.h"
+
+struct mowgli_block_
+{
+ mowgli_node_t node;
+ void *ptr;
+};
+
+struct mowgli_heap_
+{
+ mowgli_list_t blocks;
+ mowgli_allocation_policy_t *allocator;
+ size_t elem_size;
+};
+
+mowgli_heap_t *
+mowgli_heap_create_full(const size_t elem_size,
+ const size_t MOWGLI_VATTR_UNUSED mowgli_heap_elems,
+ const unsigned int MOWGLI_VATTR_UNUSED flags,
+ mowgli_allocation_policy_t *restrict allocator)
+{
+ return_null_if_fail(elem_size != 0);
+
+ if (allocator == NULL)
+ allocator = mowgli_allocator_get_policy();
+
+ mowgli_heap_t *const heap = mowgli_alloc_using_policy(allocator, sizeof *heap);
+
+ if (! heap)
+ {
+#ifdef HEAP_DEBUG
+ (void) mowgli_log_warning("mowgli_alloc for heap returned NULL");
+#endif
+ return NULL;
+ }
+
+ (void) memset(heap, 0x00, sizeof *heap);
+
+ heap->allocator = allocator;
+ heap->elem_size = elem_size;
+
+#ifdef HEAP_DEBUG
+ (void) mowgli_log("pseudoheap@%p: done", heap);
+#endif
+
+ return heap;
+}
+
+mowgli_heap_t *
+mowgli_heap_create(const size_t elem_size,
+ const size_t MOWGLI_VATTR_UNUSED mowgli_heap_elems,
+ const unsigned int MOWGLI_VATTR_UNUSED flags)
+{
+ return_null_if_fail(elem_size != 0);
+
+ return mowgli_heap_create_full(elem_size, 0, 0, NULL);
+}
+
+void
+mowgli_heap_destroy(mowgli_heap_t *const restrict heap)
+{
+ return_if_fail(heap != NULL);
+
+ mowgli_node_t *node, *tnode;
+
+ MOWGLI_LIST_FOREACH_SAFE(node, tnode, heap->blocks.head)
+ {
+ mowgli_block_t *const block = node->data;
+
+#ifdef HEAP_DEBUG
+ // An object allocated by us wasn't freed already -- possible program logic problem
+ (void) mowgli_log_warning("pseudoheap@%p: freeing ptr %p", heap, block->ptr);
+#endif
+
+ (void) mowgli_node_delete(&block->node, &heap->blocks);
+ (void) mowgli_free(block->ptr);
+ (void) mowgli_free(block);
+ }
+
+ (void) mowgli_free(heap);
+
+#ifdef HEAP_DEBUG
+ (void) mowgli_log("pseudoheap@%p: done", heap);
+#endif
+}
+
+void *
+mowgli_heap_alloc(mowgli_heap_t *const restrict heap)
+{
+ return_null_if_fail(heap != NULL);
+
+ mowgli_block_t *const block = mowgli_alloc_using_policy(heap->allocator, sizeof *block);
+
+ if (! block)
+ {
+#ifdef HEAP_DEBUG
+ (void) mowgli_log_warning("pseudoheap@%p: mowgli_alloc for block returned NULL", heap);
+#endif
+ return NULL;
+ }
+
+ if (! (block->ptr = mowgli_alloc_using_policy(heap->allocator, heap->elem_size)))
+ {
+#ifdef HEAP_DEBUG
+ (void) mowgli_log_warning("pseudoheap@%p: mowgli_alloc for ptr returned NULL", heap);
+#endif
+ (void) mowgli_free(block);
+ return NULL;
+ }
+
+ (void) mowgli_node_add(block, &block->node, &heap->blocks);
+
+#ifdef HEAP_DEBUG
+ (void) mowgli_log("pseudoheap@%p: allocated ptr %p", heap, block->ptr);
+#endif
+
+ return memset(block->ptr, 0x00, heap->elem_size);
+}
+
+void
+mowgli_heap_free(mowgli_heap_t *const restrict heap, void *const restrict ptr)
+{
+ return_if_fail(heap != NULL);
+ return_if_fail(ptr != NULL);
+
+ mowgli_node_t *node;
+
+ MOWGLI_LIST_FOREACH(node, heap->blocks.head)
+ {
+ mowgli_block_t *const block = node->data;
+
+ if (block->ptr != ptr)
+ continue;
+
+ (void) mowgli_node_delete(&block->node, &heap->blocks);
+ (void) mowgli_free(block->ptr);
+ (void) mowgli_free(block);
+
+#ifdef HEAP_DEBUG
+ (void) mowgli_log("pseudoheap@%p: freed ptr %p", heap, ptr);
+#endif
+
+ return;
+ }
+
+#ifdef HEAP_DEBUG
+ (void) mowgli_log_warning("pseudoheap@%p: cannot free ptr %p: not found in blocks list", heap, ptr);
+#endif
+}
--- /dev/null
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * heap.c: Heap allocation.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ * Copyright (c) 2005-2006 Theo Julienne <terminal -at- atheme.org>
+ * Copyright (c) 2011 Andrew Wilcox <awilcox -at- wilcox-tech.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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 AUTHOR 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.
+ *
+ * Legal note: code devised from claro.base.block module r288 (Pre MPL)
+ */
+
+#include "mowgli.h"
+
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+# if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+# define MAP_ANON MAP_ANONYMOUS
+# endif
+#endif
+
+/* A block of memory allocated to the allocator */
+struct mowgli_block_
+{
+ mowgli_node_t node;
+
+ /* link back to our heap */
+ mowgli_heap_t *heap;
+
+ /* pointer to the first item */
+ void *data;
+
+ /* singly linked list of free items */
+ void *first_free;
+
+ unsigned int num_allocated;
+};
+
+/* A pile of blocks */
+struct mowgli_heap_
+{
+ unsigned int elem_size;
+ unsigned int mowgli_heap_elems;
+ unsigned int free_elems;
+
+ unsigned int alloc_size;
+
+ unsigned int flags;
+
+ mowgli_list_t blocks; /* list of non-empty blocks */
+
+ mowgli_allocation_policy_t *allocator;
+ mowgli_boolean_t use_mmap;
+
+ mowgli_mutex_t mutex;
+
+ mowgli_block_t *empty_block; /* a single entirely free block, or NULL */
+};
+
+typedef struct mowgli_heap_elem_header_ mowgli_heap_elem_header_t;
+
+struct mowgli_heap_elem_header_
+{
+ union
+ {
+ mowgli_block_t *block; /* for allocated elems: block ptr */
+ mowgli_heap_elem_header_t *next;/* for free elems: next free */
+ } un;
+};
+
+/* expands a mowgli_heap_t by 1 block */
+static void
+mowgli_heap_expand(mowgli_heap_t *bh)
+{
+ mowgli_block_t *block = NULL;
+ void *blp = NULL;
+ mowgli_heap_elem_header_t *node, *prev;
+ char *offset;
+ unsigned int a;
+ size_t blp_size;
+
+ blp_size = sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems);
+
+ if (bh->empty_block != NULL)
+ return;
+
+#if defined(HAVE_MMAP) && defined(MAP_ANON)
+
+ if (bh->use_mmap)
+ blp = mmap(NULL, sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems),
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ else
+#elif defined(_WIN32)
+
+ if (bh->use_mmap)
+ blp = VirtualAlloc(NULL, sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems),
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ else
+#endif
+ blp = mowgli_alloc_using_policy(bh->allocator, blp_size);
+
+ block = (mowgli_block_t *) blp;
+
+ offset = (char *) blp + sizeof(mowgli_block_t);
+ block->data = offset;
+ block->heap = bh;
+
+ prev = NULL;
+
+ for (a = 0; a < bh->mowgli_heap_elems; a++)
+ {
+ node = (mowgli_heap_elem_header_t *) offset;
+ node->un.next = prev;
+ offset += bh->alloc_size;
+ prev = node;
+ }
+
+ block->first_free = prev;
+
+ bh->empty_block = block;
+ bh->free_elems += bh->mowgli_heap_elems;
+}
+
+/* shrinks a mowgli_heap_t by 1 block. */
+static void
+mowgli_heap_shrink(mowgli_heap_t *heap, mowgli_block_t *b)
+{
+ return_if_fail(b != NULL);
+
+ if (b == heap->empty_block)
+ heap->empty_block = NULL;
+ else
+ mowgli_node_delete(&b->node, &heap->blocks);
+
+#if defined(HAVE_MMAP) && defined(MAP_ANON)
+
+ if (heap->use_mmap)
+ munmap(b, sizeof(mowgli_block_t) + (heap->alloc_size * heap->mowgli_heap_elems));
+ else
+#elif defined(_WIN32)
+
+ if (heap->use_mmap)
+ VirtualFree(b, 0, MEM_RELEASE);
+ else
+#endif
+ mowgli_free(b);
+
+ heap->free_elems -= heap->mowgli_heap_elems;
+}
+
+/* creates a new mowgli_heap_t */
+mowgli_heap_t *
+mowgli_heap_create_full(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags, mowgli_allocation_policy_t *allocator)
+{
+ mowgli_allocation_policy_t *bhallocator = allocator;
+
+ if (bhallocator == NULL)
+ bhallocator = mowgli_allocator_get_policy();
+
+ mowgli_heap_t *bh = mowgli_alloc_using_policy(bhallocator, sizeof *bh);
+ int numpages, pagesize;
+
+ bh->elem_size = elem_size;
+ bh->mowgli_heap_elems = mowgli_heap_elems;
+
+ /* at least 2, this avoids some silly special cases */
+ if (bh->mowgli_heap_elems < 2)
+ bh->mowgli_heap_elems = 2;
+
+ bh->free_elems = 0;
+
+ bh->alloc_size = bh->elem_size + sizeof(mowgli_heap_elem_header_t);
+
+ /* don't waste part of a page */
+ if (allocator == NULL)
+ {
+#ifdef HAVE_MMAP
+ pagesize = getpagesize();
+#else
+ pagesize = 4096;
+#endif
+ numpages = (sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems) + pagesize - 1) / pagesize;
+ bh->mowgli_heap_elems = (numpages * pagesize - sizeof(mowgli_block_t)) / bh->alloc_size;
+ }
+
+ bh->flags = flags;
+ bh->allocator = bhallocator;
+
+#if (defined(HAVE_MMAP) && defined(MAP_ANON)) || defined(_WIN32)
+ bh->use_mmap = allocator != NULL ? FALSE : TRUE;
+#endif
+
+ if (mowgli_mutex_init(&bh->mutex) != 0)
+ mowgli_log_fatal("heap mutex can't be created");
+
+ if (flags & BH_NOW)
+ {
+ mowgli_mutex_lock(&bh->mutex);
+ mowgli_heap_expand(bh);
+ mowgli_mutex_unlock(&bh->mutex);
+ }
+
+ return bh;
+}
+
+mowgli_heap_t *
+mowgli_heap_create(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags)
+{
+ return mowgli_heap_create_full(elem_size, mowgli_heap_elems, flags, NULL);
+}
+
+/* completely frees a mowgli_heap_t and all blocks */
+void
+mowgli_heap_destroy(mowgli_heap_t *heap)
+{
+ mowgli_node_t *n, *tn;
+
+ MOWGLI_LIST_FOREACH_SAFE(n, tn, heap->blocks.head)
+ {
+ mowgli_heap_shrink(heap, n->data);
+ }
+
+ if (heap->empty_block)
+ mowgli_heap_shrink(heap, heap->empty_block);
+
+ mowgli_mutex_uninit(&heap->mutex);
+
+ /* everything related to heap has gone, time for itself */
+ mowgli_free(heap);
+}
+
+/* allocates a new item from a mowgli_heap_t */
+void *
+mowgli_heap_alloc(mowgli_heap_t *heap)
+{
+ mowgli_node_t *n;
+ mowgli_block_t *b;
+ mowgli_heap_elem_header_t *h;
+
+ if (mowgli_mutex_lock(&heap->mutex) != 0)
+ mowgli_log_fatal("heap mutex can't be locked");
+
+ /* no free space? */
+ if (heap->free_elems == 0)
+ {
+ mowgli_heap_expand(heap);
+
+ if (heap->free_elems == 0)
+ {
+ mowgli_mutex_unlock(&heap->mutex);
+ return NULL;
+ }
+ }
+
+ /* try a partially used block before using a fully free block */
+ n = heap->blocks.head;
+ b = n != NULL ? n->data : NULL;
+
+ if ((b == NULL) || (b->first_free == NULL))
+ b = heap->empty_block;
+
+ /* due to above check */
+ return_val_if_fail(b != NULL, NULL);
+
+ /* pull the first free node from the list */
+ h = b->first_free;
+ return_val_if_fail(h != NULL, NULL);
+
+ /* mark it as used */
+ b->first_free = h->un.next;
+ h->un.block = b;
+
+ /* keep count */
+ heap->free_elems--;
+ b->num_allocated++;
+
+ /* move it between the lists if needed */
+
+ /* note that a block has at least two items in it, so these cases
+ * cannot both occur in the same allocation */
+ if (b->num_allocated == 1)
+ {
+ heap->empty_block = NULL;
+ mowgli_node_add_head(b, &b->node, &heap->blocks);
+ }
+ else if (b->first_free == NULL)
+ {
+ /* move full blocks to the end of the list */
+ mowgli_node_delete(&b->node, &heap->blocks);
+ mowgli_node_add(b, &b->node, &heap->blocks);
+ }
+
+#ifdef HEAP_DEBUG
+
+ /* debug */
+ mowgli_log("mowgli_heap_alloc(heap = @%p) -> %p", heap, (char*) h + sizeof(mowgli_heap_elem_header_t));
+#endif
+
+ mowgli_mutex_unlock(&heap->mutex);
+
+ /* return pointer to it */
+ return (char *) h + sizeof(mowgli_heap_elem_header_t);
+}
+
+/* frees an item back to the mowgli_heap_t */
+void
+mowgli_heap_free(mowgli_heap_t *heap, void *data)
+{
+ mowgli_block_t *b;
+ mowgli_heap_elem_header_t *h;
+
+ if (mowgli_mutex_lock(&heap->mutex) != 0)
+ mowgli_log_fatal("heap mutex can't be locked");
+
+ h = (mowgli_heap_elem_header_t *) ((char *) data - sizeof(mowgli_heap_elem_header_t));
+ b = h->un.block;
+
+ return_if_fail(b->heap == heap);
+ return_if_fail(b->num_allocated > 0);
+
+ /* memset the element before returning it to the heap. */
+ memset(data, 0, b->heap->elem_size);
+
+ /* mark it as free */
+ h->un.next = b->first_free;
+ b->first_free = h;
+
+ /* keep count */
+ heap->free_elems++;
+ b->num_allocated--;
+#ifdef HEAP_DEBUG
+
+ /* debug */
+ mowgli_log("mowgli_heap_free(heap = @%p, data = %p)", heap, data);
+#endif
+
+ /* move it between the lists if needed */
+ if (b->num_allocated == 0)
+ {
+ if (heap->empty_block != NULL)
+ mowgli_heap_shrink(heap, heap->empty_block);
+
+ mowgli_node_delete(&b->node, &heap->blocks);
+ heap->empty_block = b;
+ }
+ else if (b->num_allocated == heap->mowgli_heap_elems - 1)
+ {
+ mowgli_node_delete(&b->node, &heap->blocks);
+ mowgli_node_add_head(b, &b->node, &heap->blocks);
+ }
+
+ mowgli_mutex_unlock(&heap->mutex);
+}
#define MOWGLI_SRC_LIBMOWGLI_PLATFORM_AUTOCONF_H_INCLUDE_GUARD 1
+/* Disable the heap allocator */
+#undef DISABLE_HEAP_ALLOCATOR
+
/* Define to 1 if you have the `dispatch_block' function. */
#undef HAVE_DISPATCH_BLOCK