summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Holy <oholy@redhat.com>2019-10-10 07:34:02 +0000
committerOndrej Holy <oholy@redhat.com>2019-11-11 12:32:02 +0000
commit2ee9624f47b99fa39a6ea6bb755226d43909202f (patch)
treed81489b8cc12f7432090b967b6f985f1acbcfbbc
parentc1bf1edbf99d4775669cfdd0ceb179ed47eb2a06 (diff)
downloadgvfs-2ee9624f47b99fa39a6ea6bb755226d43909202f.tar.gz
gdbus: Add workaround for deadlocks when cancelling jobs
GVfs calls gvfs_dbus_daemon_proxy_new() in cancelled signal handler which internally needs CONNECTION_LOCK(connection). The lock can be unfortunately held by gdbus worker thread which can call g_cancellable_disconnect(). This obviously leads to deadlocks. I don't see any reason why we have to block g_cancellable_disconnect() because of gvfs_dbus_daemon_proxy_new() resp. gvfs_dbus_daemon_call_cancel(). Let's call it over idle source to not block the cancelled signal handler in order to prevent the deadlocks. It would be better to fix this issue directly in gdbus codes, however, it is not fully clear to me, what is a proper way to fix this. https://gitlab.gnome.org/GNOME/glib/issues/1023 (cherry picked from commit a1e85edaa95d5f69c1aa4a883fb1d308e2ad8a3a)
-rw-r--r--client/gvfsdaemondbus.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/client/gvfsdaemondbus.c b/client/gvfsdaemondbus.c
index e12d2936..f8deb097 100644
--- a/client/gvfsdaemondbus.c
+++ b/client/gvfsdaemondbus.c
@@ -365,10 +365,8 @@ cancelled_got_proxy (GObject *source_object,
g_object_unref (proxy);
}
-/* Might be called on another thread */
-static void
-async_call_cancelled_cb (GCancellable *cancellable,
- gpointer _data)
+static gboolean
+async_call_cancelled_cb_on_idle (gpointer _data)
{
AsyncCallCancelData *data = _data;
@@ -380,6 +378,29 @@ async_call_cancelled_cb (GCancellable *cancellable,
NULL,
cancelled_got_proxy,
GUINT_TO_POINTER (data->serial)); /* not passing "data" in as long it may not exist anymore between async calls */
+
+ return FALSE;
+}
+
+/* Might be called on another thread */
+static void
+async_call_cancelled_cb (GCancellable *cancellable,
+ gpointer _data)
+{
+ AsyncCallCancelData *data = _data;
+ AsyncCallCancelData *idle_data;
+
+ idle_data = g_new0 (AsyncCallCancelData, 1);
+ idle_data->connection = g_object_ref (data->connection);
+ idle_data->serial = data->serial;
+
+ /* Call on idle to not block g_cancellable_disconnect() as it causes deadlocks
+ * in gdbus codes, see: https://gitlab.gnome.org/GNOME/glib/issues/1023.
+ */
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ async_call_cancelled_cb_on_idle,
+ idle_data,
+ async_call_cancel_data_free);
}
gulong