GDBus: Don't use abstract sockets in test code
[platform/upstream/glib.git] / gio / gdbusconnection.c
index 572b867..a4abc14 100644 (file)
  *      kind of pitfalls it avoids
  *      - Export objects before claiming names
  *    - Talk about auto-starting services (cf. GBusNameWatcherFlags)
+ *
+ *  - use abstract sockets in test code
+ *   - right now it doesn't work, dbus-daemon(1) fails with
+ *
+ *        /gdbus/connection/filter: Failed to start message bus: Failed to bind
+ *        socket "/tmp/g-dbus-tests-pid-28531": Address already in use
+ *        ** WARNING **: Error reading address from dbus daemon, 0 bytes read
+ *
+ *     or similar.
  */
 
 #include "config.h"
@@ -180,6 +189,77 @@ static GDBusConnection *the_system_bus = NULL;
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct
+{
+  GDestroyNotify              callback;
+  gpointer                    user_data;
+  GMainContext               *context;
+} CallDestroyNotifyData;
+
+static gboolean
+call_destroy_notify_data_in_idle (gpointer user_data)
+{
+  CallDestroyNotifyData *data = user_data;
+  data->callback (data->user_data);
+  return FALSE;
+}
+
+static void
+call_destroy_notify_data_free (CallDestroyNotifyData *data)
+{
+  if (data->context != NULL)
+    g_main_context_unref (data->context);
+  g_free (data);
+}
+
+/*
+ * call_destroy_notify: <internal>
+ * @context: A #GMainContext or %NULL.
+ * @callback: A #GDestroyNotify or %NULL.
+ * @user_data: Data to pass to @callback.
+ *
+ * Schedules @callback to run in @context.
+ */
+static void
+call_destroy_notify (GMainContext  *context,
+                     GDestroyNotify callback,
+                     gpointer       user_data)
+{
+  if (callback == NULL)
+    goto out;
+
+  if (context == g_main_context_get_thread_default ())
+    {
+      callback (user_data);
+    }
+  else
+    {
+      GSource *idle_source;
+      CallDestroyNotifyData *data;
+
+      data = g_new0 (CallDestroyNotifyData, 1);
+      data->callback = callback;
+      data->user_data = user_data;
+      data->context = context;
+      if (data->context != NULL)
+        g_main_context_ref (data->context);
+
+      idle_source = g_idle_source_new ();
+      g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
+      g_source_set_callback (idle_source,
+                             call_destroy_notify_data_in_idle,
+                             data,
+                             (GDestroyNotify) call_destroy_notify_data_free);
+      g_source_attach (idle_source, data->context);
+      g_source_unref (idle_source);
+    }
+
+ out:
+  ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gboolean
 _g_strv_has_string (const gchar* const *haystack,
                     const gchar        *needle)
@@ -375,13 +455,14 @@ G_DEFINE_TYPE_WITH_CODE (GDBusConnection, g_dbus_connection, G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
                          );
 
+static GHashTable *alive_connections = NULL;
+
 static void
 g_dbus_connection_dispose (GObject *object)
 {
   GDBusConnection *connection = G_DBUS_CONNECTION (object);
 
   G_LOCK (message_bus_lock);
-  //g_debug ("disposing %p", connection);
   if (connection == the_session_bus)
     {
       the_session_bus = NULL;
@@ -390,11 +471,20 @@ g_dbus_connection_dispose (GObject *object)
     {
       the_system_bus = NULL;
     }
+  CONNECTION_LOCK (connection);
   if (connection->worker != NULL)
     {
       _g_dbus_worker_stop (connection->worker);
       connection->worker = NULL;
+      if (alive_connections != NULL)
+        g_warn_if_fail (g_hash_table_remove (alive_connections, connection));
     }
+  else
+    {
+      if (alive_connections != NULL)
+        g_warn_if_fail (g_hash_table_lookup (alive_connections, connection) == NULL);
+    }
+  CONNECTION_UNLOCK (connection);
   G_UNLOCK (message_bus_lock);
 
   if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose != NULL)
@@ -1957,19 +2047,31 @@ on_worker_message_received (GDBusWorker  *worker,
                             GDBusMessage *message,
                             gpointer      user_data)
 {
-  GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+  GDBusConnection *connection;
   FilterCallback *filters;
   gboolean consumed_by_filter;
   gboolean altered_by_filter;
   guint num_filters;
   guint n;
+  gboolean alive;
+
+  G_LOCK (message_bus_lock);
+  alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+  if (!alive)
+    {
+      G_UNLOCK (message_bus_lock);
+      return;
+    }
+  connection = G_DBUS_CONNECTION (user_data);
+  g_object_ref (connection);
+  G_UNLOCK (message_bus_lock);
 
   //g_debug ("in on_worker_message_received");
 
   g_object_ref (message);
   g_dbus_message_lock (message);
 
-  g_object_ref (connection);
+  //g_debug ("boo ref_count = %d %p %p", G_OBJECT (connection)->ref_count, connection, connection->worker);
 
   /* First collect the set of callback functions */
   CONNECTION_LOCK (connection);
@@ -2051,13 +2153,24 @@ on_worker_message_about_to_be_sent (GDBusWorker  *worker,
                                     GDBusMessage *message,
                                     gpointer      user_data)
 {
-  GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+  GDBusConnection *connection;
   FilterCallback *filters;
   guint num_filters;
   guint n;
+  gboolean alive;
 
-  //g_debug ("in on_worker_message_about_to_be_sent");
+  G_LOCK (message_bus_lock);
+  alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+  if (!alive)
+    {
+      G_UNLOCK (message_bus_lock);
+      return message;
+    }
+  connection = G_DBUS_CONNECTION (user_data);
   g_object_ref (connection);
+  G_UNLOCK (message_bus_lock);
+
+  //g_debug ("in on_worker_message_about_to_be_sent");
 
   /* First collect the set of callback functions */
   CONNECTION_LOCK (connection);
@@ -2096,7 +2209,19 @@ on_worker_closed (GDBusWorker *worker,
                   GError      *error,
                   gpointer     user_data)
 {
-  GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+  GDBusConnection *connection;
+  gboolean alive;
+
+  G_LOCK (message_bus_lock);
+  alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+  if (!alive)
+    {
+      G_UNLOCK (message_bus_lock);
+      return;
+    }
+  connection = G_DBUS_CONNECTION (user_data);
+  g_object_ref (connection);
+  G_UNLOCK (message_bus_lock);
 
   //g_debug ("in on_worker_closed: %s", error->message);
 
@@ -2104,6 +2229,8 @@ on_worker_closed (GDBusWorker *worker,
   if (!connection->closed)
     set_closed_unlocked (connection, remote_peer_vanished, error);
   CONNECTION_UNLOCK (connection);
+
+  g_object_unref (connection);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -2244,6 +2371,12 @@ initable_init (GInitable     *initable,
     }
 #endif
 
+  G_LOCK (message_bus_lock);
+  if (alive_connections == NULL)
+    alive_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
+  g_hash_table_insert (alive_connections, connection, connection);
+  G_UNLOCK (message_bus_lock);
+
   connection->worker = _g_dbus_worker_new (connection->stream,
                                            connection->capabilities,
                                            (connection->flags & G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING),
@@ -3181,8 +3314,9 @@ g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
     {
       SignalSubscriber *subscriber;
       subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
-      if (subscriber->user_data_free_func != NULL)
-        subscriber->user_data_free_func (subscriber->user_data);
+      call_destroy_notify (subscriber->context,
+                           subscriber->user_data_free_func,
+                           subscriber->user_data);
       if (subscriber->context != NULL)
         g_main_context_unref (subscriber->context);
     }
@@ -3428,8 +3562,9 @@ purge_all_signal_subscriptions (GDBusConnection *connection)
     {
       SignalSubscriber *subscriber;
       subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
-      if (subscriber->user_data_free_func != NULL)
-        subscriber->user_data_free_func (subscriber->user_data);
+      call_destroy_notify (subscriber->context,
+                           subscriber->user_data_free_func,
+                           subscriber->user_data);
       if (subscriber->context != NULL)
         g_main_context_unref (subscriber->context);
     }
@@ -3511,9 +3646,9 @@ exported_interface_free (ExportedInterface *ei)
 {
   g_dbus_interface_info_unref ((GDBusInterfaceInfo *) ei->interface_info);
 
-  if (ei->user_data_free_func != NULL)
-    /* TODO: push to thread-default mainloop */
-    ei->user_data_free_func (ei->user_data);
+  call_destroy_notify (ei->context,
+                       ei->user_data_free_func,
+                       ei->user_data);
 
   if (ei->context != NULL)
     g_main_context_unref (ei->context);
@@ -5196,9 +5331,9 @@ struct ExportedSubtree
 static void
 exported_subtree_free (ExportedSubtree *es)
 {
-  if (es->user_data_free_func != NULL)
-    /* TODO: push to thread-default mainloop */
-    es->user_data_free_func (es->user_data);
+  call_destroy_notify (es->context,
+                       es->user_data_free_func,
+                       es->user_data);
 
   if (es->context != NULL)
     g_main_context_unref (es->context);