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; }