dbus-1.3.0: add performance optimization patches from https://bugs.freedesktop.org...
authorMichael 'Mickey' Lauer <mickey@vanille-media.de>
Tue, 5 Jan 2010 18:11:50 +0000 (19:11 +0100)
committerMichael 'Mickey' Lauer <mickey@vanille-media.de>
Tue, 5 Jan 2010 18:16:56 +0000 (19:16 +0100)
recipes/dbus/dbus-1.3.0/will-1.patch [new file with mode: 0644]
recipes/dbus/dbus-1.3.0/will-2.patch [new file with mode: 0644]
recipes/dbus/dbus-1.3.0/will-3.patch [new file with mode: 0644]
recipes/dbus/dbus-1.3.0/will-4.patch [new file with mode: 0644]
recipes/dbus/dbus-1.3.0/will-5.patch [new file with mode: 0644]
recipes/dbus/dbus-1.3.0/will-6.patch [new file with mode: 0644]
recipes/dbus/dbus_1.3.0.bb

diff --git a/recipes/dbus/dbus-1.3.0/will-1.patch b/recipes/dbus/dbus-1.3.0/will-1.patch
new file mode 100644 (file)
index 0000000..eb3bb90
--- /dev/null
@@ -0,0 +1,25 @@
+From aebf924fce126e4eb1409e995edb78f7c02f65b1 Mon Sep 17 00:00:00 2001
+From: Will Thompson <will.thompson@collabora.co.uk>
+Date: Wed, 29 Jul 2009 17:47:04 +0100
+Subject: [PATCH 1/6] Add a constant for the number of message types
+
+---
+ dbus/dbus-protocol.h |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
+index a2284ee..17798e9 100644
+--- a/dbus/dbus-protocol.h
++++ b/dbus/dbus-protocol.h
+@@ -239,6 +239,8 @@ extern "C" {
+ /** Message type of a signal message, see dbus_message_get_type() */
+ #define DBUS_MESSAGE_TYPE_SIGNAL        4
++#define DBUS_NUM_MESSAGE_TYPES          5
++
+ /* Header flags */
+ /** If set, this flag means that the sender of a message does not care about getting
+-- 
+1.6.3.3
+
diff --git a/recipes/dbus/dbus-1.3.0/will-2.patch b/recipes/dbus/dbus-1.3.0/will-2.patch
new file mode 100644 (file)
index 0000000..e1c756b
--- /dev/null
@@ -0,0 +1,370 @@
+From 2d4da5596b34cbd5de2b97971fbb484657a1f485 Mon Sep 17 00:00:00 2001
+From: Will Thompson <will.thompson@collabora.co.uk>
+Date: Wed, 29 Jul 2009 17:48:21 +0100
+Subject: [PATCH 2/6] Index match rules by message type
+
+This avoids scanning all the signal matches while dispatching method
+calls and returns, which are rarely matched against.
+---
+ bus/signals.c |  217 ++++++++++++++++++++++++++++++++++++--------------------
+ 1 files changed, 139 insertions(+), 78 deletions(-)
+
+diff --git a/bus/signals.c b/bus/signals.c
+index b020a76..10e0b5e 100644
+--- a/bus/signals.c
++++ b/bus/signals.c
+@@ -1022,7 +1022,11 @@ struct BusMatchmaker
+ {
+   int refcount;
+-  DBusList *all_rules;
++  /* lists of rules, grouped by the type of message they match. 0
++   * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
++   * type.
++   */
++  DBusList *rules_by_type[DBUS_NUM_MESSAGE_TYPES];
+ };
+ BusMatchmaker*
+@@ -1039,6 +1043,16 @@ bus_matchmaker_new (void)
+   return matchmaker;
+ }
++static DBusList **
++bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
++                          int            message_type)
++{
++  _dbus_assert (message_type >= 0);
++  _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
++
++  return matchmaker->rules_by_type + message_type;
++}
++
+ BusMatchmaker *
+ bus_matchmaker_ref (BusMatchmaker *matchmaker)
+ {
+@@ -1057,14 +1071,20 @@ bus_matchmaker_unref (BusMatchmaker *matchmaker)
+   matchmaker->refcount -= 1;
+   if (matchmaker->refcount == 0)
+     {
+-      while (matchmaker->all_rules != NULL)
++      int i;
++
++      for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+         {
+-          BusMatchRule *rule;
++          DBusList **rules = bus_matchmaker_get_rules (matchmaker, i);
++
++          while (*rules != NULL)
++            {
++              BusMatchRule *rule;
+-          rule = matchmaker->all_rules->data;
+-          bus_match_rule_unref (rule);
+-          _dbus_list_remove_link (&matchmaker->all_rules,
+-                                  matchmaker->all_rules);
++              rule = (*rules)->data;
++              bus_match_rule_unref (rule);
++              _dbus_list_remove_link (rules, *rules);
++            }
+         }
+       dbus_free (matchmaker);
+@@ -1076,14 +1096,18 @@ dbus_bool_t
+ bus_matchmaker_add_rule (BusMatchmaker   *matchmaker,
+                          BusMatchRule    *rule)
+ {
++  DBusList **rules;
++
+   _dbus_assert (bus_connection_is_active (rule->matches_go_to));
+-  if (!_dbus_list_append (&matchmaker->all_rules, rule))
++  rules = bus_matchmaker_get_rules (matchmaker, rule->message_type);
++
++  if (!_dbus_list_append (rules, rule))
+     return FALSE;
+   if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
+     {
+-      _dbus_list_remove_last (&matchmaker->all_rules, rule);
++      _dbus_list_remove_last (rules, rule);
+       return FALSE;
+     }
+   
+@@ -1171,13 +1195,13 @@ match_rule_equal (BusMatchRule *a,
+ }
+ static void
+-bus_matchmaker_remove_rule_link (BusMatchmaker   *matchmaker,
++bus_matchmaker_remove_rule_link (DBusList       **rules,
+                                  DBusList        *link)
+ {
+   BusMatchRule *rule = link->data;
+   
+   bus_connection_remove_match_rule (rule->matches_go_to, rule);
+-  _dbus_list_remove_link (&matchmaker->all_rules, link);
++  _dbus_list_remove_link (rules, link);
+ #ifdef DBUS_ENABLE_VERBOSE_MODE
+   {
+@@ -1196,8 +1220,12 @@ void
+ bus_matchmaker_remove_rule (BusMatchmaker   *matchmaker,
+                             BusMatchRule    *rule)
+ {
++  DBusList **rules;
++
+   bus_connection_remove_match_rule (rule->matches_go_to, rule);
+-  _dbus_list_remove (&matchmaker->all_rules, rule);
++
++  rules = bus_matchmaker_get_rules (matchmaker, rule->message_type);
++  _dbus_list_remove (rules, rule);
+ #ifdef DBUS_ENABLE_VERBOSE_MODE
+   {
+@@ -1219,24 +1247,26 @@ bus_matchmaker_remove_rule_by_value (BusMatchmaker   *matchmaker,
+                                      DBusError       *error)
+ {
+   /* FIXME this is an unoptimized linear scan */
+-
++  DBusList **rules;
+   DBusList *link;
++  rules = bus_matchmaker_get_rules (matchmaker, value->message_type);
++
+   /* we traverse backward because bus_connection_remove_match_rule()
+    * removes the most-recently-added rule
+    */
+-  link = _dbus_list_get_last_link (&matchmaker->all_rules);
++  link = _dbus_list_get_last_link (rules);
+   while (link != NULL)
+     {
+       BusMatchRule *rule;
+       DBusList *prev;
+       rule = link->data;
+-      prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
++      prev = _dbus_list_get_prev_link (rules, link);
+       if (match_rule_equal (rule, value))
+         {
+-          bus_matchmaker_remove_rule_link (matchmaker, link);
++          bus_matchmaker_remove_rule_link (rules, link);
+           break;
+         }
+@@ -1258,6 +1288,7 @@ bus_matchmaker_disconnected (BusMatchmaker   *matchmaker,
+                              DBusConnection  *disconnected)
+ {
+   DBusList *link;
++  int i;
+   /* FIXME
+    *
+@@ -1270,41 +1301,46 @@ bus_matchmaker_disconnected (BusMatchmaker   *matchmaker,
+   
+   _dbus_assert (bus_connection_is_active (disconnected));
+-  link = _dbus_list_get_first_link (&matchmaker->all_rules);
+-  while (link != NULL)
++  for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+     {
+-      BusMatchRule *rule;
+-      DBusList *next;
++      DBusList **rules = bus_matchmaker_get_rules (matchmaker, i);
+-      rule = link->data;
+-      next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
+-
+-      if (rule->matches_go_to == disconnected)
+-        {
+-          bus_matchmaker_remove_rule_link (matchmaker, link);
+-        }
+-      else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
+-               ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
++      link = _dbus_list_get_first_link (rules);
++      while (link != NULL)
+         {
+-          /* The rule matches to/from a base service, see if it's the
+-           * one being disconnected, since we know this service name
+-           * will never be recycled.
+-           */
+-          const char *name;
+-
+-          name = bus_connection_get_name (disconnected);
+-          _dbus_assert (name != NULL); /* because we're an active connection */
+-
+-          if (((rule->flags & BUS_MATCH_SENDER) &&
+-               strcmp (rule->sender, name) == 0) ||
+-              ((rule->flags & BUS_MATCH_DESTINATION) &&
+-               strcmp (rule->destination, name) == 0))
++          BusMatchRule *rule;
++          DBusList *next;
++
++          rule = link->data;
++          next = _dbus_list_get_next_link (rules, link);
++
++          if (rule->matches_go_to == disconnected)
+             {
+-              bus_matchmaker_remove_rule_link (matchmaker, link);
++              bus_matchmaker_remove_rule_link (rules, link);
++            }
++          else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
++                   ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
++            {
++              /* The rule matches to/from a base service, see if it's the
++               * one being disconnected, since we know this service name
++               * will never be recycled.
++               */
++              const char *name;
++
++              name = bus_connection_get_name (disconnected);
++              _dbus_assert (name != NULL); /* because we're an active connection */
++
++              if (((rule->flags & BUS_MATCH_SENDER) &&
++                   strcmp (rule->sender, name) == 0) ||
++                  ((rule->flags & BUS_MATCH_DESTINATION) &&
++                   strcmp (rule->destination, name) == 0))
++                {
++                  bus_matchmaker_remove_rule_link (rules, link);
++                }
+             }
+-        }
+-      link = next;
++          link = next;
++        }
+     }
+ }
+@@ -1504,38 +1540,16 @@ match_rule_matches (BusMatchRule    *rule,
+   return TRUE;
+ }
+-dbus_bool_t
+-bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
+-                               BusConnections  *connections,
+-                               DBusConnection  *sender,
+-                               DBusConnection  *addressed_recipient,
+-                               DBusMessage     *message,
+-                               DBusList       **recipients_p)
++static dbus_bool_t
++get_recipients_from_list (DBusList       **rules,
++                          DBusConnection  *sender,
++                          DBusConnection  *addressed_recipient,
++                          DBusMessage     *message,
++                          DBusList       **recipients_p)
+ {
+-  /* FIXME for now this is a wholly unoptimized linear search */
+-  /* Guessing the important optimization is to skip the signal-related
+-   * match lists when processing method call and exception messages.
+-   * So separate match rule lists for signals?
+-   */
+-  
+   DBusList *link;
+-  _dbus_assert (*recipients_p == NULL);
+-
+-  /* This avoids sending same message to the same connection twice.
+-   * Purpose of the stamp instead of a bool is to avoid iterating over
+-   * all connections resetting the bool each time.
+-   */
+-  bus_connections_increment_stamp (connections);
+-
+-  /* addressed_recipient is already receiving the message, don't add to list.
+-   * NULL addressed_recipient means either bus driver, or this is a signal
+-   * and thus lacks a specific addressed_recipient.
+-   */
+-  if (addressed_recipient != NULL)
+-    bus_connection_mark_stamp (addressed_recipient);
+-
+-  link = _dbus_list_get_first_link (&matchmaker->all_rules);
++  link = _dbus_list_get_first_link (rules);
+   while (link != NULL)
+     {
+       BusMatchRule *rule;
+@@ -1545,7 +1559,7 @@ bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
+ #ifdef DBUS_ENABLE_VERBOSE_MODE
+       {
+         char *s = match_rule_to_string (rule);
+-        
++
+         _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
+                        s, rule->matches_go_to);
+         dbus_free (s);
+@@ -1556,12 +1570,12 @@ bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
+                               sender, addressed_recipient, message))
+         {
+           _dbus_verbose ("Rule matched\n");
+-          
++
+           /* Append to the list if we haven't already */
+           if (bus_connection_mark_stamp (rule->matches_go_to))
+             {
+               if (!_dbus_list_append (recipients_p, rule->matches_go_to))
+-                goto nomem;
++                return FALSE;
+             }
+ #ifdef DBUS_ENABLE_VERBOSE_MODE
+           else
+@@ -1571,10 +1585,57 @@ bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
+ #endif /* DBUS_ENABLE_VERBOSE_MODE */
+         }
+-      link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
++      link = _dbus_list_get_next_link (rules, link);
+     }
+   return TRUE;
++}
++
++dbus_bool_t
++bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
++                               BusConnections  *connections,
++                               DBusConnection  *sender,
++                               DBusConnection  *addressed_recipient,
++                               DBusMessage     *message,
++                               DBusList       **recipients_p)
++{
++  /* FIXME for now this is a wholly unoptimized linear search */
++  /* Guessing the important optimization is to skip the signal-related
++   * match lists when processing method call and exception messages.
++   * So separate match rule lists for signals?
++   */
++  int type;
++
++  _dbus_assert (*recipients_p == NULL);
++
++  /* This avoids sending same message to the same connection twice.
++   * Purpose of the stamp instead of a bool is to avoid iterating over
++   * all connections resetting the bool each time.
++   */
++  bus_connections_increment_stamp (connections);
++
++  /* addressed_recipient is already receiving the message, don't add to list.
++   * NULL addressed_recipient means either bus driver, or this is a signal
++   * and thus lacks a specific addressed_recipient.
++   */
++  if (addressed_recipient != NULL)
++    bus_connection_mark_stamp (addressed_recipient);
++
++  /* We always need to try the rules that don't specify a message type */
++  if (!get_recipients_from_list (
++          bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID),
++          sender, addressed_recipient, message, recipients_p))
++    goto nomem;
++
++  /* Also try rules that match the type of this message */
++  type = dbus_message_get_type (message);
++  if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
++    if (!get_recipients_from_list (
++            bus_matchmaker_get_rules (matchmaker, type),
++            sender, addressed_recipient, message, recipients_p))
++      goto nomem;
++
++  return TRUE;
+  nomem:
+   _dbus_list_clear (recipients_p);
+-- 
+1.6.3.3
+
diff --git a/recipes/dbus/dbus-1.3.0/will-3.patch b/recipes/dbus/dbus-1.3.0/will-3.patch
new file mode 100644 (file)
index 0000000..80e1f33
--- /dev/null
@@ -0,0 +1,119 @@
+From 8946958989828312ecf58dbaa581cbcebea8bcea Mon Sep 17 00:00:00 2001
+From: Will Thompson <will.thompson@collabora.co.uk>
+Date: Wed, 29 Jul 2009 17:53:37 +0100
+Subject: [PATCH 3/6] Don't bother re-matching features we've checked.
+
+This is currently not a big deal, but will make more of a difference
+once the set of match rules is partitioned by more features than just
+the message type.
+---
+ bus/signals.c |   29 ++++++++++++++++++-----------
+ 1 files changed, 18 insertions(+), 11 deletions(-)
+
+diff --git a/bus/signals.c b/bus/signals.c
+index 10e0b5e..0509dd5 100644
+--- a/bus/signals.c
++++ b/bus/signals.c
+@@ -1369,8 +1369,11 @@ static dbus_bool_t
+ match_rule_matches (BusMatchRule    *rule,
+                     DBusConnection  *sender,
+                     DBusConnection  *addressed_recipient,
+-                    DBusMessage     *message)
++                    DBusMessage     *message,
++                    BusMatchFlags    already_matched)
+ {
++  int flags;
++
+   /* All features of the match rule are AND'd together,
+    * so FALSE if any of them don't match.
+    */
+@@ -1379,8 +1382,11 @@ match_rule_matches (BusMatchRule    *rule,
+    * or for addressed_recipient may mean a message with no
+    * specific recipient (i.e. a signal)
+    */
+-  
+-  if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
++
++  /* Don't bother re-matching features we've already checked implicitly. */
++  flags = rule->flags & (~already_matched);
++
++  if (flags & BUS_MATCH_MESSAGE_TYPE)
+     {
+       _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
+@@ -1388,7 +1394,7 @@ match_rule_matches (BusMatchRule    *rule,
+         return FALSE;
+     }
+-  if (rule->flags & BUS_MATCH_INTERFACE)
++  if (flags & BUS_MATCH_INTERFACE)
+     {
+       const char *iface;
+@@ -1402,7 +1408,7 @@ match_rule_matches (BusMatchRule    *rule,
+         return FALSE;
+     }
+-  if (rule->flags & BUS_MATCH_MEMBER)
++  if (flags & BUS_MATCH_MEMBER)
+     {
+       const char *member;
+@@ -1416,7 +1422,7 @@ match_rule_matches (BusMatchRule    *rule,
+         return FALSE;
+     }
+-  if (rule->flags & BUS_MATCH_SENDER)
++  if (flags & BUS_MATCH_SENDER)
+     {
+       _dbus_assert (rule->sender != NULL);
+@@ -1433,7 +1439,7 @@ match_rule_matches (BusMatchRule    *rule,
+         }
+     }
+-  if (rule->flags & BUS_MATCH_DESTINATION)
++  if (flags & BUS_MATCH_DESTINATION)
+     {
+       const char *destination;
+@@ -1456,7 +1462,7 @@ match_rule_matches (BusMatchRule    *rule,
+         }
+     }
+-  if (rule->flags & BUS_MATCH_PATH)
++  if (flags & BUS_MATCH_PATH)
+     {
+       const char *path;
+@@ -1470,7 +1476,7 @@ match_rule_matches (BusMatchRule    *rule,
+         return FALSE;
+     }
+-  if (rule->flags & BUS_MATCH_ARGS)
++  if (flags & BUS_MATCH_ARGS)
+     {
+       int i;
+       DBusMessageIter iter;
+@@ -1567,7 +1573,8 @@ get_recipients_from_list (DBusList       **rules,
+ #endif
+       
+       if (match_rule_matches (rule,
+-                              sender, addressed_recipient, message))
++                              sender, addressed_recipient, message,
++                              BUS_MATCH_MESSAGE_TYPE))
+         {
+           _dbus_verbose ("Rule matched\n");
+@@ -2004,7 +2011,7 @@ check_matches (dbus_bool_t  expected_to_match,
+   _dbus_assert (rule != NULL);
+   /* We can't test sender/destination rules since we pass NULL here */
+-  matched = match_rule_matches (rule, NULL, NULL, message);
++  matched = match_rule_matches (rule, NULL, NULL, message, 0);
+   if (matched != expected_to_match)
+     {
+-- 
+1.6.3.3
+
diff --git a/recipes/dbus/dbus-1.3.0/will-4.patch b/recipes/dbus/dbus-1.3.0/will-4.patch
new file mode 100644 (file)
index 0000000..2b2303b
--- /dev/null
@@ -0,0 +1,56 @@
+From 9da8cbb9d9155bce885e0cfb39ba18a22ee6a76d Mon Sep 17 00:00:00 2001
+From: Will Thompson <will.thompson@collabora.co.uk>
+Date: Wed, 29 Jul 2009 18:52:28 +0100
+Subject: [PATCH 4/6] Extract freeing a DBusList<BusMatchRule>
+
+---
+ bus/signals.c |   26 ++++++++++++++------------
+ 1 files changed, 14 insertions(+), 12 deletions(-)
+
+diff --git a/bus/signals.c b/bus/signals.c
+index 0509dd5..3cf846e 100644
+--- a/bus/signals.c
++++ b/bus/signals.c
+@@ -1029,6 +1029,19 @@ struct BusMatchmaker
+   DBusList *rules_by_type[DBUS_NUM_MESSAGE_TYPES];
+ };
++static void
++rule_list_free (DBusList **rules)
++{
++  while (*rules != NULL)
++    {
++      BusMatchRule *rule;
++
++      rule = (*rules)->data;
++      bus_match_rule_unref (rule);
++      _dbus_list_remove_link (rules, *rules);
++    }
++}
++
+ BusMatchmaker*
+ bus_matchmaker_new (void)
+ {
+@@ -1074,18 +1087,7 @@ bus_matchmaker_unref (BusMatchmaker *matchmaker)
+       int i;
+       for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+-        {
+-          DBusList **rules = bus_matchmaker_get_rules (matchmaker, i);
+-
+-          while (*rules != NULL)
+-            {
+-              BusMatchRule *rule;
+-
+-              rule = (*rules)->data;
+-              bus_match_rule_unref (rule);
+-              _dbus_list_remove_link (rules, *rules);
+-            }
+-        }
++        rule_list_free (bus_matchmaker_get_rules (matchmaker, i));
+       dbus_free (matchmaker);
+     }
+-- 
+1.6.3.3
+
diff --git a/recipes/dbus/dbus-1.3.0/will-5.patch b/recipes/dbus/dbus-1.3.0/will-5.patch
new file mode 100644 (file)
index 0000000..ed10000
--- /dev/null
@@ -0,0 +1,116 @@
+From a40a026527e718547f32e134e7c27a561b1eba47 Mon Sep 17 00:00:00 2001
+From: Will Thompson <will.thompson@collabora.co.uk>
+Date: Wed, 29 Jul 2009 20:03:40 +0100
+Subject: [PATCH 5/6] Extract rule_list_remove_by_connection
+
+---
+ bus/signals.c |   82 +++++++++++++++++++++++++++++++-------------------------
+ 1 files changed, 45 insertions(+), 37 deletions(-)
+
+diff --git a/bus/signals.c b/bus/signals.c
+index 3cf846e..c6f122b 100644
+--- a/bus/signals.c
++++ b/bus/signals.c
+@@ -1285,11 +1285,54 @@ bus_matchmaker_remove_rule_by_value (BusMatchmaker   *matchmaker,
+   return TRUE;
+ }
++static void
++rule_list_remove_by_connection (DBusList       **rules,
++                                DBusConnection  *disconnected)
++{
++  DBusList *link;
++
++  link = _dbus_list_get_first_link (rules);
++  while (link != NULL)
++    {
++      BusMatchRule *rule;
++      DBusList *next;
++
++      rule = link->data;
++      next = _dbus_list_get_next_link (rules, link);
++
++      if (rule->matches_go_to == disconnected)
++        {
++          bus_matchmaker_remove_rule_link (rules, link);
++        }
++      else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
++               ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
++        {
++          /* The rule matches to/from a base service, see if it's the
++           * one being disconnected, since we know this service name
++           * will never be recycled.
++           */
++          const char *name;
++
++          name = bus_connection_get_name (disconnected);
++          _dbus_assert (name != NULL); /* because we're an active connection */
++
++          if (((rule->flags & BUS_MATCH_SENDER) &&
++               strcmp (rule->sender, name) == 0) ||
++              ((rule->flags & BUS_MATCH_DESTINATION) &&
++               strcmp (rule->destination, name) == 0))
++            {
++              bus_matchmaker_remove_rule_link (rules, link);
++            }
++        }
++
++      link = next;
++    }
++}
++
+ void
+ bus_matchmaker_disconnected (BusMatchmaker   *matchmaker,
+                              DBusConnection  *disconnected)
+ {
+-  DBusList *link;
+   int i;
+   /* FIXME
+@@ -1307,42 +1350,7 @@ bus_matchmaker_disconnected (BusMatchmaker   *matchmaker,
+     {
+       DBusList **rules = bus_matchmaker_get_rules (matchmaker, i);
+-      link = _dbus_list_get_first_link (rules);
+-      while (link != NULL)
+-        {
+-          BusMatchRule *rule;
+-          DBusList *next;
+-
+-          rule = link->data;
+-          next = _dbus_list_get_next_link (rules, link);
+-
+-          if (rule->matches_go_to == disconnected)
+-            {
+-              bus_matchmaker_remove_rule_link (rules, link);
+-            }
+-          else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
+-                   ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
+-            {
+-              /* The rule matches to/from a base service, see if it's the
+-               * one being disconnected, since we know this service name
+-               * will never be recycled.
+-               */
+-              const char *name;
+-
+-              name = bus_connection_get_name (disconnected);
+-              _dbus_assert (name != NULL); /* because we're an active connection */
+-
+-              if (((rule->flags & BUS_MATCH_SENDER) &&
+-                   strcmp (rule->sender, name) == 0) ||
+-                  ((rule->flags & BUS_MATCH_DESTINATION) &&
+-                   strcmp (rule->destination, name) == 0))
+-                {
+-                  bus_matchmaker_remove_rule_link (rules, link);
+-                }
+-            }
+-
+-          link = next;
+-        }
++      rule_list_remove_by_connection (rules, disconnected);
+     }
+ }
+-- 
+1.6.3.3
+
diff --git a/recipes/dbus/dbus-1.3.0/will-6.patch b/recipes/dbus/dbus-1.3.0/will-6.patch
new file mode 100644 (file)
index 0000000..05d9c49
--- /dev/null
@@ -0,0 +1,456 @@
+From 023bb6fdc82304866353a28cd503863e80c3ea0d Mon Sep 17 00:00:00 2001
+From: Will Thompson <will.thompson@collabora.co.uk>
+Date: Thu, 30 Jul 2009 10:49:33 +0100
+Subject: [PATCH 6/6] Group match rules by their interface.
+
+In my informal studies of "normal" sets of match rules, only checking
+match rules with the appropriate interface for the message reduces the
+number that need to be checked by almost 100x on average (ranging from
+halving for messages from the bus daemon, to a >200x reduction in many
+cases). This reduces the overhead added to dispatching each message by
+having lots of irrelevant match rules.
+---
+ bus/signals.c |  292 ++++++++++++++++++++++++++++++++++++++++++++++-----------
+ 1 files changed, 239 insertions(+), 53 deletions(-)
+
+diff --git a/bus/signals.c b/bus/signals.c
+index c6f122b..23bf98a 100644
+--- a/bus/signals.c
++++ b/bus/signals.c
+@@ -1018,15 +1018,25 @@ bus_match_rule_parse (DBusConnection   *matches_go_to,
+   return rule;
+ }
++typedef struct RulePool RulePool;
++struct RulePool
++{
++  /* Maps non-NULL interface names to non-NULL (DBusList **)s */
++  DBusHashTable *rules_by_iface;
++
++  /* List of BusMatchRules which don't specify an interface */
++  DBusList *rules_without_iface;
++};
++
+ struct BusMatchmaker
+ {
+   int refcount;
+-  /* lists of rules, grouped by the type of message they match. 0
++  /* Pools of rules, grouped by the type of message they match. 0
+    * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a message
+    * type.
+    */
+-  DBusList *rules_by_type[DBUS_NUM_MESSAGE_TYPES];
++  RulePool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
+ };
+ static void
+@@ -1042,28 +1052,139 @@ rule_list_free (DBusList **rules)
+     }
+ }
++static void
++rule_list_ptr_free (DBusList **list)
++{
++  /* We have to cope with NULL because the hash table frees the "existing"
++   * value (which is NULL) when creating a new table entry...
++   */
++  if (list != NULL)
++    {
++      rule_list_free (list);
++      dbus_free (list);
++    }
++}
++
+ BusMatchmaker*
+ bus_matchmaker_new (void)
+ {
+   BusMatchmaker *matchmaker;
++  int i;
+   matchmaker = dbus_new0 (BusMatchmaker, 1);
+   if (matchmaker == NULL)
+     return NULL;
+   matchmaker->refcount = 1;
+-  
++
++  for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
++    {
++      RulePool *p = matchmaker->rules_by_type + i;
++
++      p->rules_by_iface = _dbus_hash_table_new (DBUS_HASH_STRING,
++          dbus_free, (DBusFreeFunction) rule_list_ptr_free);
++
++      if (p->rules_by_iface == NULL)
++        goto nomem;
++    }
++
+   return matchmaker;
++
++ nomem:
++  for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
++    {
++      RulePool *p = matchmaker->rules_by_type + i;
++
++      if (p->rules_by_iface == NULL)
++        break;
++      else
++        _dbus_hash_table_unref (p->rules_by_iface);
++    }
++
++  return NULL;
+ }
+ static DBusList **
+ bus_matchmaker_get_rules (BusMatchmaker *matchmaker,
+-                          int            message_type)
++                          int            message_type,
++                          const char    *interface,
++                          dbus_bool_t    create)
+ {
++  RulePool *p;
++
+   _dbus_assert (message_type >= 0);
+   _dbus_assert (message_type < DBUS_NUM_MESSAGE_TYPES);
+-  return matchmaker->rules_by_type + message_type;
++  _dbus_verbose ("Looking up rules for message_type %d, interface %s\n",
++                 message_type,
++                 interface != NULL ? interface : "<null>");
++
++  p = matchmaker->rules_by_type + message_type;
++
++  if (interface == NULL)
++    {
++      return &p->rules_without_iface;
++    }
++  else
++    {
++      DBusList **list;
++
++      list = _dbus_hash_table_lookup_string (p->rules_by_iface, interface);
++
++      if (list == NULL && create)
++        {
++          char *dupped_interface;
++
++          list = dbus_new0 (DBusList *, 1);
++          if (list == NULL)
++            return NULL;
++
++          dupped_interface = _dbus_strdup (interface);
++          if (dupped_interface == NULL)
++            {
++              dbus_free (list);
++              return NULL;
++            }
++
++          _dbus_verbose ("Adding list for type %d, iface %s\n", message_type,
++                         interface);
++
++          if (!_dbus_hash_table_insert_string (p->rules_by_iface,
++                                               dupped_interface, list))
++            {
++              dbus_free (list);
++              dbus_free (dupped_interface);
++              return NULL;
++            }
++        }
++
++      return list;
++    }
++}
++
++static void
++bus_matchmaker_gc_rules (BusMatchmaker *matchmaker,
++                         int            message_type,
++                         const char    *interface,
++                         DBusList     **rules)
++{
++  RulePool *p;
++
++  if (interface == NULL)
++    return;
++
++  if (*rules != NULL)
++    return;
++
++  _dbus_verbose ("GCing HT entry for message_type %u, interface %s\n",
++                 message_type, interface);
++
++  p = matchmaker->rules_by_type + message_type;
++
++  _dbus_assert (_dbus_hash_table_lookup_string (p->rules_by_iface, interface)
++      == rules);
++
++  _dbus_hash_table_remove_string (p->rules_by_iface, interface);
+ }
+ BusMatchmaker *
+@@ -1087,7 +1208,12 @@ bus_matchmaker_unref (BusMatchmaker *matchmaker)
+       int i;
+       for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+-        rule_list_free (bus_matchmaker_get_rules (matchmaker, i));
++        {
++          RulePool *p = matchmaker->rules_by_type + i;
++
++          _dbus_hash_table_unref (p->rules_by_iface);
++          rule_list_free (&p->rules_without_iface);
++        }
+       dbus_free (matchmaker);
+     }
+@@ -1102,7 +1228,15 @@ bus_matchmaker_add_rule (BusMatchmaker   *matchmaker,
+   _dbus_assert (bus_connection_is_active (rule->matches_go_to));
+-  rules = bus_matchmaker_get_rules (matchmaker, rule->message_type);
++  _dbus_verbose ("Adding rule with message_type %d, interface %s\n",
++                 rule->message_type,
++                 rule->interface != NULL ? rule->interface : "<null>");
++
++  rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
++                                    rule->interface, TRUE);
++
++  if (rules == NULL)
++    return FALSE;
+   if (!_dbus_list_append (rules, rule))
+     return FALSE;
+@@ -1110,9 +1244,11 @@ bus_matchmaker_add_rule (BusMatchmaker   *matchmaker,
+   if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
+     {
+       _dbus_list_remove_last (rules, rule);
++      bus_matchmaker_gc_rules (matchmaker, rule->message_type,
++                               rule->interface, rules);
+       return FALSE;
+     }
+-  
++
+   bus_match_rule_ref (rule);
+ #ifdef DBUS_ENABLE_VERBOSE_MODE
+@@ -1224,10 +1360,23 @@ bus_matchmaker_remove_rule (BusMatchmaker   *matchmaker,
+ {
+   DBusList **rules;
++  _dbus_verbose ("Removing rule with message_type %d, interface %s\n",
++                 rule->message_type,
++                 rule->interface != NULL ? rule->interface : "<null>");
++
+   bus_connection_remove_match_rule (rule->matches_go_to, rule);
+-  rules = bus_matchmaker_get_rules (matchmaker, rule->message_type);
++  rules = bus_matchmaker_get_rules (matchmaker, rule->message_type,
++                                    rule->interface, FALSE);
++
++  /* We should only be asked to remove a rule by identity right after it was
++   * added, so there should be a list for it.
++   */
++  _dbus_assert (rules != NULL);
++
+   _dbus_list_remove (rules, rule);
++  bus_matchmaker_gc_rules (matchmaker, rule->message_type, rule->interface,
++      rules);
+ #ifdef DBUS_ENABLE_VERBOSE_MODE
+   {
+@@ -1248,31 +1397,38 @@ bus_matchmaker_remove_rule_by_value (BusMatchmaker   *matchmaker,
+                                      BusMatchRule    *value,
+                                      DBusError       *error)
+ {
+-  /* FIXME this is an unoptimized linear scan */
+   DBusList **rules;
+-  DBusList *link;
++  DBusList *link = NULL;
+-  rules = bus_matchmaker_get_rules (matchmaker, value->message_type);
++  _dbus_verbose ("Removing rule by value with message_type %d, interface %s\n",
++                 value->message_type,
++                 value->interface != NULL ? value->interface : "<null>");
+-  /* we traverse backward because bus_connection_remove_match_rule()
+-   * removes the most-recently-added rule
+-   */
+-  link = _dbus_list_get_last_link (rules);
+-  while (link != NULL)
++  rules = bus_matchmaker_get_rules (matchmaker, value->message_type,
++      value->interface, FALSE);
++
++  if (rules != NULL)
+     {
+-      BusMatchRule *rule;
+-      DBusList *prev;
++      /* we traverse backward because bus_connection_remove_match_rule()
++       * removes the most-recently-added rule
++       */
++      link = _dbus_list_get_last_link (rules);
++      while (link != NULL)
++        {
++          BusMatchRule *rule;
++          DBusList *prev;
+-      rule = link->data;
+-      prev = _dbus_list_get_prev_link (rules, link);
++          rule = link->data;
++          prev = _dbus_list_get_prev_link (rules, link);
+-      if (match_rule_equal (rule, value))
+-        {
+-          bus_matchmaker_remove_rule_link (rules, link);
+-          break;
+-        }
++          if (match_rule_equal (rule, value))
++            {
++              bus_matchmaker_remove_rule_link (rules, link);
++              break;
++            }
+-      link = prev;
++          link = prev;
++        }
+     }
+   if (link == NULL)
+@@ -1282,6 +1438,9 @@ bus_matchmaker_remove_rule_by_value (BusMatchmaker   *matchmaker,
+       return FALSE;
+     }
++  bus_matchmaker_gc_rules (matchmaker, value->message_type, value->interface,
++      rules);
++
+   return TRUE;
+ }
+@@ -1341,16 +1500,29 @@ bus_matchmaker_disconnected (BusMatchmaker   *matchmaker,
+    * for the rules belonging to the connection, since we keep
+    * a list of those; but for the rules that just refer to
+    * the connection we'd need to do something more elaborate.
+-   * 
+    */
+-  
++
+   _dbus_assert (bus_connection_is_active (disconnected));
++  _dbus_verbose ("Removing all rules for connection %p\n", disconnected);
++
+   for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++)
+     {
+-      DBusList **rules = bus_matchmaker_get_rules (matchmaker, i);
++      RulePool *p = matchmaker->rules_by_type + i;
++      DBusHashIter iter;
++
++      rule_list_remove_by_connection (&p->rules_without_iface, disconnected);
++
++      _dbus_hash_iter_init (p->rules_by_iface, &iter);
++      while (_dbus_hash_iter_next (&iter))
++        {
++          DBusList **items = _dbus_hash_iter_get_value (&iter);
+-      rule_list_remove_by_connection (rules, disconnected);
++          rule_list_remove_by_connection (items, disconnected);
++
++          if (*items == NULL)
++            _dbus_hash_iter_remove_entry (&iter);
++        }
+     }
+ }
+@@ -1565,6 +1737,9 @@ get_recipients_from_list (DBusList       **rules,
+ {
+   DBusList *link;
++  if (rules == NULL)
++    return TRUE;
++
+   link = _dbus_list_get_first_link (rules);
+   while (link != NULL)
+     {
+@@ -1581,10 +1756,10 @@ get_recipients_from_list (DBusList       **rules,
+         dbus_free (s);
+       }
+ #endif
+-      
++
+       if (match_rule_matches (rule,
+                               sender, addressed_recipient, message,
+-                              BUS_MATCH_MESSAGE_TYPE))
++                              BUS_MATCH_MESSAGE_TYPE | BUS_MATCH_INTERFACE))
+         {
+           _dbus_verbose ("Rule matched\n");
+@@ -1616,12 +1791,9 @@ bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
+                                DBusMessage     *message,
+                                DBusList       **recipients_p)
+ {
+-  /* FIXME for now this is a wholly unoptimized linear search */
+-  /* Guessing the important optimization is to skip the signal-related
+-   * match lists when processing method call and exception messages.
+-   * So separate match rule lists for signals?
+-   */
+   int type;
++  const char *interface;
++  DBusList **neither, **just_type, **just_iface, **both;
+   _dbus_assert (*recipients_p == NULL);
+@@ -1638,25 +1810,39 @@ bus_matchmaker_get_recipients (BusMatchmaker   *matchmaker,
+   if (addressed_recipient != NULL)
+     bus_connection_mark_stamp (addressed_recipient);
+-  /* We always need to try the rules that don't specify a message type */
+-  if (!get_recipients_from_list (
+-          bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID),
+-          sender, addressed_recipient, message, recipients_p))
+-    goto nomem;
+-
+-  /* Also try rules that match the type of this message */
+   type = dbus_message_get_type (message);
++  interface = dbus_message_get_interface (message);
++
++  neither = bus_matchmaker_get_rules (matchmaker, DBUS_MESSAGE_TYPE_INVALID,
++      NULL, FALSE);
++  just_type = just_iface = both = NULL;
++
++  if (interface != NULL)
++    just_iface = bus_matchmaker_get_rules (matchmaker,
++        DBUS_MESSAGE_TYPE_INVALID, interface, FALSE);
++
+   if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES)
+-    if (!get_recipients_from_list (
+-            bus_matchmaker_get_rules (matchmaker, type),
+-            sender, addressed_recipient, message, recipients_p))
+-      goto nomem;
++    {
++      just_type = bus_matchmaker_get_rules (matchmaker, type, NULL, FALSE);
+-  return TRUE;
++      if (interface != NULL)
++        both = bus_matchmaker_get_rules (matchmaker, type, interface, FALSE);
++    }
+- nomem:
+-  _dbus_list_clear (recipients_p);
+-  return FALSE;
++  if (!(get_recipients_from_list (neither, sender, addressed_recipient,
++                                  message, recipients_p) &&
++        get_recipients_from_list (just_iface, sender, addressed_recipient,
++                                  message, recipients_p) &&
++        get_recipients_from_list (just_type, sender, addressed_recipient,
++                                  message, recipients_p) &&
++        get_recipients_from_list (both, sender, addressed_recipient,
++                                  message, recipients_p)))
++    {
++      _dbus_list_clear (recipients_p);
++      return FALSE;
++    }
++
++  return TRUE;
+ }
+ #ifdef DBUS_BUILD_TESTS
+-- 
+1.6.3.3
+
index 562ed1b..3abc40a 100644 (file)
@@ -2,6 +2,14 @@ include dbus.inc
 
 SRC_URI = "\
   http://dbus.freedesktop.org/releases/dbus/dbus-${PV}.tar.gz \
+  \
+  file://will-1.patch;patch=1 \
+  file://will-2.patch;patch=1 \
+  file://will-3.patch;patch=1 \
+  file://will-4.patch;patch=1 \
+  file://will-5.patch;patch=1 \
+  file://will-6.patch;patch=1 \
+  \
   file://tmpdir.patch;patch=1 \
   file://fix-install-daemon.patch;patch=1 \
   file://0001-Make-the-default-DBus-reply-timeout-configurable.patch;patch=1 \
@@ -11,4 +19,4 @@ SRC_URI = "\
 # This is the development version of dbus that will lead to 1.4.x
 DEFAULT_PREFERENCE = "-1"
 
-PR = "r0"
+PR = "r1"