D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* refcount is 0, free the slot */ 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 /* We need to take the allocator lock here, because the allocator could 00231 * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts 00232 * are disabled, since then the asserts are empty. 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 /* We need to take the allocator lock here, because the allocator could 00291 * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts 00292 * are disabled, since then the asserts are empty. 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 /* we don't really want apps to rely on this ordered 00389 * allocation, but it simplifies things to rely on it 00390 * here. 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 /* DBUS_ENABLE_EMBEDDED_TESTS */