Main Page | Modules | Data Structures | Directories | 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.1
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 
00324 void
00325 _dbus_data_slot_list_clear (DBusDataSlotList *list)
00326 {
00327   int i;
00328 
00329   i = 0;
00330   while (i < list->n_slots)
00331     {
00332       if (list->slots[i].free_data_func)
00333         (* list->slots[i].free_data_func) (list->slots[i].data);
00334       list->slots[i].data = NULL;
00335       list->slots[i].free_data_func = NULL;
00336       ++i;
00337     }
00338 }
00339 
00347 void
00348 _dbus_data_slot_list_free (DBusDataSlotList *list)
00349 {
00350   _dbus_data_slot_list_clear (list);
00351   
00352   dbus_free (list->slots);
00353   list->slots = NULL;
00354   list->n_slots = 0;
00355 }
00356 
00359 #ifdef DBUS_BUILD_TESTS
00360 #include "dbus-test.h"
00361 #include <stdio.h>
00362 
00363 static int free_counter;
00364 
00365 static void
00366 test_free_slot_data_func (void *data)
00367 {
00368   int i = _DBUS_POINTER_TO_INT (data);
00369 
00370   _dbus_assert (free_counter == i);
00371   ++free_counter;
00372 }
00373 
00377 dbus_bool_t
00378 _dbus_data_slot_test (void)
00379 {
00380   DBusDataSlotAllocator allocator;
00381   DBusDataSlotList list;
00382   int i;
00383   DBusFreeFunction old_free_func;
00384   void *old_data;
00385   DBusMutex *mutex;
00386   
00387   if (!_dbus_data_slot_allocator_init (&allocator))
00388     _dbus_assert_not_reached ("no memory for allocator");
00389 
00390   _dbus_data_slot_list_init (&list);
00391 
00392   mutex = dbus_mutex_new ();
00393   if (mutex == NULL)
00394     _dbus_assert_not_reached ("failed to alloc mutex");
00395   
00396 #define N_SLOTS 100
00397 
00398   i = 0;
00399   while (i < N_SLOTS)
00400     {
00401       /* we don't really want apps to rely on this ordered
00402        * allocation, but it simplifies things to rely on it
00403        * here.
00404        */
00405       dbus_int32_t tmp = -1;
00406       
00407       _dbus_data_slot_allocator_alloc (&allocator, mutex, &tmp);
00408 
00409       if (tmp != i)
00410         _dbus_assert_not_reached ("did not allocate slots in numeric order\n");
00411 
00412       ++i;
00413     }
00414 
00415   i = 0;
00416   while (i < N_SLOTS)
00417     {
00418       if (!_dbus_data_slot_list_set (&allocator, &list,
00419                                      i,
00420                                      _DBUS_INT_TO_POINTER (i), 
00421                                      test_free_slot_data_func,
00422                                      &old_free_func, &old_data))
00423         _dbus_assert_not_reached ("no memory to set data");
00424 
00425       _dbus_assert (old_free_func == NULL);
00426       _dbus_assert (old_data == NULL);
00427 
00428       _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00429                     _DBUS_INT_TO_POINTER (i));
00430       
00431       ++i;
00432     }
00433 
00434   free_counter = 0;
00435   i = 0;
00436   while (i < N_SLOTS)
00437     {
00438       if (!_dbus_data_slot_list_set (&allocator, &list,
00439                                      i,
00440                                      _DBUS_INT_TO_POINTER (i), 
00441                                      test_free_slot_data_func,
00442                                      &old_free_func, &old_data))
00443         _dbus_assert_not_reached ("no memory to set data");
00444 
00445       _dbus_assert (old_free_func == test_free_slot_data_func);
00446       _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i);
00447 
00448       (* old_free_func) (old_data);
00449       _dbus_assert (i == (free_counter - 1));
00450 
00451       _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00452                     _DBUS_INT_TO_POINTER (i));
00453       
00454       ++i;
00455     }
00456 
00457   free_counter = 0;
00458   _dbus_data_slot_list_free (&list);
00459 
00460   _dbus_assert (N_SLOTS == free_counter);
00461 
00462   i = 0;
00463   while (i < N_SLOTS)
00464     {
00465       dbus_int32_t tmp = i;
00466       
00467       _dbus_data_slot_allocator_free (&allocator, &tmp);
00468       _dbus_assert (tmp == -1);
00469       ++i;
00470     }
00471 
00472   dbus_mutex_free (mutex);
00473   
00474   return TRUE;
00475 }
00476 
00477 #endif /* DBUS_BUILD_TESTS */

Generated on Thu Aug 11 21:11:12 2005 for D-BUS by  doxygen 1.4.0