diff options
| author | Havoc Pennington <hp@redhat.com> | 2003-03-24 03:16:58 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2003-03-24 03:16:58 +0000 | 
| commit | c3af5ccdbc22e8990d04ec2f89ad1f2e053655e9 (patch) | |
| tree | 6010b0b9a2be255b3ff3ac9f62e4c04ce57aef83 | |
| parent | a26607ab68bf0878f23d2dbddec781b4b760d034 (diff) | |
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
| -rw-r--r-- | ChangeLog | 24 | ||||
| -rw-r--r-- | bus/policy.c | 10 | ||||
| -rw-r--r-- | bus/test-main.c | 11 | ||||
| -rw-r--r-- | dbus/dbus-bus.c | 24 | ||||
| -rw-r--r-- | dbus/dbus-connection.c | 19 | ||||
| -rw-r--r-- | dbus/dbus-dataslot.c | 54 | ||||
| -rw-r--r-- | dbus/dbus-dataslot.h | 33 | ||||
| -rw-r--r-- | dbus/dbus-internals.c | 35 | ||||
| -rw-r--r-- | dbus/dbus-internals.h | 41 | ||||
| -rw-r--r-- | dbus/dbus-list.c | 24 | ||||
| -rw-r--r-- | dbus/dbus-memory.c | 161 | ||||
| -rw-r--r-- | dbus/dbus-memory.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-message-handler.c | 47 | ||||
| -rw-r--r-- | dbus/dbus-server.c | 19 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 100 | ||||
| -rw-r--r-- | dbus/dbus-test-main.c | 1 | ||||
| -rw-r--r-- | dbus/dbus-test.c | 19 | ||||
| -rw-r--r-- | dbus/dbus-threads.c | 116 | 
18 files changed, 508 insertions, 232 deletions
| @@ -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 (®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 <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;  } | 
