[glib/wip/ghandle: 10/16] magic gcan functions



commit b35633ff2cfc33c2704a6d20f97ee6544c1619b9
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Dec 18 20:14:26 2014 -0500

    magic gcan functions

 gio/gcancellable.c |   87 ++++++++++++++++++++++++++++++----------------------
 1 files changed, 50 insertions(+), 37 deletions(-)
---
diff --git a/gio/gcancellable.c b/gio/gcancellable.c
index 9fa887b..1665e94 100644
--- a/gio/gcancellable.c
+++ b/gio/gcancellable.c
@@ -1123,12 +1123,22 @@ g_cancellable_remove_critical_thread (GCancellable *cancellable,
  * g_thread_enter_critical_section_using_handle() is called and the
  * result is returned.
  *
- * The result is that the returned handle will poll as ready if
+ * You cannot call g_thread_wakeup() on @thread for yourself because you
+ * cannot acquire the lock that this function will use the establish the
+ * critical section.
+ *
+ * The overall result is that the returned handle will poll as ready if
  * @cancellable is triggered.
  *
  * You must call g_cancellable_leave_critical_section() when you are
  * done.
  *
+ * If @cancellable is %NULL then this function will still enter the
+ * critical section and return a valid handle, but that handle will
+ * never become ready.  This is relatively low-overhead but you could
+ * save yourself the trouble of polling on an extra object by checking
+ * for @cancellable being %NULL before calling this function.
+ *
  * The example in the documentation for
  * g_thread_enter_critical_section_using_handle() could be written
  * using GCancellable as follows:
@@ -1137,7 +1147,6 @@ g_cancellable_remove_critical_thread (GCancellable *cancellable,
  * static gpointer worker (gpointer user_data) {
  *   GCancellable *cancellable = user_data;
  *   GThread *self = g_thread_self ();
- *   gboolean should_exit = FALSE;
  *
  *   while (TRUE)
  *     {
@@ -1156,7 +1165,6 @@ g_cancellable_remove_critical_thread (GCancellable *cancellable,
  * }
  *
  * void start_cancellable_worker (GCancellable *cancellable) {
- *   g_atomic_set (&continue_work, 1);
  *   g_thread_unref (g_thread_new ("worker", worker, cancellable));
  * }
  * ]|
@@ -1172,30 +1180,35 @@ g_cancellable_enter_critical_section_using_handle (GCancellable  *cancellable,
                                                    GThread       *thread,
                                                    GError       **error)
 {
-  if (cancellable)
-    {
-      gboolean cancelled = FALSE;
+  ghandle result = G_HANDLE_NULL;
 
-      g_mutex_lock (&cancellable_mutex);
+  /* We're about to call a function that is documented as requiring a
+   * lock to be held... without holding a lock.
+   *
+   * That's actually OK because we're operating on thread-local data and
+   * there is no chance that g_thread_wakeup() can be called if the
+   * cancellable is %NULL.
+   */
+  if (!cancellable)
+    return g_thread_enter_critical_section_using_handle (thread);
 
-      cancelled = cancellable->priv->cancelled;
+  g_mutex_lock (&cancellable_mutex);
 
-      if (!cancelled)
-        g_cancellable_add_critical_thread (cancellable, thread);
+  if (!cancellable->priv->cancelled)
+    {
+      result = g_thread_enter_critical_section_using_handle (thread);
+      g_cancellable_add_critical_thread (cancellable, thread);
+    }
 
-      g_mutex_unlock (&cancellable_mutex);
+  g_mutex_unlock (&cancellable_mutex);
 
-      if (cancelled)
-        {
-          g_set_error_literal (error,
-                               G_IO_ERROR,
-                               G_IO_ERROR_CANCELLED,
-                               _("Operation was cancelled"));
-          return G_HANDLE_NULL;
-        }
-    }
+  if (!g_handle_is_valid (result))
+    g_set_error_literal (error,
+                         G_IO_ERROR,
+                         G_IO_ERROR_CANCELLED,
+                         _("Operation was cancelled"));
 
-  return g_thread_enter_critical_section_using_handle (thread);
+  return result;
 }
 
 /**
@@ -1223,28 +1236,28 @@ g_cancellable_leave_critical_section (GCancellable  *cancellable,
                                       GThread       *thread,
                                       GError       **error)
 {
-  g_thread_leave_critical_section (thread);
+  gboolean success = TRUE;
 
-  if (cancellable)
+  /* See comment above */
+  if (!cancellable)
     {
-      gboolean cancelled = FALSE;
+      g_thread_leave_critical_section (thread);
+      return TRUE;
+    }
 
-      g_mutex_lock (&cancellable_mutex);
+  g_mutex_lock (&cancellable_mutex);
 
-      g_cancellable_remove_critical_thread (cancellable, thread);
-      cancelled = cancellable->priv->cancelled;
+  g_cancellable_remove_critical_thread (cancellable, thread);
+  g_thread_leave_critical_section (thread);
+  success = !cancellable->priv->cancelled;
 
-      g_mutex_unlock (&cancellable_mutex);
+  g_mutex_unlock (&cancellable_mutex);
 
-      if (cancelled)
-        {
-          g_set_error_literal (error,
-                               G_IO_ERROR,
-                               G_IO_ERROR_CANCELLED,
-                               _("Operation was cancelled"));
-          return FALSE;
-        }
-    }
+  if (!success)
+    g_set_error_literal (error,
+                         G_IO_ERROR,
+                         G_IO_ERROR_CANCELLED,
+                         _("Operation was cancelled"));
 
   return TRUE;
 }


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