pidgin/pidgin

Implement PurpleMemoryPool class

2014-03-22, Tomasz Wasilczyk
eff51bb998b0
Parents 6283b3708b03
Children 95f34a3f4172
Implement PurpleMemoryPool class
--- a/libpurple/Makefile.am Sat Mar 22 14:37:31 2014 +0100
+++ b/libpurple/Makefile.am Sat Mar 22 17:59:35 2014 +0100
@@ -81,6 +81,7 @@
media/enum-types.c \
media.c \
mediamanager.c \
+ memorypool.c \
mime.c \
nat-pmp.c \
network.c \
@@ -154,6 +155,7 @@
media.h \
media-gst.h \
mediamanager.h \
+ memorypool.h \
mime.h \
nat-pmp.h \
network.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/memorypool.c Sat Mar 22 17:59:35 2014 +0100
@@ -0,0 +1,295 @@
+/*
+ * Purple
+ *
+ * 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
+ */
+
+#include "memorypool.h"
+
+#include <string.h>
+
+#define PURPLE_MEMORY_POOL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEMORY_POOL, PurpleMemoryPoolPrivate))
+#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)
+
+typedef struct _PurpleMemoryPoolBlock PurpleMemoryPoolBlock;
+
+typedef struct
+{
+ gulong block_size;
+
+ PurpleMemoryPoolBlock *first_block;
+ PurpleMemoryPoolBlock *last_block;
+} PurpleMemoryPoolPrivate;
+
+struct _PurpleMemoryPoolBlock
+{
+ gpointer available_ptr;
+ gpointer end_ptr;
+ PurpleMemoryPoolBlock *next;
+};
+
+/*******************************************************************************
+ * Memory allocation/deallocation
+ ******************************************************************************/
+
+static PurpleMemoryPoolBlock *
+purple_memory_pool_block_new(gulong block_size)
+{
+ gpointer block_raw;
+ PurpleMemoryPoolBlock *block;
+ gsize total_size;
+
+ total_size = (sizeof(PurpleMemoryPoolBlock) - 1) /
+ PURPLE_MEMORY_POOL_BLOCK_PADDING + 1;
+ total_size += block_size;
+
+ block_raw = g_try_malloc(total_size);
+ if (block_raw == NULL) {
+ g_error("out of memory");
+ return NULL;
+ }
+ block = block_raw;
+
+ /* 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);
+
+ memset(block, 0, sizeof(PurpleMemoryPoolBlock));
+
+ return block;
+}
+
+static gpointer
+purple_memory_pool_alloc_impl(PurpleMemoryPool *pool, gulong size, guint alignment)
+{
+ PurpleMemoryPoolPrivate *priv = PURPLE_MEMORY_POOL_GET_PRIVATE(pool);
+ PurpleMemoryPoolBlock *blk;
+ gpointer mem = NULL;
+
+ g_return_val_if_fail(priv != NULL, NULL);
+ g_return_val_if_fail(size <= priv->block_size, NULL);
+
+ g_warn_if_fail(alignment >= 1);
+ if (alignment < 1)
+ alignment = 1;
+
+ blk = priv->last_block;
+
+ if (blk) {
+ mem = PURPLE_MEMORY_PADDED(blk->available_ptr, alignment);
+ if (mem >= blk->end_ptr)
+ mem = NULL;
+ else if (mem < blk->available_ptr) /* gpointer overflow */
+ mem = NULL;
+ else if (PURPLE_MEMORY_POINTER_SHIFT(mem, size) >= blk->end_ptr)
+ mem = NULL;
+ }
+
+ if (mem == NULL) {
+ blk = purple_memory_pool_block_new(priv->block_size);
+ g_return_val_if_fail(blk != NULL, NULL);
+
+ if (priv->first_block == NULL) {
+ priv->first_block = blk;
+ priv->last_block = blk;
+ } else {
+ priv->last_block->next = blk;
+ priv->last_block = blk;
+ }
+
+ mem = PURPLE_MEMORY_PADDED(blk->available_ptr, alignment);
+ g_assert(mem < blk->end_ptr);
+ g_assert(mem >= blk->available_ptr); /* gpointer overflow */
+ }
+
+ g_assert(blk != NULL);
+ g_assert(mem != NULL);
+
+ blk->available_ptr = PURPLE_MEMORY_POINTER_SHIFT(mem, size);
+ g_assert(blk->available_ptr <= blk->end_ptr);
+
+ return mem;
+}
+
+/*******************************************************************************
+ * API implementation
+ ******************************************************************************/
+
+gpointer
+purple_memory_pool_alloc(PurpleMemoryPool *pool, gulong 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);
+}
+
+gpointer
+purple_memory_pool_alloc0(PurpleMemoryPool *pool, gulong size, guint alignment)
+{
+ gpointer mem;
+
+ mem = purple_memory_pool_alloc(pool, size, alignment);
+ g_return_val_if_fail(mem != NULL, NULL);
+
+ memset(mem, 0, size);
+
+ return mem;
+}
+
+void
+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);
+
+ if (klass->pfree)
+ klass->pfree(pool, mem);
+}
+
+
+/*******************************************************************************
+ * Object stuff
+ ******************************************************************************/
+
+enum
+{
+ PROP_ZERO,
+ PROP_BLOCK_SIZE,
+ PROP_LAST
+};
+
+static GObjectClass *parent_class = NULL;
+static GParamSpec *properties[PROP_LAST];
+
+PurpleMemoryPool *
+purple_memory_pool_new(gulong block_size)
+{
+ return g_object_new(PURPLE_TYPE_MEMORY_POOL,
+ "block-size", block_size,
+ NULL);
+}
+
+static void
+purple_memory_pool_finalize(GObject *obj)
+{
+ PurpleMemoryPoolPrivate *priv = PURPLE_MEMORY_POOL_GET_PRIVATE(obj);
+ PurpleMemoryPoolBlock *blk;
+
+ blk = priv->first_block;
+ while (blk) {
+ PurpleMemoryPoolBlock *next = blk->next;
+ g_free(blk);
+ blk = next;
+ }
+
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+
+static void
+purple_memory_pool_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *pspec)
+{
+ PurpleMemoryPool *pool = PURPLE_MEMORY_POOL(obj);
+ PurpleMemoryPoolPrivate *priv = PURPLE_MEMORY_POOL_GET_PRIVATE(pool);
+
+ switch (param_id) {
+ case PROP_BLOCK_SIZE:
+ g_value_set_ulong(value, priv->block_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ }
+}
+
+static void
+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_PRIVATE(pool);
+
+ switch (param_id) {
+ case PROP_BLOCK_SIZE:
+ priv->block_size = g_value_get_ulong(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ }
+}
+
+static void
+purple_memory_pool_class_init(PurpleMemoryPoolClass *klass)
+{
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ g_type_class_add_private(klass, sizeof(PurpleMemoryPoolPrivate));
+
+ 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;
+
+ properties[PROP_BLOCK_SIZE] = g_param_spec_ulong("block-size",
+ "Block size", "The size of each block of pool memory. Allocated"
+ " items have to be smaller than this value",
+ 1, G_MAXULONG, 1024,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(obj_class, PROP_LAST, properties);
+}
+
+GType
+purple_memory_pool_get_type(void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY(type == 0)) {
+ static const GTypeInfo info = {
+ .class_size = sizeof(PurpleMemoryPoolClass),
+ .class_init = (GClassInitFunc)purple_memory_pool_class_init,
+ .instance_size = sizeof(PurpleMemoryPool),
+ };
+
+ type = g_type_register_static(G_TYPE_OBJECT,
+ "PurpleMemoryPool", &info, 0);
+ }
+
+ return type;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/memorypool.h Sat Mar 22 17:59:35 2014 +0100
@@ -0,0 +1,122 @@
+/*
+ * Purple
+ *
+ * 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
+ */
+
+#ifndef PURPLE_MEMORY_POOL_H
+#define PURPLE_MEMORY_POOL_H
+
+#include <glib-object.h>
+
+#define PURPLE_TYPE_MEMORY_POOL (purple_memory_pool_get_type())
+#define PURPLE_MEMORY_POOL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_MEMORY_POOL, PurpleMemoryPool))
+#define PURPLE_MEMORY_POOL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_MEMORY_POOL, PurpleMemoryPoolClass))
+#define PURPLE_IS_MEMORY_POOL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_MEMORY_POOL))
+#define PURPLE_IS_MEMORY_POOL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEMORY_POOL))
+#define PURPLE_MEMORY_POOL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEMORY_POOL, PurpleMemoryPoolClass))
+
+typedef struct _PurpleMemoryPool PurpleMemoryPool;
+typedef struct _PurpleMemoryPoolClass PurpleMemoryPoolClass;
+
+struct _PurpleMemoryPool
+{
+ /*< private >*/
+ GObject parent_instance;
+};
+
+struct _PurpleMemoryPoolClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ gpointer (*palloc)(PurpleMemoryPool *pool, gulong size, guint alignment);
+ gpointer (*pfree)(PurpleMemoryPool *pool, gpointer mem);
+
+ void (*purple_reserved1)(void);
+ void (*purple_reserved2)(void);
+ void (*purple_reserved3)(void);
+ void (*purple_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType
+purple_memory_pool_get_type(void);
+
+/**
+ * purple_memory_pool_new:
+ * @blocksize: The size of each block of pool memory. Allocated items have to
+ * be smaller than this value.
+ *
+ * Creates a new memory pool.
+ *
+ * Returns: The new PurpleMemoryPool.
+ */
+PurpleMemoryPool *
+purple_memory_pool_new(gulong block_size);
+
+/**
+ * purple_memory_pool_alloc:
+ * @pool: The memory pool.
+ * @size: The size of memory to be allocated.
+ * @alignment: The alignment of memory block (should be a power of two).
+ *
+ * Allocates an aligned memory block within a pool.
+ *
+ * Returns: the pointer to a memory block. This should be freed with
+ * a call to purple_memory_pool_free.
+ */
+gpointer
+purple_memory_pool_alloc(PurpleMemoryPool *pool, gulong size, guint alignment);
+
+/**
+ * purple_memory_pool_alloc0:
+ * @pool: The memory pool.
+ * @size: The size of memory to be allocated.
+ * @alignment: The alignment of memory block (should be a power of two).
+ *
+ * Allocates an aligned memory block within a pool and sets its contents to
+ * zeros.
+ *
+ * Returns: the pointer to a memory block. This should be freed with
+ * a call to purple_memory_pool_free.
+ */
+gpointer
+purple_memory_pool_alloc0(PurpleMemoryPool *pool, gulong size, guint alignment);
+
+/**
+ * purple_memory_pool_free:
+ * @pool: The memory pool.
+ * @mem: The pointer to a memory block.
+ *
+ * Frees a memory allocated within a memory pool. This can be a no-op in certain
+ * implementations.
+ */
+void
+purple_memory_pool_free(PurpleMemoryPool *pool, gpointer mem);
+
+G_END_DECLS
+
+#endif /* PURPLE_MEMORY_POOL_H */