• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

dbus-dataslot.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-dataslot.h"
00026 #include "dbus-threads-internal.h"
00027 
00045 dbus_bool_t
00046 _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator)
00047 {
00048   allocator->allocated_slots = NULL;
00049   allocator->n_allocated_slots = 0;
00050   allocator->n_used_slots = 0;
00051   allocator->lock_loc = NULL;
00052   
00053   return TRUE;
00054 }
00055 
00068 dbus_bool_t
00069 _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
00070                                  DBusMutex             **mutex_loc,
00071                                  dbus_int32_t          *slot_id_p)
00072 {
00073   dbus_int32_t slot;
00074 
00075   _dbus_mutex_lock (*mutex_loc);
00076 
00077   if (allocator->n_allocated_slots == 0)
00078     {
00079       _dbus_assert (allocator->lock_loc == NULL);
00080       allocator->lock_loc = mutex_loc;
00081     }
00082   else if (allocator->lock_loc != mutex_loc)
00083     {
00084       _dbus_warn_check_failed ("D-Bus threads were initialized after first using the D-Bus library. If your application does not directly initialize threads or use D-Bus, keep in mind that some library or plugin may have used D-Bus or initialized threads behind your back. You can often fix this problem by calling dbus_init_threads() or dbus_g_threads_init() early in your main() method, before D-Bus is used.\n");
00085       _dbus_assert_not_reached ("exiting");
00086     }
00087 
00088   if (*slot_id_p >= 0)
00089     {
00090       slot = *slot_id_p;
00091       
00092       _dbus_assert (slot < allocator->n_allocated_slots);
00093       _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00094       
00095       allocator->allocated_slots[slot].refcount += 1;
00096 
00097       goto out;
00098     }
00099 
00100   _dbus_assert (*slot_id_p < 0);
00101   
00102   if (allocator->n_used_slots < allocator->n_allocated_slots)
00103     {
00104       slot = 0;
00105       while (slot < allocator->n_allocated_slots)
00106         {
00107           if (allocator->allocated_slots[slot].slot_id < 0)
00108             {
00109               allocator->allocated_slots[slot].slot_id = slot;
00110               allocator->allocated_slots[slot].refcount = 1;
00111               allocator->n_used_slots += 1;
00112               break;
00113             }
00114           ++slot;
00115         }
00116 
00117       _dbus_assert (slot < allocator->n_allocated_slots);
00118     }
00119   else
00120     {
00121       DBusAllocatedSlot *tmp;
00122       
00123       slot = -1;
00124       tmp = dbus_realloc (allocator->allocated_slots,
00125                           sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1));
00126       if (tmp == NULL)
00127         goto out;
00128 
00129       allocator->allocated_slots = tmp;
00130       slot = allocator->n_allocated_slots;
00131       allocator->n_allocated_slots += 1;
00132       allocator->n_used_slots += 1;
00133       allocator->allocated_slots[slot].slot_id = slot;
00134       allocator->allocated_slots[slot].refcount = 1;
00135     }
00136 
00137   _dbus_assert (slot >= 0);
00138   _dbus_assert (slot < allocator->n_allocated_slots);
00139   _dbus_assert (*slot_id_p < 0);
00140   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00141   _dbus_assert (allocator->allocated_slots[slot].refcount == 1);
00142   
00143   *slot_id_p = slot;
00144   
00145   _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n",
00146                  slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00147   
00148  out:
00149   _dbus_mutex_unlock (*(allocator->lock_loc));
00150   return slot >= 0;
00151 }
00152 
00164 void
00165 _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
00166                                 dbus_int32_t          *slot_id_p)
00167 {
00168   _dbus_mutex_lock (*(allocator->lock_loc));
00169   
00170   _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
00171   _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
00172   _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0);
00173 
00174   allocator->allocated_slots[*slot_id_p].refcount -= 1;
00175 
00176   if (allocator->allocated_slots[*slot_id_p].refcount > 0)
00177     {
00178       _dbus_mutex_unlock (*(allocator->lock_loc));
00179       return;
00180     }
00181 
00182   /* refcount is 0, free the slot */
00183   _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n",
00184                  *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00185   
00186   allocator->allocated_slots[*slot_id_p].slot_id = -1;
00187   *slot_id_p = -1;
00188   
00189   allocator->n_used_slots -= 1;
00190   
00191   if (allocator->n_used_slots == 0)
00192     {
00193       DBusMutex **mutex_loc = allocator->lock_loc;
00194       
00195       dbus_free (allocator->allocated_slots);
00196       allocator->allocated_slots = NULL;
00197       allocator->n_allocated_slots = 0;
00198       allocator->lock_loc = NULL;
00199 
00200       _dbus_mutex_unlock (*mutex_loc);
00201     }
00202   else
00203     {
00204       _dbus_mutex_unlock (*(allocator->lock_loc));
00205     }
00206 }
00207 
00212 void
00213 _dbus_data_slot_list_init (DBusDataSlotList *list)
00214 {
00215   list->slots = NULL;
00216   list->n_slots = 0;
00217 }
00218 
00236 dbus_bool_t
00237 _dbus_data_slot_list_set  (DBusDataSlotAllocator *allocator,
00238                            DBusDataSlotList      *list,
00239                            int                    slot,
00240                            void                  *data,
00241                            DBusFreeFunction       free_data_func,
00242                            DBusFreeFunction      *old_free_func,
00243                            void                 **old_data)
00244 {
00245 #ifndef DBUS_DISABLE_ASSERT
00246   /* We need to take the allocator lock here, because the allocator could
00247    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
00248    * are disabled, since then the asserts are empty.
00249    */
00250   _dbus_mutex_lock (*(allocator->lock_loc));
00251   _dbus_assert (slot < allocator->n_allocated_slots);
00252   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00253   _dbus_mutex_unlock (*(allocator->lock_loc));
00254 #endif
00255   
00256   if (slot >= list->n_slots)
00257     {
00258       DBusDataSlot *tmp;
00259       int i;
00260       
00261       tmp = dbus_realloc (list->slots,
00262                           sizeof (DBusDataSlot) * (slot + 1));
00263       if (tmp == NULL)
00264         return FALSE;
00265       
00266       list->slots = tmp;
00267       i = list->n_slots;
00268       list->n_slots = slot + 1;
00269       while (i < list->n_slots)
00270         {
00271           list->slots[i].data = NULL;
00272           list->slots[i].free_data_func = NULL;
00273           ++i;
00274         }
00275     }
00276 
00277   _dbus_assert (slot < list->n_slots);
00278 
00279   *old_data = list->slots[slot].data;
00280   *old_free_func = list->slots[slot].free_data_func;
00281 
00282   list->slots[slot].data = data;
00283   list->slots[slot].free_data_func = free_data_func;
00284 
00285   return TRUE;
00286 }
00287 
00297 void*
00298 _dbus_data_slot_list_get  (DBusDataSlotAllocator *allocator,
00299                            DBusDataSlotList      *list,
00300                            int                    slot)
00301 {
00302 #ifndef DBUS_DISABLE_ASSERT
00303   /* We need to take the allocator lock here, because the allocator could
00304    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
00305    * are disabled, since then the asserts are empty.
00306    */
00307   _dbus_mutex_lock (*(allocator->lock_loc));
00308   _dbus_assert (slot >= 0);
00309   _dbus_assert (slot < allocator->n_allocated_slots);
00310   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00311   _dbus_mutex_unlock (*(allocator->lock_loc));
00312 #endif
00313 
00314   if (slot >= list->n_slots)
00315     return NULL;
00316   else
00317     return list->slots[slot].data;
00318 }
00319 
00326 void
00327 _dbus_data_slot_list_clear (DBusDataSlotList *list)
00328 {
00329   int i;
00330 
00331   i = 0;
00332   while (i < list->n_slots)
00333     {
00334       if (list->slots[i].free_data_func)
00335         (* list->slots[i].free_data_func) (list->slots[i].data);
00336       list->slots[i].data = NULL;
00337       list->slots[i].free_data_func = NULL;
00338       ++i;
00339     }
00340 }
00341 
00349 void
00350 _dbus_data_slot_list_free (DBusDataSlotList *list)
00351 {
00352   _dbus_data_slot_list_clear (list);
00353   
00354   dbus_free (list->slots);
00355   list->slots = NULL;
00356   list->n_slots = 0;
00357 }
00358 
00361 #ifdef DBUS_BUILD_TESTS
00362 #include "dbus-test.h"
00363 #include <stdio.h>
00364 
00365 static int free_counter;
00366 
00367 static void
00368 test_free_slot_data_func (void *data)
00369 {
00370   int i = _DBUS_POINTER_TO_INT (data);
00371 
00372   _dbus_assert (free_counter == i);
00373   ++free_counter;
00374 }
00375 
00379 dbus_bool_t
00380 _dbus_data_slot_test (void)
00381 {
00382   DBusDataSlotAllocator allocator;
00383   DBusDataSlotList list;
00384   int i;
00385   DBusFreeFunction old_free_func;
00386   void *old_data;
00387   DBusMutex *mutex;
00388   
00389   if (!_dbus_data_slot_allocator_init (&allocator))
00390     _dbus_assert_not_reached ("no memory for allocator");
00391 
00392   _dbus_data_slot_list_init (&list);
00393 
00394   _dbus_mutex_new_at_location (&mutex);
00395   if (mutex == NULL)
00396     _dbus_assert_not_reached ("failed to alloc mutex");
00397   
00398 #define N_SLOTS 100
00399 
00400   i = 0;
00401   while (i < N_SLOTS)
00402     {
00403       /* we don't really want apps to rely on this ordered
00404        * allocation, but it simplifies things to rely on it
00405        * here.
00406        */
00407       dbus_int32_t tmp = -1;
00408       
00409       _dbus_data_slot_allocator_alloc (&allocator, &mutex, &tmp);
00410 
00411       if (tmp != i)
00412         _dbus_assert_not_reached ("did not allocate slots in numeric order\n");
00413 
00414       ++i;
00415     }
00416 
00417   i = 0;
00418   while (i < N_SLOTS)
00419     {
00420       if (!_dbus_data_slot_list_set (&allocator, &list,
00421                                      i,
00422                                      _DBUS_INT_TO_POINTER (i), 
00423                                      test_free_slot_data_func,
00424                                      &old_free_func, &old_data))
00425         _dbus_assert_not_reached ("no memory to set data");
00426 
00427       _dbus_assert (old_free_func == NULL);
00428       _dbus_assert (old_data == NULL);
00429 
00430       _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00431                     _DBUS_INT_TO_POINTER (i));
00432       
00433       ++i;
00434     }
00435 
00436   free_counter = 0;
00437   i = 0;
00438   while (i < N_SLOTS)
00439     {
00440       if (!_dbus_data_slot_list_set (&allocator, &list,
00441                                      i,
00442                                      _DBUS_INT_TO_POINTER (i), 
00443                                      test_free_slot_data_func,
00444                                      &old_free_func, &old_data))
00445         _dbus_assert_not_reached ("no memory to set data");
00446 
00447       _dbus_assert (old_free_func == test_free_slot_data_func);
00448       _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i);
00449 
00450       (* old_free_func) (old_data);
00451       _dbus_assert (i == (free_counter - 1));
00452 
00453       _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00454                     _DBUS_INT_TO_POINTER (i));
00455       
00456       ++i;
00457     }
00458 
00459   free_counter = 0;
00460   _dbus_data_slot_list_free (&list);
00461 
00462   _dbus_assert (N_SLOTS == free_counter);
00463 
00464   i = 0;
00465   while (i < N_SLOTS)
00466     {
00467       dbus_int32_t tmp = i;
00468       
00469       _dbus_data_slot_allocator_free (&allocator, &tmp);
00470       _dbus_assert (tmp == -1);
00471       ++i;
00472     }
00473 
00474   _dbus_mutex_free_at_location (&mutex);
00475   
00476   return TRUE;
00477 }
00478 
00479 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Dec 21 2010 for D-Bus by  doxygen 1.7.1