mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-06 14:10:15 +01:00
2003-08-06 Havoc Pennington <hp@pobox.com>
* 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
This commit is contained in:
parent
ff8908f1e9
commit
cefb84edc5
8 changed files with 644 additions and 87 deletions
|
|
@ -1,3 +1,12 @@
|
|||
2003-08-06 Havoc Pennington <hp@pobox.com>
|
||||
|
||||
* 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
|
||||
|
||||
2003-08-02 Havoc Pennington <hp@pobox.com>
|
||||
|
||||
* dbus/dbus-message.c (dbus_message_get_no_reply)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -212,6 +257,33 @@ validate_id (DBusObjectRegistry *registry,
|
|||
return ®istry->entries[idx];
|
||||
}
|
||||
|
||||
static void
|
||||
id_from_entry (DBusObjectRegistry *registry,
|
||||
DBusObjectID *object_id,
|
||||
DBusObjectEntry *entry)
|
||||
{
|
||||
#ifdef DBUS_BUILD_TESTS
|
||||
if (registry->connection)
|
||||
#endif
|
||||
_dbus_connection_init_id (registry->connection,
|
||||
object_id);
|
||||
#ifdef DBUS_BUILD_TESTS
|
||||
else
|
||||
{
|
||||
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 (object_id) != 0);
|
||||
_dbus_assert (dbus_object_id_get_client_bits (object_id) != 0);
|
||||
|
||||
dbus_object_id_set_instance_bits (object_id,
|
||||
ENTRY_TO_ID (entry));
|
||||
|
||||
_dbus_assert (dbus_object_id_get_instance_bits (object_id) != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
info_from_entry (DBusObjectRegistry *registry,
|
||||
DBusObjectInfo *info,
|
||||
|
|
@ -219,26 +291,8 @@ info_from_entry (DBusObjectRegistry *registry,
|
|||
{
|
||||
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);
|
||||
#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);
|
||||
}
|
||||
#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_object_id_set_instance_bits (&info->object_id,
|
||||
ENTRY_TO_ID (entry));
|
||||
|
||||
_dbus_assert (dbus_object_id_get_instance_bits (&info->object_id) != 0);
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue