diff -up evolution-data-server-3.12.4/camel/providers/imapx/camel-imapx-server.c.imapx-job-stuck-with-idle evolution-data-server-3.12.4/camel/providers/imapx/camel-imapx-server.c --- evolution-data-server-3.12.4/camel/providers/imapx/camel-imapx-server.c.imapx-job-stuck-with-idle 2014-07-13 20:22:01.000000000 +0200 +++ evolution-data-server-3.12.4/camel/providers/imapx/camel-imapx-server.c 2014-07-18 11:59:00.797448928 +0200 @@ -320,6 +320,7 @@ typedef enum { IMAPX_IDLE_STARTED, /* IDLE continuation received; IDLE active */ IMAPX_IDLE_CANCEL, /* Cancelled from ISSUED state; need to send DONE as soon as we receive continuation */ + IMAPX_IDLE_WAIT_DONE /* DONE was issued, waiting for a confirmation response */ } CamelIMAPXIdleState; #define IMAPX_IDLE_DWELL_TIME 2 /* Number of seconds to remain in PENDING @@ -390,7 +391,7 @@ struct _CamelIMAPXServerPrivate { gchar inbox_separator; /* IDLE support */ - GMutex idle_lock; + GRecMutex idle_lock; GThread *idle_thread; GMainLoop *idle_main_loop; GMainContext *idle_main_context; @@ -1472,7 +1473,7 @@ imapx_command_start_next (CamelIMAPXServ "waiting for idle to stop \n"); /* if there are more pending commands, * then they should be processed too */ - break; + return; case IMAPX_IDLE_STOP_ERROR: return; @@ -3054,25 +3055,27 @@ imapx_continuation (CamelIMAPXServer *is return FALSE; c (is->tagprefix, "Got continuation response for IDLE \n"); - g_mutex_lock (&is->priv->idle_lock); + g_rec_mutex_lock (&is->priv->idle_lock); /* We might have actually sent the DONE already! */ - if (is->priv->idle_state == IMAPX_IDLE_ISSUED) + if (is->priv->idle_state == IMAPX_IDLE_ISSUED) { is->priv->idle_state = IMAPX_IDLE_STARTED; - else if (is->priv->idle_state == IMAPX_IDLE_CANCEL) { + } else if (is->priv->idle_state == IMAPX_IDLE_CANCEL) { /* IDLE got cancelled after we sent the command, while * we were waiting for this continuation. Send DONE * immediately. */ if (!imapx_command_idle_stop (is, error)) { - g_mutex_unlock (&is->priv->idle_lock); + g_rec_mutex_unlock (&is->priv->idle_lock); return FALSE; } - is->priv->idle_state = IMAPX_IDLE_OFF; + is->priv->idle_state = IMAPX_IDLE_WAIT_DONE; + } else if (is->priv->idle_state == IMAPX_IDLE_WAIT_DONE) { + /* Do nothing, just wait */ } else { c ( is->tagprefix, "idle starts in wrong state %d\n", is->priv->idle_state); } - g_mutex_unlock (&is->priv->idle_lock); + g_rec_mutex_unlock (&is->priv->idle_lock); QUEUE_LOCK (is); is->literal = NULL; @@ -3548,9 +3551,9 @@ imapx_command_idle_done (CamelIMAPXServe camel_imapx_job_take_error (job, local_error); } - g_mutex_lock (&is->priv->idle_lock); + g_rec_mutex_lock (&is->priv->idle_lock); is->priv->idle_state = IMAPX_IDLE_OFF; - g_mutex_unlock (&is->priv->idle_lock); + g_rec_mutex_unlock (&is->priv->idle_lock); imapx_unregister_job (is, job); } @@ -3579,29 +3582,23 @@ imapx_job_idle_start (CamelIMAPXJob *job cp = g_queue_peek_head (&ic->parts); cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION; - g_mutex_lock (&is->priv->idle_lock); + QUEUE_LOCK (is); + g_rec_mutex_lock (&is->priv->idle_lock); /* Don't issue it if the idle was cancelled already */ if (is->priv->idle_state == IMAPX_IDLE_PENDING) { is->priv->idle_state = IMAPX_IDLE_ISSUED; - g_mutex_unlock (&is->priv->idle_lock); - QUEUE_LOCK (is); - /* It can be that another thread started a command between - the two locks above had been interchanged, thus also test - whether the active command queue is empty, before starting - the IDLE command. */ if (camel_imapx_command_queue_is_empty (is->active)) { imapx_command_start (is, ic); } else { c (is->tagprefix, "finally cancelling IDLE, other command was quicker\n"); + is->priv->idle_state = IMAPX_IDLE_OFF; imapx_unregister_job (is, job); } } else { - g_mutex_unlock (&is->priv->idle_lock); - - QUEUE_LOCK (is); imapx_unregister_job (is, job); } + g_rec_mutex_unlock (&is->priv->idle_lock); QUEUE_UNLOCK (is); camel_imapx_command_unref (ic); @@ -3690,13 +3687,16 @@ imapx_call_idle (gpointer data) goto exit; /* XXX Rename to 'pending_lock'? */ - g_mutex_lock (&is->priv->idle_lock); + g_rec_mutex_lock (&is->priv->idle_lock); g_source_unref (is->priv->idle_pending); is->priv->idle_pending = NULL; - g_mutex_unlock (&is->priv->idle_lock); - if (is->priv->idle_state != IMAPX_IDLE_PENDING) + if (is->priv->idle_state != IMAPX_IDLE_PENDING) { + g_rec_mutex_unlock (&is->priv->idle_lock); goto exit; + } + + g_rec_mutex_unlock (&is->priv->idle_lock); g_mutex_lock (&is->priv->select_lock); mailbox = g_weak_ref_get (&is->priv->select_mailbox); @@ -3765,7 +3765,7 @@ imapx_idle_thread (gpointer data) * regressions. */ - g_mutex_lock (&is->priv->idle_lock); + g_rec_mutex_lock (&is->priv->idle_lock); g_warn_if_fail (is->priv->idle_pending == NULL); pending = g_timeout_source_new_seconds (IMAPX_IDLE_DWELL_TIME); @@ -3778,7 +3778,7 @@ imapx_idle_thread (gpointer data) is->priv->idle_pending = g_source_ref (pending); g_source_unref (pending); - g_mutex_unlock (&is->priv->idle_lock); + g_rec_mutex_unlock (&is->priv->idle_lock); g_main_loop_run (is->priv->idle_main_loop); @@ -3798,36 +3798,40 @@ imapx_stop_idle (CamelIMAPXServer *is, time (&now); - g_mutex_lock (&is->priv->idle_lock); + g_rec_mutex_lock (&is->priv->idle_lock); switch (is->priv->idle_state) { case IMAPX_IDLE_ISSUED: is->priv->idle_state = IMAPX_IDLE_CANCEL; - /* fall through */ + result = IMAPX_IDLE_STOP_SUCCESS; + break; case IMAPX_IDLE_CANCEL: + case IMAPX_IDLE_WAIT_DONE: result = IMAPX_IDLE_STOP_SUCCESS; break; case IMAPX_IDLE_STARTED: if (imapx_command_idle_stop (is, error)) { result = IMAPX_IDLE_STOP_SUCCESS; + is->priv->idle_state = IMAPX_IDLE_WAIT_DONE; } else { result = IMAPX_IDLE_STOP_ERROR; + is->priv->idle_state = IMAPX_IDLE_OFF; goto exit; } - /* fall through */ + break; case IMAPX_IDLE_PENDING: is->priv->idle_state = IMAPX_IDLE_OFF; - /* fall through */ + break; case IMAPX_IDLE_OFF: break; } exit: - g_mutex_unlock (&is->priv->idle_lock); + g_rec_mutex_unlock (&is->priv->idle_lock); return result; } @@ -3838,9 +3842,14 @@ imapx_start_idle (CamelIMAPXServer *is) if (camel_application_is_exiting) return; - g_mutex_lock (&is->priv->idle_lock); + g_rec_mutex_lock (&is->priv->idle_lock); + + if (is->priv->idle_state != IMAPX_IDLE_OFF) { + g_warn_if_fail (is->priv->idle_state == IMAPX_IDLE_OFF); + g_rec_mutex_unlock (&is->priv->idle_lock); + return; + } - g_return_if_fail (is->priv->idle_state == IMAPX_IDLE_OFF); is->priv->idle_state = IMAPX_IDLE_PENDING; if (is->priv->idle_thread == NULL) { @@ -3861,7 +3870,7 @@ imapx_start_idle (CamelIMAPXServer *is) g_source_unref (pending); } - g_mutex_unlock (&is->priv->idle_lock); + g_rec_mutex_unlock (&is->priv->idle_lock); } static gboolean @@ -3869,12 +3878,12 @@ imapx_in_idle (CamelIMAPXServer *is) { gboolean in_idle = FALSE; - g_mutex_lock (&is->priv->idle_lock); + g_rec_mutex_lock (&is->priv->idle_lock); if (is->priv->idle_thread != NULL) in_idle = (is->priv->idle_state > IMAPX_IDLE_OFF); - g_mutex_unlock (&is->priv->idle_lock); + g_rec_mutex_unlock (&is->priv->idle_lock); return in_idle; } @@ -7809,7 +7818,7 @@ imapx_server_finalize (GObject *object) g_hash_table_destroy (is->priv->known_alerts); g_mutex_clear (&is->priv->known_alerts_lock); - g_mutex_clear (&is->priv->idle_lock); + g_rec_mutex_clear (&is->priv->idle_lock); g_main_loop_unref (is->priv->idle_main_loop); g_main_context_unref (is->priv->idle_main_context); @@ -7993,7 +8002,7 @@ camel_imapx_server_init (CamelIMAPXServe main_context = g_main_context_new (); - g_mutex_init (&is->priv->idle_lock); + g_rec_mutex_init (&is->priv->idle_lock); is->priv->idle_main_loop = g_main_loop_new (main_context, FALSE); is->priv->idle_main_context = g_main_context_ref (main_context);