diff -up evolution-3.12.11/e-util/e-client-cache.c.client-cache-stuck evolution-3.12.11/e-util/e-client-cache.c
--- evolution-3.12.11/e-util/e-client-cache.c.client-cache-stuck 2015-01-27 14:46:14.000000000 +0100
+++ evolution-3.12.11/e-util/e-client-cache.c 2015-07-15 18:08:54.368866342 +0200
@@ -531,8 +531,12 @@ client_cache_process_results (ClientData
if (client != NULL) {
EClientCache *client_cache;
- /* Make sure we're not leaking a reference. */
- g_warn_if_fail (client_data->client == NULL);
+ /* Make sure we're not leaking a reference. This can happen when
+ a synchronous and an asynchronous open are interleaving. The
+ synchronous open bypasses pending openings, thus can eventually
+ overwrite, or preset, the client.
+ */
+ g_clear_object (&client_data->client);
client_data->client = g_object_ref (client);
client_data->dead_backend = FALSE;
@@ -1047,28 +1051,6 @@ e_client_cache_ref_registry (EClientCach
return g_object_ref (client_cache->priv->registry);
}
-typedef struct _GetClientSyncData {
- GMutex mutex;
- EAsyncClosure *closure;
-} GetClientSyncData;
-
-static void
-client_cache_get_client_sync_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GetClientSyncData *data = user_data;
-
- g_return_if_fail (E_IS_CLIENT_CACHE (source_object));
- g_return_if_fail (data != NULL);
-
- g_mutex_lock (&data->mutex);
-
- e_async_closure_callback (source_object, result, data->closure);
-
- g_mutex_unlock (&data->mutex);
-}
-
/**
* e_client_cache_get_client_sync:
* @client_cache: an #EClientCache
@@ -1116,37 +1098,68 @@ e_client_cache_get_client_sync (EClientC
GCancellable *cancellable,
GError **error)
{
- GetClientSyncData data;
- GAsyncResult *result;
- EClient *client;
+ ClientData *client_data;
+ EClient *client = NULL;
+ GError *local_error = NULL;
g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL);
g_return_val_if_fail (E_IS_SOURCE (source), NULL);
g_return_val_if_fail (extension_name != NULL, NULL);
- g_mutex_init (&data.mutex);
- g_mutex_lock (&data.mutex);
+ client_data = client_ht_lookup (client_cache, source, extension_name);
- e_client_cache_get_client (
- client_cache, source, extension_name,cancellable,
- client_cache_get_client_sync_cb, &data);
+ if (client_data == NULL) {
+ g_set_error (
+ error, G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Cannot create a client object from "
+ "extension name '%s'"), extension_name);
+ return NULL;
+ }
- /* This is needed, because e_async_closure_new() pushes its own thread default main context,
- which was later taken into an EClient within e_client_cache_get_client(), but that's wrong,
- because that main context effectively dies at the end of this function. */
- data.closure = e_async_closure_new ();
+ g_mutex_lock (&client_data->lock);
- g_mutex_unlock (&data.mutex);
+ if (client_data->client != NULL)
+ client = g_object_ref (client_data->client);
- result = e_async_closure_wait (data.closure);
+ g_mutex_unlock (&client_data->lock);
- client = e_client_cache_get_client_finish (
- client_cache, result, error);
+ /* If a cached EClient already exists, we're done. */
+ if (client != NULL) {
+ client_data_unref (client_data);
+ return client;
+ }
- g_mutex_lock (&data.mutex);
- e_async_closure_free (data.closure);
- g_mutex_unlock (&data.mutex);
- g_mutex_clear (&data.mutex);
+ /* Create an appropriate EClient instance for the extension
+ * name. The client_ht_lookup() call above ensures us that
+ * one of these options will match. */
+
+ if (g_str_equal (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
+ client = e_book_client_connect_sync (source,
+ cancellable, &local_error);
+ } else if (g_str_equal (extension_name, E_SOURCE_EXTENSION_CALENDAR)) {
+ client = e_cal_client_connect_sync (
+ source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
+ cancellable, &local_error);
+ } else if (g_str_equal (extension_name, E_SOURCE_EXTENSION_MEMO_LIST)) {
+ client = e_cal_client_connect_sync (
+ source, E_CAL_CLIENT_SOURCE_TYPE_MEMOS,
+ cancellable, &local_error);
+ } else if (g_str_equal (extension_name, E_SOURCE_EXTENSION_TASK_LIST)) {
+ client = e_cal_client_connect_sync (
+ source, E_CAL_CLIENT_SOURCE_TYPE_TASKS,
+ cancellable, &local_error);
+ } else {
+ g_warn_if_reached (); /* Should never happen. */
+ }
+
+ if (client)
+ client_cache_process_results (client_data, client, local_error);
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ client_data_unref (client_data);
return client;
}