1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-object-registry.c DBusObjectRegistry (internals of DBusConnection)
4 * Copyright (C) 2003 Red Hat Inc.
6 * Licensed under the Academic Free License version 1.2
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "dbus-object-registry.h"
24 #include "dbus-connection-internal.h"
25 #include "dbus-internals.h"
26 #include "dbus-hash.h"
27 #include "dbus-protocol.h"
31 * @defgroup DBusObjectRegistry Map object IDs to implementations
32 * @ingroup DBusInternals
33 * @brief DBusObjectRegistry is used by DBusConnection to track object IDs
35 * Types and functions related to DBusObjectRegistry. These
38 * @todo interface entries and signal connections are handled pretty
39 * much identically, with lots of duplicate code. Once we're sure
40 * they will always be the same, we could merge this code.
45 typedef struct DBusObjectEntry DBusObjectEntry;
46 typedef struct DBusInterfaceEntry DBusInterfaceEntry;
47 typedef struct DBusSignalEntry DBusSignalEntry;
49 #define DBUS_MAX_OBJECTS_PER_INTERFACE 65535
50 struct DBusInterfaceEntry
52 unsigned int n_objects : 16; /**< Number of objects with this interface */
53 unsigned int n_allocated : 16; /**< Allocated size of objects array */
54 dbus_uint16_t *objects; /**< Index of each object with the interface */
55 char name[4]; /**< Name of interface (actually allocated larger) */
58 #define DBUS_MAX_CONNECTIONS_PER_SIGNAL 65535
59 struct DBusSignalEntry
61 unsigned int n_connections : 16; /**< Number of connections to this signal */
62 unsigned int n_allocated : 16; /**< Allocated size of objects array */
63 dbus_uint16_t *connections; /**< Index of each object connected (can have dups for multiple
66 char name[4]; /**< Name of signal (actually allocated larger) */
69 /* 14 bits for object index, 32K objects */
70 #define DBUS_OBJECT_INDEX_BITS (14)
71 #define DBUS_OBJECT_INDEX_MASK (0x3fff)
72 #define DBUS_MAX_OBJECTS_PER_CONNECTION DBUS_OBJECT_INDEX_MASK
73 struct DBusObjectEntry
75 unsigned int id_index : 14; /**< Index of this entry in the entries array */
76 unsigned int id_times_used : 18; /**< Count of times entry has been used; avoids recycling IDs too often */
78 void *object_impl; /**< Pointer to application-supplied implementation */
79 const DBusObjectVTable *vtable; /**< Virtual table for this object */
80 DBusInterfaceEntry **interfaces; /**< NULL-terminated list of interfaces */
81 DBusSignalEntry **signals; /**< Signal connections (contains dups, one each time we connect) */
84 struct DBusObjectRegistry
87 DBusConnection *connection;
89 DBusObjectEntry *entries;
90 int n_entries_allocated;
93 DBusHashTable *interface_table;
95 DBusHashTable *signal_table;
99 free_interface_entry (void *entry)
101 DBusInterfaceEntry *iface = entry;
103 if (iface == NULL) /* DBusHashTable stupidity */
106 dbus_free (iface->objects);
111 free_signal_entry (void *entry)
113 DBusSignalEntry *signal = entry;
115 if (signal == NULL) /* DBusHashTable stupidity */
118 dbus_free (signal->connections);
123 _dbus_object_registry_new (DBusConnection *connection)
125 DBusObjectRegistry *registry;
126 DBusHashTable *interface_table;
127 DBusHashTable *signal_table;
129 /* the connection passed in here isn't fully constructed,
130 * so don't do anything more than store a pointer to
135 interface_table = NULL;
138 registry = dbus_new0 (DBusObjectRegistry, 1);
139 if (registry == NULL)
142 interface_table = _dbus_hash_table_new (DBUS_HASH_STRING,
143 NULL, free_interface_entry);
144 if (interface_table == NULL)
147 signal_table = _dbus_hash_table_new (DBUS_HASH_STRING,
148 NULL, free_signal_entry);
149 if (signal_table == NULL)
152 registry->refcount = 1;
153 registry->connection = connection;
154 registry->interface_table = interface_table;
155 registry->signal_table = signal_table;
161 dbus_free (registry);
163 _dbus_hash_table_unref (interface_table);
165 _dbus_hash_table_unref (signal_table);
171 _dbus_object_registry_ref (DBusObjectRegistry *registry)
173 _dbus_assert (registry->refcount > 0);
175 registry->refcount += 1;
179 _dbus_object_registry_unref (DBusObjectRegistry *registry)
181 _dbus_assert (registry->refcount > 0);
183 registry->refcount -= 1;
185 if (registry->refcount == 0)
189 _dbus_assert (registry->n_entries_used == 0);
190 _dbus_assert (_dbus_hash_table_get_n_entries (registry->interface_table) == 0);
191 _dbus_assert (_dbus_hash_table_get_n_entries (registry->signal_table) == 0);
194 while (i < registry->n_entries_allocated)
196 if (registry->entries[i].interfaces)
197 dbus_free (registry->entries[i].interfaces);
198 if (registry->entries[i].signals)
199 dbus_free (registry->entries[i].signals);
203 _dbus_hash_table_unref (registry->interface_table);
204 _dbus_hash_table_unref (registry->signal_table);
205 dbus_free (registry->entries);
206 dbus_free (registry);
210 #define ENTRY_TO_ID(entry) \
211 (((dbus_uint32_t) (entry)->id_index) | \
212 (((dbus_uint32_t)(entry)->id_times_used) << DBUS_OBJECT_INDEX_BITS))
214 #define ID_TO_INDEX(id) \
215 (((dbus_uint32_t) (id)) & DBUS_OBJECT_INDEX_MASK)
217 #define ID_TO_TIMES_USED(id) \
218 (((dbus_uint32_t) (id)) >> DBUS_OBJECT_INDEX_BITS)
220 static DBusObjectEntry*
221 validate_id (DBusObjectRegistry *registry,
222 const DBusObjectID *object_id)
226 dbus_uint32_t instance_bits;
228 instance_bits = dbus_object_id_get_instance_bits (object_id);
230 /* Verify that connection ID bits are the same */
231 #ifdef DBUS_BUILD_TESTS
232 if (registry->connection)
237 _dbus_connection_init_id (registry->connection,
239 dbus_object_id_set_instance_bits (&tmp_id, instance_bits);
241 if (!dbus_object_id_equal (&tmp_id, object_id))
245 idx = ID_TO_INDEX (instance_bits);
246 times_used = ID_TO_TIMES_USED (instance_bits);
248 if (idx >= registry->n_entries_allocated)
250 if (registry->entries[idx].vtable == NULL)
252 if (registry->entries[idx].id_times_used != times_used)
254 _dbus_assert (registry->entries[idx].id_index == idx);
255 _dbus_assert (registry->n_entries_used > 0);
257 return ®istry->entries[idx];
261 id_from_entry (DBusObjectRegistry *registry,
262 DBusObjectID *object_id,
263 DBusObjectEntry *entry)
265 #ifdef DBUS_BUILD_TESTS
266 if (registry->connection)
268 _dbus_connection_init_id (registry->connection,
270 #ifdef DBUS_BUILD_TESTS
273 dbus_object_id_set_server_bits (object_id, 1);
274 dbus_object_id_set_client_bits (object_id, 2);
278 _dbus_assert (dbus_object_id_get_server_bits (object_id) != 0);
279 _dbus_assert (dbus_object_id_get_client_bits (object_id) != 0);
281 dbus_object_id_set_instance_bits (object_id,
282 ENTRY_TO_ID (entry));
284 _dbus_assert (dbus_object_id_get_instance_bits (object_id) != 0);
288 info_from_entry (DBusObjectRegistry *registry,
289 DBusObjectInfo *info,
290 DBusObjectEntry *entry)
292 info->connection = registry->connection;
293 info->object_impl = entry->object_impl;
295 id_from_entry (registry, &info->object_id, entry);
298 static DBusInterfaceEntry*
299 lookup_interface (DBusObjectRegistry *registry,
301 dbus_bool_t create_if_not_found)
303 DBusInterfaceEntry *entry;
307 entry = _dbus_hash_table_lookup_string (registry->interface_table,
309 if (entry != NULL || !create_if_not_found)
312 _dbus_assert (create_if_not_found);
315 sz = _DBUS_STRUCT_OFFSET (DBusInterfaceEntry, name) + len + 1;
316 entry = dbus_malloc (sz);
319 entry->n_objects = 0;
320 entry->n_allocated = 0;
321 entry->objects = NULL;
322 memcpy (entry->name, name, len + 1);
324 if (!_dbus_hash_table_insert_string (registry->interface_table,
335 delete_interface (DBusObjectRegistry *registry,
336 DBusInterfaceEntry *entry)
338 _dbus_hash_table_remove_string (registry->interface_table,
343 interface_entry_add_object (DBusInterfaceEntry *entry,
344 dbus_uint16_t object_index)
346 if (entry->n_objects == entry->n_allocated)
348 unsigned int new_alloc;
349 dbus_uint16_t *new_objects;
351 if (entry->n_allocated == 0)
354 new_alloc = entry->n_allocated * 2;
356 /* Right now MAX_OBJECTS_PER_INTERFACE can't possibly be reached
357 * since the max number of objects _total_ is smaller, but the
358 * code is here for future robustness.
361 if (new_alloc > DBUS_MAX_OBJECTS_PER_INTERFACE)
362 new_alloc = DBUS_MAX_OBJECTS_PER_INTERFACE;
363 if (new_alloc == entry->n_allocated)
365 _dbus_warn ("Attempting to register another instance with interface %s, but max count %d reached\n",
366 entry->name, DBUS_MAX_OBJECTS_PER_INTERFACE);
370 new_objects = dbus_realloc (entry->objects, new_alloc * sizeof (dbus_uint16_t));
371 if (new_objects == NULL)
373 entry->objects = new_objects;
374 entry->n_allocated = new_alloc;
377 _dbus_assert (entry->n_objects < entry->n_allocated);
379 entry->objects[entry->n_objects] = object_index;
380 entry->n_objects += 1;
386 interface_entry_remove_object (DBusInterfaceEntry *entry,
387 dbus_uint16_t object_index)
392 while (i < entry->n_objects)
394 if (entry->objects[i] == object_index)
399 if (i == entry->n_objects)
401 _dbus_assert_not_reached ("Tried to remove object from an interface that didn't list that object\n");
405 memmove (&entry->objects[i],
406 &entry->objects[i+1],
407 (entry->n_objects - i - 1) * sizeof (entry->objects[0]));
408 entry->n_objects -= 1;
412 object_remove_from_interfaces (DBusObjectRegistry *registry,
413 DBusObjectEntry *entry)
415 if (entry->interfaces != NULL)
420 while (entry->interfaces[i] != NULL)
422 DBusInterfaceEntry *iface = entry->interfaces[i];
424 interface_entry_remove_object (iface, entry->id_index);
425 if (iface->n_objects == 0)
426 delete_interface (registry, iface);
432 static DBusSignalEntry*
433 lookup_signal (DBusObjectRegistry *registry,
435 dbus_bool_t create_if_not_found)
437 DBusSignalEntry *entry;
441 entry = _dbus_hash_table_lookup_string (registry->signal_table,
443 if (entry != NULL || !create_if_not_found)
446 _dbus_assert (create_if_not_found);
449 sz = _DBUS_STRUCT_OFFSET (DBusSignalEntry, name) + len + 1;
450 entry = dbus_malloc (sz);
453 entry->n_connections = 0;
454 entry->n_allocated = 0;
455 entry->connections = NULL;
456 memcpy (entry->name, name, len + 1);
458 if (!_dbus_hash_table_insert_string (registry->signal_table,
469 delete_signal (DBusObjectRegistry *registry,
470 DBusSignalEntry *entry)
472 _dbus_hash_table_remove_string (registry->signal_table,
477 signal_entry_add_object (DBusSignalEntry *entry,
478 dbus_uint16_t object_index)
480 if (entry->n_connections == entry->n_allocated)
482 unsigned int new_alloc;
483 dbus_uint16_t *new_objects;
485 if (entry->n_allocated == 0)
488 new_alloc = entry->n_allocated * 2;
490 /* Right now MAX_CONNECTIONS_PER_SIGNAL can't possibly be reached
491 * since the max number of objects _total_ is smaller, but the
492 * code is here for future robustness.
495 if (new_alloc > DBUS_MAX_CONNECTIONS_PER_SIGNAL)
496 new_alloc = DBUS_MAX_CONNECTIONS_PER_SIGNAL;
497 if (new_alloc == entry->n_allocated)
499 _dbus_warn ("Attempting to register another instance with signal %s, but max count %d reached\n",
500 entry->name, DBUS_MAX_CONNECTIONS_PER_SIGNAL);
504 new_objects = dbus_realloc (entry->connections, new_alloc * sizeof (dbus_uint16_t));
505 if (new_objects == NULL)
507 entry->connections = new_objects;
508 entry->n_allocated = new_alloc;
511 _dbus_assert (entry->n_connections < entry->n_allocated);
513 entry->connections[entry->n_connections] = object_index;
514 entry->n_connections += 1;
520 signal_entry_remove_object (DBusSignalEntry *entry,
521 dbus_uint16_t object_index)
526 while (i < entry->n_connections)
528 if (entry->connections[i] == object_index)
533 if (i == entry->n_connections)
535 _dbus_assert_not_reached ("Tried to remove object from an signal that didn't list that object\n");
539 memmove (&entry->connections[i],
540 &entry->connections[i+1],
541 (entry->n_connections - i - 1) * sizeof (entry->connections[0]));
542 entry->n_connections -= 1;
546 object_remove_from_signals (DBusObjectRegistry *registry,
547 DBusObjectEntry *entry)
549 if (entry->signals != NULL)
554 while (entry->signals[i] != NULL)
556 DBusSignalEntry *iface = entry->signals[i];
558 signal_entry_remove_object (iface, entry->id_index);
559 if (iface->n_connections == 0)
560 delete_signal (registry, iface);
567 * Connect this object to the given signal, such that if a
568 * signal emission message is received with the given
569 * signal name, the message will be routed to the
572 * Must be called with #DBusConnection lock held.
574 * @param registry the object registry
575 * @param object_id object that would like to see the signal
576 * @param signal signal name
578 * @returns #FALSE if no memory
581 _dbus_object_registry_connect_locked (DBusObjectRegistry *registry,
582 const DBusObjectID *object_id,
583 const char *signal_name)
585 DBusSignalEntry **new_signals;
586 DBusSignalEntry *signal;
587 DBusObjectEntry *entry;
590 entry = validate_id (registry, object_id);
593 _dbus_warn ("Tried to connect a nonexistent D-BUS object ID to signal \"%s\"\n",
599 /* O(n) in number of connections unfortunately, but in practice I
600 * don't think it will matter. It's marginally a space-time
601 * tradeoff (save an n_signals field) but the NULL termination is
602 * just as large as an n_signals once we have even a single
606 if (entry->signals != NULL)
608 while (entry->signals[i] != NULL)
612 new_signals = dbus_realloc (entry->signals,
613 (i + 2) * sizeof (DBusSignalEntry*));
615 if (new_signals == NULL)
618 entry->signals = new_signals;
620 signal = lookup_signal (registry, signal_name, TRUE);
624 if (!signal_entry_add_object (signal, entry->id_index))
627 entry->signals[i] = signal;
629 entry->signals[i] = NULL;
634 if (signal && signal->n_connections == 0)
635 delete_signal (registry, signal);
641 * Reverses effects of _dbus_object_registry_disconnect_locked().
643 * @param registry the object registry
644 * @param object_id object that would like to see the signal
645 * @param signal signal name
648 _dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry,
649 const DBusObjectID *object_id,
650 const char *signal_name)
652 DBusObjectEntry *entry;
653 DBusSignalEntry *signal;
655 entry = validate_id (registry, object_id);
658 _dbus_warn ("Tried to disconnect signal \"%s\" from a nonexistent D-BUS object ID\n",
664 signal = lookup_signal (registry, signal_name, FALSE);
667 _dbus_warn ("Tried to disconnect signal \"%s\" but no such signal is connected\n",
672 signal_entry_remove_object (signal, entry->id_index);
674 if (signal->n_connections == 0)
675 delete_signal (registry, signal);
678 static DBusHandlerResult
679 handle_method_call_and_unlock (DBusObjectRegistry *registry,
680 DBusMessage *message)
682 DBusInterfaceEntry *iface_entry;
683 DBusObjectEntry *object_entry;
685 const DBusObjectVTable *vtable;
687 _dbus_assert (registry != NULL);
688 _dbus_assert (message != NULL);
690 /* FIXME handle calls to an object ID instead of just an
694 /* If the message isn't to a specific object ID, we send
695 * it to the first object that supports the given interface.
697 iface_entry = lookup_interface (registry,
698 dbus_message_get_name (message),
701 if (iface_entry == NULL)
703 #ifdef DBUS_BUILD_TESTS
704 if (registry->connection)
706 _dbus_connection_unlock (registry->connection);
708 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
711 _dbus_assert (iface_entry->n_objects > 0);
712 _dbus_assert (iface_entry->objects != NULL);
714 object_entry = ®istry->entries[iface_entry->objects[0]];
717 /* Once we have an object entry, pass message to the object */
719 _dbus_assert (object_entry->vtable != NULL);
721 info_from_entry (registry, &info, object_entry);
722 vtable = object_entry->vtable;
724 /* Drop lock and invoke application code */
725 #ifdef DBUS_BUILD_TESTS
726 if (registry->connection)
728 _dbus_connection_unlock (registry->connection);
730 (* vtable->message) (&info, message);
732 return DBUS_HANDLER_RESULT_HANDLED;
740 static DBusHandlerResult
741 handle_signal_and_unlock (DBusObjectRegistry *registry,
742 DBusMessage *message)
744 DBusSignalEntry *signal_entry;
746 ObjectEmitData *objects;
749 _dbus_assert (registry != NULL);
750 _dbus_assert (message != NULL);
752 signal_entry = lookup_signal (registry,
753 dbus_message_get_name (message),
756 if (signal_entry == NULL)
758 #ifdef DBUS_BUILD_TESTS
759 if (registry->connection)
761 _dbus_connection_unlock (registry->connection);
763 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
766 _dbus_assert (signal_entry->n_connections > 0);
767 _dbus_assert (signal_entry->connections != NULL);
769 /* make a copy for safety vs. reentrancy */
771 /* FIXME (?) if you disconnect a signal during (vs. before)
772 * emission, you still receive that signal. To fix this uses more
773 * memory because we don't have a per-connection object at the
774 * moment. You would have to introduce a connection object and
775 * refcount it and have a "disconnected" flag. This is more like
776 * GObject semantics but also maybe not important at this level (the
777 * GObject/Qt wrappers can mop it up).
780 n_objects = signal_entry->n_connections;
781 objects = dbus_new (ObjectEmitData, n_objects);
785 #ifdef DBUS_BUILD_TESTS
786 if (registry->connection)
788 _dbus_connection_unlock (registry->connection);
790 return DBUS_HANDLER_RESULT_NEED_MEMORY;
794 while (i < signal_entry->n_connections)
796 DBusObjectEntry *object_entry;
799 idx = signal_entry->connections[i];
801 object_entry = ®istry->entries[idx];
803 _dbus_assert (object_entry->vtable != NULL);
805 id_from_entry (registry,
812 #ifdef DBUS_BUILD_TESTS
813 if (registry->connection)
815 _dbus_connection_ref_unlocked (registry->connection);
816 _dbus_object_registry_ref (registry);
817 dbus_message_ref (message);
820 while (i < n_objects)
822 DBusObjectEntry *object_entry;
824 /* If an object ID no longer exists, don't send the
827 object_entry = validate_id (registry, &objects[i].id);
828 if (object_entry != NULL)
830 const DBusObjectVTable *vtable;
833 info_from_entry (registry, &info, object_entry);
834 vtable = object_entry->vtable;
836 /* Drop lock and invoke application code */
837 #ifdef DBUS_BUILD_TESTS
838 if (registry->connection)
840 _dbus_connection_unlock (registry->connection);
842 (* vtable->message) (&info, message);
845 #ifdef DBUS_BUILD_TESTS
846 if (registry->connection)
848 _dbus_connection_lock (registry->connection);
853 dbus_message_unref (message);
854 _dbus_object_registry_unref (registry);
855 #ifdef DBUS_BUILD_TESTS
856 if (registry->connection)
858 _dbus_connection_unref_unlocked (registry->connection);
862 /* Drop lock a final time */
863 #ifdef DBUS_BUILD_TESTS
864 if (registry->connection)
866 _dbus_connection_unlock (registry->connection);
868 return DBUS_HANDLER_RESULT_HANDLED;
872 * Handle a message, passing it to any objects in the registry that
875 * @todo handle messages to an object ID, not just those to
878 * @param registry the object registry
879 * @param message the message to handle
880 * @returns what to do with the message next
883 _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry,
884 DBusMessage *message)
888 _dbus_assert (registry != NULL);
889 _dbus_assert (message != NULL);
891 type = dbus_message_get_type (message);
895 case DBUS_MESSAGE_TYPE_METHOD_CALL:
896 return handle_method_call_and_unlock (registry, message);
897 case DBUS_MESSAGE_TYPE_SIGNAL:
898 return handle_signal_and_unlock (registry, message);
900 #ifdef DBUS_BUILD_TESTS
901 if (registry->connection)
903 _dbus_connection_unlock (registry->connection);
905 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
910 _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry,
911 const char **interfaces,
912 const DBusObjectVTable *vtable,
914 DBusObjectID *object_id)
920 if (registry->n_entries_used == registry->n_entries_allocated)
922 DBusObjectEntry *new_entries;
925 if (registry->n_entries_allocated == 0)
929 if (registry->n_entries_allocated == DBUS_MAX_OBJECTS_PER_CONNECTION)
931 _dbus_warn ("Attempting to register a new D-BUS object, but maximum object count of %d reached\n",
932 DBUS_MAX_OBJECTS_PER_CONNECTION);
936 new_alloc = registry->n_entries_allocated * 2;
937 if (new_alloc > DBUS_MAX_OBJECTS_PER_CONNECTION)
938 new_alloc = DBUS_MAX_OBJECTS_PER_CONNECTION;
941 new_entries = dbus_realloc (registry->entries,
942 new_alloc * sizeof (DBusObjectEntry));
944 if (new_entries == NULL)
947 memset (&new_entries[registry->n_entries_allocated],
949 sizeof (DBusObjectEntry) * (new_alloc - registry->n_entries_allocated));
951 registry->entries = new_entries;
952 registry->n_entries_allocated = new_alloc;
954 _dbus_assert (registry->n_entries_used < registry->n_entries_allocated);
956 /* We linear search for an available entry. However, short-circuit
957 * the hopefully-common situation where we don't have a sparse
960 if (registry->entries[registry->n_entries_used].vtable == NULL)
962 idx = registry->n_entries_used;
966 /* If we do have a sparse array, we try to get rid of it rather
967 * than using empty slots on the end, so we won't hit this case
971 /* If index n_entries_used is occupied, then
972 * there is at least one entry outside of
973 * the range [0, n_entries_used). Thus, there is
974 * at least one blank entry inside that range.
977 while (idx < registry->n_entries_used)
979 if (registry->entries[idx].vtable == NULL)
984 _dbus_assert (idx < registry->n_entries_used);
987 registry->entries[idx].id_index = idx;
988 /* Overflow is OK here, but zero isn't as it's a null ID */
989 registry->entries[idx].id_times_used += 1;
990 if (registry->entries[idx].id_times_used == 0)
991 registry->entries[idx].id_times_used += 1;
993 registry->entries[idx].vtable = vtable;
994 registry->entries[idx].object_impl = object_impl;
996 registry->n_entries_used += 1;
999 if (interfaces != NULL)
1001 while (interfaces[i] != NULL)
1007 DBusInterfaceEntry **new_interfaces;
1010 dbus_realloc (registry->entries[idx].interfaces,
1011 (i + 1) * sizeof (DBusInterfaceEntry*));
1013 if (new_interfaces == NULL)
1015 /* maintain invariant that .interfaces array points to something
1016 * valid in oom handler (entering this function it pointed to
1017 * stale data but a valid malloc block)
1019 dbus_free (registry->entries[idx].interfaces);
1020 registry->entries[idx].interfaces = NULL;
1024 /* NULL-init so it's NULL-terminated and the OOM
1025 * case can see how far we got
1029 new_interfaces[i] = NULL;
1033 registry->entries[idx].interfaces = new_interfaces;
1037 dbus_free (registry->entries[idx].interfaces);
1038 registry->entries[idx].interfaces = NULL;
1041 /* Fill in interfaces */
1042 if (interfaces != NULL)
1045 while (interfaces[i] != NULL)
1047 DBusInterfaceEntry *iface;
1049 iface = lookup_interface (registry, interfaces[i],
1054 if (!interface_entry_add_object (iface, idx))
1056 if (iface->n_objects == 0)
1057 delete_interface (registry, iface);
1061 registry->entries[idx].interfaces[i] = iface;
1067 info_from_entry (registry, &info, ®istry->entries[idx]);
1069 *object_id = info.object_id;
1071 /* Drop lock and invoke application code */
1072 #ifdef DBUS_BUILD_TESTS
1073 if (registry->connection)
1075 _dbus_connection_unlock (registry->connection);
1077 (* vtable->registered) (&info);
1082 registry->entries[idx].vtable = NULL;
1083 registry->entries[idx].object_impl = NULL;
1084 registry->n_entries_used -= 1;
1086 object_remove_from_interfaces (registry,
1087 ®istry->entries[idx]);
1090 #ifdef DBUS_BUILD_TESTS
1091 if (registry->connection)
1093 _dbus_connection_unlock (registry->connection);
1098 _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry,
1099 const DBusObjectID *object_id)
1101 DBusObjectInfo info;
1102 DBusObjectEntry *entry;
1103 const DBusObjectVTable *vtable;
1105 entry = validate_id (registry, object_id);
1108 _dbus_warn ("Tried to unregister a nonexistent D-BUS object ID\n");
1109 #ifdef DBUS_BUILD_TESTS
1110 if (registry->connection)
1112 _dbus_connection_unlock (registry->connection);
1117 object_remove_from_signals (registry, entry);
1118 object_remove_from_interfaces (registry, entry);
1120 info_from_entry (registry, &info, entry);
1121 vtable = entry->vtable;
1122 entry->vtable = NULL;
1123 entry->object_impl = NULL;
1124 registry->n_entries_used -= 1;
1126 /* Drop lock and invoke application code */
1127 #ifdef DBUS_BUILD_TESTS
1128 if (registry->connection)
1130 _dbus_connection_unlock (registry->connection);
1132 (* vtable->unregistered) (&info);
1137 _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry)
1142 while (registry->n_entries_used > 0)
1144 _dbus_assert (i < registry->n_entries_allocated);
1145 if (registry->entries[i].vtable != NULL)
1147 DBusObjectInfo info;
1148 const DBusObjectVTable *vtable;
1150 object_remove_from_interfaces (registry,
1151 ®istry->entries[i]);
1153 info_from_entry (registry, &info, ®istry->entries[i]);
1154 vtable = registry->entries[i].vtable;
1155 registry->entries[i].vtable = NULL;
1156 registry->entries[i].object_impl = NULL;
1157 registry->n_entries_used -= 1;
1158 _dbus_assert (registry->n_entries_used >= 0);
1160 (* vtable->unregistered) (&info);
1166 _dbus_assert (registry->n_entries_used == 0);
1171 #ifdef DBUS_BUILD_TESTS
1172 #include "dbus-test.h"
1176 noop_message_function (DBusObjectInfo *info,
1177 DBusMessage *message)
1183 add_and_remove_objects (DBusObjectRegistry *registry)
1185 #define N_OBJECTS 73
1186 DBusObjectID ids[N_OBJECTS];
1187 const char *zero_interfaces[] = { NULL };
1188 const char *one_interface[] = { "org.freedesktop.Test.Blah", NULL };
1189 const char *three_interfaces[] = { "org.freedesktop.Test.Blah",
1190 "org.freedesktop.Test.Baz",
1191 "org.freedesktop.Test.Foo",
1194 DBusMessage *message;
1197 while (i < N_OBJECTS)
1199 DBusCallbackObject *callback;
1200 const char **interfaces;
1202 callback = dbus_callback_object_new (noop_message_function, NULL, NULL);
1203 if (callback == NULL)
1210 interfaces = zero_interfaces;
1213 interfaces = one_interface;
1216 interfaces = three_interfaces;
1219 _dbus_assert (interfaces != NULL);
1221 if (!_dbus_object_registry_add_and_unlock (registry,
1223 dbus_callback_object_vtable,
1227 dbus_callback_object_unref (callback);
1231 dbus_callback_object_unref (callback);
1237 while (i < N_OBJECTS)
1239 if (i > (N_OBJECTS - 20) || (i % 3) == 0)
1241 _dbus_object_registry_remove_and_unlock (registry,
1243 dbus_object_id_set_null (&ids[i]);
1250 while (i < N_OBJECTS)
1252 if (dbus_object_id_is_null (&ids[i]))
1254 DBusCallbackObject *callback;
1255 const char **interfaces;
1257 callback = dbus_callback_object_new (noop_message_function, NULL, NULL);
1258 if (callback == NULL)
1268 interfaces = zero_interfaces;
1271 interfaces = one_interface;
1274 interfaces = three_interfaces;
1278 if (!_dbus_object_registry_add_and_unlock (registry,
1280 dbus_callback_object_vtable,
1284 dbus_callback_object_unref (callback);
1288 dbus_callback_object_unref (callback);
1294 message = dbus_message_new_method_call ("org.freedesktop.Test.Foo", NULL);
1295 if (message != NULL)
1297 if (_dbus_object_registry_handle_and_unlock (registry, message) !=
1298 DBUS_HANDLER_RESULT_HANDLED)
1299 _dbus_assert_not_reached ("message not handled\n");
1300 dbus_message_unref (message);
1303 message = dbus_message_new_method_call ("org.freedesktop.Test.Blah", NULL);
1304 if (message != NULL)
1306 if (_dbus_object_registry_handle_and_unlock (registry, message) !=
1307 DBUS_HANDLER_RESULT_HANDLED)
1308 _dbus_assert_not_reached ("message not handled\n");
1309 dbus_message_unref (message);
1312 message = dbus_message_new_method_call ("org.freedesktop.Test.NotRegisteredIface", NULL);
1313 if (message != NULL)
1315 if (_dbus_object_registry_handle_and_unlock (registry, message) !=
1316 DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1317 _dbus_assert_not_reached ("message handled but no handler was registered\n");
1318 dbus_message_unref (message);
1322 while (i < (N_OBJECTS - 30))
1324 _dbus_assert (!dbus_object_id_is_null (&ids[i]));
1326 _dbus_object_registry_remove_and_unlock (registry,
1332 /* unregister the rest this way, to test this function */
1333 _dbus_object_registry_free_all_unlocked (registry);
1337 object_registry_test_iteration (void *data)
1339 DBusObjectRegistry *registry;
1341 registry = _dbus_object_registry_new (NULL);
1342 if (registry == NULL)
1345 /* we do this twice since realloc behavior will differ each time,
1346 * and the IDs will get recycled leading to slightly different
1349 add_and_remove_objects (registry);
1350 add_and_remove_objects (registry);
1352 _dbus_object_registry_unref (registry);
1358 * @ingroup DBusObjectRegistry
1359 * Unit test for DBusObjectRegistry
1360 * @returns #TRUE on success.
1363 _dbus_object_registry_test (void)
1365 _dbus_test_oom_handling ("object registry",
1366 object_registry_test_iteration,
1372 #endif /* DBUS_BUILD_TESTS */