00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
00247
00248
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
00304
00305
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
00404
00405
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