Cleanup: polish verbose mode checking
[platform/upstream/dbus.git] / dbus / dbus-dataslot.c
index 46e2bfc..e37c9dd 100644 (file)
@@ -1,9 +1,9 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-dataslot.c  storing data on objects
  *
  * Copyright (C) 2003 Red Hat, Inc.
  *
- * Licensed under the Academic Free License version 1.2
+ * Licensed under the Academic Free License version 2.1
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * 
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+#include <config.h>
 #include "dbus-dataslot.h"
-#include "dbus-threads.h"
+#include "dbus-threads-internal.h"
 
 /**
  * @defgroup DBusDataSlot Data slots
  * @param allocator the allocator to initialize
  */
 dbus_bool_t
-_dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator)
+_dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator,
+                                DBusGlobalLock         lock)
 {
   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 = lock;
+
+  return TRUE;
 }
 
 /**
  * Allocates an integer ID to be used for storing data
- * in a #DBusDataSlotList.
- *
- * @todo all over the code we have foo_slot and foo_slot_refcount,
- * would be better to add an interface for that to
- * DBusDataSlotAllocator so it isn't cut-and-pasted everywhere.
+ * in a #DBusDataSlotList. If the value at *slot_id_p is
+ * not -1, this function just increments the refcount for
+ * the existing slot ID. If the value is -1, a new slot ID
+ * is allocated and stored at *slot_id_p.
  * 
  * @param allocator the allocator
- * @returns the integer ID, or -1 on failure
+ * @param slot_id_p address to fill with the slot ID
+ * @returns #TRUE on success
  */
-int
-_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator)
+dbus_bool_t
+_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
+                                 dbus_int32_t          *slot_id_p)
 {
-  int slot;
-  
-  if (!dbus_mutex_lock (allocator->lock))
-    return -1;
+  dbus_int32_t slot;
+
+  if (!_dbus_lock (allocator->lock))
+    return FALSE;
+
+  if (*slot_id_p >= 0)
+    {
+      slot = *slot_id_p;
+      
+      _dbus_assert (slot < allocator->n_allocated_slots);
+      _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+      
+      allocator->allocated_slots[slot].refcount += 1;
 
+      goto out;
+    }
+
+  _dbus_assert (*slot_id_p < 0);
+  
   if (allocator->n_used_slots < allocator->n_allocated_slots)
     {
       slot = 0;
       while (slot < allocator->n_allocated_slots)
         {
-          if (allocator->allocated_slots[slot] < 0)
+          if (allocator->allocated_slots[slot].slot_id < 0)
             {
-              allocator->allocated_slots[slot] = slot;
+              allocator->allocated_slots[slot].slot_id = slot;
+              allocator->allocated_slots[slot].refcount = 1;
               allocator->n_used_slots += 1;
               break;
             }
@@ -90,11 +107,11 @@ _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator)
     }
   else
     {
-      int *tmp;
+      DBusAllocatedSlot *tmp;
       
       slot = -1;
       tmp = dbus_realloc (allocator->allocated_slots,
-                          sizeof (int) * (allocator->n_allocated_slots + 1));
+                          sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1));
       if (tmp == NULL)
         goto out;
 
@@ -102,42 +119,66 @@ _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator)
       slot = allocator->n_allocated_slots;
       allocator->n_allocated_slots += 1;
       allocator->n_used_slots += 1;
-      allocator->allocated_slots[slot] = slot;
+      allocator->allocated_slots[slot].slot_id = slot;
+      allocator->allocated_slots[slot].refcount = 1;
     }
 
   _dbus_assert (slot >= 0);
   _dbus_assert (slot < allocator->n_allocated_slots);
-
+  _dbus_assert (*slot_id_p < 0);
+  _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+  _dbus_assert (allocator->allocated_slots[slot].refcount == 1);
+  
+  *slot_id_p = slot;
+  
   _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n",
                  slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
   
  out:
-  dbus_mutex_unlock (allocator->lock);
-  return slot;
+  _dbus_unlock (allocator->lock);
+  return slot >= 0;
 }
 
 /**
  * Deallocates an ID previously allocated with
  * _dbus_data_slot_allocator_alloc().  Existing data stored on
- * existing #DBusDataList objects with this ID will be freed when the
+ * existing #DBusDataSlotList objects with this ID will be freed when the
  * data list is finalized, but may not be retrieved (and may only be
  * replaced if someone else reallocates the slot).
+ * The slot value is reset to -1 if this is the last unref.
  *
  * @param allocator the allocator
- * @param slot the slot to deallocate
+ * @param slot_id_p address where we store the slot
  */
 void
 _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
-                                int slot)
+                                dbus_int32_t          *slot_id_p)
 {
-  dbus_mutex_lock (allocator->lock);
+  if (!_dbus_lock (allocator->lock))
+    _dbus_assert_not_reached ("we should have initialized global locks "
+        "before we allocated this slot");
 
-  _dbus_assert (slot < allocator->n_allocated_slots);
-  _dbus_assert (allocator->allocated_slots[slot] == slot);
+  _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
+  _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
+  _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0);
+
+  allocator->allocated_slots[*slot_id_p].refcount -= 1;
+
+  if (allocator->allocated_slots[*slot_id_p].refcount > 0)
+    {
+      _dbus_unlock (allocator->lock);
+      return;
+    }
+
+  /* refcount is 0, free the slot */
+  _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n",
+                 *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
+  
+  allocator->allocated_slots[*slot_id_p].slot_id = -1;
+  *slot_id_p = -1;
   
-  allocator->allocated_slots[slot] = -1;
   allocator->n_used_slots -= 1;
-
+  
   if (allocator->n_used_slots == 0)
     {
       dbus_free (allocator->allocated_slots);
@@ -145,10 +186,7 @@ _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
       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);
+  _dbus_unlock (allocator->lock);
 }
 
 /**
@@ -193,11 +231,13 @@ _dbus_data_slot_list_set  (DBusDataSlotAllocator *allocator,
    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
    * are disabled, since then the asserts are empty.
    */
-  if (!dbus_mutex_lock (allocator->lock))
-    return FALSE;
+  if (!_dbus_lock (allocator->lock))
+    _dbus_assert_not_reached ("we should have initialized global locks "
+        "before we allocated this slot");
+
   _dbus_assert (slot < allocator->n_allocated_slots);
-  _dbus_assert (allocator->allocated_slots[slot] == slot);
-  dbus_mutex_unlock (allocator->lock);
+  _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+  _dbus_unlock (allocator->lock);
 #endif
   
   if (slot >= list->n_slots)
@@ -251,12 +291,14 @@ _dbus_data_slot_list_get  (DBusDataSlotAllocator *allocator,
    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
    * are disabled, since then the asserts are empty.
    */
-  if (!dbus_mutex_lock (allocator->lock))
-    return FALSE;
+  if (!_dbus_lock (allocator->lock))
+    _dbus_assert_not_reached ("we should have initialized global locks "
+        "before we allocated this slot");
+
   _dbus_assert (slot >= 0);
   _dbus_assert (slot < allocator->n_allocated_slots);
-  _dbus_assert (allocator->allocated_slots[slot] == slot);
-  dbus_mutex_unlock (allocator->lock);
+  _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
+  _dbus_unlock (allocator->lock);
 #endif
 
   if (slot >= list->n_slots)
@@ -266,14 +308,13 @@ _dbus_data_slot_list_get  (DBusDataSlotAllocator *allocator,
 }
 
 /**
- * Frees the data slot list and all data slots contained
- * in it, calling application-provided free functions
- * if they exist.
+ * Frees all data slots contained in the list, calling
+ * application-provided free functions if they exist.
  *
- * @param list the list to free
+ * @param list the list to clear
  */
 void
-_dbus_data_slot_list_free (DBusDataSlotList *list)
+_dbus_data_slot_list_clear (DBusDataSlotList *list)
 {
   int i;
 
@@ -286,7 +327,20 @@ _dbus_data_slot_list_free (DBusDataSlotList *list)
       list->slots[i].free_data_func = NULL;
       ++i;
     }
+}
 
+/**
+ * Frees the data slot list and all data slots contained
+ * in it, calling application-provided free functions
+ * if they exist.
+ *
+ * @param list the list to free
+ */
+void
+_dbus_data_slot_list_free (DBusDataSlotList *list)
+{
+  _dbus_data_slot_list_clear (list);
+  
   dbus_free (list->slots);
   list->slots = NULL;
   list->n_slots = 0;
@@ -294,7 +348,7 @@ _dbus_data_slot_list_free (DBusDataSlotList *list)
 
 /** @} */
 
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
 #include "dbus-test.h"
 #include <stdio.h>
 
@@ -320,8 +374,8 @@ _dbus_data_slot_test (void)
   int i;
   DBusFreeFunction old_free_func;
   void *old_data;
-  
-  if (!_dbus_data_slot_allocator_init (&allocator))
+
+  if (!_dbus_data_slot_allocator_init (&allocator, _DBUS_LOCK_server_slots))
     _dbus_assert_not_reached ("no memory for allocator");
 
   _dbus_data_slot_list_init (&list);
@@ -335,7 +389,11 @@ _dbus_data_slot_test (void)
        * allocation, but it simplifies things to rely on it
        * here.
        */
-      if (_dbus_data_slot_allocator_alloc (&allocator) != i)
+      dbus_int32_t tmp = -1;
+
+      _dbus_data_slot_allocator_alloc (&allocator, &tmp);
+
+      if (tmp != i)
         _dbus_assert_not_reached ("did not allocate slots in numeric order\n");
 
       ++i;
@@ -391,11 +449,14 @@ _dbus_data_slot_test (void)
   i = 0;
   while (i < N_SLOTS)
     {
-      _dbus_data_slot_allocator_free (&allocator, i);
+      dbus_int32_t tmp = i;
+      
+      _dbus_data_slot_allocator_free (&allocator, &tmp);
+      _dbus_assert (tmp == -1);
       ++i;
     }
-  
+
   return TRUE;
 }
 
-#endif /* DBUS_BUILD_TESTS */
+#endif /* DBUS_ENABLE_EMBEDDED_TESTS */