[glib] GSimpleAsyncResult: support reliable cancellation



commit 4804094472e90a537b534c32e3c225b624c4500e
Author: Ryan Lortie <desrt desrt ca>
Date:   Tue Mar 13 16:09:01 2012 -0400

    GSimpleAsyncResult: support reliable cancellation
    
    Add a function g_simple_async_result_set_check_cancellable() to provide
    a GCancellable that is checked for being cancelled during the call to
    g_simple_async_result_propagate_error().
    
    This gives asynchronous operation implementations an easy way to
    provide reliable cancellation of those operations -- even in the case
    that a positive result has occured and is pending dispatch at the time
    the operation is cancelled.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=672013

 docs/reference/gio/gio-sections.txt |    1 +
 gio/gio.symbols                     |    1 +
 gio/gsimpleasyncresult.c            |   58 +++++++++++++++++++++++++++++++++++
 gio/gsimpleasyncresult.h            |    2 +
 4 files changed, 62 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index fc4a48b..6212c5e 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1211,6 +1211,7 @@ g_simple_async_result_new
 g_simple_async_result_new_error
 g_simple_async_result_new_from_error
 g_simple_async_result_new_take_error
+g_simple_async_result_set_check_cancellable
 g_simple_async_result_set_op_res_gpointer
 g_simple_async_result_get_op_res_gpointer
 g_simple_async_result_set_op_res_gssize
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 23938fe..2489a0b 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -596,6 +596,7 @@ g_simple_async_result_new
 g_simple_async_result_new_error
 g_simple_async_result_new_from_error
 g_simple_async_result_new_take_error
+g_simple_async_result_set_check_cancellable
 g_simple_async_result_set_op_res_gpointer
 g_simple_async_result_get_op_res_gpointer
 g_simple_async_result_set_op_res_gssize
diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c
index 178721d..7ab2cd2 100644
--- a/gio/gsimpleasyncresult.c
+++ b/gio/gsimpleasyncresult.c
@@ -227,6 +227,7 @@ struct _GSimpleAsyncResult
   GError *error;
   gboolean failed;
   gboolean handle_cancellation;
+  GCancellable *check_cancellable;
 
   gpointer source_tag;
 
@@ -268,6 +269,9 @@ g_simple_async_result_finalize (GObject *object)
   if (simple->source_object)
     g_object_unref (simple->source_object);
 
+  if (simple->check_cancellable)
+    g_object_unref (simple->check_cancellable);
+
   g_main_context_unref (simple->context);
 
   clear_op_res (simple);
@@ -303,6 +307,15 @@ g_simple_async_result_init (GSimpleAsyncResult *simple)
  *
  * Creates a #GSimpleAsyncResult.
  *
+ * The common convention is to create the #GSimpleAsyncResult in the
+ * function that starts the asynchronous operation and use that same
+ * function as the @source_tag.
+ *
+ * If your operation supports cancellation with #GCancellable (which it
+ * probably should) then you should provide the user's cancellable to
+ * g_simple_async_result_set_check_cancellable() immediately after
+ * this function returns.
+ *
  * Returns: a #GSimpleAsyncResult.
  **/
 GSimpleAsyncResult *
@@ -458,6 +471,9 @@ g_simple_async_result_async_result_iface_init (GAsyncResultIface *iface)
  *
  * Sets whether to handle cancellation within the asynchronous operation.
  *
+ * This function has nothing to do with
+ * g_simple_async_result_set_check_cancellable().  It only refers to the
+ * #GCancellable passed to g_simple_async_result_run_in_thread().
  **/
 void
 g_simple_async_result_set_handle_cancellation (GSimpleAsyncResult *simple,
@@ -490,6 +506,10 @@ g_simple_async_result_get_source_tag (GSimpleAsyncResult *simple)
  * Propagates an error from within the simple asynchronous result to
  * a given destination.
  *
+ * If the #GCancellable given to a prior call to
+ * g_simple_async_result_set_check_cancellable() is cancelled then this
+ * function will return %TRUE with @dest set appropriately.
+ *
  * Returns: %TRUE if the error was propagated to @dest. %FALSE otherwise.
  **/
 gboolean
@@ -498,6 +518,9 @@ g_simple_async_result_propagate_error (GSimpleAsyncResult  *simple,
 {
   g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (simple), FALSE);
 
+  if (g_cancellable_set_error_if_cancelled (simple->check_cancellable, dest))
+    return TRUE;
+
   if (simple->failed)
     {
       g_propagate_error (dest, simple->error);
@@ -1034,3 +1057,38 @@ g_simple_async_report_take_gerror_in_idle (GObject *object,
   g_simple_async_result_complete_in_idle (simple);
   g_object_unref (simple);
 }
+
+/**
+ * g_simple_async_result_set_check_cancellable:
+ * @simple: a #GSimpleAsyncResult
+ * @check_cancellable: a #GCancellable to check, or %NULL to unset
+ *
+ * Sets a #GCancellable to check before dispatching results.
+ *
+ * This function has one very specific purpose: the provided cancellable
+ * is checked at the time of g_simple_async_result_propagate_error() If
+ * it is cancelled, these functions will return an "Operation was
+ * cancelled" error (%G_IO_ERROR_CANCELLED).
+ *
+ * Implementors of cancellable asynchronous functions should use this in
+ * order to provide a guarantee to their callers that cancelling an
+ * async operation will reliably result in an error being returned for
+ * that operation (even if a positive result for the operation has
+ * already been sent as an idle to the main context to be dispatched).
+ *
+ * The checking described above is done regardless of any call to the
+ * unrelated g_simple_async_result_set_handle_cancellation() function.
+ *
+ * Since: 2.32
+ **/
+void
+g_simple_async_result_set_check_cancellable (GSimpleAsyncResult *simple,
+                                             GCancellable *check_cancellable)
+{
+  g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (simple));
+  g_return_if_fail (check_cancellable == NULL || G_IS_CANCELLABLE (check_cancellable));
+
+  g_clear_object (&simple->check_cancellable);
+  if (check_cancellable)
+    simple->check_cancellable = g_object_ref (check_cancellable);
+}
diff --git a/gio/gsimpleasyncresult.h b/gio/gsimpleasyncresult.h
index 6d99c7a..7d786fc 100644
--- a/gio/gsimpleasyncresult.h
+++ b/gio/gsimpleasyncresult.h
@@ -83,6 +83,8 @@ gboolean            g_simple_async_result_get_op_res_gboolean (GSimpleAsyncResul
 
 
 
+void                g_simple_async_result_set_check_cancellable (GSimpleAsyncResult *simple,
+                                                                 GCancellable       *check_cancellable);
 gpointer            g_simple_async_result_get_source_tag   (GSimpleAsyncResult      *simple);
 void                g_simple_async_result_set_handle_cancellation (GSimpleAsyncResult      *simple,
 								   gboolean          handle_cancellation);



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