{
GSource source;
GPollFD pollfd;
- GCancellable *cancellable;
- gulong cancelled_tag;
} FDSource;
static gboolean
fd_source_prepare (GSource *source,
gint *timeout)
{
- FDSource *fd_source = (FDSource *)source;
*timeout = -1;
-
- return g_cancellable_is_cancelled (fd_source->cancellable);
+ return FALSE;
}
static gboolean
{
FDSource *fd_source = (FDSource *)source;
- return
- g_cancellable_is_cancelled (fd_source->cancellable) ||
- fd_source->pollfd.revents != 0;
+ return fd_source->pollfd.revents != 0;
}
static gboolean
static void
fd_source_finalize (GSource *source)
{
- FDSource *fd_source = (FDSource *)source;
-
- /* we don't use g_cancellable_disconnect() here, since we are holding
- * the main context lock here, and the ::disconnect signal handler
- * will try to grab that, and deadlock looms.
- */
- if (fd_source->cancelled_tag)
- g_signal_handler_disconnect (fd_source->cancellable,
- fd_source->cancelled_tag);
-
- if (fd_source->cancellable)
- g_object_unref (fd_source->cancellable);
}
static gboolean
(GSourceDummyMarshal)fd_source_closure_marshal,
};
-/* Might be called on another thread */
-static void
-fd_source_cancelled_cb (GCancellable *cancellable,
- gpointer data)
-{
- /* Wake up the mainloop in case we're waiting on async calls with FDSource */
- g_main_context_wakeup (NULL);
-}
-
GSource *
_g_fd_source_new (int fd,
gushort events,
source = g_source_new (&fd_source_funcs, sizeof (FDSource));
fd_source = (FDSource *)source;
- if (cancellable)
- fd_source->cancellable = g_object_ref (cancellable);
-
fd_source->pollfd.fd = fd;
fd_source->pollfd.events = events;
g_source_add_poll (source, &fd_source->pollfd);
if (cancellable)
- fd_source->cancelled_tag =
- g_cancellable_connect (cancellable,
- (GCallback)fd_source_cancelled_cb,
- NULL, NULL);
-
+ {
+ GSource *cancellable_source = g_cancellable_source_new (cancellable);
+
+ g_source_set_dummy_callback (cancellable_source);
+ g_source_add_child_source (source, cancellable_source);
+ g_source_unref (cancellable_source);
+ }
+
return source;
}
#include <io.h>
#endif
#include "gcancellable.h"
+#include "gio-marshal.h"
#include "glibintl.h"
g_signal_handler_disconnect (cancellable, handler_id);
G_UNLOCK (cancellable);
}
+
+typedef struct {
+ GSource source;
+
+ GCancellable *cancellable;
+ GPollFD pollfd;
+} GCancellableSource;
+
+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);
+}
+
+static gboolean
+cancellable_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ GCancellableSourceFunc func = (GCancellableSourceFunc)callback;
+ GCancellableSource *cancellable_source = (GCancellableSource *)source;
+
+ return (*func) (cancellable_source->cancellable, user_data);
+}
+
+static void
+cancellable_source_finalize (GSource *source)
+{
+ GCancellableSource *cancellable_source = (GCancellableSource *)source;
+
+ if (cancellable_source->cancellable)
+ g_object_unref (cancellable_source->cancellable);
+}
+
+static gboolean
+cancellable_source_closure_callback (GCancellable *cancellable,
+ gpointer data)
+{
+ GClosure *closure = data;
+
+ GValue params = { 0, };
+ GValue result_value = { 0, };
+ gboolean result;
+
+ g_value_init (&result_value, G_TYPE_BOOLEAN);
+
+ g_value_init (¶ms, G_TYPE_CANCELLABLE);
+ g_value_set_object (¶ms, cancellable);
+
+ g_closure_invoke (closure, &result_value, 1, ¶ms, NULL);
+
+ result = g_value_get_boolean (&result_value);
+ g_value_unset (&result_value);
+ g_value_unset (¶ms);
+
+ return result;
+}
+
+static GSourceFuncs cancellable_source_funcs =
+{
+ cancellable_source_prepare,
+ cancellable_source_check,
+ cancellable_source_dispatch,
+ cancellable_source_finalize,
+ (GSourceFunc)cancellable_source_closure_callback,
+ (GSourceDummyMarshal)_gio_marshal_BOOLEAN__VOID,
+};
+
+/**
+ * g_cancellable_source_new:
+ * @cancellable: a #GCancellable, or %NULL
+ *
+ * Creates a source that triggers if @cancellable is cancelled and
+ * calls its callback of type #GCancellableSourceFunc. This is
+ * primarily useful for attaching to another (non-cancellable) source
+ * with g_source_add_child_source() to add cancellability to it.
+ *
+ * For convenience, you can call this with a %NULL #GCancellable,
+ * in which case the source will never trigger.
+ *
+ * Return value: the new #GSource.
+ *
+ * Since: 2.28
+ */
+GSource *
+g_cancellable_source_new (GCancellable *cancellable)
+{
+ GSource *source;
+ GCancellableSource *cancellable_source;
+
+ source = g_source_new (&cancellable_source_funcs, sizeof (GCancellableSource));
+ g_source_set_name (source, "GCancellable");
+ cancellable_source = (GCancellableSource *)source;
+
+ if (g_cancellable_make_pollfd (cancellable,
+ &cancellable_source->pollfd))
+ {
+ cancellable_source->cancellable = g_object_ref (cancellable);
+ g_source_add_poll (source, &cancellable_source->pollfd);
+ }
+
+ return source;
+}