D-Bus 1.13.18

dbus-dataslot.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* dbus-dataslot.c storing data on objects
3 *
4 * Copyright (C) 2003 Red Hat, Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 */
23
24#include <config.h>
25#include "dbus-dataslot.h"
26#include "dbus-threads-internal.h"
27#include <dbus/dbus-test-tap.h>
28
46 dbus_bool_t
47_dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator,
48 DBusGlobalLock lock)
49{
50 allocator->allocated_slots = NULL;
51 allocator->n_allocated_slots = 0;
52 allocator->n_used_slots = 0;
53 allocator->lock = lock;
54
55 return TRUE;
56}
57
69 dbus_bool_t
70_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
71 dbus_int32_t *slot_id_p)
72{
73 dbus_int32_t slot;
74
75 if (!_dbus_lock (allocator->lock))
76 return FALSE;
77
78 if (*slot_id_p >= 0)
79 {
80 slot = *slot_id_p;
81
82 _dbus_assert (slot < allocator->n_allocated_slots);
83 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
84
85 allocator->allocated_slots[slot].refcount += 1;
86
87 goto out;
88 }
89
90 _dbus_assert (*slot_id_p < 0);
91
92 if (allocator->n_used_slots < allocator->n_allocated_slots)
93 {
94 slot = 0;
95 while (slot < allocator->n_allocated_slots)
96 {
97 if (allocator->allocated_slots[slot].slot_id < 0)
98 {
99 allocator->allocated_slots[slot].slot_id = slot;
100 allocator->allocated_slots[slot].refcount = 1;
101 allocator->n_used_slots += 1;
102 break;
103 }
104 ++slot;
105 }
106
107 _dbus_assert (slot < allocator->n_allocated_slots);
108 }
109 else
110 {
111 DBusAllocatedSlot *tmp;
112
113 slot = -1;
114 tmp = dbus_realloc (allocator->allocated_slots,
115 sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1));
116 if (tmp == NULL)
117 goto out;
118
119 allocator->allocated_slots = tmp;
120 slot = allocator->n_allocated_slots;
121 allocator->n_allocated_slots += 1;
122 allocator->n_used_slots += 1;
123 allocator->allocated_slots[slot].slot_id = slot;
124 allocator->allocated_slots[slot].refcount = 1;
125 }
126
127 _dbus_assert (slot >= 0);
128 _dbus_assert (slot < allocator->n_allocated_slots);
129 _dbus_assert (*slot_id_p < 0);
130 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
131 _dbus_assert (allocator->allocated_slots[slot].refcount == 1);
132
133 *slot_id_p = slot;
134
135 _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n",
136 slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
137
138 out:
139 _dbus_unlock (allocator->lock);
140 return slot >= 0;
141}
142
154 void
155_dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
156 dbus_int32_t *slot_id_p)
157{
158 if (!_dbus_lock (allocator->lock))
159 _dbus_assert_not_reached ("we should have initialized global locks "
160 "before we allocated this slot");
161
162 _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
163 _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
164 _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0);
165
166 allocator->allocated_slots[*slot_id_p].refcount -= 1;
167
168 if (allocator->allocated_slots[*slot_id_p].refcount > 0)
169 {
170 _dbus_unlock (allocator->lock);
171 return;
172 }
173
174 /* refcount is 0, free the slot */
175 _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n",
176 *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
177
178 allocator->allocated_slots[*slot_id_p].slot_id = -1;
179 *slot_id_p = -1;
180
181 allocator->n_used_slots -= 1;
182
183 if (allocator->n_used_slots == 0)
184 {
185 dbus_free (allocator->allocated_slots);
186 allocator->allocated_slots = NULL;
187 allocator->n_allocated_slots = 0;
188 }
189
190 _dbus_unlock (allocator->lock);
191}
192
197 void
198_dbus_data_slot_list_init (DBusDataSlotList *list)
199{
200 list->slots = NULL;
201 list->n_slots = 0;
202}
203
221 dbus_bool_t
222_dbus_data_slot_list_set (DBusDataSlotAllocator *allocator,
223 DBusDataSlotList *list,
224 int slot,
225 void *data,
226 DBusFreeFunction free_data_func,
227 DBusFreeFunction *old_free_func,
228 void **old_data)
229{
230#ifndef DBUS_DISABLE_ASSERT
231 /* We need to take the allocator lock here, because the allocator could
232 * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
233 * are disabled, since then the asserts are empty.
234 */
235 if (!_dbus_lock (allocator->lock))
236 _dbus_assert_not_reached ("we should have initialized global locks "
237 "before we allocated this slot");
238
239 _dbus_assert (slot < allocator->n_allocated_slots);
240 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
241 _dbus_unlock (allocator->lock);
242#endif
243
244 if (slot >= list->n_slots)
245 {
246 DBusDataSlot *tmp;
247 int i;
248
249 tmp = dbus_realloc (list->slots,
250 sizeof (DBusDataSlot) * (slot + 1));
251 if (tmp == NULL)
252 return FALSE;
253
254 list->slots = tmp;
255 i = list->n_slots;
256 list->n_slots = slot + 1;
257 while (i < list->n_slots)
258 {
259 list->slots[i].data = NULL;
260 list->slots[i].free_data_func = NULL;
261 ++i;
262 }
263 }
264
265 _dbus_assert (slot < list->n_slots);
266
267 *old_data = list->slots[slot].data;
268 *old_free_func = list->slots[slot].free_data_func;
269
270 list->slots[slot].data = data;
271 list->slots[slot].free_data_func = free_data_func;
272
273 return TRUE;
274}
275
285 void*
286_dbus_data_slot_list_get (DBusDataSlotAllocator *allocator,
287 DBusDataSlotList *list,
288 int slot)
289{
290#ifndef DBUS_DISABLE_ASSERT
291 /* We need to take the allocator lock here, because the allocator could
292 * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
293 * are disabled, since then the asserts are empty.
294 */
295 if (!_dbus_lock (allocator->lock))
296 _dbus_assert_not_reached ("we should have initialized global locks "
297 "before we allocated this slot");
298
299 _dbus_assert (slot >= 0);
300 _dbus_assert (slot < allocator->n_allocated_slots);
301 _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
302 _dbus_unlock (allocator->lock);
303#endif
304
305 if (slot >= list->n_slots)
306 return NULL;
307 else
308 return list->slots[slot].data;
309}
310
317 void
318_dbus_data_slot_list_clear (DBusDataSlotList *list)
319{
320 int i;
321
322 i = 0;
323 while (i < list->n_slots)
324 {
325 if (list->slots[i].free_data_func)
326 (* list->slots[i].free_data_func) (list->slots[i].data);
327 list->slots[i].data = NULL;
328 list->slots[i].free_data_func = NULL;
329 ++i;
330 }
331}
332
340 void
341_dbus_data_slot_list_free (DBusDataSlotList *list)
342{
343 _dbus_data_slot_list_clear (list);
344
345 dbus_free (list->slots);
346 list->slots = NULL;
347 list->n_slots = 0;
348}
349
352#ifdef DBUS_ENABLE_EMBEDDED_TESTS
353#include "dbus-test.h"
354#include <stdio.h>
355
356/* Test-only, does not need to be thread-safe */
357 static int free_counter;
358
359 static void
360test_free_slot_data_func (void *data)
361{
362 int i = _DBUS_POINTER_TO_INT (data);
363
364 _dbus_assert (free_counter == i);
365 ++free_counter;
366}
367
371 dbus_bool_t
372_dbus_data_slot_test (const char *test_data_dir _DBUS_GNUC_UNUSED)
373{
374 DBusDataSlotAllocator allocator;
375 DBusDataSlotList list;
376 int i;
377 DBusFreeFunction old_free_func;
378 void *old_data;
379
380 if (!_dbus_data_slot_allocator_init (&allocator, _DBUS_LOCK_server_slots))
381 _dbus_test_fatal ("no memory for allocator");
382
383 _dbus_data_slot_list_init (&list);
384
385#define N_SLOTS 100
386
387 i = 0;
388 while (i < N_SLOTS)
389 {
390 /* we don't really want apps to rely on this ordered
391 * allocation, but it simplifies things to rely on it
392 * here.
393 */
394 dbus_int32_t tmp = -1;
395
396 _dbus_data_slot_allocator_alloc (&allocator, &tmp);
397
398 if (tmp != i)
399 _dbus_test_fatal ("did not allocate slots in numeric order");
400
401 ++i;
402 }
403
404 i = 0;
405 while (i < N_SLOTS)
406 {
407 if (!_dbus_data_slot_list_set (&allocator, &list,
408 i,
409 _DBUS_INT_TO_POINTER (i),
410 test_free_slot_data_func,
411 &old_free_func, &old_data))
412 _dbus_test_fatal ("no memory to set data");
413
414 _dbus_assert (old_free_func == NULL);
415 _dbus_assert (old_data == NULL);
416
417 _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
418 _DBUS_INT_TO_POINTER (i));
419
420 ++i;
421 }
422
423 free_counter = 0;
424 i = 0;
425 while (i < N_SLOTS)
426 {
427 if (!_dbus_data_slot_list_set (&allocator, &list,
428 i,
429 _DBUS_INT_TO_POINTER (i),
430 test_free_slot_data_func,
431 &old_free_func, &old_data))
432 _dbus_test_fatal ("no memory to set data");
433
434 _dbus_assert (old_free_func == test_free_slot_data_func);
435 _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i);
436
437 (* old_free_func) (old_data);
438 _dbus_assert (i == (free_counter - 1));
439
440 _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
441 _DBUS_INT_TO_POINTER (i));
442
443 ++i;
444 }
445
446 free_counter = 0;
447 _dbus_data_slot_list_free (&list);
448
449 _dbus_assert (N_SLOTS == free_counter);
450
451 i = 0;
452 while (i < N_SLOTS)
453 {
454 dbus_int32_t tmp = i;
455
456 _dbus_data_slot_allocator_free (&allocator, &tmp);
457 _dbus_assert (tmp == -1);
458 ++i;
459 }
460
461 return TRUE;
462}
463
464#endif /* DBUS_ENABLE_EMBEDDED_TESTS */
_dbus_data_slot_allocator_free
void _dbus_data_slot_allocator_free(DBusDataSlotAllocator *allocator, dbus_int32_t *slot_id_p)
Deallocates an ID previously allocated with _dbus_data_slot_allocator_alloc().
Definition: dbus-dataslot.c:155
_dbus_data_slot_list_clear
void _dbus_data_slot_list_clear(DBusDataSlotList *list)
Frees all data slots contained in the list, calling application-provided free functions if they exist...
Definition: dbus-dataslot.c:318
_dbus_data_slot_allocator_init
dbus_bool_t _dbus_data_slot_allocator_init(DBusDataSlotAllocator *allocator, DBusGlobalLock lock)
Initializes a data slot allocator object, used to assign integer IDs for data slots.
Definition: dbus-dataslot.c:47
_dbus_data_slot_list_init
void _dbus_data_slot_list_init(DBusDataSlotList *list)
Initializes a slot list.
Definition: dbus-dataslot.c:198
_dbus_data_slot_list_free
void _dbus_data_slot_list_free(DBusDataSlotList *list)
Frees the data slot list and all data slots contained in it, calling application-provided free functi...
Definition: dbus-dataslot.c:341
_dbus_data_slot_list_get
void * _dbus_data_slot_list_get(DBusDataSlotAllocator *allocator, DBusDataSlotList *list, int slot)
Retrieves data previously set with _dbus_data_slot_list_set_data().
Definition: dbus-dataslot.c:286
_dbus_data_slot_list_set
dbus_bool_t _dbus_data_slot_list_set(DBusDataSlotAllocator *allocator, DBusDataSlotList *list, int slot, void *data, DBusFreeFunction free_data_func, DBusFreeFunction *old_free_func, void **old_data)
Stores a pointer in the data slot list, along with an optional function to be used for freeing the da...
Definition: dbus-dataslot.c:222
_dbus_data_slot_allocator_alloc
dbus_bool_t _dbus_data_slot_allocator_alloc(DBusDataSlotAllocator *allocator, dbus_int32_t *slot_id_p)
Allocates an integer ID to be used for storing data in a DBusDataSlotList.
Definition: dbus-dataslot.c:70
_DBUS_INT_TO_POINTER
#define _DBUS_INT_TO_POINTER(integer)
Safely stuffs an integer into a pointer, to be extracted later with _DBUS_POINTER_TO_INT.
Definition: dbus-internals.h:192
_dbus_assert_not_reached
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
Definition: dbus-internals.h:164
_dbus_assert
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
Definition: dbus-internals.h:153
_DBUS_POINTER_TO_INT
#define _DBUS_POINTER_TO_INT(pointer)
Safely casts a void* to an integer; should only be used on void* that actually contain integers,...
Definition: dbus-internals.h:191
NULL
#define NULL
A null pointer, defined appropriately for C or C++.
TRUE
#define TRUE
Expands to "1".
FALSE
#define FALSE
Expands to "0".
DBusFreeFunction
void(* DBusFreeFunction)(void *memory)
The type of a function which frees a block of memory.
Definition: dbus-memory.h:63
dbus_free
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:704
dbus_realloc
void * dbus_realloc(void *memory, size_t bytes)
Resizes a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:604
dbus_bool_t
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
DBusAllocatedSlot
An allocated slot for storing data.
Definition: dbus-dataslot.h:47
DBusAllocatedSlot::refcount
int refcount
Number of uses of the slot.
Definition: dbus-dataslot.h:49
DBusAllocatedSlot::slot_id
dbus_int32_t slot_id
ID of this slot.
Definition: dbus-dataslot.h:48
DBusDataSlotAllocator
An allocator that tracks a set of slot IDs.
Definition: dbus-dataslot.h:56
DBusDataSlotAllocator::allocated_slots
DBusAllocatedSlot * allocated_slots
Allocated slots.
Definition: dbus-dataslot.h:57
DBusDataSlotAllocator::n_allocated_slots
int n_allocated_slots
number of slots malloc'd
Definition: dbus-dataslot.h:58
DBusDataSlotAllocator::lock
DBusGlobalLock lock
index of thread lock
Definition: dbus-dataslot.h:60
DBusDataSlotAllocator::n_used_slots
int n_used_slots
number of slots used
Definition: dbus-dataslot.h:59
DBusDataSlotList
Data structure that stores the actual user data set at a given slot.
Definition: dbus-dataslot.h:70
DBusDataSlotList::n_slots
int n_slots
Slots we have storage for in data_slots.
Definition: dbus-dataslot.h:72
DBusDataSlotList::slots
DBusDataSlot * slots
Data slots.
Definition: dbus-dataslot.h:71
DBusDataSlot
DBusDataSlot is used to store application data on the connection.
Definition: dbus-dataslot.h:37
DBusDataSlot::data
void * data
The application data.
Definition: dbus-dataslot.h:38
DBusDataSlot::free_data_func
DBusFreeFunction free_data_func
Free the application data.
Definition: dbus-dataslot.h:39