[glib/gdbus] Process D-Bus messages in idle to avoid reentrancy issues



commit ccb19719e7206b5578aa9d34af9775aaa938be42
Author: David Zeuthen <davidz redhat com>
Date:   Tue Apr 28 10:53:16 2009 -0400

    Process D-Bus messages in idle to avoid reentrancy issues
    
    We might want to remove this after auditing what really is going on /
    fixing the bugs it causes. Suffice to say, this is needed right now to
    handle recursive mainloops being started from D-Bus signal handlers
    (e.g. on_bus_name_appeared). While recursive mainloops is generally
    frowned upon, we rely on this in our test cases.
---
 gdbus/gbusnameowner.c   |   54 +++++++++++++++++++++++++++++++++++++++----
 gdbus/gbusnamewatcher.c |   58 ++++++++++++++++++++++++++++++++++++++++++----
 gdbus/gdbusconnection.c |   55 +++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 151 insertions(+), 16 deletions(-)

diff --git a/gdbus/gbusnameowner.c b/gdbus/gbusnameowner.c
index 9db45c1..d76df78 100644
--- a/gdbus/gbusnameowner.c
+++ b/gdbus/gbusnameowner.c
@@ -58,6 +58,10 @@ struct _GBusNameOwnerPrivate
   gboolean owns_name;
 
   gboolean is_initialized;
+
+  /* stack of messages to process in idle */
+  GPtrArray *idle_processing_messages;
+  guint idle_processing_event_source_id;
 };
 
 enum
@@ -162,6 +166,14 @@ g_bus_name_owner_finalize (GObject *object)
     }
   g_free (owner->priv->name);
 
+  if (owner->priv->idle_processing_event_source_id > 0)
+    g_source_remove (owner->priv->idle_processing_event_source_id);
+  if (owner->priv->idle_processing_messages != NULL)
+    {
+      g_ptr_array_foreach (owner->priv->idle_processing_messages, (GFunc) dbus_message_unref, NULL);
+      g_ptr_array_free (owner->priv->idle_processing_messages, TRUE);
+    }
+
   if (G_OBJECT_CLASS (g_bus_name_owner_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (g_bus_name_owner_parent_class)->finalize (object);
 }
@@ -277,12 +289,10 @@ g_bus_name_owner_set_property (GObject      *object,
              dbus_message_get_member (message));        \
   } while (FALSE)
 
-static DBusHandlerResult
-filter_function (DBusConnection *dbus_1_connection,
-                 DBusMessage    *message,
-                 void           *user_data)
+static void
+process_message (GBusNameOwner *owner,
+                 DBusMessage   *message)
 {
-  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
   DBusError dbus_error;
   const gchar *name;
   gboolean old_owns_name;
@@ -357,6 +367,40 @@ filter_function (DBusConnection *dbus_1_connection,
           dbus_error_free (&dbus_error);
         }
     }
+}
+
+static gboolean
+process_messages_in_idle (gpointer user_data)
+{
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+  guint n;
+
+  for (n = 0; n < owner->priv->idle_processing_messages->len; n++)
+    {
+      DBusMessage *message = owner->priv->idle_processing_messages->pdata[n];
+      process_message (owner, message);
+      dbus_message_unref (message);
+    }
+
+  g_ptr_array_remove_range (owner->priv->idle_processing_messages,
+                            0,
+                            owner->priv->idle_processing_messages->len);
+  owner->priv->idle_processing_event_source_id = 0;
+  return FALSE;
+}
+
+static DBusHandlerResult
+filter_function (DBusConnection *dbus_1_connection,
+                 DBusMessage    *message,
+                 void           *user_data)
+{
+  GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+
+  if (owner->priv->idle_processing_messages == NULL)
+    owner->priv->idle_processing_messages = g_ptr_array_new ();
+  g_ptr_array_add (owner->priv->idle_processing_messages, dbus_message_ref (message));
+  if (owner->priv->idle_processing_event_source_id == 0)
+    owner->priv->idle_processing_event_source_id = g_idle_add (process_messages_in_idle, owner);
 
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
diff --git a/gdbus/gbusnamewatcher.c b/gdbus/gbusnamewatcher.c
index e0a4321..2e8da33 100644
--- a/gdbus/gbusnamewatcher.c
+++ b/gdbus/gbusnamewatcher.c
@@ -59,6 +59,10 @@ struct _GBusNameWatcherPrivate
   gchar *match_rule;
 
   gboolean is_initialized;
+
+  /* stack of messages to process in idle */
+  GPtrArray *idle_processing_messages;
+  guint idle_processing_event_source_id;
 };
 
 enum
@@ -160,6 +164,14 @@ g_bus_name_watcher_finalize (GObject *object)
   g_free (watcher->priv->name);
   g_free (watcher->priv->name_owner);
 
+  if (watcher->priv->idle_processing_event_source_id > 0)
+    g_source_remove (watcher->priv->idle_processing_event_source_id);
+  if (watcher->priv->idle_processing_messages != NULL)
+    {
+      g_ptr_array_foreach (watcher->priv->idle_processing_messages, (GFunc) dbus_message_unref, NULL);
+      g_ptr_array_free (watcher->priv->idle_processing_messages, TRUE);
+    }
+
   if (G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (g_bus_name_watcher_parent_class)->finalize (object);
 }
@@ -267,12 +279,12 @@ g_bus_name_watcher_set_property (GObject      *object,
              dbus_message_get_member (message));        \
   } while (FALSE)
 
-static DBusHandlerResult
-filter_function (DBusConnection *dbus_1_connection,
-                 DBusMessage    *message,
-                 void           *user_data)
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+process_message (GBusNameWatcher *watcher,
+                 DBusMessage   *message)
 {
-  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
   const gchar *name;
   const gchar *old_owner;
   const gchar *new_owner;
@@ -325,6 +337,42 @@ filter_function (DBusConnection *dbus_1_connection,
     }
 
  out:
+  ;
+}
+
+static gboolean
+process_messages_in_idle (gpointer user_data)
+{
+  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
+  guint n;
+
+  for (n = 0; n < watcher->priv->idle_processing_messages->len; n++)
+    {
+      DBusMessage *message = watcher->priv->idle_processing_messages->pdata[n];
+      process_message (watcher, message);
+      dbus_message_unref (message);
+    }
+
+  g_ptr_array_remove_range (watcher->priv->idle_processing_messages,
+                            0,
+                            watcher->priv->idle_processing_messages->len);
+  watcher->priv->idle_processing_event_source_id = 0;
+  return FALSE;
+}
+
+static DBusHandlerResult
+filter_function (DBusConnection *dbus_1_connection,
+                 DBusMessage    *message,
+                 void           *user_data)
+{
+  GBusNameWatcher *watcher = G_BUS_NAME_WATCHER (user_data);
+
+  if (watcher->priv->idle_processing_messages == NULL)
+    watcher->priv->idle_processing_messages = g_ptr_array_new ();
+  g_ptr_array_add (watcher->priv->idle_processing_messages, dbus_message_ref (message));
+  if (watcher->priv->idle_processing_event_source_id == 0)
+    watcher->priv->idle_processing_event_source_id = g_idle_add (process_messages_in_idle, watcher);
+
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c
index a2ad3c9..4850b26 100644
--- a/gdbus/gdbusconnection.c
+++ b/gdbus/gdbusconnection.c
@@ -68,6 +68,10 @@ struct _GDBusConnectionPrivate
 
   guint global_pending_call_id;
   GHashTable *pending_call_id_to_simple;
+
+  /* stack of messages to process in idle */
+  GPtrArray *idle_processing_messages;
+  guint idle_processing_event_source_id;
 };
 
 enum
@@ -143,6 +147,14 @@ g_dbus_connection_finalize (GObject *object)
 
   g_hash_table_destroy (connection->priv->pending_call_id_to_simple);
 
+  if (connection->priv->idle_processing_event_source_id > 0)
+    g_source_remove (connection->priv->idle_processing_event_source_id);
+  if (connection->priv->idle_processing_messages != NULL)
+    {
+      g_ptr_array_foreach (connection->priv->idle_processing_messages, (GFunc) dbus_message_unref, NULL);
+      g_ptr_array_free (connection->priv->idle_processing_messages, TRUE);
+    }
+
   if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (g_dbus_connection_parent_class)->finalize (object);
 }
@@ -657,19 +669,16 @@ setup_reconnect_timer (GDBusConnection *connection)
              dbus_message_get_member (message));        \
   } while (FALSE)
 
-static DBusHandlerResult
-filter_function (DBusConnection *dbus_1_connection,
-                 DBusMessage    *message,
-                 void           *user_data)
+static void
+process_message (GDBusConnection *connection,
+                 DBusMessage *message)
 {
-  GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
   DBusError dbus_error;
 
   //g_debug ("in filter_function for dbus_1_connection %p", dbus_1_connection);
   //PRINT_MESSAGE (message);
 
   dbus_error_init (&dbus_error);
-
   /* check if we are disconnected from the bus */
   if (dbus_message_is_signal (message,
                               DBUS_INTERFACE_LOCAL,
@@ -690,6 +699,40 @@ filter_function (DBusConnection *dbus_1_connection,
           setup_reconnect_timer (connection);
         }
     }
+}
+
+static gboolean
+process_messages_in_idle (gpointer user_data)
+{
+  GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+  guint n;
+
+  for (n = 0; n < connection->priv->idle_processing_messages->len; n++)
+    {
+      DBusMessage *message = connection->priv->idle_processing_messages->pdata[n];
+      process_message (connection, message);
+      dbus_message_unref (message);
+    }
+
+  g_ptr_array_remove_range (connection->priv->idle_processing_messages,
+                            0,
+                            connection->priv->idle_processing_messages->len);
+  connection->priv->idle_processing_event_source_id = 0;
+  return FALSE;
+}
+
+static DBusHandlerResult
+filter_function (DBusConnection *dbus_1_connection,
+                 DBusMessage    *message,
+                 void           *user_data)
+{
+  GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+
+  if (connection->priv->idle_processing_messages == NULL)
+    connection->priv->idle_processing_messages = g_ptr_array_new ();
+  g_ptr_array_add (connection->priv->idle_processing_messages, dbus_message_ref (message));
+  if (connection->priv->idle_processing_event_source_id == 0)
+    connection->priv->idle_processing_event_source_id = g_idle_add (process_messages_in_idle, connection);
 
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]