/* * mempool.c: efficient memory allocation * * MonoMemPool is for fast allocation of memory. We free * all memory when the pool is destroyed. * * Author: * Dietmar Maurer (dietmar@ximian.com) * * (C) 2001 Ximian, Inc. */ #include #include #include #include "mempool.h" /* * MonoMemPool is for fast allocation of memory. We free * all memory when the pool is destroyed. */ #define MEM_ALIGN 8 #define MONO_MEMPOOL_PAGESIZE 8192 #ifndef G_LIKELY #define G_LIKELY(a) (a) #define G_UNLIKELY(a) (a) #endif struct _MonoMemPool { MonoMemPool *next; gint rest; guint8 *pos, *end; guint32 size; union { double pad; /* to assure proper alignment */ guint32 allocated; } d; }; /** * mono_mempool_new: * * Returns: a new memory pool. */ MonoMemPool * mono_mempool_new () { MonoMemPool *pool = g_malloc (MONO_MEMPOOL_PAGESIZE); pool->next = NULL; pool->pos = (char *)pool + sizeof (MonoMemPool); pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool); pool->d.allocated = pool->size = MONO_MEMPOOL_PAGESIZE; return pool; } /** * mono_mempool_destroy: * @pool: the memory pool to destroy * * Free all memory associated with this pool. */ void mono_mempool_destroy (MonoMemPool *pool) { MonoMemPool *p, *n; p = pool; while (p) { n = p->next; g_free (p); p = n; } } /** * mono_mempool_invalidate: * @pool: the memory pool to invalidate * * Fill the memory associated with this pool to 0x2a (42). Useful for debugging. */ void mono_mempool_invalidate (MonoMemPool *pool) { MonoMemPool *p, *n; p = pool; while (p) { n = p->next; memset (p, 42, p->size); p = n; } } void mono_mempool_empty (MonoMemPool *pool) { pool->pos = (char *)pool + sizeof (MonoMemPool); pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool); } /** * mono_mempool_stats: * @pool: the momory pool we need stats for * * Print a few stats about the mempool */ void mono_mempool_stats (MonoMemPool *pool) { MonoMemPool *p, *n; int count = 0; guint32 still_free = 0; p = pool; while (p) { still_free += p->end - p->pos; n = p->next; p = n; count++; } if (pool) { g_print ("Mempool %p stats:\n", pool); g_print ("Total mem allocated: %d\n", pool->d.allocated); g_print ("Num chunks: %d\n", count); g_print ("Free memory: %d\n", still_free); } } /** * mono_mempool_alloc: * @pool: the momory pool to destroy * @size: size of the momory block * * Allocates a new block of memory in @pool. * * Returns: the address of a newly allocated memory block. */ gpointer mono_mempool_alloc (MonoMemPool *pool, guint size) { gpointer rval; size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1); rval = pool->pos; pool->pos = (char*)rval + size; if (G_UNLIKELY (pool->pos >= pool->end)) { pool->pos -= size; if (size >= 4096) { MonoMemPool *np = g_malloc (sizeof (MonoMemPool) + size); np->next = pool->next; pool->next = np; np->size = sizeof (MonoMemPool) + size; pool->d.allocated += sizeof (MonoMemPool) + size; return (char *)np + sizeof (MonoMemPool); } else { MonoMemPool *np = g_malloc (MONO_MEMPOOL_PAGESIZE); np->next = pool->next; pool->next = np; pool->pos = (char *)np + sizeof (MonoMemPool); np->size = MONO_MEMPOOL_PAGESIZE; pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool); pool->d.allocated += MONO_MEMPOOL_PAGESIZE; rval = pool->pos; pool->pos += size; } } return rval; } /** * mono_mempool_alloc0: * * same as mono_mempool_alloc, but fills memory with zero. */ gpointer mono_mempool_alloc0 (MonoMemPool *pool, guint size) { gpointer rval; size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1); rval = pool->pos; pool->pos = (char*)rval + size; if (G_UNLIKELY (pool->pos >= pool->end)) { rval = mono_mempool_alloc (pool, size); } memset (rval, 0, size); return rval; } /** * mono_mempool_contains_addr: * * Determines whenever ADDR is inside the memory used by the mempool. */ gboolean mono_mempool_contains_addr (MonoMemPool *pool, gpointer addr) { MonoMemPool *p; p = pool; while (p) { if (addr > (gpointer)p && addr <= (gpointer)((guint8*)p + p->size)) return TRUE; p = p->next; } return FALSE; }