From c3af5ccdbc22e8990d04ec2f89ad1f2e053655e9 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 24 Mar 2003 03:16:58 +0000 Subject: 2003-03-23 Havoc Pennington * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with DBUS_BUILD_TESTS, actually alloc/free a block of memory for the mutex, so we can check for proper memory management and OOM handling. * dbus/dbus-dataslot.c: remove the mutex from DBusDataSlotAllocator and lock it manually when using it, to simplify fitting it into the global slots framework. * dbus/dbus-threads.c (init_static_locks): rework how we're handling global locks so they are easily shut down. * bus/policy.c (bus_policy_append_rule): fix * bus/test-main.c (main): check for memleaks * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make test suite check for memleaks * dbus/dbus-memory.c: add support in test mode for tracking number of outstanding blocks --- dbus/dbus-bus.c | 24 ++----- dbus/dbus-connection.c | 19 +----- dbus/dbus-dataslot.c | 54 ++++++++++----- dbus/dbus-dataslot.h | 33 ++++----- dbus/dbus-internals.c | 35 ++++++++++ dbus/dbus-internals.h | 41 +++++++---- dbus/dbus-list.c | 24 ++----- dbus/dbus-memory.c | 161 +++++++++++++++++++++++++++++++++++++++++--- dbus/dbus-memory.h | 2 + dbus/dbus-message-handler.c | 47 +++++-------- dbus/dbus-server.c | 19 +----- dbus/dbus-sysdeps.c | 100 ++++++++++++++------------- dbus/dbus-test-main.c | 1 + dbus/dbus-test.c | 19 +++++- dbus/dbus-threads.c | 116 ++++++++++++++++++++++++------- 15 files changed, 464 insertions(+), 231 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index c05d74a5..7a539382 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -63,24 +63,12 @@ static int bus_data_slot_refcount = 0; /** * Lock for bus_data_slot and bus_data_slot_refcount */ -static DBusMutex *slot_lock; - -/** - * Initialize the mutex used for bus_data_slot - * - * @returns the mutex - */ -DBusMutex * -_dbus_bus_init_lock (void) -{ - slot_lock = dbus_mutex_new (); - return slot_lock; -} +_DBUS_DEFINE_GLOBAL_LOCK (bus); static dbus_bool_t data_slot_ref (void) { - dbus_mutex_lock (slot_lock); + _DBUS_LOCK (bus); if (bus_data_slot < 0) { @@ -88,7 +76,7 @@ data_slot_ref (void) if (bus_data_slot < 0) { - dbus_mutex_unlock (slot_lock); + _DBUS_UNLOCK (bus); return FALSE; } @@ -97,7 +85,7 @@ data_slot_ref (void) bus_data_slot_refcount += 1; - dbus_mutex_unlock (slot_lock); + _DBUS_UNLOCK (bus); return TRUE; } @@ -105,7 +93,7 @@ data_slot_ref (void) static void data_slot_unref (void) { - dbus_mutex_lock (slot_lock); + _DBUS_LOCK (bus); _dbus_assert (bus_data_slot_refcount > 0); _dbus_assert (bus_data_slot >= 0); @@ -118,7 +106,7 @@ data_slot_unref (void) bus_data_slot = -1; } - dbus_mutex_unlock (slot_lock); + _DBUS_UNLOCK (bus); } static void diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ad8a1724..76bbfe41 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2472,21 +2472,7 @@ dbus_connection_unregister_handler (DBusConnection *connection, } static DBusDataSlotAllocator slot_allocator; - -/** - * Initialize the mutex used for #DBusConnection data - * slot reservations. - * - * @returns the mutex - */ -DBusMutex * -_dbus_connection_slots_init_lock (void) -{ - if (!_dbus_data_slot_allocator_init (&slot_allocator)) - return NULL; - else - return slot_allocator.lock; -} +_DBUS_DEFINE_GLOBAL_LOCK (connection_slots); /** * Allocates an integer ID to be used for storing application-specific @@ -2501,7 +2487,8 @@ _dbus_connection_slots_init_lock (void) int dbus_connection_allocate_data_slot (void) { - return _dbus_data_slot_allocator_alloc (&slot_allocator); + return _dbus_data_slot_allocator_alloc (&slot_allocator, + _DBUS_LOCK_NAME (connection_slots)); } /** diff --git a/dbus/dbus-dataslot.c b/dbus/dbus-dataslot.c index 46e2bfc1..def864e4 100644 --- a/dbus/dbus-dataslot.c +++ b/dbus/dbus-dataslot.c @@ -46,11 +46,9 @@ _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator) allocator->allocated_slots = NULL; allocator->n_allocated_slots = 0; allocator->n_used_slots = 0; - allocator->lock = dbus_mutex_new (); - if (allocator->lock == NULL) - return FALSE; - else - return TRUE; + allocator->lock = NULL; + + return TRUE; } /** @@ -62,16 +60,26 @@ _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator) * DBusDataSlotAllocator so it isn't cut-and-pasted everywhere. * * @param allocator the allocator + * @param mutex the lock for this allocator * @returns the integer ID, or -1 on failure */ int -_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator) +_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator, + DBusMutex *mutex) { int slot; - - if (!dbus_mutex_lock (allocator->lock)) + + if (!dbus_mutex_lock (mutex)) return -1; + if (allocator->n_allocated_slots == 0) + { + _dbus_assert (allocator->lock == NULL); + allocator->lock = mutex; + } + else + _dbus_assert (allocator->lock == mutex); + if (allocator->n_used_slots < allocator->n_allocated_slots) { slot = 0; @@ -128,27 +136,34 @@ _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator) */ void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator, - int slot) + int slot) { dbus_mutex_lock (allocator->lock); - + _dbus_assert (slot < allocator->n_allocated_slots); _dbus_assert (allocator->allocated_slots[slot] == slot); allocator->allocated_slots[slot] = -1; allocator->n_used_slots -= 1; + _dbus_verbose ("Freed slot %d on allocator %p total %d allocated %d used\n", + slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots); + if (allocator->n_used_slots == 0) { + DBusMutex *mutex = allocator->lock; + dbus_free (allocator->allocated_slots); allocator->allocated_slots = NULL; allocator->n_allocated_slots = 0; - } + allocator->lock = NULL; - _dbus_verbose ("Freed slot %d on allocator %p total %d allocated %d used\n", - slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots); - - dbus_mutex_unlock (allocator->lock); + dbus_mutex_unlock (mutex); + } + else + { + dbus_mutex_unlock (allocator->lock); + } } /** @@ -320,12 +335,17 @@ _dbus_data_slot_test (void) int i; DBusFreeFunction old_free_func; void *old_data; + DBusMutex *mutex; if (!_dbus_data_slot_allocator_init (&allocator)) _dbus_assert_not_reached ("no memory for allocator"); _dbus_data_slot_list_init (&list); + mutex = dbus_mutex_new (); + if (mutex == NULL) + _dbus_assert_not_reached ("failed to alloc mutex"); + #define N_SLOTS 100 i = 0; @@ -335,7 +355,7 @@ _dbus_data_slot_test (void) * allocation, but it simplifies things to rely on it * here. */ - if (_dbus_data_slot_allocator_alloc (&allocator) != i) + if (_dbus_data_slot_allocator_alloc (&allocator, mutex) != i) _dbus_assert_not_reached ("did not allocate slots in numeric order\n"); ++i; @@ -394,6 +414,8 @@ _dbus_data_slot_test (void) _dbus_data_slot_allocator_free (&allocator, i); ++i; } + + dbus_mutex_free (mutex); return TRUE; } diff --git a/dbus/dbus-dataslot.h b/dbus/dbus-dataslot.h index 4bb6091f..d4357325 100644 --- a/dbus/dbus-dataslot.h +++ b/dbus/dbus-dataslot.h @@ -53,23 +53,24 @@ struct DBusDataSlotList int n_slots; /**< Slots we have storage for in data_slots */ }; -dbus_bool_t _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator); -int _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator); -void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator, - int slot_id); +dbus_bool_t _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator); +int _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator, + DBusMutex *mutex); +void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator, + int slot_id); +void _dbus_data_slot_list_init (DBusDataSlotList *list); +dbus_bool_t _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator, + DBusDataSlotList *list, + int slot, + void *data, + DBusFreeFunction free_data_func, + DBusFreeFunction *old_free_func, + void **old_data); +void* _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator, + DBusDataSlotList *list, + int slot); +void _dbus_data_slot_list_free (DBusDataSlotList *list); -void _dbus_data_slot_list_init (DBusDataSlotList *list); -dbus_bool_t _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator, - DBusDataSlotList *list, - int slot, - void *data, - DBusFreeFunction free_data_func, - DBusFreeFunction *old_free_func, - void **old_data); -void* _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator, - DBusDataSlotList *list, - int slot); -void _dbus_data_slot_list_free (DBusDataSlotList *list); DBUS_END_DECLS; diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 5153a767..f9d632b4 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -127,6 +127,41 @@ * a DBusList. */ +/** + * @def _DBUS_LOCK_NAME + * + * Expands to name of a global lock variable. + */ + +/** + * @def _DBUS_DEFINE_GLOBAL_LOCK + * + * Defines a global lock variable with the given name. + * The lock must be added to the list to initialize + * in dbus_threads_init(). + */ + +/** + * @def _DBUS_DECLARE_GLOBAL_LOCK + * + * Expands to declaration of a global lock defined + * with _DBUS_DEFINE_GLOBAL_LOCK. + * The lock must be added to the list to initialize + * in dbus_threads_init(). + */ + +/** + * @def _DBUS_LOCK + * + * Locks a global lock + */ + +/** + * @def _DBUS_UNLOCK + * + * Unlocks a global lock + */ + /** * Fixed "out of memory" error message, just to avoid * making up a different string every time and wasting diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index e77c174c..72658b65 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -169,10 +169,11 @@ extern const char _dbus_no_memory_message[]; #ifdef DBUS_BUILD_TESTS /* Memory debugging */ -void _dbus_set_fail_alloc_counter (int until_next_fail); -int _dbus_get_fail_alloc_counter (void); -dbus_bool_t _dbus_decrement_fail_alloc_counter (void); -dbus_bool_t _dbus_disable_mem_pools (void); +void _dbus_set_fail_alloc_counter (int until_next_fail); +int _dbus_get_fail_alloc_counter (void); +dbus_bool_t _dbus_decrement_fail_alloc_counter (void); +dbus_bool_t _dbus_disable_mem_pools (void); +int _dbus_get_malloc_blocks_outstanding (void); #else #define _dbus_set_fail_alloc_counter(n) #define _dbus_get_fail_alloc_counter _DBUS_INT_MAX @@ -180,18 +181,32 @@ dbus_bool_t _dbus_disable_mem_pools (void); /* These are constant expressions so that blocks * they protect should be optimized away */ -#define _dbus_decrement_fail_alloc_counter() FALSE -#define _dbus_disable_mem_pools() FALSE +#define _dbus_decrement_fail_alloc_counter() (FALSE) +#define _dbus_disable_mem_pools() (FALSE) +#define _dbus_get_malloc_blocks_outstanding (0) #endif /* !DBUS_BUILD_TESTS */ +typedef void (* DBusShutdownFunction) (void *data); +dbus_bool_t _dbus_register_shutdown_func (DBusShutdownFunction function, + void *data); + +extern int _dbus_current_generation; + /* Thread initializers */ -DBusMutex *_dbus_list_init_lock (void); -DBusMutex *_dbus_connection_slots_init_lock (void); -DBusMutex *_dbus_server_slots_init_lock (void); -DBusMutex *_dbus_atomic_init_lock (void); -DBusMutex *_dbus_message_handler_init_lock (void); -DBusMutex *_dbus_user_info_init_lock (void); -DBusMutex *_dbus_bus_init_lock (void); +#define _DBUS_LOCK_NAME(name) _dbus_lock_##name +#define _DBUS_DECLARE_GLOBAL_LOCK(name) extern DBusMutex *_dbus_lock_##name +#define _DBUS_DEFINE_GLOBAL_LOCK(name) DBusMutex *_dbus_lock_##name +#define _DBUS_LOCK(name) dbus_mutex_lock (_dbus_lock_##name) +#define _DBUS_UNLOCK(name) dbus_mutex_unlock (_dbus_lock_##name) + +_DBUS_DECLARE_GLOBAL_LOCK (list); +_DBUS_DECLARE_GLOBAL_LOCK (connection_slots); +_DBUS_DECLARE_GLOBAL_LOCK (server_slots); +_DBUS_DECLARE_GLOBAL_LOCK (atomic); +_DBUS_DECLARE_GLOBAL_LOCK (message_handler); +_DBUS_DECLARE_GLOBAL_LOCK (user_info); +_DBUS_DECLARE_GLOBAL_LOCK (bus); +#define _DBUS_N_GLOBAL_LOCKS (7) DBUS_END_DECLS; diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c index 4c530dc7..b2efff6c 100644 --- a/dbus/dbus-list.c +++ b/dbus/dbus-list.c @@ -35,19 +35,7 @@ */ static DBusMemPool *list_pool; -static DBusMutex *list_pool_lock = NULL; - -/** - * Initializes the global mutex used for allocating list nodes. - * - * @returns the mutex - */ -DBusMutex * -_dbus_list_init_lock (void) -{ - list_pool_lock = dbus_mutex_new (); - return list_pool_lock; -} +_DBUS_DEFINE_GLOBAL_LOCK (list); /** * @defgroup DBusListInternals Linked list implementation details @@ -67,7 +55,7 @@ alloc_link (void *data) { DBusList *link; - if (!dbus_mutex_lock (list_pool_lock)) + if (!_DBUS_LOCK (list)) return NULL; if (!list_pool) @@ -76,7 +64,7 @@ alloc_link (void *data) if (list_pool == NULL) { - dbus_mutex_unlock (list_pool_lock); + _DBUS_UNLOCK (list); return NULL; } } @@ -85,7 +73,7 @@ alloc_link (void *data) if (link) link->data = data; - dbus_mutex_unlock (list_pool_lock); + _DBUS_UNLOCK (list); return link; } @@ -93,13 +81,13 @@ alloc_link (void *data) static void free_link (DBusList *link) { - dbus_mutex_lock (list_pool_lock); + _DBUS_LOCK (list); if (_dbus_mem_pool_dealloc (list_pool, link)) { _dbus_mem_pool_free (list_pool); list_pool = NULL; } - dbus_mutex_unlock (list_pool_lock); + _DBUS_UNLOCK (list); } static void 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 @@ -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 @@ -215,6 +217,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. */ @@ -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; +} + /** @} */ diff --git a/dbus/dbus-memory.h b/dbus/dbus-memory.h index 7a0e3163..c0623c8d 100644 --- a/dbus/dbus-memory.h +++ b/dbus/dbus-memory.h @@ -45,6 +45,8 @@ void dbus_free_string_array (char **str_array); typedef void (* DBusFreeFunction) (void *memory); +void dbus_shutdown (void); + DBUS_END_DECLS; #endif /* DBUS_MEMORY_H */ diff --git a/dbus/dbus-message-handler.c b/dbus/dbus-message-handler.c index 6d5bb78d..fb9eff07 100644 --- a/dbus/dbus-message-handler.c +++ b/dbus/dbus-message-handler.c @@ -37,20 +37,7 @@ * @{ */ -static DBusMutex *message_handler_lock = NULL; - -/** - * Initializes the mutex used for threadsafe access to - * #DBusMessageHandler objects. - * - * @returns the mutex - */ -DBusMutex * -_dbus_message_handler_init_lock (void) -{ - message_handler_lock = dbus_mutex_new (); - return message_handler_lock; -} +_DBUS_DEFINE_GLOBAL_LOCK (message_handler); /** * @brief Internals of DBusMessageHandler @@ -83,7 +70,7 @@ _dbus_message_handler_add_connection (DBusMessageHandler *handler, { dbus_bool_t res; - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); /* This is a bit wasteful - we just put the connection in the list * once per time it's added. :-/ */ @@ -92,7 +79,7 @@ _dbus_message_handler_add_connection (DBusMessageHandler *handler, else res = TRUE; - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); return res; } @@ -106,10 +93,10 @@ void _dbus_message_handler_remove_connection (DBusMessageHandler *handler, DBusConnection *connection) { - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); if (!_dbus_list_remove (&handler->connections, connection)) _dbus_warn ("Function _dbus_message_handler_remove_connection() called when the connection hadn't been added\n"); - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); } @@ -131,10 +118,10 @@ _dbus_message_handler_handle_message (DBusMessageHandler *handler, DBusHandleMessageFunction function; void *user_data; - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); function = handler->function; user_data = handler->user_data; - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); /* This function doesn't ref handler/connection/message * since that's done in dbus_connection_dispatch(). @@ -205,11 +192,11 @@ dbus_message_handler_new (DBusHandleMessageFunction function, void dbus_message_handler_ref (DBusMessageHandler *handler) { - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); _dbus_assert (handler != NULL); handler->refcount += 1; - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); } /** @@ -223,7 +210,7 @@ dbus_message_handler_unref (DBusMessageHandler *handler) { int refcount; - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); _dbus_assert (handler != NULL); _dbus_assert (handler->refcount > 0); @@ -231,7 +218,7 @@ dbus_message_handler_unref (DBusMessageHandler *handler) handler->refcount -= 1; refcount = handler->refcount; - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); if (refcount == 0) { @@ -267,9 +254,9 @@ void* dbus_message_handler_get_data (DBusMessageHandler *handler) { void* user_data; - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); user_data = handler->user_data; - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); return user_data; } @@ -290,13 +277,13 @@ dbus_message_handler_set_data (DBusMessageHandler *handler, DBusFreeFunction old_free_func; void *old_user_data; - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); old_free_func = handler->free_user_data; old_user_data = handler->user_data; handler->user_data = user_data; handler->free_user_data = free_user_data; - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); if (old_free_func) (* old_free_func) (old_user_data); @@ -314,9 +301,9 @@ void dbus_message_handler_set_function (DBusMessageHandler *handler, DBusHandleMessageFunction function) { - dbus_mutex_lock (message_handler_lock); + _DBUS_LOCK (message_handler); handler->function = function; - dbus_mutex_unlock (message_handler_lock); + _DBUS_UNLOCK (message_handler); } /** @} */ diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index ba48cd97..e717096e 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -589,21 +589,7 @@ dbus_server_get_n_connections (DBusServer *server) static DBusDataSlotAllocator slot_allocator; - -/** - * Initialize the mutex used for #DBusConnection data - * slot reservations. - * - * @returns the mutex - */ -DBusMutex * -_dbus_server_slots_init_lock (void) -{ - if (!_dbus_data_slot_allocator_init (&slot_allocator)) - return NULL; - else - return slot_allocator.lock; -} +_DBUS_DEFINE_GLOBAL_LOCK (server_slots); /** * Allocates an integer ID to be used for storing application-specific @@ -618,7 +604,8 @@ _dbus_server_slots_init_lock (void) int dbus_server_allocate_data_slot (void) { - return _dbus_data_slot_allocator_alloc (&slot_allocator); + return _dbus_data_slot_allocator_alloc (&slot_allocator, + _DBUS_LOCK_NAME (server_slots)); } /** diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 200fbddd..948b0836 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1232,17 +1232,22 @@ _dbus_credentials_from_user_id (unsigned long user_id, return get_user_info (NULL, user_id, credentials, NULL, NULL); } -static DBusMutex *user_info_lock = NULL; -/** - * Initializes the global mutex for the process's user information. - * - * @returns the mutex - */ -DBusMutex * -_dbus_user_info_init_lock (void) +_DBUS_DEFINE_GLOBAL_LOCK (user_info); + +typedef struct { - user_info_lock = dbus_mutex_new (); - return user_info_lock; + DBusString name; + DBusString dir; + DBusCredentials creds; +} UserInfo; + +static void +shutdown_user_info (void *data) +{ + UserInfo *u = data; + + _dbus_string_free (&u->name); + _dbus_string_free (&u->dir); } /** @@ -1258,53 +1263,58 @@ _dbus_user_info_from_current_process (const DBusString **username, const DBusString **homedir, const DBusCredentials **credentials) { - static DBusString name; - static DBusString dir; - static DBusCredentials creds; - static dbus_bool_t initialized = FALSE; + static UserInfo u; + static int initialized_generation = 0; - if (!dbus_mutex_lock (user_info_lock)) + if (!_DBUS_LOCK (user_info)) return FALSE; - if (!initialized) + if (initialized_generation != _dbus_current_generation) { - if (!_dbus_string_init (&name, _DBUS_INT_MAX)) + if (!_dbus_string_init (&u.name, _DBUS_INT_MAX)) { - dbus_mutex_unlock (user_info_lock); + _DBUS_UNLOCK (user_info); return FALSE; } - if (!_dbus_string_init (&dir, _DBUS_INT_MAX)) + if (!_dbus_string_init (&u.dir, _DBUS_INT_MAX)) { - _dbus_string_free (&name); - dbus_mutex_unlock (user_info_lock); + _dbus_string_free (&u.name); + _DBUS_UNLOCK (user_info); return FALSE; } - creds.uid = -1; - creds.gid = -1; - creds.pid = -1; + u.creds.uid = -1; + u.creds.gid = -1; + u.creds.pid = -1; if (!get_user_info (NULL, getuid (), - &creds, &dir, &name)) + &u.creds, &u.dir, &u.name)) + goto fail_init; + + if (!_dbus_register_shutdown_func (shutdown_user_info, + &u)) + goto fail_init; + + initialized_generation = _dbus_current_generation; + fail_init: + if (initialized_generation != _dbus_current_generation) { - _dbus_string_free (&name); - _dbus_string_free (&dir); - dbus_mutex_unlock (user_info_lock); + _dbus_string_free (&u.name); + _dbus_string_free (&u.dir); + _DBUS_UNLOCK (user_info); return FALSE; } - - initialized = TRUE; } if (username) - *username = &name; + *username = &u.name; if (homedir) - *homedir = &dir; + *homedir = &u.dir; if (credentials) - *credentials = &creds; + *credentials = &u.creds; - dbus_mutex_unlock (user_info_lock); + _DBUS_UNLOCK (user_info); return TRUE; } @@ -1594,19 +1604,7 @@ _dbus_string_append_our_uid (DBusString *str) } -static DBusMutex *atomic_lock = NULL; -/** - * Initializes the global mutex for the fallback implementation - * of atomic integers. - * - * @returns the mutex - */ -DBusMutex * -_dbus_atomic_init_lock (void) -{ - atomic_lock = dbus_mutex_new (); - return atomic_lock; -} +_DBUS_DEFINE_GLOBAL_LOCK (atomic); /** * Atomically increments an integer @@ -1621,10 +1619,10 @@ _dbus_atomic_inc (dbus_atomic_t *atomic) { dbus_atomic_t res; - dbus_mutex_lock (atomic_lock); + _DBUS_LOCK (atomic); *atomic += 1; res = *atomic; - dbus_mutex_unlock (atomic_lock); + _DBUS_UNLOCK (atomic); return res; } @@ -1641,10 +1639,10 @@ _dbus_atomic_dec (dbus_atomic_t *atomic) { dbus_atomic_t res; - dbus_mutex_lock (atomic_lock); + _DBUS_LOCK (atomic); *atomic -= 1; res = *atomic; - dbus_mutex_unlock (atomic_lock); + _DBUS_UNLOCK (atomic); return res; } diff --git a/dbus/dbus-test-main.c b/dbus/dbus-test-main.c index 6275d61a..0c607ec8 100644 --- a/dbus/dbus-test-main.c +++ b/dbus/dbus-test-main.c @@ -39,5 +39,6 @@ main (int argc, test_data_dir = NULL; dbus_internal_do_not_use_run_tests (test_data_dir); + return 0; } diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 466e8b84..34160116 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -24,15 +24,18 @@ #include #include "dbus-test.h" #include "dbus-sysdeps.h" +#include "dbus-internals.h" #include #include +#ifdef DBUS_BUILD_TESTS static void die (const char *failure) { fprintf (stderr, "Unit test failed: %s\n", failure); exit (1); } +#endif /* DBUS_BUILD_TESTS */ /** * An exported symbol to be run in order to execute @@ -58,7 +61,7 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) printf ("%s: running string tests\n", "dbus-test"); if (!_dbus_string_test ()) die ("strings"); - + printf ("%s: running data slot tests\n", "dbus-test"); if (!_dbus_data_slot_test ()) die ("dataslot"); @@ -96,7 +99,7 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) printf ("%s: running memory pool tests\n", "dbus-test"); if (!_dbus_mem_pool_test ()) die ("memory pools"); - + printf ("%s: running linked list tests\n", "dbus-test"); if (!_dbus_list_test ()) die ("lists"); @@ -104,11 +107,21 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) printf ("%s: running hash table tests\n", "dbus-test"); if (!_dbus_hash_test ()) die ("hash tables"); - + printf ("%s: running dict tests\n", "dbus-test"); if (!_dbus_dict_test ()) die ("dicts"); + dbus_shutdown (); + + printf ("%s: checking for memleaks\n", "dbus-test"); + if (_dbus_get_malloc_blocks_outstanding () != 0) + { + _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_get_malloc_blocks_outstanding ()); + die ("memleaks"); + } + printf ("%s: completed successfully\n", "dbus-test"); #else printf ("Not compiled with unit tests, not running any\n"); diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index ec83180d..d481479b 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -32,12 +32,21 @@ static DBusThreadFunctions thread_functions = NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +static int thread_init_generation = 0; /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */ -#define _DBUS_DUMMY_MUTEX ((void*)0xABCDEF) +#ifdef DBUS_BUILD_TESTS +#define _DBUS_DUMMY_MUTEX_NEW ((DBusMutex*)_dbus_strdup ("FakeMutex")) +#else +#define _DBUS_DUMMY_MUTEX_NEW ((DBusMutex*)0xABCDEF) +#endif /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */ -#define _DBUS_DUMMY_CONDVAR ((void*)0xABCDEF2) +#ifdef DBUS_BUILD_TESTS +#define _DBUS_DUMMY_CONDVAR_NEW ((DBusCondVar*)_dbus_strdup ("FakeCondvar")) +#else +#define _DBUS_DUMMY_CONDVAR_NEW ((DBusCondVar*)0xABCDEF2) +#endif /** * @defgroup DBusThreads Thread functions @@ -63,7 +72,7 @@ dbus_mutex_new (void) if (thread_functions.mutex_new) return (* thread_functions.mutex_new) (); else - return _DBUS_DUMMY_MUTEX; + return _DBUS_DUMMY_MUTEX_NEW; } /** @@ -75,6 +84,11 @@ dbus_mutex_free (DBusMutex *mutex) { if (mutex && thread_functions.mutex_free) (* thread_functions.mutex_free) (mutex); +#ifdef DBUS_BUILD_TESTS + /* Free the fake mutex */ + else + dbus_free (mutex); +#endif } /** @@ -120,7 +134,7 @@ dbus_condvar_new (void) if (thread_functions.condvar_new) return (* thread_functions.condvar_new) (); else - return _DBUS_DUMMY_MUTEX; + return _DBUS_DUMMY_CONDVAR_NEW; } /** @@ -132,6 +146,11 @@ dbus_condvar_free (DBusCondVar *cond) { if (cond && thread_functions.condvar_free) (* thread_functions.condvar_free) (cond); +#ifdef DBUS_BUILD_TESTS + else + /* Free the fake condvar */ + dbus_free (cond); +#endif } /** @@ -195,37 +214,77 @@ dbus_condvar_wake_all (DBusCondVar *cond) (* thread_functions.condvar_wake_all) (cond); } +static void +shutdown_global_locks (void *data) +{ + DBusMutex ***locks = data; + int i; + + i = 0; + while (i < _DBUS_N_GLOBAL_LOCKS) + { + dbus_mutex_free (*(locks[i])); + *(locks[i]) = NULL; + ++i; + } + + dbus_free (locks); +} + static dbus_bool_t -init_static_locks(void) +init_global_locks (void) { int i; + DBusMutex ***dynamic_global_locks; - struct { - DBusMutex *(*init_func)(void); - DBusMutex *mutex; - } static_locks[] = { - {&_dbus_list_init_lock}, - {&_dbus_server_slots_init_lock}, - {&_dbus_connection_slots_init_lock}, - {&_dbus_atomic_init_lock}, - {&_dbus_message_handler_init_lock}, - {&_dbus_user_info_init_lock}, - {&_dbus_bus_init_lock} + DBusMutex **global_locks[] = { +#define LOCK_ADDR(name) (& _dbus_lock_##name) + LOCK_ADDR (list), + LOCK_ADDR (connection_slots), + LOCK_ADDR (server_slots), + LOCK_ADDR (atomic), + LOCK_ADDR (message_handler), + LOCK_ADDR (user_info), + LOCK_ADDR (bus) +#undef LOCK_ADDR }; + + _dbus_assert (_DBUS_N_ELEMENTS (global_locks) == + _DBUS_N_GLOBAL_LOCKS); + + i = 0; - for (i = 0; i < _DBUS_N_ELEMENTS (static_locks); i++) + dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS); + if (dynamic_global_locks == NULL) + goto failed; + + while (i < _DBUS_N_ELEMENTS (global_locks)) { - static_locks[i].mutex = (*static_locks[i].init_func)(); - - if (static_locks[i].mutex == NULL) - { - for (i = i - 1; i >= 0; i--) - dbus_mutex_free (static_locks[i].mutex); - return FALSE; - } + *global_locks[i] = dbus_mutex_new (); + if (*global_locks[i] == NULL) + goto failed; + + dynamic_global_locks[i] = global_locks[i]; + + ++i; } + + if (!_dbus_register_shutdown_func (shutdown_global_locks, + dynamic_global_locks)) + goto failed; + return TRUE; + + failed: + dbus_free (dynamic_global_locks); + + for (i = i - 1; i >= 0; i--) + { + dbus_mutex_free (*global_locks[i]); + *global_locks[i] = NULL; + } + return FALSE; } @@ -276,6 +335,9 @@ dbus_threads_init (const DBusThreadFunctions *functions) * new bits. */ _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0); + + if (thread_init_generation != _dbus_current_generation) + thread_functions.mask = 0; /* allow re-init in new generation */ if (thread_functions.mask != 0) { @@ -297,8 +359,10 @@ dbus_threads_init (const DBusThreadFunctions *functions) thread_functions.mask = functions->mask; - if (!init_static_locks ()) + if (!init_global_locks ()) return FALSE; + + thread_init_generation = _dbus_current_generation; return TRUE; } -- cgit