gio: Fix regression encoding an array of doubles
[platform/upstream/glib.git] / gio / gcancellable.c
index 3186ea6..fcfca3f 100644 (file)
@@ -13,9 +13,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Alexander Larsson <alexl@redhat.com>
  */
@@ -92,16 +90,14 @@ g_cancellable_class_init (GCancellableClass *klass)
    *
    * Note that disconnecting from this signal (or any signal) in a
    * multi-threaded program is prone to race conditions. For instance
-   * it is possible that a signal handler may be invoked even
-   * <emphasis>after</emphasis> a call to
-   * g_signal_handler_disconnect() for that handler has already
-   * returned.
+   * it is possible that a signal handler may be invoked even after
+   * a call to g_signal_handler_disconnect() for that handler has
+   * already returned.
    * 
-   * There is also a problem when cancellation happen
-   * right before connecting to the signal. If this happens the
-   * signal will unexpectedly not be emitted, and checking before
-   * connecting to the signal leaves a race condition where this is
-   * still happening.
+   * There is also a problem when cancellation happens right before
+   * connecting to the signal. If this happens the signal will
+   * unexpectedly not be emitted, and checking before connecting to
+   * the signal leaves a race condition where this is still happening.
    *
    * In order to make it safe and easy to connect handlers there
    * are two helper functions: g_cancellable_connect() and
@@ -109,13 +105,13 @@ g_cancellable_class_init (GCancellableClass *klass)
    * like this.
    *
    * An example of how to us this:
-   * |[
-   *     /<!-- -->* Make sure we don't do any unnecessary work if already cancelled *<!-- -->/
-   *     if (g_cancellable_set_error_if_cancelled (cancellable))
+   * |[<!-- language="C" -->
+   *     // Make sure we don't do unnecessary work if already cancelled
+   *     if (g_cancellable_set_error_if_cancelled (cancellable, error))
    *       return;
    *
-   *     /<!-- -->* Set up all the data needed to be able to
-   *      * handle cancellation of the operation *<!-- -->/
+   *     // Set up all the data needed to be able to handle cancellation
+   *     // of the operation
    *     my_data = my_data_new (...);
    *
    *     id = 0;
@@ -124,12 +120,12 @@ g_cancellable_class_init (GCancellableClass *klass)
    *                                 G_CALLBACK (cancelled_handler)
    *                                 data, NULL);
    *
-   *     /<!-- -->* cancellable operation here... *<!-- -->/
+   *     // cancellable operation here...
    *
    *     g_cancellable_disconnect (cancellable, id);
    *
-   *     /<!-- -->* cancelled_handler is never called after this, it
-   *      * is now safe to free the data *<!-- -->/
+   *     // cancelled_handler is never called after this, it is now safe
+   *     // to free the data
    *     my_data_free (my_data);  
    * ]|
    *
@@ -225,8 +221,8 @@ g_cancellable_pop_current (GCancellable *cancellable)
  *
  * Gets the top cancellable from the stack.
  *
- * Returns: (transfer none): a #GCancellable from the top of the stack, or %NULL
- * if the stack is empty.
+ * Returns: (nullable) (transfer none): a #GCancellable from the top
+ * of the stack, or %NULL if the stack is empty.
  **/
 GCancellable *
 g_cancellable_get_current  (void)
@@ -535,6 +531,11 @@ g_cancellable_cancel (GCancellable *cancellable)
  *
  * See #GCancellable::cancelled for details on how to use this.
  *
+ * Since GLib 2.40, the lock protecting @cancellable is not held when
+ * @callback is invoked.  This lifts a restriction in place for
+ * earlier GLib versions which now makes it easier to write cleanup
+ * code that unconditionally invokes e.g. g_cancellable_cancel().
+ *
  * Returns: The id of the signal handler or 0 if @cancellable has already
  *          been cancelled.
  *
@@ -557,6 +558,8 @@ g_cancellable_connect (GCancellable   *cancellable,
       void (*_callback) (GCancellable *cancellable,
                          gpointer      user_data);
 
+      g_mutex_unlock (&cancellable_mutex);
+
       _callback = (void *)callback;
       id = 0;
 
@@ -571,9 +574,10 @@ g_cancellable_connect (GCancellable   *cancellable,
                                   callback, data,
                                   (GClosureNotify) data_destroy_func,
                                   0);
+
+      g_mutex_unlock (&cancellable_mutex);
     }
 
-  g_mutex_unlock (&cancellable_mutex);
 
   return id;
 }
@@ -628,6 +632,7 @@ typedef struct {
   GSource       source;
 
   GCancellable *cancellable;
+  guint         cancelled_handler;
 } GCancellableSource;
 
 static void
@@ -636,25 +641,8 @@ cancellable_source_cancelled (GCancellable *cancellable,
 {
   GSource *source = user_data;
 
-  g_main_context_wakeup (g_source_get_context (source));
-}
-
-static gboolean
-cancellable_source_prepare (GSource *source,
-                           gint    *timeout)
-{
-  GCancellableSource *cancellable_source = (GCancellableSource *)source;
-
-  *timeout = -1;
-  return g_cancellable_is_cancelled (cancellable_source->cancellable);
-}
-
-static gboolean
-cancellable_source_check (GSource *source)
-{
-  GCancellableSource *cancellable_source = (GCancellableSource *)source;
-
-  return g_cancellable_is_cancelled (cancellable_source->cancellable);
+  if (!g_source_is_destroyed (source))
+    g_source_set_ready_time (source, 0);
 }
 
 static gboolean
@@ -665,6 +653,7 @@ cancellable_source_dispatch (GSource     *source,
   GCancellableSourceFunc func = (GCancellableSourceFunc)callback;
   GCancellableSource *cancellable_source = (GCancellableSource *)source;
 
+  g_source_set_ready_time (source, -1);
   return (*func) (cancellable_source->cancellable, user_data);
 }
 
@@ -675,9 +664,8 @@ cancellable_source_finalize (GSource *source)
 
   if (cancellable_source->cancellable)
     {
-      g_signal_handlers_disconnect_by_func (cancellable_source->cancellable,
-                                           G_CALLBACK (cancellable_source_cancelled),
-                                           cancellable_source);
+      g_cancellable_disconnect (cancellable_source->cancellable,
+                                cancellable_source->cancelled_handler);
       g_object_unref (cancellable_source->cancellable);
     }
 }
@@ -708,8 +696,8 @@ cancellable_source_closure_callback (GCancellable *cancellable,
 
 static GSourceFuncs cancellable_source_funcs =
 {
-  cancellable_source_prepare,
-  cancellable_source_check,
+  NULL,
+  NULL,
   cancellable_source_dispatch,
   cancellable_source_finalize,
   (GSourceFunc)cancellable_source_closure_callback,
@@ -727,7 +715,7 @@ static GSourceFuncs cancellable_source_funcs =
  * For convenience, you can call this with a %NULL #GCancellable,
  * in which case the source will never trigger.
  *
- * Return value: (transfer full): the new #GSource.
+ * Returns: (transfer full): the new #GSource.
  *
  * Since: 2.28
  */
@@ -744,9 +732,16 @@ g_cancellable_source_new (GCancellable *cancellable)
   if (cancellable)
     {
       cancellable_source->cancellable = g_object_ref (cancellable);
-      g_signal_connect (cancellable, "cancelled",
-                       G_CALLBACK (cancellable_source_cancelled),
-                       source);
+
+      /* We intentionally don't use g_cancellable_connect() here,
+       * because we don't want the "at most once" behavior.
+       */
+      cancellable_source->cancelled_handler =
+        g_signal_connect (cancellable, "cancelled",
+                          G_CALLBACK (cancellable_source_cancelled),
+                          source);
+      if (g_cancellable_is_cancelled (cancellable))
+        g_source_set_ready_time (source, 0);
     }
 
   return source;