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
This commit is contained in:
Havoc Pennington 2003-03-24 03:16:58 +00:00
parent a26607ab68
commit c3af5ccdbc
18 changed files with 511 additions and 235 deletions

View file

@ -1,3 +1,27 @@
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

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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));
}
/**

View file

@ -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;
if (allocator->n_used_slots == 0)
{
dbus_free (allocator->allocated_slots);
allocator->allocated_slots = NULL;
allocator->n_allocated_slots = 0;
}
_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);
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_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;
}

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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
@ -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 (&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;
}
/** @} */

View file

@ -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 */

View file

@ -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);
}
/** @} */

View file

@ -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));
}
/**

View file

@ -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;
}

View file

@ -39,5 +39,6 @@ main (int argc,
test_data_dir = NULL;
dbus_internal_do_not_use_run_tests (test_data_dir);
return 0;
}

View file

@ -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");

View file

@ -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;
}