diff options
| -rw-r--r-- | ChangeLog | 9 | ||||
| -rw-r--r-- | dbus/dbus-connection-internal.h | 1 | ||||
| -rw-r--r-- | dbus/dbus-connection.c | 48 | ||||
| -rw-r--r-- | dbus/dbus-internals.c | 27 | ||||
| -rw-r--r-- | dbus/dbus-internals.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-object-registry.c | 617 | ||||
| -rw-r--r-- | dbus/dbus-object-registry.h | 8 | ||||
| -rw-r--r-- | dbus/dbus-object.h | 5 | 
8 files changed, 637 insertions, 80 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) 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  | 
