/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * * This library is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation. * * This library 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * */ #include "camel-mempool.h" #include typedef struct _MemPoolNode { struct _MemPoolNode *next; gint free; } MemPoolNode; typedef struct _MemPoolThresholdNode { struct _MemPoolThresholdNode *next; } MemPoolThresholdNode; #define ALIGNED_SIZEOF(t) ((sizeof (t) + G_MEM_ALIGN - 1) & -G_MEM_ALIGN) struct _CamelMemPool { gint blocksize; gint threshold; guint align; struct _MemPoolNode *blocks; struct _MemPoolThresholdNode *threshold_blocks; }; /** * camel_mempool_new: * @blocksize: The base blocksize to use for all system alocations. * @threshold: If the allocation exceeds the threshold, then it is * allocated separately and stored in a separate list. * @flags: Alignment options: CAMEL_MEMPOOL_ALIGN_STRUCT uses native * struct alignment, CAMEL_MEMPOOL_ALIGN_WORD aligns to 16 bits (2 bytes), * and CAMEL_MEMPOOL_ALIGN_BYTE aligns to the nearest byte. The default * is to align to native structures. * * Create a new mempool header. Mempools can be used to efficiently * allocate data which can then be freed as a whole. * * Mempools can also be used to efficiently allocate arbitrarily * aligned data (such as strings) without incurring the space overhead * of aligning each allocation (which is not required for strings). * * However, each allocation cannot be freed individually, only all * or nothing. * * Returns: * * Since: 2.32 **/ CamelMemPool * camel_mempool_new (gint blocksize, gint threshold, CamelMemPoolFlags flags) { CamelMemPool *pool; pool = g_slice_new0 (CamelMemPool); if (threshold >= blocksize) threshold = blocksize * 2 / 3; pool->blocksize = blocksize; pool->threshold = threshold; pool->blocks = NULL; pool->threshold_blocks = NULL; switch (flags & CAMEL_MEMPOOL_ALIGN_MASK) { case CAMEL_MEMPOOL_ALIGN_STRUCT: default: pool->align = G_MEM_ALIGN - 1; break; case CAMEL_MEMPOOL_ALIGN_WORD: pool->align = 2 - 1; break; case CAMEL_MEMPOOL_ALIGN_BYTE: pool->align = 1 - 1; } return pool; } /** * camel_mempool_alloc: * @pool: a #CamelMemPool * @size: * * Allocate a new data block in the mempool. Size will * be rounded up to the mempool's alignment restrictions * before being used. * * Since: 2.32 **/ gpointer camel_mempool_alloc (CamelMemPool *pool, register gint size) { size = (size + pool->align) & (~(pool->align)); if (size >= pool->threshold) { MemPoolThresholdNode *n; n = g_malloc (ALIGNED_SIZEOF (*n) + size); n->next = pool->threshold_blocks; pool->threshold_blocks = n; return (gchar *) n + ALIGNED_SIZEOF (*n); } else { register MemPoolNode *n; n = pool->blocks; if (n && n->free >= size) { n->free -= size; return (gchar *) n + ALIGNED_SIZEOF (*n) + n->free; } /* maybe we could do some sort of the free blocks based on size, but * it doubt its worth it at all */ n = g_malloc (ALIGNED_SIZEOF (*n) + pool->blocksize); n->next = pool->blocks; pool->blocks = n; n->free = pool->blocksize - size; return (gchar *) n + ALIGNED_SIZEOF (*n) + n->free; } } /** * camel_mempool_strdup: * @pool: a #CamelMemPool * @str: * * Since: 2.32 **/ gchar * camel_mempool_strdup (CamelMemPool *pool, const gchar *str) { gchar *out; gsize out_len; out_len = strlen (str) + 1; out = camel_mempool_alloc (pool, out_len); g_strlcpy (out, str, out_len); return out; } /** * camel_mempool_flush: * @pool: a #CamelMemPool * @freeall: free all system allocated blocks as well * * Flush used memory and mark allocated blocks as free. * * If @freeall is %TRUE, then all allocated blocks are free'd * as well. Otherwise only blocks above the threshold are * actually freed, and the others are simply marked as empty. * * Since: 2.32 **/ void camel_mempool_flush (CamelMemPool *pool, gint freeall) { MemPoolThresholdNode *tn, *tw; MemPoolNode *pw, *pn; tw = pool->threshold_blocks; while (tw) { tn = tw->next; g_free (tw); tw = tn; } pool->threshold_blocks = NULL; if (freeall) { pw = pool->blocks; while (pw) { pn = pw->next; g_free (pw); pw = pn; } pool->blocks = NULL; } else { pw = pool->blocks; while (pw) { pw->free = pool->blocksize; pw = pw->next; } } } /** * camel_mempool_destroy: * @pool: a #CamelMemPool * * Free all memory associated with a mempool. * * Since: 2.32 **/ void camel_mempool_destroy (CamelMemPool *pool) { if (pool) { camel_mempool_flush (pool, 1); g_slice_free (CamelMemPool, pool); } }