* Purple is the legal property of its developers, whose names are too * numerous to list here. Please refer to the COPYRIGHT file distributed * with this source distribution * This program 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 of the License, or (at * your option) any later version. * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #define PURPLE_MEMORY_POOL_BLOCK_PADDING (sizeof(guint64)) #define PURPLE_MEMORY_POINTER_SHIFT(pointer, value) \ (gpointer)((guintptr)(pointer) + (value)) #define PURPLE_MEMORY_PADDED(pointer, padding) \ (gpointer)((((guintptr)(pointer) - 1) / (padding) + 1) * padding) #define PURPLE_MEMORY_POOL_DEFAULT_BLOCK_SIZE 1024 #define PURPLE_MEMORY_POOL_DISABLED FALSE typedef struct _PurpleMemoryPoolBlock PurpleMemoryPoolBlock; PurpleMemoryPoolBlock *first_block; PurpleMemoryPoolBlock *last_block; } PurpleMemoryPoolPrivate; struct _PurpleMemoryPoolBlock PurpleMemoryPoolBlock *next; static GParamSpec *properties[PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurpleMemoryPool, purple_memory_pool, /******************************************************************************* * Memory allocation/deallocation ******************************************************************************/ static PurpleMemoryPoolBlock * purple_memory_pool_block_new(gulong block_size) PurpleMemoryPoolBlock *block; /* ceil block struct size to the multipy of align */ total_size = ((sizeof(PurpleMemoryPoolBlock) - 1) / PURPLE_MEMORY_POOL_BLOCK_PADDING + 1) * sizeof(PurpleMemoryPoolBlock); g_return_val_if_fail(block_size < G_MAXSIZE - total_size, NULL); total_size += block_size; block_raw = g_try_malloc(total_size); g_return_val_if_fail(block_raw != NULL, NULL); /* in fact, we don't set available_ptr padded to * PURPLE_MEMORY_POOL_BLOCK_PADDING, but we guarantee, there is at least * block_size long block if padded to that value. */ block->available_ptr = PURPLE_MEMORY_POINTER_SHIFT(block_raw, sizeof(PurpleMemoryPoolBlock)); block->end_ptr = PURPLE_MEMORY_POINTER_SHIFT(block_raw, total_size); purple_memory_pool_alloc_impl(PurpleMemoryPool *pool, gsize size, guint alignment) PurpleMemoryPoolPrivate *priv = NULL; PurpleMemoryPoolBlock *blk; g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool), NULL); priv = purple_memory_pool_get_instance_private(pool); /* XXX: this may cause some leaks */ return g_try_malloc(size); g_return_val_if_fail(alignment <= PURPLE_MEMORY_POOL_BLOCK_PADDING, NULL); g_warn_if_fail(alignment >= 1); mem = PURPLE_MEMORY_PADDED(blk->available_ptr, alignment); else if (mem < blk->available_ptr) /* gpointer overflow */ else if (PURPLE_MEMORY_POINTER_SHIFT(mem, size) >= blk->end_ptr) gsize real_size = priv->block_size; blk = purple_memory_pool_block_new(real_size); g_return_val_if_fail(blk != NULL, NULL); g_assert((priv->first_block == NULL) == (priv->last_block == NULL)); if (priv->first_block == NULL) { priv->last_block->next = blk; mem = PURPLE_MEMORY_PADDED(blk->available_ptr, alignment); g_assert((guintptr)mem + size < (guintptr)blk->end_ptr); g_assert(mem >= blk->available_ptr); /* gpointer overflow */ blk->available_ptr = PURPLE_MEMORY_POINTER_SHIFT(mem, size); g_assert(blk->available_ptr <= blk->end_ptr); purple_memory_pool_cleanup_impl(PurpleMemoryPool *pool) PurpleMemoryPoolPrivate *priv = purple_memory_pool_get_instance_private(pool); PurpleMemoryPoolBlock *blk; priv->first_block = NULL; PurpleMemoryPoolBlock *next = blk->next; /******************************************************************************* ******************************************************************************/ purple_memory_pool_set_block_size(PurpleMemoryPool *pool, gulong block_size) PurpleMemoryPoolPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool)); priv = purple_memory_pool_get_instance_private(pool); priv->block_size = block_size; g_object_notify_by_pspec(G_OBJECT(pool), properties[PROP_BLOCK_SIZE]); purple_memory_pool_alloc(PurpleMemoryPool *pool, gsize size, guint alignment) PurpleMemoryPoolClass *klass; g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool), NULL); klass = PURPLE_MEMORY_POOL_GET_CLASS(pool); g_return_val_if_fail(klass != NULL, NULL); g_return_val_if_fail(klass->palloc != NULL, NULL); return klass->palloc(pool, size, alignment); purple_memory_pool_alloc0(PurpleMemoryPool *pool, gsize size, guint alignment) mem = purple_memory_pool_alloc(pool, size, alignment); g_return_val_if_fail(mem != NULL, NULL); purple_memory_pool_free(PurpleMemoryPool *pool, gpointer mem) PurpleMemoryPoolClass *klass; g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool)); klass = PURPLE_MEMORY_POOL_GET_CLASS(pool); g_return_if_fail(klass != NULL); purple_memory_pool_cleanup(PurpleMemoryPool *pool) PurpleMemoryPoolClass *klass; g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool)); klass = PURPLE_MEMORY_POOL_GET_CLASS(pool); g_return_if_fail(klass != NULL); /******************************************************************************* ******************************************************************************/ purple_memory_pool_new(void) return g_object_new(PURPLE_TYPE_MEMORY_POOL, NULL); purple_memory_pool_init(PurpleMemoryPool *pool) PurpleMemoryPoolPrivate *priv = purple_memory_pool_get_instance_private(pool); priv->disabled = PURPLE_MEMORY_POOL_DISABLED; purple_memory_pool_finalize(GObject *obj) purple_memory_pool_cleanup(PURPLE_MEMORY_POOL(obj)); G_OBJECT_CLASS(purple_memory_pool_parent_class)->finalize(obj); purple_memory_pool_get_property(GObject *obj, guint param_id, GValue *value, PurpleMemoryPool *pool = PURPLE_MEMORY_POOL(obj); PurpleMemoryPoolPrivate *priv = purple_memory_pool_get_instance_private(pool); g_value_set_ulong(value, priv->block_size); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); purple_memory_pool_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) PurpleMemoryPool *pool = PURPLE_MEMORY_POOL(obj); PurpleMemoryPoolPrivate *priv = purple_memory_pool_get_instance_private(pool); priv->block_size = g_value_get_ulong(value); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); purple_memory_pool_class_init(PurpleMemoryPoolClass *klass) GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->finalize = purple_memory_pool_finalize; obj_class->get_property = purple_memory_pool_get_property; obj_class->set_property = purple_memory_pool_set_property; klass->palloc = purple_memory_pool_alloc_impl; klass->cleanup = purple_memory_pool_cleanup_impl; properties[PROP_BLOCK_SIZE] = g_param_spec_ulong("block-size", "Block size", "The default size of each block of pool memory.", 0, G_MAXULONG, PURPLE_MEMORY_POOL_DEFAULT_BLOCK_SIZE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, PROP_LAST, properties); purple_memory_pool_strdup(PurpleMemoryPool *pool, const gchar *str) g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool), NULL); str_dup = purple_memory_pool_alloc(pool, str_len + 1, sizeof(gchar)); g_return_val_if_fail(str_dup != NULL, NULL); memcpy(str_dup, str, str_len);