[evolution-data-server] Bug 746276 - Add thread-safety into EAsyncClosure
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 746276 - Add thread-safety into EAsyncClosure
- Date: Tue, 14 Apr 2015 15:17:42 +0000 (UTC)
commit d22de175f250e96755d85fb7162ae7b03484ae73
Author: Milan Crha <mcrha redhat com>
Date: Tue Apr 14 17:14:14 2015 +0200
Bug 746276 - Add thread-safety into EAsyncClosure
It could happen that the e_async_closure_callback() was called before
the e_async_closure_wait() was called, more precisely before
the closure's loop was run, which could eventually cause indefinite
waiting for the closure's loop to quit.
libedataserver/e-data-server-util.c | 44 ++++++++++++++++++++++++++++++++--
1 files changed, 41 insertions(+), 3 deletions(-)
---
diff --git a/libedataserver/e-data-server-util.c b/libedataserver/e-data-server-util.c
index 709016b..7fccb96 100644
--- a/libedataserver/e-data-server-util.c
+++ b/libedataserver/e-data-server-util.c
@@ -1608,6 +1608,8 @@ struct _EAsyncClosure {
GMainLoop *loop;
GMainContext *context;
GAsyncResult *result;
+ gboolean finished;
+ GMutex lock;
};
/**
@@ -1627,12 +1629,26 @@ e_async_closure_new (void)
closure = g_slice_new0 (EAsyncClosure);
closure->context = g_main_context_new ();
closure->loop = g_main_loop_new (closure->context, FALSE);
+ closure->finished = FALSE;
+ g_mutex_init (&closure->lock);
g_main_context_push_thread_default (closure->context);
return closure;
}
+static gboolean
+e_async_closure_unlock_mutex_cb (gpointer user_data)
+{
+ EAsyncClosure *closure = user_data;
+
+ g_return_val_if_fail (closure != NULL, FALSE);
+
+ g_mutex_unlock (&closure->lock);
+
+ return FALSE;
+}
+
/**
* e_async_closure_wait:
* @closure: an #EAsyncClosure
@@ -1653,7 +1669,22 @@ e_async_closure_wait (EAsyncClosure *closure)
{
g_return_val_if_fail (closure != NULL, NULL);
- g_main_loop_run (closure->loop);
+ g_mutex_lock (&closure->lock);
+ if (closure->finished) {
+ g_mutex_unlock (&closure->lock);
+ } else {
+ GSource *idle_source;
+
+ /* Unlock the closure->lock in the main loop, to ensure thread safety.
+ It should be processed before anything else, otherwise deadlock happens. */
+ idle_source = g_idle_source_new ();
+ g_source_set_callback (idle_source, e_async_closure_unlock_mutex_cb, closure, NULL);
+ g_source_set_priority (idle_source, G_PRIORITY_HIGH * 2);
+ g_source_attach (idle_source, closure->context);
+ g_source_unref (idle_source);
+
+ g_main_loop_run (closure->loop);
+ }
return closure->result;
}
@@ -1676,8 +1707,10 @@ e_async_closure_free (EAsyncClosure *closure)
g_main_loop_unref (closure->loop);
g_main_context_unref (closure->context);
- if (closure->result != NULL)
- g_object_unref (closure->result);
+ g_mutex_lock (&closure->lock);
+ g_clear_object (&closure->result);
+ g_mutex_unlock (&closure->lock);
+ g_mutex_clear (&closure->lock);
g_slice_free (EAsyncClosure, closure);
}
@@ -1707,10 +1740,15 @@ e_async_closure_callback (GObject *object,
real_closure = closure;
+ g_mutex_lock (&real_closure->lock);
+
/* Replace any previous result. */
if (real_closure->result != NULL)
g_object_unref (real_closure->result);
real_closure->result = g_object_ref (result);
+ real_closure->finished = TRUE;
+
+ g_mutex_unlock (&real_closure->lock);
g_main_loop_quit (real_closure->loop);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]