Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

dbus-dataslot.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-dataslot.c  storing data on objects
00003  *
00004  * Copyright (C) 2003 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.0
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include "dbus-dataslot.h"
00024 #include "dbus-threads.h"
00025 
00043 dbus_bool_t
00044 _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator)
00045 {
00046   allocator->allocated_slots = NULL;
00047   allocator->n_allocated_slots = 0;
00048   allocator->n_used_slots = 0;
00049   allocator->lock = NULL;
00050   
00051   return TRUE;
00052 }
00053 
00066 dbus_bool_t
00067 _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
00068                                  DBusMutex             *mutex,
00069                                  dbus_int32_t          *slot_id_p)
00070 {
00071   dbus_int32_t slot;
00072 
00073   if (!dbus_mutex_lock (mutex))
00074     return FALSE;
00075 
00076   if (allocator->n_allocated_slots == 0)
00077     {
00078       _dbus_assert (allocator->lock == NULL);
00079       allocator->lock = mutex;
00080     }
00081   else
00082     _dbus_assert (allocator->lock == mutex);
00083 
00084   if (*slot_id_p >= 0)
00085     {
00086       slot = *slot_id_p;
00087       
00088       _dbus_assert (slot < allocator->n_allocated_slots);
00089       _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00090       
00091       allocator->allocated_slots[slot].refcount += 1;
00092 
00093       goto out;
00094     }
00095 
00096   _dbus_assert (*slot_id_p < 0);
00097   
00098   if (allocator->n_used_slots < allocator->n_allocated_slots)
00099     {
00100       slot = 0;
00101       while (slot < allocator->n_allocated_slots)
00102         {
00103           if (allocator->allocated_slots[slot].slot_id < 0)
00104             {
00105               allocator->allocated_slots[slot].slot_id = slot;
00106               allocator->allocated_slots[slot].refcount = 1;
00107               allocator->n_used_slots += 1;
00108               break;
00109             }
00110           ++slot;
00111         }
00112 
00113       _dbus_assert (slot < allocator->n_allocated_slots);
00114     }
00115   else
00116     {
00117       DBusAllocatedSlot *tmp;
00118       
00119       slot = -1;
00120       tmp = dbus_realloc (allocator->allocated_slots,
00121                           sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1));
00122       if (tmp == NULL)
00123         goto out;
00124 
00125       allocator->allocated_slots = tmp;
00126       slot = allocator->n_allocated_slots;
00127       allocator->n_allocated_slots += 1;
00128       allocator->n_used_slots += 1;
00129       allocator->allocated_slots[slot].slot_id = slot;
00130       allocator->allocated_slots[slot].refcount = 1;
00131     }
00132 
00133   _dbus_assert (slot >= 0);
00134   _dbus_assert (slot < allocator->n_allocated_slots);
00135   _dbus_assert (*slot_id_p < 0);
00136   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00137   _dbus_assert (allocator->allocated_slots[slot].refcount == 1);
00138   
00139   *slot_id_p = slot;
00140   
00141   _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n",
00142                  slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00143   
00144  out:
00145   dbus_mutex_unlock (allocator->lock);
00146   return slot >= 0;
00147 }
00148 
00160 void
00161 _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
00162                                 dbus_int32_t          *slot_id_p)
00163 {
00164   dbus_mutex_lock (allocator->lock);
00165   
00166   _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
00167   _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
00168   _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0);
00169 
00170   allocator->allocated_slots[*slot_id_p].refcount -= 1;
00171 
00172   if (allocator->allocated_slots[*slot_id_p].refcount > 0)
00173     {
00174       dbus_mutex_unlock (allocator->lock);
00175       return;
00176     }
00177 
00178   /* refcount is 0, free the slot */
00179   _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n",
00180                  *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00181   
00182   allocator->allocated_slots[*slot_id_p].slot_id = -1;
00183   *slot_id_p = -1;
00184   
00185   allocator->n_used_slots -= 1;
00186   
00187   if (allocator->n_used_slots == 0)
00188     {
00189       DBusMutex *mutex = allocator->lock;
00190       
00191       dbus_free (allocator->allocated_slots);
00192       allocator->allocated_slots = NULL;
00193       allocator->n_allocated_slots = 0;
00194       allocator->lock = NULL;
00195 
00196       dbus_mutex_unlock (mutex);
00197     }
00198   else
00199     {
00200       dbus_mutex_unlock (allocator->lock);
00201     }
00202 }
00203 
00208 void
00209 _dbus_data_slot_list_init (DBusDataSlotList *list)
00210 {
00211   list->slots = NULL;
00212   list->n_slots = 0;
00213 }
00214 
00232 dbus_bool_t
00233 _dbus_data_slot_list_set  (DBusDataSlotAllocator *allocator,
00234                            DBusDataSlotList      *list,
00235                            int                    slot,
00236                            void                  *data,
00237                            DBusFreeFunction       free_data_func,
00238                            DBusFreeFunction      *old_free_func,
00239                            void                 **old_data)
00240 {
00241 #ifndef DBUS_DISABLE_ASSERT
00242   /* We need to take the allocator lock here, because the allocator could
00243    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
00244    * are disabled, since then the asserts are empty.
00245    */
00246   if (!dbus_mutex_lock (allocator->lock))
00247     return FALSE;
00248   _dbus_assert (slot < allocator->n_allocated_slots);
00249   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00250   dbus_mutex_unlock (allocator->lock);
00251 #endif
00252   
00253   if (slot >= list->n_slots)
00254     {
00255       DBusDataSlot *tmp;
00256       int i;
00257       
00258       tmp = dbus_realloc (list->slots,
00259                           sizeof (DBusDataSlot) * (slot + 1));
00260       if (tmp == NULL)
00261         return FALSE;
00262       
00263       list->slots = tmp;
00264       i = list->n_slots;
00265       list->n_slots = slot + 1;
00266       while (i < list->n_slots)
00267         {
00268           list->slots[i].data = NULL;
00269           list->slots[i].free_data_func = NULL;
00270           ++i;
00271         }
00272     }
00273 
00274   _dbus_assert (slot < list->n_slots);
00275 
00276   *old_data = list->slots[slot].data;
00277   *old_free_func = list->slots[slot].free_data_func;
00278 
00279   list->slots[slot].data = data;
00280   list->slots[slot].free_data_func = free_data_func;
00281 
00282   return TRUE;
00283 }
00284 
00294 void*
00295 _dbus_data_slot_list_get  (DBusDataSlotAllocator *allocator,
00296                            DBusDataSlotList      *list,
00297                            int                    slot)
00298 {
00299 #ifndef DBUS_DISABLE_ASSERT
00300   /* We need to take the allocator lock here, because the allocator could
00301    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
00302    * are disabled, since then the asserts are empty.
00303    */
00304   if (!dbus_mutex_lock (allocator->lock))
00305     return FALSE;
00306   _dbus_assert (slot >= 0);
00307   _dbus_assert (slot < allocator->n_allocated_slots);
00308   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00309   dbus_mutex_unlock (allocator->lock);
00310 #endif
00311 
00312   if (slot >= list->n_slots)
00313     return NULL;
00314   else
00315     return list->slots[slot].data;
00316 }
00317 
00325 void
00326 _dbus_data_slot_list_free (DBusDataSlotList *list)
00327 {
00328   int i;
00329 
00330   i = 0;
00331   while (i < list->n_slots)
00332     {
00333       if (list->slots[i].free_data_func)
00334         (* list->slots[i].free_data_func) (list->slots[i].data);
00335       list->slots[i].data = NULL;
00336       list->slots[i].free_data_func = NULL;
00337       ++i;
00338     }
00339 
00340   dbus_free (list->slots);
00341   list->slots = NULL;
00342   list->n_slots = 0;
00343 }
00344 
00347 #ifdef DBUS_BUILD_TESTS
00348 #include "dbus-test.h"
00349 #include <stdio.h>
00350 
00351 static int free_counter;
00352 
00353 static void
00354 test_free_slot_data_func (void *data)
00355 {
00356   int i = _DBUS_POINTER_TO_INT (data);
00357 
00358   _dbus_assert (free_counter == i);
00359   ++free_counter;
00360 }
00361 
00365 dbus_bool_t
00366 _dbus_data_slot_test (void)
00367 {
00368   DBusDataSlotAllocator allocator;
00369   DBusDataSlotList list;
00370   int i;
00371   DBusFreeFunction old_free_func;
00372   void *old_data;
00373   DBusMutex *mutex;
00374   
00375   if (!_dbus_data_slot_allocator_init (&allocator))
00376     _dbus_assert_not_reached ("no memory for allocator");
00377 
00378   _dbus_data_slot_list_init (&list);
00379 
00380   mutex = dbus_mutex_new ();
00381   if (mutex == NULL)
00382     _dbus_assert_not_reached ("failed to alloc mutex");
00383   
00384 #define N_SLOTS 100
00385 
00386   i = 0;
00387   while (i < N_SLOTS)
00388     {
00389       /* we don't really want apps to rely on this ordered
00390        * allocation, but it simplifies things to rely on it
00391        * here.
00392        */
00393       dbus_int32_t tmp = -1;
00394       
00395       _dbus_data_slot_allocator_alloc (&allocator, mutex, &tmp);
00396 
00397       if (tmp != i)
00398         _dbus_assert_not_reached ("did not allocate slots in numeric order\n");
00399 
00400       ++i;
00401     }
00402 
00403   i = 0;
00404   while (i < N_SLOTS)
00405     {
00406       if (!_dbus_data_slot_list_set (&allocator, &list,
00407                                      i,
00408                                      _DBUS_INT_TO_POINTER (i), 
00409                                      test_free_slot_data_func,
00410                                      &old_free_func, &old_data))
00411         _dbus_assert_not_reached ("no memory to set data");
00412 
00413       _dbus_assert (old_free_func == NULL);
00414       _dbus_assert (old_data == NULL);
00415 
00416       _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00417                     _DBUS_INT_TO_POINTER (i));
00418       
00419       ++i;
00420     }
00421 
00422   free_counter = 0;
00423   i = 0;
00424   while (i < N_SLOTS)
00425     {
00426       if (!_dbus_data_slot_list_set (&allocator, &list,
00427                                      i,
00428                                      _DBUS_INT_TO_POINTER (i), 
00429                                      test_free_slot_data_func,
00430                                      &old_free_func, &old_data))
00431         _dbus_assert_not_reached ("no memory to set data");
00432 
00433       _dbus_assert (old_free_func == test_free_slot_data_func);
00434       _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i);
00435 
00436       (* old_free_func) (old_data);
00437       _dbus_assert (i == (free_counter - 1));
00438 
00439       _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00440                     _DBUS_INT_TO_POINTER (i));
00441       
00442       ++i;
00443     }
00444 
00445   free_counter = 0;
00446   _dbus_data_slot_list_free (&list);
00447 
00448   _dbus_assert (N_SLOTS == free_counter);
00449 
00450   i = 0;
00451   while (i < N_SLOTS)
00452     {
00453       dbus_int32_t tmp = i;
00454       
00455       _dbus_data_slot_allocator_free (&allocator, &tmp);
00456       _dbus_assert (tmp == -1);
00457       ++i;
00458     }
00459 
00460   dbus_mutex_free (mutex);
00461   
00462   return TRUE;
00463 }
00464 
00465 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Jun 9 05:01:25 2004 for D-BUS by doxygen1.2.15