00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
00243
00244
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
00301
00302
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
00390
00391
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