[evolution-data-server] Bug #664793 - Deadlock on EClient operation cancel
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug #664793 - Deadlock on EClient operation cancel
- Date: Wed, 4 Apr 2012 17:10:58 +0000 (UTC)
commit 2d6f9dcca031268b7563287f0294d768480813a9
Author: Milan Crha <mcrha redhat com>
Date: Wed Apr 4 19:10:31 2012 +0200
Bug #664793 - Deadlock on EClient operation cancel
libedataserver/e-client.c | 10 ++++++
libedataserver/e-gdbus-templates.c | 58 ++++++++++++++++++++++++++----------
libedataserverui/e-client-utils.c | 3 ++
3 files changed, 55 insertions(+), 16 deletions(-)
---
diff --git a/libedataserver/e-client.c b/libedataserver/e-client.c
index 0f58720..74d7c02 100644
--- a/libedataserver/e-client.c
+++ b/libedataserver/e-client.c
@@ -880,10 +880,18 @@ struct EClientAuthData {
static gboolean
client_process_authentication_idle_cb (gpointer user_data)
{
+ static gboolean processing_one = FALSE;
struct EClientAuthData *auth_data = user_data;
g_return_val_if_fail (auth_data != NULL, FALSE);
+ /* there is one currently processing, postpone this request for later */
+ if (processing_one)
+ return TRUE;
+
+ /* no need for locking, this is always main-thread's idle */
+ processing_one = TRUE;
+
if (e_client_emit_authenticate (auth_data->client, auth_data->credentials)) {
client_handle_authentication (auth_data->client, auth_data->credentials);
} else {
@@ -907,6 +915,8 @@ client_process_authentication_idle_cb (gpointer user_data)
g_object_unref (auth_data->client);
g_free (auth_data);
+ processing_one = FALSE;
+
return FALSE;
}
diff --git a/libedataserver/e-gdbus-templates.c b/libedataserver/e-gdbus-templates.c
index fe31eb8..61b594d 100644
--- a/libedataserver/e-gdbus-templates.c
+++ b/libedataserver/e-gdbus-templates.c
@@ -836,6 +836,7 @@ typedef struct _AsyncOpData
GCancellable *cancellable;
gulong cancel_id;
+ guint cancel_idle_id;
gpointer async_source_tag;
GAsyncReadyCallback async_callback;
@@ -857,6 +858,18 @@ async_op_data_free (AsyncOpData *op_data)
g_return_if_fail (op_data != NULL);
+ if (op_data->cancel_idle_id) {
+ GError *error = NULL;
+
+ g_source_remove (op_data->cancel_idle_id);
+ op_data->cancel_idle_id = 0;
+
+ if (!e_gdbus_async_op_keeper_cancel_op_sync (op_data->proxy, op_data->opid, NULL, &error)) {
+ g_debug ("%s: Failed to cancel operation: %s\n", G_STRFUNC, error ? error->message : "Unknown error");
+ g_clear_error (&error);
+ }
+ }
+
if (op_data->cancellable) {
if (op_data->cancel_id)
g_cancellable_disconnect (op_data->cancellable, op_data->cancel_id);
@@ -906,28 +919,41 @@ async_op_complete (AsyncOpData *op_data,
g_object_unref (simple);
}
-static void
-e_gdbus_op_cancelled_cb (GCancellable *cancellable,
- AsyncOpData *op_data)
+static gboolean
+e_gdbus_op_cancelled_idle_cb (gpointer user_data)
{
- GError *call_error = NULL;
-
- g_return_if_fail (op_data != NULL);
+ AsyncOpData *op_data = user_data;
+ GCancellable *cancellable;
+ GError *error = NULL;
- if (!e_gdbus_async_op_keeper_cancel_op_sync (op_data->proxy, op_data->opid, NULL, &call_error)) {
- /* only if failed, because otherwise will receive cancelled signal from the server */
- GError *error = NULL;
+ g_return_val_if_fail (op_data != NULL, FALSE);
- g_return_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
+ cancellable = op_data->cancellable;
+ op_data->cancel_idle_id = 0;
- async_op_complete (op_data, error, TRUE);
- g_error_free (error);
+ if (!e_gdbus_async_op_keeper_cancel_op_sync (op_data->proxy, op_data->opid, NULL, &error)) {
+ g_debug ("%s: Failed to cancel operation: %s\n", G_STRFUNC, error ? error->message : "Unknown error");
+ g_clear_error (&error);
}
- if (call_error) {
- g_debug ("%s: Failed to cancel operation: %s\n", G_STRFUNC, call_error->message);
- g_error_free (call_error);
- }
+ g_return_val_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error), FALSE);
+
+ async_op_complete (op_data, error, TRUE);
+ g_clear_error (&error);
+
+ return FALSE;
+}
+
+static void
+e_gdbus_op_cancelled_cb (GCancellable *cancellable,
+ AsyncOpData *op_data)
+{
+ g_return_if_fail (op_data != NULL);
+ g_return_if_fail (op_data->cancellable == cancellable);
+
+ /* do this on idle, because this callback should be left
+ as soon as possible, with no sync calls being done */
+ op_data->cancel_idle_id = g_idle_add (e_gdbus_op_cancelled_idle_cb, op_data);
}
static void
diff --git a/libedataserverui/e-client-utils.c b/libedataserverui/e-client-utils.c
index 948bc17..3784535 100644
--- a/libedataserverui/e-client-utils.c
+++ b/libedataserverui/e-client-utils.c
@@ -598,6 +598,9 @@ client_utils_open_new_auth_cb (EClient *client,
g_return_val_if_fail (async_data != NULL, FALSE);
g_return_val_if_fail (async_data->auth_handler != NULL, FALSE);
+ if (async_data->cancellable && g_cancellable_is_cancelled (async_data->cancellable))
+ return FALSE;
+
if (async_data->used_credentials) {
const gchar *reason = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_REASON);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]