[gvfs] GVfsDaemon: Don't deadlock on cliend disconnect
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs] GVfsDaemon: Don't deadlock on cliend disconnect
- Date: Thu, 26 Sep 2013 11:34:25 +0000 (UTC)
commit 3448fa01d514e31d0b0c1071f7738b3c8101c8ab
Author: Alexander Larsson <alexl redhat com>
Date: Thu Sep 26 13:29:49 2013 +0200
GVfsDaemon: Don't deadlock on cliend disconnect
There was a deadlock that could happen on client disconnect in
peer_connection_closed(). If the cancelled job immediately called back into
job_finished_callback() we would deadlock on daemon->mutex.
So, make sure we cancel jobs without holding the lock, just like
handle_cancel() does.
https://bugzilla.gnome.org/show_bug.cgi?id=708816
daemon/gvfsdaemon.c | 36 ++++++++++++++++++++++++++----------
1 files changed, 26 insertions(+), 10 deletions(-)
---
diff --git a/daemon/gvfsdaemon.c b/daemon/gvfsdaemon.c
index 6cb3341..9a9cb00 100644
--- a/daemon/gvfsdaemon.c
+++ b/daemon/gvfsdaemon.c
@@ -624,19 +624,35 @@ peer_connection_closed (GDBusConnection *connection,
GVfsDaemon *daemon = G_VFS_DAEMON (user_data);
GList *l;
GVfsDBusDaemon *daemon_skeleton;
+ GVfsJob *job_to_cancel;
- g_mutex_lock (&daemon->lock);
- for (l = daemon->jobs; l != NULL; l = l->next)
+ do
{
- GVfsJob *job = G_VFS_JOB (l->data);
-
- if (G_VFS_IS_JOB_DBUS (job) &&
- G_VFS_JOB_DBUS (job)->invocation &&
- g_dbus_method_invocation_get_connection (G_VFS_JOB_DBUS (job)->invocation) == connection)
- g_vfs_job_cancel (job);
- }
- g_mutex_unlock (&daemon->lock);
+ job_to_cancel = NULL;
+
+ g_mutex_lock (&daemon->lock);
+ for (l = daemon->jobs; l != NULL; l = l->next)
+ {
+ GVfsJob *job = G_VFS_JOB (l->data);
+
+ if (G_VFS_IS_JOB_DBUS (job) &&
+ !g_vfs_job_is_cancelled (job) &&
+ G_VFS_JOB_DBUS (job)->invocation &&
+ g_dbus_method_invocation_get_connection (G_VFS_JOB_DBUS (job)->invocation) == connection)
+ {
+ job_to_cancel = g_object_ref (job);
+ break;
+ }
+ }
+ g_mutex_unlock (&daemon->lock);
+ if (job_to_cancel)
+ {
+ g_vfs_job_cancel (job_to_cancel);
+ g_object_unref (job_to_cancel);
+ }
+ }
+ while (job_to_cancel != NULL);
daemon_skeleton = g_object_get_data (G_OBJECT (connection), "daemon_skeleton");
/* daemon_skeleton should be always valid in this case */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]