From cefb84edc5f84011c5a171e5d052e37c56c55d27 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 7 Aug 2003 02:18:54 +0000 Subject: 2003-08-06 Havoc Pennington * dbus/dbus-object-registry.c: implement signal connection and dispatch * dbus/dbus-connection.c (_dbus_connection_unref_unlocked): new * dbus/dbus-internals.c (_dbus_memdup): new function --- dbus/dbus-connection-internal.h | 1 + dbus/dbus-connection.c | 48 +++- dbus/dbus-internals.c | 27 +- dbus/dbus-internals.h | 2 + dbus/dbus-object-registry.c | 617 +++++++++++++++++++++++++++++++++++----- dbus/dbus-object-registry.h | 8 +- dbus/dbus-object.h | 5 +- 7 files changed, 628 insertions(+), 80 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 5bcbcc2f..423df5f8 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -42,6 +42,7 @@ typedef enum void _dbus_connection_lock (DBusConnection *connection); void _dbus_connection_unlock (DBusConnection *connection); void _dbus_connection_ref_unlocked (DBusConnection *connection); +void _dbus_connection_unref_unlocked (DBusConnection *connection); dbus_bool_t _dbus_connection_queue_received_message (DBusConnection *connection, DBusMessage *message); void _dbus_connection_queue_received_message_link (DBusConnection *connection, diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ced50bd1..407b4d24 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -203,7 +203,7 @@ static void _dbus_connection_remove_timeout_locked (DB static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection); static void _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection, DBusDispatchStatus new_status); - +static void _dbus_connection_last_unref (DBusConnection *connection); /** @@ -824,6 +824,39 @@ _dbus_connection_ref_unlocked (DBusConnection *connection) #endif } +/** + * Decrements the reference count of a DBusConnection. + * Requires that the caller already holds the connection lock. + * + * @param connection the connection. + */ +void +_dbus_connection_unref_unlocked (DBusConnection *connection) +{ + dbus_bool_t last_unref; + + _dbus_return_if_fail (connection != NULL); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ + +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&connection->refcount) == 1); +#else + _dbus_assert (connection->refcount.value > 0); + + connection->refcount.value -= 1; + last_unref = (connection->refcount.value == 0); +#if 0 + printf ("unref_unlocked() connection %p count = %d\n", connection, connection->refcount.value); +#endif +#endif + + if (last_unref) + _dbus_connection_last_unref (connection); +} + static dbus_uint32_t _dbus_connection_get_next_client_serial (DBusConnection *connection) { @@ -2215,6 +2248,8 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) * does not necessarily dispatch a message, as the data may * be part of authentication or the like. * + * @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY + * * @param connection the connection * @returns dispatch status */ @@ -2310,7 +2345,7 @@ dbus_connection_dispatch (DBusConnection *connection) result = _dbus_message_handler_handle_message (handler, connection, message); - if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + if (result != DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS) break; link = next; @@ -2323,6 +2358,9 @@ dbus_connection_dispatch (DBusConnection *connection) CONNECTION_LOCK (connection); + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + /* FIXME */ ; + /* Did a reply we were waiting on get filtered? */ if (reply_handler_data && result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) { @@ -2342,7 +2380,7 @@ dbus_connection_dispatch (DBusConnection *connection) if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) goto out; - + if (reply_handler_data) { CONNECTION_UNLOCK (connection); @@ -2364,9 +2402,13 @@ dbus_connection_dispatch (DBusConnection *connection) result = _dbus_object_registry_handle_and_unlock (connection->objects, message); + CONNECTION_LOCK (connection); if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) goto out; + + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + /* FIXME */ ; _dbus_verbose (" done dispatching %p (%s) on connection %p\n", message, dbus_message_get_name (message), connection); diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 6e7f9e16..ccc11776 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -248,7 +248,7 @@ _dbus_verbose_reset_real (void) char* _dbus_strdup (const char *str) { - int len; + size_t len; char *copy; if (str == NULL) @@ -265,6 +265,31 @@ _dbus_strdup (const char *str) return copy; } +#ifdef DBUS_BUILD_TESTS /* memdup not used at the moment */ +/** + * Duplicates a block of memory. Returns + * #NULL on failure. + * + * @param mem memory to copy + * @param n_bytes number of bytes to copy + * @returns the copy + */ +void* +_dbus_memdup (const void *mem, + size_t n_bytes) +{ + void *copy; + + copy = dbus_malloc (n_bytes); + if (copy == NULL) + return NULL; + + memcpy (copy, mem, n_bytes); + + return copy; +} +#endif + /** * Duplicates a string array. Result may be freed with * dbus_free_string_array(). Returns #NULL if memory allocation fails. diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 7acda71a..6d120f1b 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -144,6 +144,8 @@ extern const char _dbus_return_if_fail_warning_format[]; ((void*)_DBUS_ALIGN_VALUE(this, boundary)) char* _dbus_strdup (const char *str); +void* _dbus_memdup (const void *mem, + size_t n_bytes); dbus_bool_t _dbus_string_array_contains (const char **array, const char *str); char** _dbus_dup_string_array (const char **array); diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index a4d92216..55f8f749 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -35,11 +35,16 @@ * Types and functions related to DBusObjectRegistry. These * are all internal. * + * @todo interface entries and signal connections are handled pretty + * much identically, with lots of duplicate code. Once we're sure + * they will always be the same, we could merge this code. + * * @{ */ typedef struct DBusObjectEntry DBusObjectEntry; typedef struct DBusInterfaceEntry DBusInterfaceEntry; +typedef struct DBusSignalEntry DBusSignalEntry; #define DBUS_MAX_OBJECTS_PER_INTERFACE 65535 struct DBusInterfaceEntry @@ -50,6 +55,17 @@ struct DBusInterfaceEntry char name[4]; /**< Name of interface (actually allocated larger) */ }; +#define DBUS_MAX_CONNECTIONS_PER_SIGNAL 65535 +struct DBusSignalEntry +{ + unsigned int n_connections : 16; /**< Number of connections to this signal */ + unsigned int n_allocated : 16; /**< Allocated size of objects array */ + dbus_uint16_t *connections; /**< Index of each object connected (can have dups for multiple + * connections) + */ + char name[4]; /**< Name of signal (actually allocated larger) */ +}; + /* 14 bits for object index, 32K objects */ #define DBUS_OBJECT_INDEX_BITS (14) #define DBUS_OBJECT_INDEX_MASK (0x3fff) @@ -62,6 +78,7 @@ struct DBusObjectEntry void *object_impl; /**< Pointer to application-supplied implementation */ const DBusObjectVTable *vtable; /**< Virtual table for this object */ DBusInterfaceEntry **interfaces; /**< NULL-terminated list of interfaces */ + DBusSignalEntry **signals; /**< Signal connections (contains dups, one each time we connect) */ }; struct DBusObjectRegistry @@ -74,6 +91,8 @@ struct DBusObjectRegistry int n_entries_used; DBusHashTable *interface_table; + + DBusHashTable *signal_table; }; static void @@ -88,11 +107,24 @@ free_interface_entry (void *entry) dbus_free (iface); } +static void +free_signal_entry (void *entry) +{ + DBusSignalEntry *signal = entry; + + if (signal == NULL) /* DBusHashTable stupidity */ + return; + + dbus_free (signal->connections); + dbus_free (signal); +} + DBusObjectRegistry* _dbus_object_registry_new (DBusConnection *connection) { DBusObjectRegistry *registry; DBusHashTable *interface_table; + DBusHashTable *signal_table; /* the connection passed in here isn't fully constructed, * so don't do anything more than store a pointer to @@ -101,6 +133,7 @@ _dbus_object_registry_new (DBusConnection *connection) registry = NULL; interface_table = NULL; + signal_table = NULL; registry = dbus_new0 (DBusObjectRegistry, 1); if (registry == NULL) @@ -110,10 +143,16 @@ _dbus_object_registry_new (DBusConnection *connection) NULL, free_interface_entry); if (interface_table == NULL) goto oom; + + signal_table = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, free_signal_entry); + if (signal_table == NULL) + goto oom; registry->refcount = 1; registry->connection = connection; registry->interface_table = interface_table; + registry->signal_table = signal_table; return registry; @@ -122,7 +161,9 @@ _dbus_object_registry_new (DBusConnection *connection) dbus_free (registry); if (interface_table) _dbus_hash_table_unref (interface_table); - + if (signal_table) + _dbus_hash_table_unref (signal_table); + return NULL; } @@ -147,16 +188,20 @@ _dbus_object_registry_unref (DBusObjectRegistry *registry) _dbus_assert (registry->n_entries_used == 0); _dbus_assert (_dbus_hash_table_get_n_entries (registry->interface_table) == 0); + _dbus_assert (_dbus_hash_table_get_n_entries (registry->signal_table) == 0); i = 0; while (i < registry->n_entries_allocated) { if (registry->entries[i].interfaces) dbus_free (registry->entries[i].interfaces); + if (registry->entries[i].signals) + dbus_free (registry->entries[i].signals); ++i; } _dbus_hash_table_unref (registry->interface_table); + _dbus_hash_table_unref (registry->signal_table); dbus_free (registry->entries); dbus_free (registry); } @@ -213,32 +258,41 @@ validate_id (DBusObjectRegistry *registry, } static void -info_from_entry (DBusObjectRegistry *registry, - DBusObjectInfo *info, - DBusObjectEntry *entry) +id_from_entry (DBusObjectRegistry *registry, + DBusObjectID *object_id, + DBusObjectEntry *entry) { - info->connection = registry->connection; - info->object_impl = entry->object_impl; #ifdef DBUS_BUILD_TESTS if (registry->connection) #endif _dbus_connection_init_id (registry->connection, - &info->object_id); + object_id); #ifdef DBUS_BUILD_TESTS else { - dbus_object_id_set_server_bits (&info->object_id, 1); - dbus_object_id_set_client_bits (&info->object_id, 2); + dbus_object_id_set_server_bits (object_id, 1); + dbus_object_id_set_client_bits (object_id, 2); } #endif - _dbus_assert (dbus_object_id_get_server_bits (&info->object_id) != 0); - _dbus_assert (dbus_object_id_get_client_bits (&info->object_id) != 0); + _dbus_assert (dbus_object_id_get_server_bits (object_id) != 0); + _dbus_assert (dbus_object_id_get_client_bits (object_id) != 0); - dbus_object_id_set_instance_bits (&info->object_id, + dbus_object_id_set_instance_bits (object_id, ENTRY_TO_ID (entry)); - _dbus_assert (dbus_object_id_get_instance_bits (&info->object_id) != 0); + _dbus_assert (dbus_object_id_get_instance_bits (object_id) != 0); +} + +static void +info_from_entry (DBusObjectRegistry *registry, + DBusObjectInfo *info, + DBusObjectEntry *entry) +{ + info->connection = registry->connection; + info->object_impl = entry->object_impl; + + id_from_entry (registry, &info->object_id, entry); } static DBusInterfaceEntry* @@ -375,6 +429,483 @@ object_remove_from_interfaces (DBusObjectRegistry *registry, } } +static DBusSignalEntry* +lookup_signal (DBusObjectRegistry *registry, + const char *name, + dbus_bool_t create_if_not_found) +{ + DBusSignalEntry *entry; + int sz; + int len; + + entry = _dbus_hash_table_lookup_string (registry->signal_table, + name); + if (entry != NULL || !create_if_not_found) + return entry; + + _dbus_assert (create_if_not_found); + + len = strlen (name); + sz = _DBUS_STRUCT_OFFSET (DBusSignalEntry, name) + len + 1; + entry = dbus_malloc (sz); + if (entry == NULL) + return NULL; + entry->n_connections = 0; + entry->n_allocated = 0; + entry->connections = NULL; + memcpy (entry->name, name, len + 1); + + if (!_dbus_hash_table_insert_string (registry->signal_table, + entry->name, entry)) + { + dbus_free (entry); + return NULL; + } + + return entry; +} + +static void +delete_signal (DBusObjectRegistry *registry, + DBusSignalEntry *entry) +{ + _dbus_hash_table_remove_string (registry->signal_table, + entry->name); +} + +static dbus_bool_t +signal_entry_add_object (DBusSignalEntry *entry, + dbus_uint16_t object_index) +{ + if (entry->n_connections == entry->n_allocated) + { + unsigned int new_alloc; + dbus_uint16_t *new_objects; + + if (entry->n_allocated == 0) + new_alloc = 2; + else + new_alloc = entry->n_allocated * 2; + + /* Right now MAX_CONNECTIONS_PER_SIGNAL can't possibly be reached + * since the max number of objects _total_ is smaller, but the + * code is here for future robustness. + */ + + if (new_alloc > DBUS_MAX_CONNECTIONS_PER_SIGNAL) + new_alloc = DBUS_MAX_CONNECTIONS_PER_SIGNAL; + if (new_alloc == entry->n_allocated) + { + _dbus_warn ("Attempting to register another instance with signal %s, but max count %d reached\n", + entry->name, DBUS_MAX_CONNECTIONS_PER_SIGNAL); + return FALSE; + } + + new_objects = dbus_realloc (entry->connections, new_alloc * sizeof (dbus_uint16_t)); + if (new_objects == NULL) + return FALSE; + entry->connections = new_objects; + entry->n_allocated = new_alloc; + } + + _dbus_assert (entry->n_connections < entry->n_allocated); + + entry->connections[entry->n_connections] = object_index; + entry->n_connections += 1; + + return TRUE; +} + +static void +signal_entry_remove_object (DBusSignalEntry *entry, + dbus_uint16_t object_index) +{ + unsigned int i; + + i = 0; + while (i < entry->n_connections) + { + if (entry->connections[i] == object_index) + break; + ++i; + } + + if (i == entry->n_connections) + { + _dbus_assert_not_reached ("Tried to remove object from an signal that didn't list that object\n"); + return; + } + + memmove (&entry->connections[i], + &entry->connections[i+1], + (entry->n_connections - i - 1) * sizeof (entry->connections[0])); + entry->n_connections -= 1; +} + +static void +object_remove_from_signals (DBusObjectRegistry *registry, + DBusObjectEntry *entry) +{ + if (entry->signals != NULL) + { + int i; + + i = 0; + while (entry->signals[i] != NULL) + { + DBusSignalEntry *iface = entry->signals[i]; + + signal_entry_remove_object (iface, entry->id_index); + if (iface->n_connections == 0) + delete_signal (registry, iface); + ++i; + } + } +} + +/** + * Connect this object to the given signal, such that if a + * signal emission message is received with the given + * signal name, the message will be routed to the + * given object. + * + * Must be called with #DBusConnection lock held. + * + * @param registry the object registry + * @param object_id object that would like to see the signal + * @param signal signal name + * + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_object_registry_connect_locked (DBusObjectRegistry *registry, + const DBusObjectID *object_id, + const char *signal_name) +{ + DBusSignalEntry **new_signals; + DBusSignalEntry *signal; + DBusObjectEntry *entry; + int i; + + entry = validate_id (registry, object_id); + if (entry == NULL) + { + _dbus_warn ("Tried to connect a nonexistent D-BUS object ID to signal \"%s\"\n", + signal_name); + + return FALSE; + } + + /* O(n) in number of connections unfortunately, but in practice I + * don't think it will matter. It's marginally a space-time + * tradeoff (save an n_signals field) but the NULL termination is + * just as large as an n_signals once we have even a single + * connection. + */ + i = 0; + if (entry->signals != NULL) + { + while (entry->signals[i] != NULL) + ++i; + } + + new_signals = dbus_realloc (entry->signals, + (i + 2) * sizeof (DBusSignalEntry*)); + + if (new_signals == NULL) + return FALSE; + + entry->signals = new_signals; + + signal = lookup_signal (registry, signal_name, TRUE); + if (signal == NULL) + goto oom; + + if (!signal_entry_add_object (signal, entry->id_index)) + goto oom; + + entry->signals[i] = signal; + ++i; + entry->signals[i] = NULL; + + return TRUE; + + oom: + if (signal && signal->n_connections == 0) + delete_signal (registry, signal); + + return FALSE; +} + +/** + * Reverses effects of _dbus_object_registry_disconnect_locked(). + * + * @param registry the object registry + * @param object_id object that would like to see the signal + * @param signal signal name + */ +void +_dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry, + const DBusObjectID *object_id, + const char *signal_name) +{ + DBusObjectEntry *entry; + DBusSignalEntry *signal; + + entry = validate_id (registry, object_id); + if (entry == NULL) + { + _dbus_warn ("Tried to disconnect signal \"%s\" from a nonexistent D-BUS object ID\n", + signal_name); + + return; + } + + signal = lookup_signal (registry, signal_name, FALSE); + if (signal == NULL) + { + _dbus_warn ("Tried to disconnect signal \"%s\" but no such signal is connected\n", + signal_name); + return; + } + + signal_entry_remove_object (signal, entry->id_index); + + if (signal->n_connections == 0) + delete_signal (registry, signal); +} + +static DBusHandlerResult +handle_method_call_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + DBusInterfaceEntry *iface_entry; + DBusObjectEntry *object_entry; + DBusObjectInfo info; + const DBusObjectVTable *vtable; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + /* FIXME handle calls to an object ID instead of just an + * interface name + */ + + /* If the message isn't to a specific object ID, we send + * it to the first object that supports the given interface. + */ + iface_entry = lookup_interface (registry, + dbus_message_get_name (message), + FALSE); + + if (iface_entry == NULL) + { +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + } + + _dbus_assert (iface_entry->n_objects > 0); + _dbus_assert (iface_entry->objects != NULL); + + object_entry = ®istry->entries[iface_entry->objects[0]]; + + + /* Once we have an object entry, pass message to the object */ + + _dbus_assert (object_entry->vtable != NULL); + + info_from_entry (registry, &info, object_entry); + vtable = object_entry->vtable; + + /* Drop lock and invoke application code */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + (* vtable->message) (&info, message); + + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; +} + +typedef struct +{ + DBusObjectID id; +} ObjectEmitData; + +static DBusHandlerResult +handle_signal_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + DBusSignalEntry *signal_entry; + int i; + ObjectEmitData *objects; + int n_objects; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + signal_entry = lookup_signal (registry, + dbus_message_get_name (message), + FALSE); + + if (signal_entry == NULL) + { +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + } + + _dbus_assert (signal_entry->n_connections > 0); + _dbus_assert (signal_entry->connections != NULL); + + /* make a copy for safety vs. reentrancy */ + + /* FIXME (?) if you disconnect a signal during (vs. before) + * emission, you still receive that signal. To fix this uses more + * memory because we don't have a per-connection object at the + * moment. You would have to introduce a connection object and + * refcount it and have a "disconnected" flag. This is more like + * GObject semantics but also maybe not important at this level (the + * GObject/Qt wrappers can mop it up). + */ + + n_objects = signal_entry->n_connections; + objects = dbus_new (ObjectEmitData, n_objects); + + if (objects == NULL) + { +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + i = 0; + while (i < signal_entry->n_connections) + { + DBusObjectEntry *object_entry; + int idx; + + idx = signal_entry->connections[i]; + + object_entry = ®istry->entries[idx]; + + _dbus_assert (object_entry->vtable != NULL); + + id_from_entry (registry, + &objects[i].id, + object_entry); + + ++i; + } + +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_ref_unlocked (registry->connection); + _dbus_object_registry_ref (registry); + dbus_message_ref (message); + + i = 0; + while (i < n_objects) + { + DBusObjectEntry *object_entry; + + /* If an object ID no longer exists, don't send the + * signal + */ + object_entry = validate_id (registry, &objects[i].id); + if (object_entry != NULL) + { + DBusObjectVTable *vtable; + DBusObjectInfo info; + + info_from_entry (registry, &info, object_entry); + vtable = object_entry->vtable; + + /* Drop lock and invoke application code */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + (* vtable->message) (&info, message); + + /* Reacquire lock */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_lock (registry->connection); + } + ++i; + } + + dbus_message_unref (message); + _dbus_object_registry_unref (registry); +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unref_unlocked (registry->connection); + + dbus_free (objects); + + /* Drop lock a final time */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; +} + +/** + * Handle a message, passing it to any objects in the registry that + * should receive it. + * + * @todo handle messages to an object ID, not just those to + * an interface name. + * + * @param registry the object registry + * @param message the message to handle + * @returns what to do with the message next + */ +DBusHandlerResult +_dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + int type; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + type = dbus_message_get_type (message); + + switch (type) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return handle_method_call_and_unlock (registry, message); + case DBUS_MESSAGE_TYPE_SIGNAL: + return handle_signal_and_unlock (registry, message); + default: +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + } +} + dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, const char **interfaces, @@ -583,6 +1114,7 @@ _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, return; } + object_remove_from_signals (registry, entry); object_remove_from_interfaces (registry, entry); info_from_entry (registry, &info, entry); @@ -600,65 +1132,6 @@ _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, (* vtable->unregistered) (&info); } -/** - * Handle a message, passing it to any objects in the registry that - * should receive it. - * - * @todo handle messages to an object ID, not just those to - * an interface name. - * - * @param registry the object registry - * @param message the message to handle - * @returns what to do with the message next - */ -DBusHandlerResult -_dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, - DBusMessage *message) -{ - DBusInterfaceEntry *iface_entry; - DBusObjectEntry *object_entry; - DBusObjectInfo info; - const DBusObjectVTable *vtable; - - _dbus_assert (registry != NULL); - _dbus_assert (message != NULL); - - if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - - /* If the message isn't to a specific object ID, we send - * it to the first object that supports the given interface. - */ - iface_entry = lookup_interface (registry, - dbus_message_get_name (message), - FALSE); - - if (iface_entry == NULL) - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - - _dbus_assert (iface_entry->n_objects > 0); - _dbus_assert (iface_entry->objects != NULL); - - object_entry = ®istry->entries[iface_entry->objects[0]]; - - - /* Once we have an object entry, pass message to the object */ - - _dbus_assert (object_entry->vtable != NULL); - - info_from_entry (registry, &info, object_entry); - vtable = object_entry->vtable; - - /* Drop lock and invoke application code */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - (* vtable->message) (&info, message); - - return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; -} void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) diff --git a/dbus/dbus-object-registry.h b/dbus/dbus-object-registry.h index 57009c87..bcbd0f84 100644 --- a/dbus/dbus-object-registry.h +++ b/dbus/dbus-object-registry.h @@ -43,8 +43,12 @@ void _dbus_object_registry_remove_and_unlock (DBusObjectRegistry DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, DBusMessage *message); void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry); - - +dbus_bool_t _dbus_object_registry_connect_locked (DBusObjectRegistry *registry, + const DBusObjectID *object_id, + const char *signal); +void _dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry, + const DBusObjectID *object_id, + const char *signal); DBUS_END_DECLS; diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h index a0a53eb0..76d0e6f6 100644 --- a/dbus/dbus-object.h +++ b/dbus/dbus-object.h @@ -41,8 +41,9 @@ typedef struct DBusCallbackObject DBusCallbackObject; typedef enum { - DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */ - DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS /**< Run any additional handlers that are interested in this message. */ + DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */ + DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS, /**< Run any additional handlers that are interested in this message. */ + DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory to handle this message. */ } DBusHandlerResult; struct DBusObjectInfo -- cgit