[evolution-data-server/gnome-3-16] Bug 750146 - [IMAPx] Deadlock when FETCH and STORE run at one time



commit f9739027db40256955b53d3dfe50663b8cfbede7
Author: Milan Crha <mcrha redhat com>
Date:   Mon Jun 1 20:58:03 2015 +0200

    Bug 750146 - [IMAPx] Deadlock when FETCH and STORE run at one time

 camel/providers/imapx/camel-imapx-job.c     |   46 +++++++++++++++++++++++++++
 camel/providers/imapx/camel-imapx-job.h     |    3 ++
 camel/providers/imapx/camel-imapx-mailbox.c |   30 ++++++++++++++---
 camel/providers/imapx/camel-imapx-server.c  |   10 +-----
 4 files changed, 76 insertions(+), 13 deletions(-)
---
diff --git a/camel/providers/imapx/camel-imapx-job.c b/camel/providers/imapx/camel-imapx-job.c
index 7c79496..c470754 100644
--- a/camel/providers/imapx/camel-imapx-job.c
+++ b/camel/providers/imapx/camel-imapx-job.c
@@ -46,6 +46,8 @@ struct _CamelIMAPXRealJob {
 
        CamelIMAPXMailbox *mailbox;
        GMutex mailbox_lock;
+
+       CamelIMAPXMailbox *guard_mailbox_update; /* uses the mailbox_lock */
 };
 
 static void
@@ -124,6 +126,13 @@ camel_imapx_job_unref (CamelIMAPXJob *job)
                if (real_job->destroy_data != NULL)
                        real_job->destroy_data (real_job->data);
 
+               g_mutex_lock (&real_job->mailbox_lock);
+               if (real_job->guard_mailbox_update) {
+                       camel_imapx_mailbox_unlock_update (real_job->guard_mailbox_update);
+                       g_clear_object (&real_job->guard_mailbox_update);
+               }
+               g_mutex_unlock (&real_job->mailbox_lock);
+
                g_clear_object (&real_job->mailbox);
                g_mutex_clear (&real_job->mailbox_lock);
 
@@ -232,6 +241,13 @@ camel_imapx_job_done (CamelIMAPXJob *job)
 
        real_job = (CamelIMAPXRealJob *) job;
 
+       g_mutex_lock (&real_job->mailbox_lock);
+       if (real_job->guard_mailbox_update) {
+               camel_imapx_mailbox_unlock_update (real_job->guard_mailbox_update);
+               g_clear_object (&real_job->guard_mailbox_update);
+       }
+       g_mutex_unlock (&real_job->mailbox_lock);
+
        g_mutex_lock (&real_job->done_mutex);
        real_job->done_flag = TRUE;
        g_cond_broadcast (&real_job->done_cond);
@@ -263,6 +279,36 @@ camel_imapx_job_run (CamelIMAPXJob *job,
        return success;
 }
 
+void
+camel_imapx_job_guard_mailbox_update (CamelIMAPXJob *job,
+                                     CamelIMAPXMailbox *mailbox)
+{
+       CamelIMAPXRealJob *real_job;
+
+       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+
+       if (mailbox)
+               g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+
+       real_job = (CamelIMAPXRealJob *) job;
+
+       g_mutex_lock (&real_job->mailbox_lock);
+
+       if (mailbox != real_job->guard_mailbox_update) {
+               if (real_job->guard_mailbox_update) {
+                       camel_imapx_mailbox_unlock_update (real_job->guard_mailbox_update);
+                       g_clear_object (&real_job->guard_mailbox_update);
+               }
+
+               if (mailbox) {
+                       real_job->guard_mailbox_update = g_object_ref (mailbox);
+                       camel_imapx_mailbox_lock_update (real_job->guard_mailbox_update);
+               }
+       }
+
+       g_mutex_unlock (&real_job->mailbox_lock);
+}
+
 gboolean
 camel_imapx_job_matches (CamelIMAPXJob *job,
                          CamelIMAPXMailbox *mailbox,
diff --git a/camel/providers/imapx/camel-imapx-job.h b/camel/providers/imapx/camel-imapx-job.h
index b234880..cf09fc3 100644
--- a/camel/providers/imapx/camel-imapx-job.h
+++ b/camel/providers/imapx/camel-imapx-job.h
@@ -64,6 +64,9 @@ void          camel_imapx_job_done            (CamelIMAPXJob *job);
 gboolean       camel_imapx_job_run             (CamelIMAPXJob *job,
                                                 CamelIMAPXServer *is,
                                                 GError **error);
+void           camel_imapx_job_guard_mailbox_update
+                                               (CamelIMAPXJob *job,
+                                                CamelIMAPXMailbox *mailbox);
 gboolean       camel_imapx_job_matches         (CamelIMAPXJob *job,
                                                 CamelIMAPXMailbox *mailbox,
                                                 const gchar *uid);
diff --git a/camel/providers/imapx/camel-imapx-mailbox.c b/camel/providers/imapx/camel-imapx-mailbox.c
index 62c0b51..5e576e4 100644
--- a/camel/providers/imapx/camel-imapx-mailbox.c
+++ b/camel/providers/imapx/camel-imapx-mailbox.c
@@ -51,7 +51,9 @@ struct _CamelIMAPXMailboxPrivate {
        CamelIMAPXMailboxState state;
 
        GMutex property_lock;
-       GRecMutex update_lock;
+       GMutex update_lock;
+       GCond update_cond;
+       gboolean update_is_locked;
 
        /* Protected by the "property_lock". */
        GHashTable *attributes;
@@ -98,7 +100,8 @@ imapx_mailbox_finalize (GObject *object)
        g_free (priv->name);
 
        g_mutex_clear (&priv->property_lock);
-       g_rec_mutex_clear (&priv->update_lock);
+       g_mutex_clear (&priv->update_lock);
+       g_cond_clear (&priv->update_cond);
        g_hash_table_destroy (priv->attributes);
        g_sequence_free (priv->message_map);
        g_strfreev (priv->quota_roots);
@@ -125,7 +128,9 @@ camel_imapx_mailbox_init (CamelIMAPXMailbox *mailbox)
        mailbox->priv = CAMEL_IMAPX_MAILBOX_GET_PRIVATE (mailbox);
 
        g_mutex_init (&mailbox->priv->property_lock);
-       g_rec_mutex_init (&mailbox->priv->update_lock);
+       g_mutex_init (&mailbox->priv->update_lock);
+       g_cond_init (&mailbox->priv->update_cond);
+       mailbox->priv->update_is_locked = FALSE;
        mailbox->priv->message_map = g_sequence_new (NULL);
        mailbox->priv->permanentflags = ~0;
        mailbox->priv->state = CAMEL_IMAPX_MAILBOX_STATE_CREATED;
@@ -1198,7 +1203,15 @@ camel_imapx_mailbox_lock_update (CamelIMAPXMailbox *mailbox)
 {
        g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
 
-       g_rec_mutex_lock (&mailbox->priv->update_lock);
+       g_mutex_lock (&mailbox->priv->update_lock);
+
+       while (mailbox->priv->update_is_locked) {
+               g_cond_wait (&mailbox->priv->update_cond, &mailbox->priv->update_lock);
+       }
+
+       mailbox->priv->update_is_locked = TRUE;
+
+       g_mutex_unlock (&mailbox->priv->update_lock);
 }
 
 /* Prevents running FETCH and STORE at the same time for the given mailbox */
@@ -1207,5 +1220,12 @@ camel_imapx_mailbox_unlock_update (CamelIMAPXMailbox *mailbox)
 {
        g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
 
-       g_rec_mutex_unlock (&mailbox->priv->update_lock);
+       g_mutex_lock (&mailbox->priv->update_lock);
+
+       if (mailbox->priv->update_is_locked) {
+               mailbox->priv->update_is_locked = FALSE;
+               g_cond_signal (&mailbox->priv->update_cond);
+       }
+
+       g_mutex_unlock (&mailbox->priv->update_lock);
 }
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 565a642..6a1e4f7 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -8930,7 +8930,7 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
        QUEUE_UNLOCK (is);
 
        if (registered)
-               camel_imapx_mailbox_lock_update (mailbox);
+               camel_imapx_job_guard_mailbox_update (job, mailbox);
 
        if (registered && camel_imapx_job_run (job, is, error)) {
                changes = data->changes;
@@ -8939,9 +8939,6 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
                imapx_unregister_job (is, job);
        }
 
-       if (registered)
-               camel_imapx_mailbox_unlock_update (mailbox);
-
        camel_imapx_job_unref (job);
 
        return changes;
@@ -9270,16 +9267,13 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
        QUEUE_UNLOCK (is);
 
        if (job_type == IMAPX_JOB_SYNC_CHANGES && registered)
-               camel_imapx_mailbox_lock_update (mailbox);
+               camel_imapx_job_guard_mailbox_update (job, mailbox);
 
        success = registered && camel_imapx_job_run (job, is, error);
 
        if (!success && registered)
                imapx_unregister_job (is, job);
 
-       if (job_type == IMAPX_JOB_SYNC_CHANGES && registered)
-               camel_imapx_mailbox_unlock_update (mailbox);
-
        camel_imapx_job_unref (job);
 
        g_object_unref (folder);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]