Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-dataslot.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */ 00002 /* dbus-dataslot.c storing data on objects 00003 * 00004 * Copyright (C) 2003 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 /* refcount is 0, free the slot */ 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 /* We need to take the allocator lock here, because the allocator could 00243 * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts 00244 * are disabled, since then the asserts are empty. 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 /* We need to take the allocator lock here, because the allocator could 00301 * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts 00302 * are disabled, since then the asserts are empty. 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 /* we don't really want apps to rely on this ordered 00390 * allocation, but it simplifies things to rely on it 00391 * here. 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 /* DBUS_BUILD_TESTS */

Generated on Mon Aug 16 17:40:07 2004 for D-BUS by doxygen 1.3.8