[maemo-commits] [maemo-commits] r19469 - projects/haf/trunk/dbus-glib/debian/patches

From: subversion at stage.maemo.org subversion at stage.maemo.org
Date: Thu Oct 22 14:12:40 EEST 2009
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);
+ }
+ 
+ /**

More information about the maemo-commits mailing list