mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-11 23:16:14 +01:00
GCancellable: add g_cancellable_create_source()
g_cancellable_create_source() returns a GSource that triggers when its corresponding GCancellable is cancelled. This can be used with g_source_add_child_source() to add cancellability to a source. Port gasynchelper's FDSource to use this rather than doing its own cancellable handling, and also fix up its callback argument order to be more normal. https://bugzilla.gnome.org/show_bug.cgi?id=634239
This commit is contained in:
parent
d15cdbefec
commit
6181c7de36
@ -1107,6 +1107,8 @@ g_cancellable_set_error_if_cancelled
|
||||
g_cancellable_get_fd
|
||||
g_cancellable_make_pollfd
|
||||
g_cancellable_release_fd
|
||||
g_cancellable_source_new
|
||||
GCancellableSourceFunc
|
||||
g_cancellable_get_current
|
||||
g_cancellable_pop_current
|
||||
g_cancellable_push_current
|
||||
|
@ -43,18 +43,14 @@ typedef struct
|
||||
{
|
||||
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
|
||||
@ -62,9 +58,7 @@ fd_source_check (GSource *source)
|
||||
{
|
||||
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
|
||||
@ -84,18 +78,6 @@ fd_source_dispatch (GSource *source,
|
||||
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
|
||||
@ -160,15 +142,6 @@ static GSourceFuncs fd_source_funcs = {
|
||||
(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,
|
||||
@ -180,18 +153,18 @@ _g_fd_source_new (int fd,
|
||||
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;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include "gcancellable.h"
|
||||
#include "gio-marshal.h"
|
||||
#include "glibintl.h"
|
||||
|
||||
|
||||
@ -770,3 +771,118 @@ g_cancellable_disconnect (GCancellable *cancellable,
|
||||
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;
|
||||
}
|
||||
|
@ -83,6 +83,8 @@ gboolean g_cancellable_make_pollfd (GCancellable *cancellable,
|
||||
GPollFD *pollfd);
|
||||
void g_cancellable_release_fd (GCancellable *cancellable);
|
||||
|
||||
GSource * g_cancellable_source_new (GCancellable *cancellable);
|
||||
|
||||
GCancellable *g_cancellable_get_current (void);
|
||||
void g_cancellable_push_current (GCancellable *cancellable);
|
||||
void g_cancellable_pop_current (GCancellable *cancellable);
|
||||
|
@ -193,6 +193,7 @@ g_cancellable_reset
|
||||
g_cancellable_cancel
|
||||
g_cancellable_connect
|
||||
g_cancellable_disconnect
|
||||
g_cancellable_source_new
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -376,6 +376,21 @@ typedef struct _GDBusPropertyInfo GDBusPropertyInfo;
|
||||
typedef struct _GDBusInterfaceInfo GDBusInterfaceInfo;
|
||||
typedef struct _GDBusNodeInfo GDBusNodeInfo;
|
||||
|
||||
/**
|
||||
* GCancellableSourceFunc:
|
||||
* @cancellable: the #GCancellable
|
||||
* @user_data: data passed in by the user.
|
||||
*
|
||||
* This is the function type of the callback used for the #GSource
|
||||
* returned by g_cancellable_source_new().
|
||||
*
|
||||
* Returns: it should return %FALSE if the source should be removed.
|
||||
*
|
||||
* Since: 2.28
|
||||
*/
|
||||
typedef gboolean (*GCancellableSourceFunc) (GCancellable *cancellable,
|
||||
gpointer user_data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GIO_TYPES_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user