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
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
00402
00403
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