+ if (cancellable == NULL ||
+ cancellable->priv->cancelled)
+ return;
+
+ priv = cancellable->priv;
+
+ g_mutex_lock (&cancellable_mutex);
+
+ if (priv->cancelled)
+ {
+ g_mutex_unlock (&cancellable_mutex);
+ return;
+ }
+
+ priv->cancelled = TRUE;
+ priv->cancelled_running = TRUE;
+
+ if (priv->wakeup)
+ GLIB_PRIVATE_CALL (g_wakeup_signal) (priv->wakeup);
+
+ g_mutex_unlock (&cancellable_mutex);
+
+ g_object_ref (cancellable);
+ g_signal_emit (cancellable, signals[CANCELLED], 0);
+
+ g_mutex_lock (&cancellable_mutex);
+
+ priv->cancelled_running = FALSE;
+ if (priv->cancelled_running_waiting)
+ g_cond_broadcast (&cancellable_cond);
+ priv->cancelled_running_waiting = FALSE;
+
+ g_mutex_unlock (&cancellable_mutex);
+
+ g_object_unref (cancellable);
+}
+
+/**
+ * g_cancellable_connect:
+ * @cancellable: A #GCancellable.
+ * @callback: The #GCallback to connect.
+ * @data: Data to pass to @callback.
+ * @data_destroy_func: (allow-none): Free function for @data or %NULL.
+ *
+ * Convenience function to connect to the #GCancellable::cancelled
+ * signal. Also handles the race condition that may happen
+ * if the cancellable is cancelled right before connecting.
+ *
+ * @callback is called at most once, either directly at the
+ * time of the connect if @cancellable is already cancelled,
+ * or when @cancellable is cancelled in some thread.
+ *
+ * @data_destroy_func will be called when the handler is
+ * disconnected, or immediately if the cancellable is already
+ * cancelled.
+ *
+ * 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.
+ *
+ * Since: 2.22
+ */
+gulong
+g_cancellable_connect (GCancellable *cancellable,
+ GCallback callback,
+ gpointer data,
+ GDestroyNotify data_destroy_func)
+{
+ gulong id;
+
+ g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), 0);
+
+ g_mutex_lock (&cancellable_mutex);
+
+ if (cancellable->priv->cancelled)
+ {
+ void (*_callback) (GCancellable *cancellable,
+ gpointer user_data);
+
+ g_mutex_unlock (&cancellable_mutex);
+
+ _callback = (void *)callback;
+ id = 0;
+
+ _callback (cancellable, data);
+
+ if (data_destroy_func)
+ data_destroy_func (data);
+ }
+ else
+ {
+ id = g_signal_connect_data (cancellable, "cancelled",
+ callback, data,
+ (GClosureNotify) data_destroy_func,
+ 0);
+
+ g_mutex_unlock (&cancellable_mutex);
+ }
+
+
+ return id;
+}
+
+/**
+ * g_cancellable_disconnect:
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @handler_id: Handler id of the handler to be disconnected, or %0.
+ *
+ * Disconnects a handler from a cancellable instance similar to
+ * g_signal_handler_disconnect(). Additionally, in the event that a
+ * signal handler is currently running, this call will block until the
+ * handler has finished. Calling this function from a
+ * #GCancellable::cancelled signal handler will therefore result in a
+ * deadlock.
+ *
+ * This avoids a race condition where a thread cancels at the
+ * same time as the cancellable operation is finished and the
+ * signal handler is removed. See #GCancellable::cancelled for
+ * details on how to use this.
+ *
+ * If @cancellable is %NULL or @handler_id is %0 this function does
+ * nothing.
+ *
+ * Since: 2.22
+ */
+void
+g_cancellable_disconnect (GCancellable *cancellable,
+ gulong handler_id)
+{
+ GCancellablePrivate *priv;
+
+ if (handler_id == 0 || cancellable == NULL)
+ return;
+
+ g_mutex_lock (&cancellable_mutex);
+
+ priv = cancellable->priv;
+
+ while (priv->cancelled_running)