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-internal.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_loc = NULL;
00050
00051 return TRUE;
00052 }
00053
00066 dbus_bool_t
00067 _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
00068 DBusMutex **mutex_loc,
00069 dbus_int32_t *slot_id_p)
00070 {
00071 dbus_int32_t slot;
00072
00073 _dbus_mutex_lock (*mutex_loc);
00074
00075 if (allocator->n_allocated_slots == 0)
00076 {
00077 _dbus_assert (allocator->lock_loc == NULL);
00078 allocator->lock_loc = mutex_loc;
00079 }
00080 else if (allocator->lock_loc != mutex_loc)
00081 {
00082 _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");
00083 _dbus_assert_not_reached ("exiting");
00084 }
00085
00086 if (*slot_id_p >= 0)
00087 {
00088 slot = *slot_id_p;
00089
00090 _dbus_assert (slot < allocator->n_allocated_slots);
00091 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00092
00093 allocator->allocated_slots[slot].refcount += 1;
00094
00095 goto out;
00096 }
00097
00098 _dbus_assert (*slot_id_p < 0);
00099
00100 if (allocator->n_used_slots < allocator->n_allocated_slots)
00101 {
00102 slot = 0;
00103 while (slot < allocator->n_allocated_slots)
00104 {
00105 if (allocator->allocated_slots[slot].slot_id < 0)
00106 {
00107 allocator->allocated_slots[slot].slot_id = slot;
00108 allocator->allocated_slots[slot].refcount = 1;
00109 allocator->n_used_slots += 1;
00110 break;
00111 }
00112 ++slot;
00113 }
00114
00115 _dbus_assert (slot < allocator->n_allocated_slots);
00116 }
00117 else
00118 {
00119 DBusAllocatedSlot *tmp;
00120
00121 slot = -1;
00122 tmp = dbus_realloc (allocator->allocated_slots,
00123 sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1));
00124 if (tmp == NULL)
00125 goto out;
00126
00127 allocator->allocated_slots = tmp;
00128 slot = allocator->n_allocated_slots;
00129 allocator->n_allocated_slots += 1;
00130 allocator->n_used_slots += 1;
00131 allocator->allocated_slots[slot].slot_id = slot;
00132 allocator->allocated_slots[slot].refcount = 1;
00133 }
00134
00135 _dbus_assert (slot >= 0);
00136 _dbus_assert (slot < allocator->n_allocated_slots);
00137 _dbus_assert (*slot_id_p < 0);
00138 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00139 _dbus_assert (allocator->allocated_slots[slot].refcount == 1);
00140
00141 *slot_id_p = slot;
00142
00143 _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n",
00144 slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00145
00146 out:
00147 _dbus_mutex_unlock (*(allocator->lock_loc));
00148 return slot >= 0;
00149 }
00150
00162 void
00163 _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
00164 dbus_int32_t *slot_id_p)
00165 {
00166 _dbus_mutex_lock (*(allocator->lock_loc));
00167
00168 _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
00169 _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
00170 _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0);
00171
00172 allocator->allocated_slots[*slot_id_p].refcount -= 1;
00173
00174 if (allocator->allocated_slots[*slot_id_p].refcount > 0)
00175 {
00176 _dbus_mutex_unlock (*(allocator->lock_loc));
00177 return;
00178 }
00179
00180
00181 _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n",
00182 *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00183
00184 allocator->allocated_slots[*slot_id_p].slot_id = -1;
00185 *slot_id_p = -1;
00186
00187 allocator->n_used_slots -= 1;
00188
00189 if (allocator->n_used_slots == 0)
00190 {
00191 DBusMutex **mutex_loc = allocator->lock_loc;
00192
00193 dbus_free (allocator->allocated_slots);
00194 allocator->allocated_slots = NULL;
00195 allocator->n_allocated_slots = 0;
00196 allocator->lock_loc = NULL;
00197
00198 _dbus_mutex_unlock (*mutex_loc);
00199 }
00200 else
00201 {
00202 _dbus_mutex_unlock (*(allocator->lock_loc));
00203 }
00204 }
00205
00210 void
00211 _dbus_data_slot_list_init (DBusDataSlotList *list)
00212 {
00213 list->slots = NULL;
00214 list->n_slots = 0;
00215 }
00216
00234 dbus_bool_t
00235 _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator,
00236 DBusDataSlotList *list,
00237 int slot,
00238 void *data,
00239 DBusFreeFunction free_data_func,
00240 DBusFreeFunction *old_free_func,
00241 void **old_data)
00242 {
00243 #ifndef DBUS_DISABLE_ASSERT
00244
00245
00246
00247
00248 _dbus_mutex_lock (*(allocator->lock_loc));
00249 _dbus_assert (slot < allocator->n_allocated_slots);
00250 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00251 _dbus_mutex_unlock (*(allocator->lock_loc));
00252 #endif
00253
00254 if (slot >= list->n_slots)
00255 {
00256 DBusDataSlot *tmp;
00257 int i;
00258
00259 tmp = dbus_realloc (list->slots,
00260 sizeof (DBusDataSlot) * (slot + 1));
00261 if (tmp == NULL)
00262 return FALSE;
00263
00264 list->slots = tmp;
00265 i = list->n_slots;
00266 list->n_slots = slot + 1;
00267 while (i < list->n_slots)
00268 {
00269 list->slots[i].data = NULL;
00270 list->slots[i].free_data_func = NULL;
00271 ++i;
00272 }
00273 }
00274
00275 _dbus_assert (slot < list->n_slots);
00276
00277 *old_data = list->slots[slot].data;
00278 *old_free_func = list->slots[slot].free_data_func;
00279
00280 list->slots[slot].data = data;
00281 list->slots[slot].free_data_func = free_data_func;
00282
00283 return TRUE;
00284 }
00285
00295 void*
00296 _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator,
00297 DBusDataSlotList *list,
00298 int slot)
00299 {
00300 #ifndef DBUS_DISABLE_ASSERT
00301
00302
00303
00304
00305 _dbus_mutex_lock (*(allocator->lock_loc));
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_loc));
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 _dbus_mutex_new_at_location (&mutex);
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_at_location (&mutex);
00473
00474 return TRUE;
00475 }
00476
00477 #endif