diff options
author | Milan Crha <mcrha@redhat.com> | 2016-02-03 10:32:24 +0100 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2016-02-03 10:36:59 +0100 |
commit | 144e6d76c2fb653ae55287b7f02f8a83103f904f (patch) | |
tree | d482adb79ba3a916ddd2e4d257d929b69a7fcf60 | |
parent | 2b0330f8f386c20632e6edb3760711938b8e76f3 (diff) | |
download | evolution-data-server-144e6d76c2fb653ae55287b7f02f8a83103f904f.tar.gz |
[IMAPx] Prefer graceful IDLE stop than forced reconnect
There still was an issue with stopping IDLE, the code could have run IDLE
in the preparation, like selecting the right folder, when it received
a request to stop IDLE and start other command. As the preparation was
not distinguished properly two commands could interleave and cause issues.
When in it, the IDLE stop had been done to stop it gracefully, instead
of disconnect the connection when in the middle of some command. It
should make things quicker (reconnect is slow), especially when the connection
is not stale.
-rw-r--r-- | camel/providers/imapx/camel-imapx-server.c | 77 |
1 files changed, 42 insertions, 35 deletions
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c index eb6e85e56..ecd89bc3e 100644 --- a/camel/providers/imapx/camel-imapx-server.c +++ b/camel/providers/imapx/camel-imapx-server.c @@ -5966,6 +5966,9 @@ imapx_server_idle_thread (gpointer user_data) return NULL; } + is->priv->idle_state = IMAPX_IDLE_STATE_PREPARING; + g_cond_broadcast (&is->priv->idle_cond); + mailbox = is->priv->idle_mailbox; if (mailbox) g_object_ref (mailbox); @@ -5998,9 +6001,7 @@ imapx_server_idle_thread (gpointer user_data) g_mutex_lock (&is->priv->idle_lock); if (is->priv->idle_stamp == itd->idle_stamp && - is->priv->idle_state == IMAPX_IDLE_STATE_SCHEDULED) { - is->priv->idle_state = IMAPX_IDLE_STATE_PREPARING; - g_cond_broadcast (&is->priv->idle_cond); + is->priv->idle_state == IMAPX_IDLE_STATE_PREPARING) { g_mutex_unlock (&is->priv->idle_lock); /* Blocks, until the DONE is issued or on inactivity timeout, error, ... */ @@ -6230,8 +6231,7 @@ camel_imapx_server_stop_idle_sync (CamelIMAPXServer *is, GError **error) { GCancellable *idle_cancellable; - gboolean issue_done = FALSE; - gboolean rather_disconnect = FALSE; + gulong handler_id = 0; gboolean success = TRUE; g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE); @@ -6249,16 +6249,7 @@ camel_imapx_server_stop_idle_sync (CamelIMAPXServer *is, } is->priv->idle_state = IMAPX_IDLE_STATE_OFF; - } else if (is->priv->idle_state == IMAPX_IDLE_STATE_PREPARING) { - success = FALSE; - - /* This message won't get into UI. */ - g_set_error_literal (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT, - "Reconnect after preparing IDLE command"); - } else if (is->priv->idle_state == IMAPX_IDLE_STATE_RUNNING) { - is->priv->idle_state = IMAPX_IDLE_STATE_STOPPING; g_cond_broadcast (&is->priv->idle_cond); - issue_done = TRUE; } idle_cancellable = is->priv->idle_cancellable ? g_object_ref (is->priv->idle_cancellable) : NULL; @@ -6267,9 +6258,20 @@ camel_imapx_server_stop_idle_sync (CamelIMAPXServer *is, g_clear_object (&is->priv->idle_mailbox); is->priv->idle_stamp++; - g_mutex_unlock (&is->priv->idle_lock); + if (cancellable) + handler_id = g_cancellable_connect (cancellable, G_CALLBACK (imapx_server_wait_idle_stop_cancelled_cb), is, NULL); + + while (is->priv->idle_state == IMAPX_IDLE_STATE_PREPARING && + !g_cancellable_is_cancelled (cancellable)) { + g_cond_wait (&is->priv->idle_cond, &is->priv->idle_lock); + } + + if (is->priv->idle_state == IMAPX_IDLE_STATE_RUNNING && + !g_cancellable_is_cancelled (cancellable)) { + is->priv->idle_state = IMAPX_IDLE_STATE_STOPPING; + g_cond_broadcast (&is->priv->idle_cond); + g_mutex_unlock (&is->priv->idle_lock); - if (issue_done) { g_mutex_lock (&is->priv->stream_lock); if (is->priv->output_stream) { gint previous_timeout = -1; @@ -6292,33 +6294,38 @@ camel_imapx_server_stop_idle_sync (CamelIMAPXServer *is, "Reconnect after couldn't issue DONE command"); } g_mutex_unlock (&is->priv->stream_lock); + g_mutex_lock (&is->priv->idle_lock); } - if (success) { - gulong handler_id = 0; + while (success && is->priv->idle_state != IMAPX_IDLE_STATE_OFF && + !g_cancellable_is_cancelled (cancellable)) { + g_cond_wait (&is->priv->idle_cond, &is->priv->idle_lock); + } - if (cancellable) - handler_id = g_cancellable_connect (cancellable, G_CALLBACK (imapx_server_wait_idle_stop_cancelled_cb), is, NULL); + if (cancellable && handler_id) + g_cancellable_disconnect (cancellable, handler_id); - g_mutex_lock (&is->priv->idle_lock); - while (is->priv->idle_state != IMAPX_IDLE_STATE_OFF && - !g_cancellable_set_error_if_cancelled (cancellable, error)) { - g_cond_wait (&is->priv->idle_cond, &is->priv->idle_lock); - } - g_mutex_unlock (&is->priv->idle_lock); + if (success && g_cancellable_is_cancelled (cancellable)) { + g_clear_error (error); - if (cancellable && handler_id) - g_cancellable_disconnect (cancellable, handler_id); - } else { + success = FALSE; + + /* This message won't get into UI. */ + g_set_error_literal (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT, + "Reconnect after cancelled IDLE stop command"); + } + + g_mutex_unlock (&is->priv->idle_lock); + + if (!success) { if (idle_cancellable) g_cancellable_cancel (idle_cancellable); - if (rather_disconnect) { - g_mutex_lock (&is->priv->idle_lock); - is->priv->idle_state = IMAPX_IDLE_STATE_OFF; - g_mutex_unlock (&is->priv->idle_lock); - imapx_disconnect (is); - } + g_mutex_lock (&is->priv->idle_lock); + is->priv->idle_state = IMAPX_IDLE_STATE_OFF; + g_mutex_unlock (&is->priv->idle_lock); + + imapx_disconnect (is); } g_clear_object (&idle_cancellable); |