GDBus: make use of reliable async cancellation
[platform/upstream/glib.git] / gio / gdbusconnection.c
index 34368e2..7a4a08a 100644 (file)
  * (i.e. connect to D-Bus): for instance, g_dbus_connection_new() and
  * g_bus_get(), and the synchronous versions of those methods, give you an
  * initialized connection. Language bindings for GIO should use
- * g_initable_new() or g_async_initable_new(), which also initialize the
+ * g_initable_new() or g_async_initable_new_async(), which also initialize the
  * connection.
  *
  * If you construct an uninitialized #GDBusConnection, such as via
  * g_object_new(), you must initialize it via g_initable_init() or
- * g_async_initable_init() before using its methods or properties. Calling
- * methods or accessing properties on a #GDBusConnection that has not completed
- * initialization successfully is considered to be invalid, and leads to
- * undefined behaviour. In particular, if initialization fails with a #GError,
- * the only valid thing you can do with that #GDBusConnection is to free it
- * with g_object_unref().
+ * g_async_initable_init_async() before using its methods or properties.
+ * Calling methods or accessing properties on a #GDBusConnection that has not
+ * completed initialization successfully is considered to be invalid, and leads
+ * to undefined behaviour. In particular, if initialization fails with a
+ * #GError, the only valid thing you can do with that #GDBusConnection is to
+ * free it with g_object_unref().
  *
  * <example id="gdbus-server"><title>D-Bus server example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
  *
@@ -208,8 +208,8 @@ struct _GDBusConnectionClass
 
 G_LOCK_DEFINE_STATIC (message_bus_lock);
 
-static GDBusConnection *the_session_bus = NULL;
-static GDBusConnection *the_system_bus = NULL;
+static GWeakRef the_session_bus;
+static GWeakRef the_system_bus;
 
 /* Extra pseudo-member of GDBusSendMessageFlags.
  * Set by initable_init() to indicate that despite not being initialized yet,
@@ -260,38 +260,27 @@ call_destroy_notify (GMainContext  *context,
                      GDestroyNotify callback,
                      gpointer       user_data)
 {
-  GMainContext *current_context;
+  GSource *idle_source;
+  CallDestroyNotifyData *data;
 
   if (callback == NULL)
     goto out;
 
-  current_context = g_main_context_get_thread_default ();
-  if ((context == current_context) ||
-      (current_context == NULL && context == g_main_context_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);
+  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);
-    }
+  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:
   ;
@@ -617,14 +606,6 @@ g_dbus_connection_dispose (GObject *object)
   GDBusConnection *connection = G_DBUS_CONNECTION (object);
 
   G_LOCK (message_bus_lock);
-  if (connection == the_session_bus)
-    {
-      the_session_bus = NULL;
-    }
-  else if (connection == the_system_bus)
-    {
-      the_system_bus = NULL;
-    }
   CONNECTION_LOCK (connection);
   if (connection->worker != NULL)
     {
@@ -975,6 +956,9 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass)
    * calling <literal>raise(SIGTERM)</literal>) if the connection
    * is closed by the remote peer.
    *
+   * Note that #GDBusConnection objects returned by g_bus_get_finish() and
+   * g_bus_get_sync() will (usually) have this property set to %TRUE.
+   *
    * Since: 2.26
    */
   g_object_class_install_property (gobject_class,
@@ -1262,6 +1246,7 @@ g_dbus_connection_flush (GDBusConnection     *connection,
                                       callback,
                                       user_data,
                                       g_dbus_connection_flush);
+  g_simple_async_result_set_check_cancellable (simple, cancellable);
   g_simple_async_result_run_in_thread (simple,
                                        flush_in_thread_func,
                                        G_PRIORITY_DEFAULT,
@@ -1475,6 +1460,7 @@ g_dbus_connection_close (GDBusConnection     *connection,
                                       callback,
                                       user_data,
                                       g_dbus_connection_close);
+  g_simple_async_result_set_check_cancellable (simple, cancellable);
   _g_dbus_worker_close (connection->worker, cancellable, simple);
   g_object_unref (simple);
 }
@@ -1932,6 +1918,7 @@ g_dbus_connection_send_message_with_reply_unlocked (GDBusConnection     *connect
                                       callback,
                                       user_data,
                                       g_dbus_connection_send_message_with_reply);
+  g_simple_async_result_set_check_cancellable (simple, cancellable);
 
   if (g_cancellable_is_cancelled (cancellable))
     {
@@ -5314,8 +5301,8 @@ g_dbus_connection_call_done (GObject      *source,
     {
       g_simple_async_result_set_op_res_gpointer (state->simple, state, (GDestroyNotify) call_state_free);
       g_simple_async_result_complete (state->simple);
-      g_object_unref (reply);
     }
+  g_clear_object (&reply);
   g_object_unref (simple);
 }
 
@@ -5356,6 +5343,7 @@ g_dbus_connection_call_internal (GDBusConnection        *connection,
   state->simple = g_simple_async_result_new (G_OBJECT (connection),
                                              callback, user_data,
                                              g_dbus_connection_call_internal);
+  g_simple_async_result_set_check_cancellable (state->simple, cancellable);
   state->method_name = g_strjoin (".", interface_name, method_name, NULL);
 
   if (reply_type == NULL)
@@ -6663,11 +6651,11 @@ distribute_method_call (GDBusConnection *connection,
 /* ---------------------------------------------------------------------------------------------------- */
 
 /* Called in any user thread, with the message_bus_lock held. */
-static GDBusConnection **
+static GWeakRef *
 message_bus_get_singleton (GBusType   bus_type,
                            GError   **error)
 {
-  GDBusConnection **ret;
+  GWeakRef *ret;
   const gchar *starter_bus;
 
   ret = NULL;
@@ -6731,7 +6719,7 @@ get_uninitialized_connection (GBusType       bus_type,
                               GCancellable  *cancellable,
                               GError       **error)
 {
-  GDBusConnection **singleton;
+  GWeakRef *singleton;
   GDBusConnection *ret;
 
   ret = NULL;
@@ -6741,24 +6729,24 @@ get_uninitialized_connection (GBusType       bus_type,
   if (singleton == NULL)
     goto out;
 
-  if (*singleton == NULL)
+  ret = g_weak_ref_get (singleton);
+
+  if (ret == NULL)
     {
       gchar *address;
       address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error);
       if (address == NULL)
         goto out;
-      ret = *singleton = g_object_new (G_TYPE_DBUS_CONNECTION,
-                                       "address", address,
-                                       "flags", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
-                                                G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
-                                       "exit-on-close", TRUE,
-                                       NULL);
+      ret = g_object_new (G_TYPE_DBUS_CONNECTION,
+                          "address", address,
+                          "flags", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+                                   G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
+                          "exit-on-close", TRUE,
+                          NULL);
+
+      g_weak_ref_set (singleton, ret);
       g_free (address);
     }
-  else
-    {
-      ret = g_object_ref (*singleton);
-    }
 
   g_assert (ret != NULL);
 
@@ -6875,6 +6863,7 @@ g_bus_get (GBusType             bus_type,
                                       callback,
                                       user_data,
                                       g_bus_get);
+  g_simple_async_result_set_check_cancellable (simple, cancellable);
 
   error = NULL;
   connection = get_uninitialized_connection (bus_type, cancellable, &error);