Mailing List Archive

r19469 - projects/haf/trunk/dbus-glib/debian/patches
Author: ststephe
Date: 2009-10-22 14:12:04 +0300 (Thu, 22 Oct 2009)
New Revision: 19469

Added:
projects/haf/trunk/dbus-glib/debian/patches/80-DBusGProxy-signal-match.patch
Log:
NB#141956: DBusGProxy signal match rule optimization

Added: projects/haf/trunk/dbus-glib/debian/patches/80-DBusGProxy-signal-match.patch
===================================================================
--- projects/haf/trunk/dbus-glib/debian/patches/80-DBusGProxy-signal-match.patch 2009-10-21 06:37:19 UTC (rev 19468)
+++ projects/haf/trunk/dbus-glib/debian/patches/80-DBusGProxy-signal-match.patch 2009-10-22 11:12:04 UTC (rev 19469)
@@ -0,0 +1,459 @@
+Index: dbus-glib-0.78/dbus/dbus-gproxy.c
+===================================================================
+--- dbus-glib-0.78.orig/dbus/dbus-gproxy.c
++++ dbus-glib-0.78/dbus/dbus-gproxy.c
+@@ -125,6 +125,12 @@
+ {
+ GSList *proxies; /**< The list of proxies */
+
++ /**
++ * Set of signals with the DBusGProxy which subscribes to the signals
++ * gchar *signal_name -> GHashTable* of (DBusGProxy *proxy -> guint count)
++ */
++ GHashTable *signal_subscribed;
++
+ char name[4]; /**< name (empty string for none), nul byte,
+ * path, nul byte,
+ * interface, nul byte
+@@ -147,8 +153,14 @@
+
+ GHashTable *proxy_lists; /**< Hash used to route incoming signals
+ * and iterate over proxies
++ * tristring -> DBusGProxyList
+ */
++ GHashTable *owner_match_rule; /**< Hash to keep trace of match rules of
++ * NameOwnerChanged.
++ * gchar *name -> guint refcount
++ */
+ GHashTable *owner_names; /**< Hash to keep track of mapping from
++ * char * -> GSList of DBusGProxyNameOwnerInfo
+ * base name -> [name,name,...] for proxies which
+ * are for names.
+ */
+@@ -260,6 +272,16 @@
+
+ }
+
++ if (manager->owner_match_rule)
++ {
++ /* Since we destroyed all proxies, none can be tracking
++ * name owners
++ */
++ g_assert (g_hash_table_size (manager->owner_match_rule) == 0);
++ g_hash_table_destroy (manager->owner_match_rule);
++ manager->owner_match_rule = NULL;
++ }
++
+ if (manager->owner_names)
+ {
+ /* Since we destroyed all proxies, none can be tracking
+@@ -455,6 +477,7 @@
+ priv->path,
+ priv->interface);
+ list->proxies = NULL;
++ list->signal_subscribed = NULL;
+
+ return list;
+ }
+@@ -466,37 +489,51 @@
+ * as they ref the GProxyManager
+ */
+ g_slist_free (list->proxies);
++ if (list->signal_subscribed != NULL)
++ {
++ g_hash_table_destroy (list->signal_subscribed);
++ }
+
+ g_free (list);
+ }
+
+ static char*
+-g_proxy_get_signal_match_rule (DBusGProxy *proxy)
++g_proxy_get_signal_match_rule (DBusGProxy *proxy, const gchar *signal_name)
+ {
+ DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
+ /* FIXME Escaping is required here */
+
+ if (priv->name)
+- return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
++ {
++ if (signal_name == NULL)
++ return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
+ priv->name, priv->path, priv->interface);
++ else
++ return g_strdup_printf ("type='signal',sender='%s',path='%s',"
++ "interface='%s',member='%s'",
++ priv->name, priv->path, priv->interface,
++ signal_name);
++ }
+ else
+- return g_strdup_printf ("type='signal',path='%s',interface='%s'",
+- priv->path, priv->interface);
++ {
++ if (signal_name == NULL)
++ return g_strdup_printf ("type='signal',path='%s',interface='%s'",
++ priv->path, priv->interface);
++ else
++ return g_strdup_printf ("type='signal',path='%s',interface='%s',"
++ "member='%s'",
++ priv->path, priv->interface, signal_name);
++ }
+ }
+
+ static char *
+-g_proxy_get_owner_match_rule (DBusGProxy *proxy)
++g_proxy_get_owner_match_rule (const gchar *name)
+ {
+- DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
+- if (priv->name)
+- {
+- return g_strdup_printf ("type='signal',sender='" DBUS_SERVICE_DBUS
+- "',path='" DBUS_PATH_DBUS
+- "',interface='" DBUS_INTERFACE_DBUS
+- "',member='NameOwnerChanged'"
+- ",arg0='%s'", priv->name);
+- }
+- return NULL;
++ return g_strdup_printf ("type='signal',sender='" DBUS_SERVICE_DBUS
++ "',path='" DBUS_PATH_DBUS
++ "',interface='" DBUS_INTERFACE_DBUS
++ "',member='NameOwnerChanged'"
++ ",arg0='%s'", name);
+ }
+
+ typedef struct
+@@ -921,21 +958,24 @@
+
+ LOCK_MANAGER (manager);
+
+- if (manager->owner_names == NULL)
+- {
+- manager->owner_names = g_hash_table_new_full (g_str_hash,
+- g_str_equal,
+- g_free,
+- NULL);
+- }
+-
+ if (manager->proxy_lists == NULL)
+ {
++ g_assert (manager->owner_names == NULL);
++ g_assert (manager->owner_match_rule == NULL);
++
+ list = NULL;
+ manager->proxy_lists = g_hash_table_new_full (tristring_hash,
+ tristring_equal,
+ NULL,
+ (GFreeFunc) g_proxy_list_free);
++ manager->owner_names = g_hash_table_new_full (g_str_hash,
++ g_str_equal,
++ g_free,
++ NULL);
++ manager->owner_match_rule = g_hash_table_new_full (g_str_hash,
++ g_str_equal,
++ g_free,
++ NULL);
+ }
+ else
+ {
+@@ -958,26 +998,32 @@
+
+ if (list->proxies == NULL && priv->name)
+ {
+- /* We have to add match rules to the server,
+- * but only if the server is a message bus,
+- * not if it's a peer.
+- */
+- char *rule;
+-
+- rule = g_proxy_get_signal_match_rule (proxy);
+-
+- /* We don't check for errors; it's not like anyone would handle them, and
+- * we don't want a round trip here.
+- */
+- dbus_bus_add_match (manager->connection,
+- rule, NULL);
+- g_free (rule);
+-
+- rule = g_proxy_get_owner_match_rule (proxy);
+- if (rule)
+- dbus_bus_add_match (manager->connection,
+- rule, NULL);
+- g_free (rule);
++ gpointer orig_key, value;
++
++ g_assert (list->signal_subscribed == NULL);
++ list->signal_subscribed = g_hash_table_new_full (g_str_hash,
++ g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy);
++
++ if (g_hash_table_lookup_extended (manager->owner_match_rule,
++ priv->name, &orig_key, &value))
++ {
++ /* The owner match rule is already here. Increment the refcount */
++ gint count = GPOINTER_TO_INT (value) + 1;
++ g_hash_table_steal (manager->owner_match_rule, orig_key);
++ g_hash_table_insert (manager->owner_match_rule, orig_key,
++ GINT_TO_POINTER (count));
++ }
++ else
++ {
++ char *rule;
++ rule = g_proxy_get_owner_match_rule (priv->name);
++ dbus_bus_add_match (manager->connection,
++ rule, NULL);
++ g_free (rule);
++ g_hash_table_insert (manager->owner_match_rule, g_strdup (priv->name),
++ GINT_TO_POINTER (1));
++ }
++
+ }
+
+ g_assert (g_slist_find (list->proxies, proxy) == NULL);
+@@ -1074,22 +1120,54 @@
+ }
+ }
+
++ if (list->signal_subscribed != NULL)
++ {
++ GHashTableIter iter;
++ gpointer proxy_set;
++ gpointer signal_name;
++
++ g_hash_table_iter_init (&iter, list->signal_subscribed);
++ while (g_hash_table_iter_next (&iter, &signal_name, &proxy_set))
++ {
++ g_hash_table_remove (proxy_set, proxy);
++ if (g_hash_table_size (proxy_set) == 0)
++ {
++ char *rule;
++
++ rule = g_proxy_get_signal_match_rule (proxy, (gchar *) signal_name);
++ dbus_bus_remove_match (priv->manager->connection,
++ rule, NULL);
++ g_free (rule);
++ }
++ }
++ }
++
+ if (list->proxies == NULL)
+ {
+- char *rule;
++ gpointer orig_key, value;
++
+ g_hash_table_remove (manager->proxy_lists,
+ tri);
+- list = NULL;
+-
+- rule = g_proxy_get_signal_match_rule (proxy);
+- dbus_bus_remove_match (manager->connection,
+- rule, NULL);
+- g_free (rule);
+- rule = g_proxy_get_owner_match_rule (proxy);
+- if (rule)
+- dbus_bus_remove_match (manager->connection,
+- rule, NULL);
+- g_free (rule);
++ if (priv->name && g_hash_table_lookup_extended (
++ manager->owner_match_rule, priv->name, &orig_key, &value))
++ {
++ gint count = GPOINTER_TO_INT (value) - 1;
++ if (count == 0)
++ {
++ char *rule;
++ rule = g_proxy_get_owner_match_rule (priv->name);
++ dbus_bus_remove_match (manager->connection,
++ rule, NULL);
++ g_free (rule);
++ g_hash_table_remove (manager->owner_match_rule, priv->name);
++ }
++ else
++ {
++ g_hash_table_steal (manager->owner_match_rule, orig_key);
++ g_hash_table_insert (manager->owner_match_rule, orig_key,
++ GINT_TO_POINTER (count));
++ }
++ }
+ }
+
+ if (g_hash_table_size (manager->proxy_lists) == 0)
+@@ -1098,6 +1176,12 @@
+ manager->proxy_lists = NULL;
+ }
+
++ if (g_hash_table_size (manager->owner_match_rule) == 0)
++ {
++ g_hash_table_destroy (manager->owner_match_rule);
++ manager->owner_match_rule = NULL;
++ }
++
+ g_free (tri);
+
+ UNLOCK_MANAGER (manager);
+@@ -2895,6 +2979,8 @@
+ GClosure *closure;
+ GQuark q;
+ DBusGProxyPrivate *priv;
++ char *tri;
++ DBusGProxyList *list;
+
+ g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+ g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
+@@ -2902,6 +2988,57 @@
+ g_return_if_fail (handler != NULL);
+
+ priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
++
++ tri = tristring_from_proxy (proxy);
++ list = g_hash_table_lookup (priv->manager->proxy_lists, tri);
++ g_free (tri);
++ /* We have to add match rules to the server,
++ * but only if the server is a message bus,
++ * not if it's a peer.
++ */
++ if (priv->name && list->signal_subscribed != NULL)
++ {
++ gchar *orig_key;
++ GHashTable *proxy_set;
++ gboolean found = g_hash_table_lookup_extended (list->signal_subscribed,
++ signal_name, (gpointer *) &orig_key, (gpointer *) &proxy_set);
++ gint handler_count;
++ gpointer value;
++
++ if (!found || g_hash_table_size (proxy_set) == 0)
++ {
++ char *rule;
++
++ rule = g_proxy_get_signal_match_rule (proxy, signal_name);
++ /* We don't check for errors; it's not like anyone would handle
++ * them, and we don't want a round trip here.
++ */
++ dbus_bus_add_match (priv->manager->connection,
++ rule, NULL);
++ g_free (rule);
++ }
++
++ if (!found)
++ {
++ proxy_set = g_hash_table_new (NULL, NULL);
++ orig_key = g_strdup (signal_name);
++ }
++
++ if (g_hash_table_lookup_extended (proxy_set, proxy, NULL,
++ &value))
++ {
++ handler_count = GPOINTER_TO_UINT (value) + 1;
++ }
++ else
++ {
++ handler_count = 1;
++ }
++ g_hash_table_insert (proxy_set, proxy, GINT_TO_POINTER (handler_count));
++
++ g_hash_table_steal (list->signal_subscribed, signal_name);
++ g_hash_table_insert (list->signal_subscribed, orig_key, proxy_set);
++ }
++
+ name = create_signal_name (priv->interface, signal_name);
+
+ q = g_quark_try_string (name);
+@@ -2941,9 +3078,14 @@
+ GCallback handler,
+ void *data)
+ {
++ guint matched_count;
++ gint handler_count;
+ char *name;
+ GQuark q;
+ DBusGProxyPrivate *priv;
++ char *tri;
++ DBusGProxyList *list;
++ gchar *_signal_name;
+
+ g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+ g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
+@@ -2954,25 +3096,72 @@
+ name = create_signal_name (priv->interface, signal_name);
+
+ q = g_quark_try_string (name);
++ g_free (name);
+
+- if (q != 0)
+- {
+- g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
+- G_SIGNAL_MATCH_DETAIL |
+- G_SIGNAL_MATCH_FUNC |
+- G_SIGNAL_MATCH_DATA,
+- signals[RECEIVED],
+- q,
+- NULL,
+- G_CALLBACK (handler), data);
+- }
+- else
++ if (q == 0)
+ {
+ g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
+- name);
++ signal_name);
++ return;
+ }
+
+- g_free (name);
++ /* signal_name may be freed by g_signal_handlers_disconnect_matched() :'(
++ * Keep a copy while we need it
++ */
++ _signal_name = g_strdup (signal_name);
++ matched_count = g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
++ G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
++ signals[RECEIVED], q, NULL, G_CALLBACK (handler), data);
++
++ tri = tristring_from_proxy (proxy);
++ list = g_hash_table_lookup (priv->manager->proxy_lists, tri);
++ g_free (tri);
++
++ /* Remove a match rule */
++ if (list->signal_subscribed != NULL)
++ {
++ GHashTable *proxy_set = g_hash_table_lookup (list->signal_subscribed,
++ _signal_name);
++ gpointer value;
++
++ if (proxy_set == NULL || !g_hash_table_lookup_extended (proxy_set, proxy,
++ NULL, &value))
++ {
++ g_warning ("Attempt to disconnect from signal '%s' which is not"
++ " registered\n", _signal_name);
++ g_free (_signal_name);
++ return;
++ }
++
++ handler_count = GPOINTER_TO_INT (value);
++ handler_count -= matched_count;
++ g_assert (handler_count >= 0);
++ if (handler_count == 0)
++ {
++ g_hash_table_remove (proxy_set, proxy);
++ }
++ else
++ {
++ g_hash_table_insert (proxy_set, proxy,
++ GINT_TO_POINTER (handler_count));
++ }
++
++ if (g_hash_table_size (proxy_set) == 0)
++ {
++ char *rule;
++
++ rule = g_proxy_get_signal_match_rule (proxy, _signal_name);
++ /* We don't check for errors; it's not like anyone would handle them,
++ * and we don't want a round trip here.
++ */
++ dbus_bus_remove_match (priv->manager->connection,
++ rule, NULL);
++ g_free (rule);
++
++ g_hash_table_remove (list->signal_subscribed, _signal_name);
++ }
++ }
++ g_free (_signal_name);
+ }
+
+ /**

_______________________________________________
maemo-commits mailing list
maemo-commits@maemo.org
https://lists.maemo.org/mailman/listinfo/maemo-commits