[gvfs] Avoid deadlock on cancelling async enumerate_children
- From: Alexander Larsson <alexl src gnome org>
- To: svn-commits-list gnome org
- Subject: [gvfs] Avoid deadlock on cancelling async enumerate_children
- Date: Thu, 25 Jun 2009 19:12:53 +0000 (UTC)
commit 36d06a5fb2ff170fb2388d0afc82df954383b453
Author: Alexander Larsson <alexl redhat com>
Date: Thu Jun 25 20:57:49 2009 +0200
Avoid deadlock on cancelling async enumerate_children
We can't call g_cancellable_disconnect from inside the cancel signal
emission, as that deadlocks. However we know if that happens and can
use the regular disconnect.
Also, we need to grab the infos lock when calling trigger_async_done, this
was only done in some cases, now its always done.
client/gdaemonfileenumerator.c | 25 +++++++++++++++++++++++--
1 files changed, 23 insertions(+), 2 deletions(-)
---
diff --git a/client/gdaemonfileenumerator.c b/client/gdaemonfileenumerator.c
index 7d5053a..1b6b084 100644
--- a/client/gdaemonfileenumerator.c
+++ b/client/gdaemonfileenumerator.c
@@ -228,8 +228,24 @@ trigger_async_done (GDaemonFileEnumerator *daemon, gboolean ok)
GList *rest, *l;
if (daemon->cancelled_tag != 0)
- g_cancellable_disconnect (daemon->async_cancel,
- daemon->cancelled_tag);
+ {
+ /* If ok, we're a normal callback on the main thread,
+ ensure protection against a thread cancelling and
+ running the callback again.
+ If !ok then we're in a callback which may be
+ from another thread, but we're guaranteed that
+ cancellation will only happen once. However
+ we can't use g_cancellable_disconnect, as this
+ deadlocks if we call it from within the signal
+ handler.
+ */
+ if (ok)
+ g_cancellable_disconnect (daemon->async_cancel,
+ daemon->cancelled_tag);
+ else
+ g_signal_handler_disconnect (daemon->async_cancel,
+ daemon->cancelled_tag);
+ }
/* cancelled signal handler won't execute after this */
@@ -430,14 +446,19 @@ async_cancelled (GCancellable *cancellable,
G_IO_ERROR,
G_IO_ERROR_CANCELLED,
_("Operation was cancelled"));
+ G_LOCK (infos);
trigger_async_done (daemon, FALSE);
+ G_UNLOCK (infos);
}
static gboolean
async_timeout (gpointer data)
{
GDaemonFileEnumerator *daemon = G_DAEMON_FILE_ENUMERATOR (data);
+
+ G_LOCK (infos);
trigger_async_done (daemon, TRUE);
+ G_UNLOCK (infos);
return FALSE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]