diff options
Diffstat (limited to 'dbus/dbus-memory.c')
-rw-r--r-- | dbus/dbus-memory.c | 161 |
1 files changed, 153 insertions, 8 deletions
diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c index 26766c0c..983c6e31 100644 --- a/dbus/dbus-memory.c +++ b/dbus/dbus-memory.c @@ -24,6 +24,7 @@ #include "dbus-memory.h" #include "dbus-internals.h" #include "dbus-sysdeps.h" +#include "dbus-list.h" #include <stdlib.h> @@ -81,6 +82,7 @@ static int fail_alloc_counter = _DBUS_INT_MAX; static dbus_bool_t guards = FALSE; static dbus_bool_t disable_mem_pools = FALSE; static dbus_bool_t backtrace_on_fail_alloc = FALSE; +static int n_blocks_outstanding = 0; /** value stored in guard padding for debugging buffer overrun */ #define GUARD_VALUE 0xdeadbeef @@ -216,6 +218,17 @@ _dbus_decrement_fail_alloc_counter (void) } /** + * Get the number of outstanding malloc()'d blocks. + * + * @returns number of blocks + */ +int +_dbus_get_malloc_blocks_outstanding (void) +{ + return n_blocks_outstanding; +} + +/** * Where the block came from. */ typedef enum @@ -372,11 +385,22 @@ dbus_malloc (size_t bytes) void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); + if (block) + n_blocks_outstanding += 1; + return set_guards (block, bytes, SOURCE_MALLOC); } #endif else - return malloc (bytes); + { + void *mem; + mem = malloc (bytes); +#ifdef DBUS_BUILD_TESTS + if (mem) + n_blocks_outstanding += 1; +#endif + return mem; + } } /** @@ -412,11 +436,21 @@ dbus_malloc0 (size_t bytes) void *block; block = calloc (bytes + GUARD_EXTRA_SIZE, 1); + if (block) + n_blocks_outstanding += 1; return set_guards (block, bytes, SOURCE_MALLOC_ZERO); } #endif else - return calloc (bytes, 1); + { + void *mem; + mem = calloc (bytes, 1); +#ifdef DBUS_BUILD_TESTS + if (mem) + n_blocks_outstanding += 1; +#endif + return mem; + } } /** @@ -462,9 +496,10 @@ dbus_realloc (void *memory, block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, bytes + GUARD_EXTRA_SIZE); - - /* old guards shouldn't have moved */ - check_guards (((unsigned char*)block) + GUARD_START_OFFSET); + + if (block) + /* old guards shouldn't have moved */ + check_guards (((unsigned char*)block) + GUARD_START_OFFSET); return set_guards (block, bytes, SOURCE_REALLOC); } @@ -473,13 +508,23 @@ dbus_realloc (void *memory, void *block; block = malloc (bytes + GUARD_EXTRA_SIZE); + + if (block) + n_blocks_outstanding += 1; + return set_guards (block, bytes, SOURCE_REALLOC_NULL); } } #endif else { - return realloc (memory, bytes); + void *mem; + mem = realloc (memory, bytes); +#ifdef DBUS_BUILD_TESTS + if (memory == NULL && mem != NULL) + n_blocks_outstanding += 1; +#endif + return mem; } } @@ -497,13 +542,28 @@ dbus_free (void *memory) { check_guards (memory); if (memory) - free (((unsigned char*)memory) - GUARD_START_OFFSET); + { + n_blocks_outstanding -= 1; + + _dbus_assert (n_blocks_outstanding >= 0); + + free (((unsigned char*)memory) - GUARD_START_OFFSET); + } + return; } #endif if (memory) /* we guarantee it's safe to free (NULL) */ - free (memory); + { +#ifdef DBUS_BUILD_TESTS + n_blocks_outstanding -= 1; + + _dbus_assert (n_blocks_outstanding >= 0); +#endif + + free (memory); + } } /** @@ -530,4 +590,89 @@ dbus_free_string_array (char **str_array) } } +/** + * _dbus_current_generation is used to track each + * time that dbus_shutdown() is called, so we can + * reinit things after it's been called. It is simply + * incremented each time we shut down. + */ +int _dbus_current_generation = 1; + +static DBusList *registered_globals = NULL; + +typedef struct +{ + DBusShutdownFunction func; + void *data; +} ShutdownClosure; + +/** + * The D-BUS library keeps some internal global variables, for example + * to cache the username of the current process. This function is + * used to free these global variables. It is really useful only for + * leak-checking cleanliness and the like. WARNING: this function is + * NOT thread safe, it must be called while NO other threads are using + * D-BUS. You cannot continue using D-BUS after calling this function, + * as it does things like free global mutexes created by + * dbus_threads_init(). To use a D-BUS function after calling + * dbus_shutdown(), you have to start over from scratch, e.g. calling + * dbus_threads_init() again. + */ +void +dbus_shutdown (void) +{ + DBusList *link; + + link = _dbus_list_get_first_link (®istered_globals); + while (link != NULL) + { + ShutdownClosure *c = link->data; + + (* c->func) (c->data); + + dbus_free (c); + + link = _dbus_list_get_next_link (®istered_globals, link); + } + + _dbus_list_clear (®istered_globals); + + _dbus_current_generation += 1; +} + +/** + * Register a cleanup function to be called exactly once + * the next time dbus_shutdown() is called. + * + * @param func the function + * @param data data to pass to the function + * @returns #FALSE on not enough memory + */ +dbus_bool_t +_dbus_register_shutdown_func (DBusShutdownFunction func, + void *data) +{ + ShutdownClosure *c; + + c = dbus_new (ShutdownClosure, 1); + + if (c == NULL) + return FALSE; + + c->func = func; + c->data = data; + + /* We prepend, then shutdown the list in order, so + * we shutdown last-registered stuff first which + * is right. + */ + if (!_dbus_list_prepend (®istered_globals, c)) + { + dbus_free (c); + return FALSE; + } + + return TRUE; +} + /** @} */ |