X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-memory.c;h=d59e8f8cdded95ceb3c8f9cffe60476361c02406;hb=c1a77d2c58c78abc606f1cb7918704596ebf2bfe;hp=c36601aed34d5da33344490f7ce26261e81f9d2e;hpb=7f9721a6d36697a57170c604aa845af3531bd157;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c index c36601a..d59e8f8 100644 --- a/dbus/dbus-memory.c +++ b/dbus/dbus-memory.c @@ -1,5 +1,5 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-memory.c D-BUS memory handling +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-memory.c D-Bus memory handling * * Copyright (C) 2002, 2003 Red Hat Inc. * @@ -17,14 +17,16 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ +#include #include "dbus-memory.h" #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-list.h" +#include "dbus-threads.h" #include /** @@ -95,7 +97,7 @@ * @{ */ -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS static dbus_bool_t debug_initialized = FALSE; static int fail_nth = -1; static size_t fail_size = 0; @@ -105,7 +107,8 @@ static int n_failures_this_failure = 0; 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; +static dbus_bool_t malloc_cannot_fail = FALSE; +static DBusAtomic n_blocks_outstanding = {0}; /** value stored in guard padding for debugging buffer overrun */ #define GUARD_VALUE 0xdeadbeef @@ -131,7 +134,7 @@ _dbus_initialize_malloc_debug (void) { fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH")); fail_alloc_counter = fail_nth; - _dbus_verbose ("Will fail malloc every %d times\n", fail_nth); + _dbus_verbose ("Will fail dbus_malloc every %d times\n", fail_nth); } if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL) @@ -144,7 +147,7 @@ _dbus_initialize_malloc_debug (void) if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL) { guards = TRUE; - _dbus_verbose ("Will use malloc guards\n"); + _dbus_verbose ("Will use dbus_malloc guards\n"); } if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL) @@ -156,7 +159,13 @@ _dbus_initialize_malloc_debug (void) if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL) { backtrace_on_fail_alloc = TRUE; - _dbus_verbose ("Will backtrace on failing a malloc\n"); + _dbus_verbose ("Will backtrace on failing a dbus_malloc\n"); + } + + if (_dbus_getenv ("DBUS_MALLOC_CANNOT_FAIL") != NULL) + { + malloc_cannot_fail = TRUE; + _dbus_verbose ("Will abort if system malloc() and friends fail\n"); } } } @@ -231,7 +240,7 @@ _dbus_get_fail_alloc_failures (void) return n_failures_per_failure; } -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS /** * Called when about to alloc some memory; if * it returns #TRUE, then the allocation should @@ -244,7 +253,19 @@ dbus_bool_t _dbus_decrement_fail_alloc_counter (void) { _dbus_initialize_malloc_debug (); - +#ifdef DBUS_WIN_FIXME + { + static dbus_bool_t called = 0; + + if (!called) + { + _dbus_verbose("TODO: memory allocation testing errors disabled for now\n"); + called = 1; + } + return FALSE; + } +#endif + if (fail_alloc_counter <= 0) { if (backtrace_on_fail_alloc) @@ -273,7 +294,7 @@ _dbus_decrement_fail_alloc_counter (void) return FALSE; } } -#endif /* DBUS_BUILD_TESTS */ +#endif /* DBUS_ENABLE_EMBEDDED_TESTS */ /** * Get the number of outstanding malloc()'d blocks. @@ -283,7 +304,7 @@ _dbus_decrement_fail_alloc_counter (void) int _dbus_get_malloc_blocks_outstanding (void) { - return n_blocks_outstanding; + return _dbus_atomic_get (&n_blocks_outstanding); } /** @@ -430,26 +451,28 @@ set_guards (void *real_block, * on all platforms. Returns #NULL if the allocation fails. * The memory must be released with dbus_free(). * + * dbus_malloc() memory is NOT safe to free with regular free() from + * the C library. Free it with dbus_free() only. + * * @param bytes number of bytes to allocate * @return allocated memory, or #NULL if the allocation fails. */ void* dbus_malloc (size_t bytes) { -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) { _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes); - return NULL; } #endif - + if (bytes == 0) /* some system mallocs handle this, some don't */ return NULL; -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) @@ -458,7 +481,15 @@ dbus_malloc (size_t bytes) block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) - n_blocks_outstanding += 1; + { + _dbus_atomic_inc (&n_blocks_outstanding); + } + else if (malloc_cannot_fail) + { + _dbus_warn ("out of memory: malloc (%ld + %ld)\n", + (long) bytes, (long) GUARD_EXTRA_SIZE); + _dbus_abort (); + } return set_guards (block, bytes, SOURCE_MALLOC); } @@ -467,10 +498,19 @@ dbus_malloc (size_t bytes) { void *mem; mem = malloc (bytes); -#ifdef DBUS_BUILD_TESTS + +#ifdef DBUS_ENABLE_EMBEDDED_TESTS if (mem) - n_blocks_outstanding += 1; + { + _dbus_atomic_inc (&n_blocks_outstanding); + } + else if (malloc_cannot_fail) + { + _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes); + _dbus_abort (); + } #endif + return mem; } } @@ -481,13 +521,16 @@ dbus_malloc (size_t bytes) * return #NULL if bytes is zero on all platforms. Returns #NULL if the * allocation fails. The memory must be released with dbus_free(). * + * dbus_malloc0() memory is NOT safe to free with regular free() from + * the C library. Free it with dbus_free() only. + * * @param bytes number of bytes to allocate * @return allocated memory, or #NULL if the allocation fails. */ void* dbus_malloc0 (size_t bytes) { -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) @@ -497,10 +540,10 @@ dbus_malloc0 (size_t bytes) return NULL; } #endif - + if (bytes == 0) return NULL; -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) @@ -508,8 +551,18 @@ dbus_malloc0 (size_t bytes) void *block; block = calloc (bytes + GUARD_EXTRA_SIZE, 1); + if (block) - n_blocks_outstanding += 1; + { + _dbus_atomic_inc (&n_blocks_outstanding); + } + else if (malloc_cannot_fail) + { + _dbus_warn ("out of memory: calloc (%ld + %ld, 1)\n", + (long) bytes, (long) GUARD_EXTRA_SIZE); + _dbus_abort (); + } + return set_guards (block, bytes, SOURCE_MALLOC_ZERO); } #endif @@ -517,10 +570,19 @@ dbus_malloc0 (size_t bytes) { void *mem; mem = calloc (bytes, 1); -#ifdef DBUS_BUILD_TESTS + +#ifdef DBUS_ENABLE_EMBEDDED_TESTS if (mem) - n_blocks_outstanding += 1; + { + _dbus_atomic_inc (&n_blocks_outstanding); + } + else if (malloc_cannot_fail) + { + _dbus_warn ("out of memory: calloc (%ld)\n", (long) bytes); + _dbus_abort (); + } #endif + return mem; } } @@ -539,7 +601,7 @@ void* dbus_realloc (void *memory, size_t bytes) { -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS _dbus_initialize_malloc_debug (); if (_dbus_decrement_fail_alloc_counter ()) @@ -555,7 +617,7 @@ dbus_realloc (void *memory, dbus_free (memory); return NULL; } -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS else if (fail_size != 0 && bytes > fail_size) return NULL; else if (guards) @@ -570,8 +632,20 @@ dbus_realloc (void *memory, block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, bytes + GUARD_EXTRA_SIZE); - old_bytes = *(dbus_uint32_t*)block; - if (block && bytes >= old_bytes) + if (block == NULL) + { + if (malloc_cannot_fail) + { + _dbus_warn ("out of memory: realloc (%p, %ld + %ld)\n", + memory, (long) bytes, (long) GUARD_EXTRA_SIZE); + _dbus_abort (); + } + + return NULL; + } + + old_bytes = *(dbus_uint32_t*)block; + if (bytes >= old_bytes) /* old guards shouldn't have moved */ check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE); @@ -584,8 +658,16 @@ dbus_realloc (void *memory, block = malloc (bytes + GUARD_EXTRA_SIZE); if (block) - n_blocks_outstanding += 1; - + { + _dbus_atomic_inc (&n_blocks_outstanding); + } + else if (malloc_cannot_fail) + { + _dbus_warn ("out of memory: malloc (%ld + %ld)\n", + (long) bytes, (long) GUARD_EXTRA_SIZE); + _dbus_abort (); + } + return set_guards (block, bytes, SOURCE_REALLOC_NULL); } } @@ -594,9 +676,16 @@ dbus_realloc (void *memory, { void *mem; mem = realloc (memory, bytes); -#ifdef DBUS_BUILD_TESTS + +#ifdef DBUS_ENABLE_EMBEDDED_TESTS + if (mem == NULL && malloc_cannot_fail) + { + _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes); + _dbus_abort (); + } + if (memory == NULL && mem != NULL) - n_blocks_outstanding += 1; + _dbus_atomic_inc (&n_blocks_outstanding); #endif return mem; } @@ -611,16 +700,21 @@ dbus_realloc (void *memory, void dbus_free (void *memory) { -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS if (guards) { check_guards (memory, TRUE); if (memory) { - n_blocks_outstanding -= 1; - - _dbus_assert (n_blocks_outstanding >= 0); - +#ifdef DBUS_DISABLE_ASSERT + _dbus_atomic_dec (&n_blocks_outstanding); +#else + dbus_int32_t old_value; + + old_value = _dbus_atomic_dec (&n_blocks_outstanding); + _dbus_assert (old_value >= 1); +#endif + free (((unsigned char*)memory) - GUARD_START_OFFSET); } @@ -630,10 +724,15 @@ dbus_free (void *memory) if (memory) /* we guarantee it's safe to free (NULL) */ { -#ifdef DBUS_BUILD_TESTS - n_blocks_outstanding -= 1; - - _dbus_assert (n_blocks_outstanding >= 0); +#ifdef DBUS_ENABLE_EMBEDDED_TESTS +#ifdef DBUS_DISABLE_ASSERT + _dbus_atomic_dec (&n_blocks_outstanding); +#else + dbus_int32_t old_value; + + old_value = _dbus_atomic_dec (&n_blocks_outstanding); + _dbus_assert (old_value >= 1); +#endif #endif free (memory); @@ -696,7 +795,7 @@ struct ShutdownClosure void *data; /**< Data for function */ }; -_DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs); +/* Protected by _DBUS_LOCK (shutdown_funcs) */ static ShutdownClosure *registered_globals = NULL; /** @@ -711,6 +810,20 @@ dbus_bool_t _dbus_register_shutdown_func (DBusShutdownFunction func, void *data) { + dbus_bool_t ok; + + if (!_DBUS_LOCK (shutdown_funcs)) + return FALSE; + + ok = _dbus_register_shutdown_func_unlocked (func, data); + _DBUS_UNLOCK (shutdown_funcs); + return ok; +} + +dbus_bool_t +_dbus_register_shutdown_func_unlocked (DBusShutdownFunction func, + void *data) +{ ShutdownClosure *c; c = dbus_new (ShutdownClosure, 1); @@ -721,13 +834,9 @@ _dbus_register_shutdown_func (DBusShutdownFunction func, c->func = func; c->data = data; - _DBUS_LOCK (shutdown_funcs); - c->next = registered_globals; registered_globals = c; - _DBUS_UNLOCK (shutdown_funcs); - return TRUE; } @@ -741,16 +850,41 @@ _dbus_register_shutdown_func (DBusShutdownFunction func, */ /** - * 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. + * Frees all memory allocated internally by libdbus and + * reverses the effects of dbus_threads_init(). libdbus keeps internal + * global variables, for example caches and thread locks, and it + * can be useful to free these internal data structures. + * + * dbus_shutdown() does NOT free memory that was returned + * to the application. It only returns libdbus-internal + * data structures. + * + * You MUST free all memory and release all reference counts + * returned to you by libdbus prior to calling dbus_shutdown(). + * + * You can't continue to use any D-Bus objects, such as connections, + * that were allocated prior to dbus_shutdown(). You can, however, + * start over; call dbus_threads_init() again, create new connections, + * and so forth. + * + * WARNING: dbus_shutdown() is NOT thread safe, it must be called + * while NO other threads are using D-Bus. (Remember, you have to free + * all D-Bus objects and memory before you call dbus_shutdown(), so no + * thread can be using libdbus.) + * + * The purpose of dbus_shutdown() is to allow applications to get + * clean output from memory leak checkers. dbus_shutdown() may also be + * useful if you want to dlopen() libdbus instead of linking to it, + * and want to be able to unload the library again. + * + * There is absolutely no requirement to call dbus_shutdown() - in fact, + * most applications won't bother and should not feel guilty. + * + * You have to know that nobody is using libdbus in your application's + * process before you can call dbus_shutdown(). One implication of this + * is that calling dbus_shutdown() from a library is almost certainly + * wrong, since you don't know what the rest of the app is up to. + * */ void dbus_shutdown (void) @@ -767,12 +901,18 @@ dbus_shutdown (void) dbus_free (c); } + /* We wrap this in the thread-initialization lock because + * dbus_threads_init() uses the current generation to tell whether + * we're initialized, so we need to make sure that un-initializing + * propagates into all threads. */ + _dbus_threads_lock_platform_specific (); _dbus_current_generation += 1; + _dbus_threads_unlock_platform_specific (); } /** @} */ /** End of public API docs block */ -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" /**