[evolution-data-server] Return a GError in camel_imapx_job_wait().



commit 3192936f5bc22c654cbb82db51a335e3cf1946b9
Author: Matthew Barnes <mbarnes redhat com>
Date:   Tue Aug 13 15:21:29 2013 -0400

    Return a GError in camel_imapx_job_wait().
    
    Despite the improvements in commit dacf161, there is still a disconnect
    in error propagation between CamelIMAPXCommand and CamelIMAPXJob in that
    completed jobs are still not aware of whether they failed.
    
    This commit lays the foundations for another attempt to bridge the gap,
    this time by adding a means of setting an error on a CamelIMAPXJob with
    camel_imapx_job_take_error().  We also break API in order to return the
    error through camel_imapx_job_wait().
    
    New functions:
    
      camel_imapx_job_take_error()

 camel/camel-imapx-job.c                 |   78 +++++++++++++++++++++++++++++--
 camel/camel-imapx-job.h                 |    5 ++-
 camel/camel-imapx-server.c              |    5 +-
 docs/reference/camel/camel-sections.txt |    1 +
 4 files changed, 82 insertions(+), 7 deletions(-)
---
diff --git a/camel/camel-imapx-job.c b/camel/camel-imapx-job.c
index a91e0ae..49c3988 100644
--- a/camel/camel-imapx-job.c
+++ b/camel/camel-imapx-job.c
@@ -30,6 +30,10 @@ struct _CamelIMAPXRealJob {
 
        GCancellable *cancellable;
 
+       /* This is set by camel_imapx_job_take_error(),
+        * and propagated through camel_imapx_job_wait(). */
+       GError *error;
+
        /* Used for running some jobs synchronously. */
        GCond done_cond;
        GMutex done_mutex;
@@ -111,6 +115,8 @@ camel_imapx_job_unref (CamelIMAPXJob *job)
                if (real_job->cancellable != NULL)
                        g_object_unref (real_job->cancellable);
 
+               g_clear_error (&real_job->error);
+
                g_cond_clear (&real_job->done_cond);
                g_mutex_clear (&real_job->done_mutex);
 
@@ -156,14 +162,32 @@ camel_imapx_job_cancel (CamelIMAPXJob *job)
        g_cancellable_cancel (real_job->cancellable);
 }
 
-void
-camel_imapx_job_wait (CamelIMAPXJob *job)
+/**
+ * camel_imapx_job_wait:
+ * @job: a #CamelIMAPXJob
+ * @error: return location for a #GError, or %NULL
+ *
+ * Blocks until @job completes by way of camel_imapx_job_done().  If @job
+ * completed successfully, the function returns %TRUE.  If @job was given
+ * a #GError by way of camel_imapx_job_take_error(), or its #GCancellable
+ * was cancelled, the function sets @error and returns %FALSE.
+ *
+ * Returns: whether @job completed successfully
+ *
+ * Since: 3.10
+ **/
+gboolean
+camel_imapx_job_wait (CamelIMAPXJob *job,
+                      GError **error)
 {
        CamelIMAPXRealJob *real_job;
+       GCancellable *cancellable;
+       gboolean success = TRUE;
 
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
 
        real_job = (CamelIMAPXRealJob *) job;
+       cancellable = camel_imapx_job_get_cancellable (job);
 
        g_mutex_lock (&real_job->done_mutex);
        while (!real_job->done_flag)
@@ -171,6 +195,21 @@ camel_imapx_job_wait (CamelIMAPXJob *job)
                        &real_job->done_cond,
                        &real_job->done_mutex);
        g_mutex_unlock (&real_job->done_mutex);
+
+       /* Cancellation takes priority over other errors. */
+       if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+               success = FALSE;
+       } else if (real_job->error != NULL) {
+               /* Copy the error, don't propagate it.
+                * We want our GError to remain intact. */
+               if (error != NULL) {
+                       g_warn_if_fail (*error == NULL);
+                       *error = g_error_copy (real_job->error);
+               }
+               success = FALSE;
+       }
+
+       return success;
 }
 
 void
@@ -216,7 +255,7 @@ camel_imapx_job_run (CamelIMAPXJob *job,
        success = job->start (job, is, cancellable, error);
 
        if (success && !job->noreply)
-               camel_imapx_job_wait (job);
+               success = camel_imapx_job_wait (job, error);
 
        if (cancel_id > 0)
                g_cancellable_disconnect (cancellable, cancel_id);
@@ -348,3 +387,34 @@ camel_imapx_job_get_cancellable (CamelIMAPXJob *job)
 
        return real_job->cancellable;
 }
+
+/**
+ * camel_imapx_job_take_error:
+ * @job: a #CamelIMAPXJob
+ * @error: a #GError
+ *
+ * Takes over the caller's ownership of @error, so the caller does not
+ * need to free it any more.  Call this when a #CamelIMAPXCommand fails
+ * and the @job is to be aborted.
+ *
+ * The @error will be returned to callers of camel_imapx_job_wait() or
+ * camel_imapx_job_run().
+ *
+ * Since: 3.10
+ **/
+void
+camel_imapx_job_take_error (CamelIMAPXJob *job,
+                            GError *error)
+{
+       CamelIMAPXRealJob *real_job;
+
+       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+       g_return_if_fail (error != NULL);
+
+       real_job = (CamelIMAPXRealJob *) job;
+
+       g_clear_error (&real_job->error);
+
+       real_job->error = error;  /* takes ownership */
+}
+
diff --git a/camel/camel-imapx-job.h b/camel/camel-imapx-job.h
index a6fbec8..4b57864 100644
--- a/camel/camel-imapx-job.h
+++ b/camel/camel-imapx-job.h
@@ -63,7 +63,8 @@ CamelIMAPXJob *       camel_imapx_job_ref             (CamelIMAPXJob *job);
 void           camel_imapx_job_unref           (CamelIMAPXJob *job);
 gboolean       camel_imapx_job_check           (CamelIMAPXJob *job);
 void           camel_imapx_job_cancel          (CamelIMAPXJob *job);
-void           camel_imapx_job_wait            (CamelIMAPXJob *job);
+gboolean       camel_imapx_job_wait            (CamelIMAPXJob *job,
+                                                GError **error);
 void           camel_imapx_job_done            (CamelIMAPXJob *job);
 gboolean       camel_imapx_job_run             (CamelIMAPXJob *job,
                                                 CamelIMAPXServer *is,
@@ -81,6 +82,8 @@ CamelFolder * camel_imapx_job_ref_folder      (CamelIMAPXJob *job);
 void           camel_imapx_job_set_folder      (CamelIMAPXJob *job,
                                                 CamelFolder *folder);
 GCancellable * camel_imapx_job_get_cancellable (CamelIMAPXJob *job);
+void           camel_imapx_job_take_error      (CamelIMAPXJob *job,
+                                                GError *error);
 
 G_END_DECLS
 
diff --git a/camel/camel-imapx-server.c b/camel/camel-imapx-server.c
index 39cba6b..b3cccf1 100644
--- a/camel/camel-imapx-server.c
+++ b/camel/camel-imapx-server.c
@@ -7318,7 +7318,8 @@ imapx_server_get_message (CamelIMAPXServer *is,
 
        QUEUE_LOCK (is);
 
-       if ((job = imapx_is_job_in_queue (is, folder, IMAPX_JOB_GET_MESSAGE, uid))) {
+       job = imapx_is_job_in_queue (is, folder, IMAPX_JOB_GET_MESSAGE, uid);
+       if (job != NULL) {
                /* Promote the existing GET_MESSAGE
                 * job's priority if ours is higher. */
                if (pri > job->pri)
@@ -7327,7 +7328,7 @@ imapx_server_get_message (CamelIMAPXServer *is,
                QUEUE_UNLOCK (is);
 
                /* Wait for the job to finish. */
-               camel_imapx_job_wait (job);
+               camel_imapx_job_wait (job, NULL);
 
                /* Disregard errors here.  If we failed to retreive the
                 * message from cache (implying the job we were waiting
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index 82881be..ae52d5a 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -814,6 +814,7 @@ camel_imapx_job_has_folder
 camel_imapx_job_ref_folder
 camel_imapx_job_set_folder
 camel_imapx_job_get_cancellable
+camel_imapx_job_take_error
 <SUBSECTION Private>
 uidset_state
 </SECTION>


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