diff -up evolution-data-server-3.12.11/camel/camel-async-closure.c.async-closures-thread-safety evolution-data-server-3.12.11/camel/camel-async-closure.c --- evolution-data-server-3.12.11/camel/camel-async-closure.c.async-closures-thread-safety 2014-03-24 10:07:52.000000000 +0100 +++ evolution-data-server-3.12.11/camel/camel-async-closure.c 2015-06-01 21:55:07.711600144 +0200 @@ -54,6 +54,8 @@ struct _CamelAsyncClosure { GMainLoop *loop; GMainContext *context; GAsyncResult *result; + gboolean finished; + GMutex lock; }; /** @@ -73,12 +75,26 @@ camel_async_closure_new (void) closure = g_slice_new0 (CamelAsyncClosure); 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 +camel_async_closure_unlock_mutex_cb (gpointer user_data) +{ + CamelAsyncClosure *closure = user_data; + + g_return_val_if_fail (closure != NULL, FALSE); + + g_mutex_unlock (&closure->lock); + + return FALSE; +} + /** * camel_async_closure_wait: * @closure: a #CamelAsyncClosure @@ -99,7 +115,22 @@ camel_async_closure_wait (CamelAsyncClos { 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, camel_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; } @@ -122,8 +153,10 @@ camel_async_closure_free (CamelAsyncClos 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 (CamelAsyncClosure, closure); } @@ -153,10 +186,15 @@ camel_async_closure_callback (GObject *s 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); } diff -up evolution-data-server-3.12.11/libedataserver/e-data-server-util.c.async-closures-thread-safety evolution-data-server-3.12.11/libedataserver/e-data-server-util.c --- evolution-data-server-3.12.11/libedataserver/e-data-server-util.c.async-closures-thread-safety 2014-11-11 18:40:25.000000000 +0100 +++ evolution-data-server-3.12.11/libedataserver/e-data-server-util.c 2015-06-01 21:55:07.712600137 +0200 @@ -1523,6 +1523,8 @@ struct _EAsyncClosure { GMainLoop *loop; GMainContext *context; GAsyncResult *result; + gboolean finished; + GMutex lock; }; /** @@ -1542,12 +1544,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 @@ -1568,7 +1584,22 @@ e_async_closure_wait (EAsyncClosure *clo { 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; } @@ -1591,8 +1622,10 @@ e_async_closure_free (EAsyncClosure *clo 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); } @@ -1622,10 +1655,15 @@ e_async_closure_callback (GObject *objec 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); }