diff options
author | Xavier Claessens <xavier.claessens@collabora.com> | 2014-03-26 12:34:09 -0400 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-27 15:28:20 +0000 |
commit | 40283bd0ce3efef9c7ea866db65290fd4d3a5c70 (patch) | |
tree | 44835c145d4378793a107a3dea8181484b0343b0 | |
parent | 98e7b7af4f9e2edccb5ef66203fd2726015c3b5c (diff) |
TpBaseConnection: Re-implement client interest using GDBusConnection
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r-- | telepathy-glib/base-connection.c | 287 |
1 files changed, 126 insertions, 161 deletions
diff --git a/telepathy-glib/base-connection.c b/telepathy-glib/base-connection.c index 5dc1e8768..8bd6f07e2 100644 --- a/telepathy-glib/base-connection.c +++ b/telepathy-glib/base-connection.c @@ -346,22 +346,22 @@ struct _TpBaseConnectionPrivate /* TRUE if on D-Bus */ gboolean been_registered; - /* g_strdup (unique name) => gsize total count - * - * This is derivable from @client_interests: e.g. if - * client_interests = { LOCATION => { ":1.23" => 5, ":1.42" => 2 }, - * MAIL_NOTIFICATION => { ":1.23" => 1 } } - * then it implies - * interested_clients = { ":1.23" => 6, ":1.42" => 2 } - */ - GHashTable *interested_clients; - /* GQuark iface => GHashTable { - * unique name borrowed from interested_clients => gsize count } */ - GHashTable *client_interests; + /* g_strdup (unique name) => owned ClientData struct */ + GHashTable *clients; + /* GQuark iface => number of clients interested */ + GHashTable *interests; gchar *account_path_suffix; }; +typedef struct +{ + /* GQuark iface => count */ + GHashTable *interests; + guint watch_id; +} ClientData; + +static void client_data_free (ClientData *client); static const gchar * const *tp_base_connection_get_interfaces ( TpBaseConnection *self); @@ -473,12 +473,6 @@ tp_base_connection_set_property (GObject *object, } } -static void tp_base_connection_interested_name_owner_changed_cb ( - TpDBusDaemon *it, - const gchar *unique_name, - const gchar *new_owner, - gpointer user_data); - static void tp_base_connection_unregister (TpBaseConnection *self) { @@ -487,7 +481,6 @@ tp_base_connection_unregister (TpBaseConnection *self) if (priv->bus_proxy != NULL) { GHashTableIter iter; - gpointer k; if (priv->been_registered) { @@ -501,14 +494,11 @@ tp_base_connection_unregister (TpBaseConnection *self) priv->been_registered = FALSE; } - g_hash_table_iter_init (&iter, self->priv->interested_clients); + g_hash_table_remove_all (self->priv->clients); - while (g_hash_table_iter_next (&iter, &k, NULL)) - { - tp_dbus_daemon_cancel_name_owner_watch (priv->bus_proxy, k, - tp_base_connection_interested_name_owner_changed_cb, self); - g_hash_table_iter_remove (&iter); - } + g_hash_table_iter_init (&iter, self->priv->interests); + while (g_hash_table_iter_next (&iter, NULL, NULL)) + g_hash_table_iter_replace (&iter, GUINT_TO_POINTER (0)); } } @@ -563,8 +553,8 @@ tp_base_connection_finalize (GObject *object) g_free (priv->protocol); g_free (priv->bus_name); g_free (priv->object_path); - g_hash_table_unref (priv->client_interests); - g_hash_table_unref (priv->interested_clients); + g_hash_table_unref (priv->clients); + g_hash_table_unref (priv->interests); g_free (priv->account_path_suffix); G_OBJECT_CLASS (tp_base_connection_parent_class)->finalize (object); @@ -880,9 +870,8 @@ tp_base_connection_add_possible_client_interest (TpBaseConnection *self, g_return_if_fail (TP_IS_BASE_CONNECTION (self)); g_return_if_fail (self->priv->status == TP_INTERNAL_CONNECTION_STATUS_NEW); - if (g_hash_table_lookup (self->priv->client_interests, p) == NULL) - g_hash_table_insert (self->priv->client_interests, p, - g_hash_table_new (g_str_hash, g_str_equal)); + if (!g_hash_table_contains (self->priv->interests, p)) + g_hash_table_insert (self->priv->interests, p, GUINT_TO_POINTER (0)); } /* D-Bus properties for the Requests interface */ @@ -1287,10 +1276,9 @@ tp_base_connection_init (TpBaseConnection *self) } priv->channel_requests = g_ptr_array_new_with_free_func (g_object_unref); - priv->client_interests = g_hash_table_new_full (NULL, NULL, NULL, - (GDestroyNotify) g_hash_table_unref); - priv->interested_clients = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); + priv->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) client_data_free); + priv->interests = g_hash_table_new (NULL, NULL); } static gchar * @@ -2034,44 +2022,92 @@ tp_base_connection_add_interfaces (TpBaseConnection *self, g_array_append_val (priv->interfaces, *interfaces); } +static guint +get_interest_count (GHashTable *table, + GQuark q) +{ + return GPOINTER_TO_UINT (g_hash_table_lookup (table, GUINT_TO_POINTER (q))); +} + +static guint +change_interest_count (GHashTable *table, + GQuark q, + gint delta) +{ + guint count; + + count = get_interest_count (table, q); + g_assert (delta >= 0 || count >= (guint) -delta); + count += delta; + g_hash_table_replace (table, GUINT_TO_POINTER (q), GUINT_TO_POINTER (count)); + + return count; +} + static void -tp_base_connection_interested_name_owner_changed_cb ( - TpDBusDaemon *it G_GNUC_UNUSED, +client_vanished_cb (GDBusConnection *connection, const gchar *unique_name, - const gchar *new_owner, gpointer user_data) { TpBaseConnection *self = user_data; + ClientData *client; GHashTableIter iter; - gpointer q, hash; - - /* We don't care about the initial report that :1.42 is owned by :1.42. */ - if (!tp_str_empty (new_owner)) - return; - - /* Failing that, @unique_name must have crashed... */ + gpointer key; - g_hash_table_iter_init (&iter, self->priv->client_interests); + client = g_hash_table_lookup (self->priv->clients, unique_name); + g_assert (client != NULL); - while (g_hash_table_iter_next (&iter, &q, &hash)) + /* For each iface this client was interested in, decrease the count of clients + * interested in it. Emit "clients-uninterested" if count drops to 0. */ + g_hash_table_iter_init (&iter, client->interests); + while (g_hash_table_iter_next (&iter, &key, NULL)) { - if (g_hash_table_remove (hash, unique_name) && - g_hash_table_size (hash) == 0) + GQuark q = GPOINTER_TO_UINT (key); + guint count; + + count = change_interest_count (self->priv->interests, q, -1); + if (count == 0) { - const gchar *s = g_quark_to_string (GPOINTER_TO_UINT (q)); + const gchar *s = g_quark_to_string (q); DEBUG ("%s was the last client interested in %s", unique_name, s); - g_signal_emit (self, signals[CLIENTS_UNINTERESTED], - (GQuark) GPOINTER_TO_UINT (q), s); + g_signal_emit (self, signals[CLIENTS_UNINTERESTED], q, s); } } - /* this has to be done last, because the keys in the other hashes are - * borrowed from here */ - g_hash_table_remove (self->priv->interested_clients, unique_name); + g_hash_table_remove (self->priv->clients, unique_name); +} + +static ClientData * +ensure_client_data (TpBaseConnection *self, + const gchar *unique_name) +{ + ClientData *client; + + client = g_hash_table_lookup (self->priv->clients, unique_name); + if (client == NULL) + { + client = g_slice_new0 (ClientData); + client->interests = g_hash_table_new (NULL, NULL); + client->watch_id = g_bus_watch_name_on_connection ( + tp_proxy_get_dbus_connection (self->priv->bus_proxy), + unique_name, + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, client_vanished_cb, + self, NULL); + + g_hash_table_insert (self->priv->clients, g_strdup (unique_name), client); + } - tp_dbus_daemon_cancel_name_owner_watch (self->priv->bus_proxy, - unique_name, tp_base_connection_interested_name_owner_changed_cb, self); + return client; +} + +static void +client_data_free (ClientData *client) +{ + g_hash_table_unref (client->interests); + g_bus_unwatch_name (client->watch_id); + g_slice_free (ClientData, client); } static void @@ -2080,31 +2116,13 @@ tp_base_connection_add_client_interest_impl (TpBaseConnection *self, const gchar * const *interests, gboolean only_if_uninterested) { - gpointer name_in_hash, count_p; - gsize total; + ClientData *client = NULL; const gchar * const *interest; - gboolean was_there; - - if (g_hash_table_lookup_extended (self->priv->interested_clients, - unique_name, &name_in_hash, &count_p)) - { - total = GPOINTER_TO_SIZE (count_p); - was_there = TRUE; - } - else - { - name_in_hash = g_strdup (unique_name); - total = 0; - g_hash_table_insert (self->priv->interested_clients, name_in_hash, - GSIZE_TO_POINTER (total)); - was_there = FALSE; - } for (interest = interests; *interest != NULL; interest++) { GQuark q = g_quark_try_string (*interest); - GHashTable *clients; - gsize count; + guint count; if (q == 0) { @@ -2113,61 +2131,36 @@ tp_base_connection_add_client_interest_impl (TpBaseConnection *self, continue; } - clients = g_hash_table_lookup (self->priv->client_interests, - GUINT_TO_POINTER (q)); - - if (clients == NULL) + if (!g_hash_table_contains (self->priv->interests, GUINT_TO_POINTER (q))) { /* declaring an interest in this token has no effect */ continue; } - count = GPOINTER_TO_SIZE (g_hash_table_lookup (clients, unique_name)); + if (client == NULL) + client = ensure_client_data (self, unique_name); + count = get_interest_count (client->interests, q); if (count > 0 && only_if_uninterested) { /* that client is already interested - nothing to do */ continue; } - /* name_in_hash is borrowed from interested_clients so we have to - * keep using the same one */ - g_hash_table_insert (clients, name_in_hash, - GSIZE_TO_POINTER (++count)); - total++; - - if (count == 1 && g_hash_table_size (clients) == 1) - { - /* Transition from 0 to 1 interests in total; the signal detail is - * the token. */ - DEBUG ("%s is the first to be interested in %s", unique_name, - *interest); - g_signal_emit (self, signals[CLIENTS_INTERESTED], q, *interest); - } - } - - if (total > 0) - { - /* name_in_hash is borrowed by client_interests so we have to keep - * using the same one */ - g_hash_table_steal (self->priv->interested_clients, name_in_hash); - g_hash_table_insert (self->priv->interested_clients, name_in_hash, - GSIZE_TO_POINTER (total)); - - if (!was_there) + count = change_interest_count (client->interests, q, +1); + if (count == 1) { - tp_dbus_daemon_watch_name_owner (self->priv->bus_proxy, unique_name, - tp_base_connection_interested_name_owner_changed_cb, self, NULL); + /* First time this client is interested */ + count = change_interest_count (self->priv->interests, q, +1); + if (count == 1) + { + /* First client to be interested */ + DEBUG ("%s is the first to be interested in %s", unique_name, + *interest); + g_signal_emit (self, signals[CLIENTS_INTERESTED], q, *interest); + } } } - else - { - g_hash_table_remove (self->priv->interested_clients, unique_name); - - tp_dbus_daemon_cancel_name_owner_watch (self->priv->bus_proxy, - unique_name, tp_base_connection_interested_name_owner_changed_cb, - self); - } } /** @@ -2226,11 +2219,10 @@ tp_base_connection_dbus_remove_client_interest (TpSvcConnection *svc, const gchar **interests, GDBusMethodInvocation *context) { - const gchar *unique_name = NULL; - const gchar **interest; TpBaseConnection *self = (TpBaseConnection *) svc; - gpointer name_in_hash, count_p; - gsize total; + const gchar *unique_name; + const gchar **interest; + ClientData *client; g_return_if_fail (TP_IS_BASE_CONNECTION (self)); g_return_if_fail (self->priv->bus_proxy != NULL); @@ -2240,10 +2232,8 @@ tp_base_connection_dbus_remove_client_interest (TpSvcConnection *svc, unique_name = g_dbus_method_invocation_get_sender (context); - /* this method isn't really meant to fail, so we might as well return now */ - - if (!g_hash_table_lookup_extended (self->priv->interested_clients, - unique_name, &name_in_hash, &count_p)) + client = g_hash_table_lookup (self->priv->clients, unique_name); + if (client == NULL) { /* unique_name doesn't own any client interests. Strictly speaking this * is an error, but it's probably ignoring the reply anyway, so we @@ -2251,13 +2241,10 @@ tp_base_connection_dbus_remove_client_interest (TpSvcConnection *svc, goto finally; } - total = GPOINTER_TO_SIZE (count_p); - for (interest = interests; *interest != NULL; interest++) { GQuark q = g_quark_try_string (*interest); - GHashTable *clients; - gsize count; + guint count; if (q == 0) { @@ -2266,35 +2253,25 @@ tp_base_connection_dbus_remove_client_interest (TpSvcConnection *svc, continue; } - clients = g_hash_table_lookup (self->priv->client_interests, - GUINT_TO_POINTER (q)); - - if (clients == NULL) - { - /* declaring an interest in this token has no effect */ - continue; - } - - count = GPOINTER_TO_SIZE (g_hash_table_lookup (clients, unique_name)); - + count = get_interest_count (client->interests, q); if (count == 0) { /* strictly speaking, this is an error, but nobody will be waiting * for a reply anyway */ DEBUG ("unable to decrement %s interest in %s past zero", unique_name, *interest); - continue; } - - total--; - - if (count == 1) + else if (count == 1) { - g_hash_table_remove (clients, unique_name); + /* This client is not interested anymore */ + g_hash_table_remove (client->interests, GUINT_TO_POINTER (q)); + if (g_hash_table_size (client->interests) == 0) + g_hash_table_remove (self->priv->clients, client); - if (g_hash_table_size (clients) == 0) + count = change_interest_count (self->priv->interests, q, -1); + if (count == 0) { - /* transition from 1 to 0 total interest-counts */ + /* This was the last client interested */ DEBUG ("%s was the last client interested in %s", unique_name, *interest); g_signal_emit (self, signals[CLIENTS_UNINTERESTED], q, @@ -2303,22 +2280,10 @@ tp_base_connection_dbus_remove_client_interest (TpSvcConnection *svc, } else { - /* name_in_hash is borrowed from interested_clients so we have to - * keep using the same one */ - g_hash_table_insert (clients, name_in_hash, - GSIZE_TO_POINTER (--count)); + change_interest_count (client->interests, q, -1); } } - if (total == 0) - { - g_hash_table_remove (self->priv->interested_clients, unique_name); - - tp_dbus_daemon_cancel_name_owner_watch (self->priv->bus_proxy, - unique_name, tp_base_connection_interested_name_owner_changed_cb, - self); - } - finally: tp_svc_connection_return_from_remove_client_interest (context); } |