aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/README.wmem31
-rw-r--r--epan/wmem/Makefile.common3
-rw-r--r--epan/wmem/wmem_allocator.h12
-rw-r--r--epan/wmem/wmem_core.c43
-rw-r--r--epan/wmem/wmem_core.h15
-rw-r--r--epan/wmem/wmem_test.c35
-rw-r--r--epan/wmem/wmem_user_cb.h57
7 files changed, 188 insertions, 8 deletions
diff --git a/doc/README.wmem b/doc/README.wmem
index 13ed863818..67f9967564 100644
--- a/doc/README.wmem
+++ b/doc/README.wmem
@@ -102,6 +102,37 @@ wmem_slist.h
wmem_stack.h
- A stack implementation (push, pop, etc).
+2.3 Callbacks
+
+WARNING: You probably don't actually need these; use them only when you're
+ sure you understand the implications and the consequences.
+
+Sometimes (though hopefully rarely) it may be necessary to store data in a wmem
+pool that requires additional cleanup before it is freed. For example, perhaps
+you have a pointer to a file-handle that needs to be closed. In this case, you
+can register a callback with the wmem_register_cleanup_callback function
+declared in wmem_core.h.
+
+This function takes the usual allocator, a function pointer (see wmem_user_cb_t
+also in wmem_core.h) and a void user_data pointer. Every time the memory in a
+pool is freed, all registered cleanup functions are called first, being passed
+a pointer to the allocator as well as whatever user_data was registered with
+that callback.
+
+WARNING: Callback calling order is not defined, you cannot rely on a certain
+ callback being called before or after another (in practice at the
+ moment it's first-in-last-out, but that may change).
+
+WARNING: Callbacks are not cleared when they are called - they are only cleared
+ when the pool is fully destroyed. (Do we need an unregister function?).
+
+WARNING: The user_data pointer is not freed when a callback is cleared, you
+ have to do that yourself (or just allocate it in the appropriate wmem
+ pool).
+
+WARNING: Calling wmem_free on allocated memory that a callback depends on will
+ not unregister that callback. Do not do this, it will crash!
+
3. Usage for Producers
NB: If you're just writing a dissector, you probably don't need to read
diff --git a/epan/wmem/Makefile.common b/epan/wmem/Makefile.common
index da9e6e5a51..12dbfb2e2a 100644
--- a/epan/wmem/Makefile.common
+++ b/epan/wmem/Makefile.common
@@ -45,7 +45,8 @@ LIBWMEM_INCLUDES = \
wmem_slist.h \
wmem_stack.h \
wmem_strbuf.h \
- wmem_strutl.h
+ wmem_strutl.h \
+ wmem_user_cb.h
#
diff --git a/epan/wmem/wmem_allocator.h b/epan/wmem/wmem_allocator.h
index baa7822326..296e206de5 100644
--- a/epan/wmem/wmem_allocator.h
+++ b/epan/wmem/wmem_allocator.h
@@ -26,6 +26,7 @@
#ifndef __WMEM_ALLOCATOR_H__
#define __WMEM_ALLOCATOR_H__
+#include <glib.h>
#include <string.h>
#ifdef __cplusplus
@@ -37,10 +38,6 @@ enum _wmem_allocator_type_t;
/* See section "4. Internal Design" of doc/README.wmem for details
* on this structure */
struct _wmem_allocator_t {
- /* Implementation details */
- void *private_data;
- enum _wmem_allocator_type_t type;
-
/* Consumer functions */
void *(*alloc)(void *private_data, const size_t size);
void (*free)(void *private_data, void *ptr);
@@ -50,6 +47,13 @@ struct _wmem_allocator_t {
void (*free_all)(void *private_data);
void (*gc)(void *private_data);
void (*destroy)(struct _wmem_allocator_t *allocator);
+
+ /* Callback List */
+ GSList *callbacks;
+
+ /* Implementation details */
+ void *private_data;
+ enum _wmem_allocator_type_t type;
};
#ifdef __cplusplus
diff --git a/epan/wmem/wmem_core.c b/epan/wmem/wmem_core.c
index 415826005a..8e0b0b1938 100644
--- a/epan/wmem/wmem_core.c
+++ b/epan/wmem/wmem_core.c
@@ -29,6 +29,7 @@
#include "wmem_core.h"
#include "wmem_scopes.h"
+#include "wmem_user_cb.h"
#include "wmem_allocator.h"
#include "wmem_allocator_simple.h"
#include "wmem_allocator_block.h"
@@ -101,6 +102,18 @@ wmem_realloc(wmem_allocator_t *allocator, void *ptr, const size_t size)
void
wmem_free_all(wmem_allocator_t *allocator)
{
+ GSList *tmp;
+ wmem_user_cb_container_t *cb;
+
+ /* Call all the user-registered callbacks */
+ tmp = allocator->callbacks;
+ while (tmp) {
+ cb = (wmem_user_cb_container_t*) tmp->data;
+ cb->cb(allocator, cb->user_data);
+ tmp = tmp->next;
+ }
+
+ /* Actually free-all */
allocator->free_all(allocator->private_data);
}
@@ -111,9 +124,38 @@ wmem_gc(wmem_allocator_t *allocator)
}
void
+wmem_register_cleanup_callback(wmem_allocator_t *allocator,
+ wmem_user_cb_t callback, void *user_data)
+{
+ wmem_user_cb_container_t *container;
+
+ container = g_slice_new(wmem_user_cb_container_t);
+
+ container->cb = callback;
+ container->user_data = user_data;
+
+ allocator->callbacks = g_slist_prepend(allocator->callbacks,
+ container);
+}
+
+void
wmem_destroy_allocator(wmem_allocator_t *allocator)
{
+ GSList *tmp;
+
+ /* Free-all first (this calls all the user-registered callbacks) */
wmem_free_all(allocator);
+
+ /* Destroy all user-registered callbacks
+ * (they were called in wmem_free_all) */
+ tmp = allocator->callbacks;
+ while (tmp) {
+ g_slice_free(wmem_user_cb_container_t, tmp->data);
+ tmp = tmp->next;
+ }
+ g_slist_free(allocator->callbacks);
+
+ /* Tell the allocator to destroy itself */
allocator->destroy(allocator);
}
@@ -166,6 +208,7 @@ wmem_allocator_new(const wmem_allocator_type_t type)
};
allocator->type = real_type;
+ allocator->callbacks = NULL;
return allocator;
}
diff --git a/epan/wmem/wmem_core.h b/epan/wmem/wmem_core.h
index 4ce51baba9..83735a7095 100644
--- a/epan/wmem/wmem_core.h
+++ b/epan/wmem/wmem_core.h
@@ -33,15 +33,19 @@
extern "C" {
#endif /* __cplusplus */
+/* Allocator structure and typedef */
+struct _wmem_allocator_t;
+typedef struct _wmem_allocator_t wmem_allocator_t;
+
+/* Different types of allocators */
typedef enum _wmem_allocator_type_t {
WMEM_ALLOCATOR_SIMPLE,
WMEM_ALLOCATOR_BLOCK,
WMEM_ALLOCATOR_STRICT
} wmem_allocator_type_t;
-struct _wmem_allocator_t;
-
-typedef struct _wmem_allocator_t wmem_allocator_t;
+/* User callback type for registering cleanup routines */
+typedef void (*wmem_user_cb_t) (wmem_allocator_t *, void *);
WS_DLL_PUBLIC
void *
@@ -78,6 +82,11 @@ wmem_gc(wmem_allocator_t *allocator);
WS_DLL_PUBLIC
void
+wmem_register_cleanup_callback(wmem_allocator_t *allocator,
+ wmem_user_cb_t callback, void *user_data);
+
+WS_DLL_PUBLIC
+void
wmem_destroy_allocator(wmem_allocator_t *allocator);
WS_DLL_PUBLIC
diff --git a/epan/wmem/wmem_test.c b/epan/wmem/wmem_test.c
index 7f17898a62..f1b502f55c 100644
--- a/epan/wmem/wmem_test.c
+++ b/epan/wmem/wmem_test.c
@@ -77,10 +77,28 @@ wmem_allocator_force_new(const wmem_allocator_type_t type)
};
allocator->type = type;
+ allocator->callbacks = NULL;
return allocator;
}
+/* Some helpers for properly testing the user callback functionality */
+wmem_allocator_t *cur_global_allocator;
+void *cur_global_user_data;
+gboolean cb_called;
+
+static void
+wmem_test_callback(wmem_allocator_t *allocator, void *user_data)
+{
+ g_assert(allocator == cur_global_allocator);
+ g_assert(user_data == cur_global_user_data);
+ g_assert(!cb_called);
+
+ cb_called = TRUE;
+}
+
+/* ALLOCATOR TESTING FUNCTIONS (/wmem/allocator/) */
+
static void
wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify)
{
@@ -105,8 +123,15 @@ wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify)
wmem_free(allocator, ptrs[i]);
}
+ wmem_register_cleanup_callback(allocator, &wmem_test_callback,
+ GINT_TO_POINTER(42));
+ cur_global_allocator = allocator;
+ cur_global_user_data = GINT_TO_POINTER(42);
+
if (verify) (*verify)(allocator);
+ cb_called = FALSE;
wmem_free_all(allocator);
+ g_assert(cb_called);
wmem_gc(allocator);
if (verify) (*verify)(allocator);
@@ -118,7 +143,9 @@ wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify)
}
if (verify) (*verify)(allocator);
+ cb_called = FALSE;
wmem_free_all(allocator);
+ g_assert(cb_called);
wmem_gc(allocator);
if (verify) (*verify)(allocator);
@@ -135,7 +162,9 @@ wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify)
}
if (verify) (*verify)(allocator);
+ cb_called = FALSE;
wmem_free_all(allocator);
+ g_assert(cb_called);
wmem_gc(allocator);
if (verify) (*verify)(allocator);
@@ -184,7 +213,9 @@ wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify)
if (verify) (*verify)(allocator);
}
+ cb_called = FALSE;
wmem_destroy_allocator(allocator);
+ g_assert(cb_called);
}
static void
@@ -249,6 +280,8 @@ wmem_test_allocator_strict(void)
wmem_test_allocator(WMEM_ALLOCATOR_STRICT, &wmem_strict_check_canaries);
}
+/* UTILITY TESTING FUNCTIONS (/wmem/utils/) */
+
static void
wmem_test_strutls(void)
{
@@ -280,6 +313,8 @@ wmem_test_strutls(void)
wmem_destroy_allocator(allocator);
}
+/* DATA STRUCTURE TESTING FUNCTIONS (/wmem/datastruct/) */
+
static void
wmem_test_slist(void)
{
diff --git a/epan/wmem/wmem_user_cb.h b/epan/wmem/wmem_user_cb.h
new file mode 100644
index 0000000000..8a5b093eb1
--- /dev/null
+++ b/epan/wmem/wmem_user_cb.h
@@ -0,0 +1,57 @@
+/* wmem_user_cb.h
+ * Definitions for the Wireshark Memory Manager User Callbacks
+ * Copyright 2012, Evan Huus <eapache@gmail.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * 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 02110-1301 USA.
+ */
+
+#ifndef __WMEM_USER_CB_H__
+#define __WMEM_USER_CB_H__
+
+#include "wmem_core.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _wmem_user_cb_container_t {
+ wmem_user_cb_t cb;
+ void *user_data;
+} wmem_user_cb_container_t;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __WMEM_USER_CB_H__ */
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */