summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog24
-rw-r--r--bus/policy.c10
-rw-r--r--bus/test-main.c11
-rw-r--r--dbus/dbus-bus.c24
-rw-r--r--dbus/dbus-connection.c19
-rw-r--r--dbus/dbus-dataslot.c54
-rw-r--r--dbus/dbus-dataslot.h33
-rw-r--r--dbus/dbus-internals.c35
-rw-r--r--dbus/dbus-internals.h41
-rw-r--r--dbus/dbus-list.c24
-rw-r--r--dbus/dbus-memory.c161
-rw-r--r--dbus/dbus-memory.h2
-rw-r--r--dbus/dbus-message-handler.c47
-rw-r--r--dbus/dbus-server.c19
-rw-r--r--dbus/dbus-sysdeps.c100
-rw-r--r--dbus/dbus-test-main.c1
-rw-r--r--dbus/dbus-test.c19
-rw-r--r--dbus/dbus-threads.c116
18 files changed, 508 insertions, 232 deletions
diff --git a/ChangeLog b/ChangeLog
index aad1a71f..3db6d96f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
2003-03-23 Havoc Pennington <hp@pobox.com>
+ * 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
+
+2003-03-23 Havoc Pennington <hp@pobox.com>
+
* bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny
policies code
diff --git a/bus/policy.c b/bus/policy.c
index 015757a0..75013c85 100644
--- a/bus/policy.c
+++ b/bus/policy.c
@@ -73,6 +73,10 @@ bus_policy_rule_unref (BusPolicyRule *rule)
case BUS_POLICY_RULE_OWN:
dbus_free (rule->d.own.service_name);
break;
+ case BUS_POLICY_RULE_USER:
+ case BUS_POLICY_RULE_GROUP:
+ _dbus_assert_not_reached ("invalid rule");
+ break;
}
dbus_free (rule);
@@ -203,6 +207,10 @@ bus_policy_optimize (BusPolicy *policy)
remove_preceding =
rule->d.own.service_name == NULL;
break;
+ case BUS_POLICY_RULE_USER:
+ case BUS_POLICY_RULE_GROUP:
+ _dbus_assert_not_reached ("invalid rule");
+ break;
}
if (remove_preceding)
@@ -220,7 +228,7 @@ dbus_bool_t
bus_policy_append_rule (BusPolicy *policy,
BusPolicyRule *rule)
{
- if (!_dbus_list_append (policy->rules, rule))
+ if (!_dbus_list_append (&policy->rules, rule))
return FALSE;
bus_policy_rule_ref (rule);
diff --git a/bus/test-main.c b/bus/test-main.c
index 278e4a88..2e0b952e 100644
--- a/bus/test-main.c
+++ b/bus/test-main.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <dbus/dbus-string.h>
#include <dbus/dbus-sysdeps.h>
+#include <dbus/dbus-internals.h>
static void
die (const char *failure)
@@ -55,6 +56,16 @@ main (int argc, char **argv)
if (!bus_dispatch_test (&test_data_dir))
die ("dispatch");
+ dbus_shutdown ();
+
+ printf ("%s: checking for memleaks\n", argv[0]);
+ 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: Success\n", argv[0]);
return 0;
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
@@ -128,6 +128,41 @@
*/
/**
+ * @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
* space.
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 <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 (&registered_globals);
+ while (link != NULL)
+ {
+ ShutdownClosure *c = link->data;
+
+ (* c->func) (c->data);
+
+ dbus_free (c);
+
+ link = _dbus_list_get_next_link (&registered_globals, link);
+ }
+
+ _dbus_list_clear (&registered_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 (&registered_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 <config.h>
#include "dbus-test.h"
#include "dbus-sysdeps.h"
+#include "dbus-internals.h"
#include <stdio.h>
#include <stdlib.h>
+#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;
}