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 DBusGlobalLock lock)
00048 {
00049 allocator->allocated_slots = NULL;
00050 allocator->n_allocated_slots = 0;
00051 allocator->n_used_slots = 0;
00052 allocator->lock = lock;
00053
00054 return TRUE;
00055 }
00056
00068 dbus_bool_t
00069 _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
00070 dbus_int32_t *slot_id_p)
00071 {
00072 dbus_int32_t slot;
00073
00074 if (!_dbus_lock (allocator->lock))
00075 return FALSE;
00076
00077 if (*slot_id_p >= 0)
00078 {
00079 slot = *slot_id_p;
00080
00081 _dbus_assert (slot < allocator->n_allocated_slots);
00082 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00083
00084 allocator->allocated_slots[slot].refcount += 1;
00085
00086 goto out;
00087 }
00088
00089 _dbus_assert (*slot_id_p < 0);
00090
00091 if (allocator->n_used_slots < allocator->n_allocated_slots)
00092 {
00093 slot = 0;
00094 while (slot < allocator->n_allocated_slots)
00095 {
00096 if (allocator->allocated_slots[slot].slot_id < 0)
00097 {
00098 allocator->allocated_slots[slot].slot_id = slot;
00099 allocator->allocated_slots[slot].refcount = 1;
00100 allocator->n_used_slots += 1;
00101 break;
00102 }
00103 ++slot;
00104 }
00105
00106 _dbus_assert (slot < allocator->n_allocated_slots);
00107 }
00108 else
00109 {
00110 DBusAllocatedSlot *tmp;
00111
00112 slot = -1;
00113 tmp = dbus_realloc (allocator->allocated_slots,
00114 sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1));
00115 if (tmp == NULL)
00116 goto out;
00117
00118 allocator->allocated_slots = tmp;
00119 slot = allocator->n_allocated_slots;
00120 allocator->n_allocated_slots += 1;
00121 allocator->n_used_slots += 1;
00122 allocator->allocated_slots[slot].slot_id = slot;
00123 allocator->allocated_slots[slot].refcount = 1;
00124 }
00125
00126 _dbus_assert (slot >= 0);
00127 _dbus_assert (slot < allocator->n_allocated_slots);
00128 _dbus_assert (*slot_id_p < 0);
00129 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00130 _dbus_assert (allocator->allocated_slots[slot].refcount == 1);
00131
00132 *slot_id_p = slot;
00133
00134 _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n",
00135 slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00136
00137 out:
00138 _dbus_unlock (allocator->lock);
00139 return slot >= 0;
00140 }
00141
00153 void
00154 _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
00155 dbus_int32_t *slot_id_p)
00156 {
00157 if (!_dbus_lock (allocator->lock))
00158 _dbus_assert_not_reached ("we should have initialized global locks "
00159 "before we allocated this slot");
00160
00161 _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
00162 _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
00163 _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0);
00164
00165 allocator->allocated_slots[*slot_id_p].refcount -= 1;
00166
00167 if (allocator->allocated_slots[*slot_id_p].refcount > 0)
00168 {
00169 _dbus_unlock (allocator->lock);
00170 return;
00171 }
00172
00173
00174 _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n",
00175 *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
00176
00177 allocator->allocated_slots[*slot_id_p].slot_id = -1;
00178 *slot_id_p = -1;
00179
00180 allocator->n_used_slots -= 1;
00181
00182 if (allocator->n_used_slots == 0)
00183 {
00184 dbus_free (allocator->allocated_slots);
00185 allocator->allocated_slots = NULL;
00186 allocator->n_allocated_slots = 0;
00187 }
00188
00189 _dbus_unlock (allocator->lock);
00190 }
00191
00196 void
00197 _dbus_data_slot_list_init (DBusDataSlotList *list)
00198 {
00199 list->slots = NULL;
00200 list->n_slots = 0;
00201 }
00202
00220 dbus_bool_t
00221 _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator,
00222 DBusDataSlotList *list,
00223 int slot,
00224 void *data,
00225 DBusFreeFunction free_data_func,
00226 DBusFreeFunction *old_free_func,
00227 void **old_data)
00228 {
00229 #ifndef DBUS_DISABLE_ASSERT
00230
00231
00232
00233
00234 if (!_dbus_lock (allocator->lock))
00235 _dbus_assert_not_reached ("we should have initialized global locks "
00236 "before we allocated this slot");
00237
00238 _dbus_assert (slot < allocator->n_allocated_slots);
00239 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00240 _dbus_unlock (allocator->lock);
00241 #endif
00242
00243 if (slot >= list->n_slots)
00244 {
00245 DBusDataSlot *tmp;
00246 int i;
00247
00248 tmp = dbus_realloc (list->slots,
00249 sizeof (DBusDataSlot) * (slot + 1));
00250 if (tmp == NULL)
00251 return FALSE;
00252
00253 list->slots = tmp;
00254 i = list->n_slots;
00255 list->n_slots = slot + 1;
00256 while (i < list->n_slots)
00257 {
00258 list->slots[i].data = NULL;
00259 list->slots[i].free_data_func = NULL;
00260 ++i;
00261 }
00262 }
00263
00264 _dbus_assert (slot < list->n_slots);
00265
00266 *old_data = list->slots[slot].data;
00267 *old_free_func = list->slots[slot].free_data_func;
00268
00269 list->slots[slot].data = data;
00270 list->slots[slot].free_data_func = free_data_func;
00271
00272 return TRUE;
00273 }
00274
00284 void*
00285 _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator,
00286 DBusDataSlotList *list,
00287 int slot)
00288 {
00289 #ifndef DBUS_DISABLE_ASSERT
00290
00291
00292
00293
00294 if (!_dbus_lock (allocator->lock))
00295 _dbus_assert_not_reached ("we should have initialized global locks "
00296 "before we allocated this slot");
00297
00298 _dbus_assert (slot >= 0);
00299 _dbus_assert (slot < allocator->n_allocated_slots);
00300 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
00301 _dbus_unlock (allocator->lock);
00302 #endif
00303
00304 if (slot >= list->n_slots)
00305 return NULL;
00306 else
00307 return list->slots[slot].data;
00308 }
00309
00316 void
00317 _dbus_data_slot_list_clear (DBusDataSlotList *list)
00318 {
00319 int i;
00320
00321 i = 0;
00322 while (i < list->n_slots)
00323 {
00324 if (list->slots[i].free_data_func)
00325 (* list->slots[i].free_data_func) (list->slots[i].data);
00326 list->slots[i].data = NULL;
00327 list->slots[i].free_data_func = NULL;
00328 ++i;
00329 }
00330 }
00331
00339 void
00340 _dbus_data_slot_list_free (DBusDataSlotList *list)
00341 {
00342 _dbus_data_slot_list_clear (list);
00343
00344 dbus_free (list->slots);
00345 list->slots = NULL;
00346 list->n_slots = 0;
00347 }
00348
00351 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00352 #include "dbus-test.h"
00353 #include <stdio.h>
00354
00355 static int free_counter;
00356
00357 static void
00358 test_free_slot_data_func (void *data)
00359 {
00360 int i = _DBUS_POINTER_TO_INT (data);
00361
00362 _dbus_assert (free_counter == i);
00363 ++free_counter;
00364 }
00365
00369 dbus_bool_t
00370 _dbus_data_slot_test (void)
00371 {
00372 DBusDataSlotAllocator allocator;
00373 DBusDataSlotList list;
00374 int i;
00375 DBusFreeFunction old_free_func;
00376 void *old_data;
00377
00378 if (!_dbus_data_slot_allocator_init (&allocator, _DBUS_LOCK_server_slots))
00379 _dbus_assert_not_reached ("no memory for allocator");
00380
00381 _dbus_data_slot_list_init (&list);
00382
00383 #define N_SLOTS 100
00384
00385 i = 0;
00386 while (i < N_SLOTS)
00387 {
00388
00389
00390
00391
00392 dbus_int32_t tmp = -1;
00393
00394 _dbus_data_slot_allocator_alloc (&allocator, &tmp);
00395
00396 if (tmp != i)
00397 _dbus_assert_not_reached ("did not allocate slots in numeric order\n");
00398
00399 ++i;
00400 }
00401
00402 i = 0;
00403 while (i < N_SLOTS)
00404 {
00405 if (!_dbus_data_slot_list_set (&allocator, &list,
00406 i,
00407 _DBUS_INT_TO_POINTER (i),
00408 test_free_slot_data_func,
00409 &old_free_func, &old_data))
00410 _dbus_assert_not_reached ("no memory to set data");
00411
00412 _dbus_assert (old_free_func == NULL);
00413 _dbus_assert (old_data == NULL);
00414
00415 _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00416 _DBUS_INT_TO_POINTER (i));
00417
00418 ++i;
00419 }
00420
00421 free_counter = 0;
00422 i = 0;
00423 while (i < N_SLOTS)
00424 {
00425 if (!_dbus_data_slot_list_set (&allocator, &list,
00426 i,
00427 _DBUS_INT_TO_POINTER (i),
00428 test_free_slot_data_func,
00429 &old_free_func, &old_data))
00430 _dbus_assert_not_reached ("no memory to set data");
00431
00432 _dbus_assert (old_free_func == test_free_slot_data_func);
00433 _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i);
00434
00435 (* old_free_func) (old_data);
00436 _dbus_assert (i == (free_counter - 1));
00437
00438 _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
00439 _DBUS_INT_TO_POINTER (i));
00440
00441 ++i;
00442 }
00443
00444 free_counter = 0;
00445 _dbus_data_slot_list_free (&list);
00446
00447 _dbus_assert (N_SLOTS == free_counter);
00448
00449 i = 0;
00450 while (i < N_SLOTS)
00451 {
00452 dbus_int32_t tmp = i;
00453
00454 _dbus_data_slot_allocator_free (&allocator, &tmp);
00455 _dbus_assert (tmp == -1);
00456 ++i;
00457 }
00458
00459 return TRUE;
00460 }
00461
00462 #endif