mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-25 21:46: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_get_fd
|
||||||
g_cancellable_make_pollfd
|
g_cancellable_make_pollfd
|
||||||
g_cancellable_release_fd
|
g_cancellable_release_fd
|
||||||
|
g_cancellable_source_new
|
||||||
|
GCancellableSourceFunc
|
||||||
g_cancellable_get_current
|
g_cancellable_get_current
|
||||||
g_cancellable_pop_current
|
g_cancellable_pop_current
|
||||||
g_cancellable_push_current
|
g_cancellable_push_current
|
||||||
|
@ -43,18 +43,14 @@ typedef struct
|
|||||||
{
|
{
|
||||||
GSource source;
|
GSource source;
|
||||||
GPollFD pollfd;
|
GPollFD pollfd;
|
||||||
GCancellable *cancellable;
|
|
||||||
gulong cancelled_tag;
|
|
||||||
} FDSource;
|
} FDSource;
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fd_source_prepare (GSource *source,
|
fd_source_prepare (GSource *source,
|
||||||
gint *timeout)
|
gint *timeout)
|
||||||
{
|
{
|
||||||
FDSource *fd_source = (FDSource *)source;
|
|
||||||
*timeout = -1;
|
*timeout = -1;
|
||||||
|
return FALSE;
|
||||||
return g_cancellable_is_cancelled (fd_source->cancellable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -62,9 +58,7 @@ fd_source_check (GSource *source)
|
|||||||
{
|
{
|
||||||
FDSource *fd_source = (FDSource *)source;
|
FDSource *fd_source = (FDSource *)source;
|
||||||
|
|
||||||
return
|
return fd_source->pollfd.revents != 0;
|
||||||
g_cancellable_is_cancelled (fd_source->cancellable) ||
|
|
||||||
fd_source->pollfd.revents != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -84,18 +78,6 @@ fd_source_dispatch (GSource *source,
|
|||||||
static void
|
static void
|
||||||
fd_source_finalize (GSource *source)
|
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
|
static gboolean
|
||||||
@ -160,15 +142,6 @@ static GSourceFuncs fd_source_funcs = {
|
|||||||
(GSourceDummyMarshal)fd_source_closure_marshal,
|
(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 *
|
GSource *
|
||||||
_g_fd_source_new (int fd,
|
_g_fd_source_new (int fd,
|
||||||
gushort events,
|
gushort events,
|
||||||
@ -180,18 +153,18 @@ _g_fd_source_new (int fd,
|
|||||||
source = g_source_new (&fd_source_funcs, sizeof (FDSource));
|
source = g_source_new (&fd_source_funcs, sizeof (FDSource));
|
||||||
fd_source = (FDSource *)source;
|
fd_source = (FDSource *)source;
|
||||||
|
|
||||||
if (cancellable)
|
|
||||||
fd_source->cancellable = g_object_ref (cancellable);
|
|
||||||
|
|
||||||
fd_source->pollfd.fd = fd;
|
fd_source->pollfd.fd = fd;
|
||||||
fd_source->pollfd.events = events;
|
fd_source->pollfd.events = events;
|
||||||
g_source_add_poll (source, &fd_source->pollfd);
|
g_source_add_poll (source, &fd_source->pollfd);
|
||||||
|
|
||||||
if (cancellable)
|
if (cancellable)
|
||||||
fd_source->cancelled_tag =
|
{
|
||||||
g_cancellable_connect (cancellable,
|
GSource *cancellable_source = g_cancellable_source_new (cancellable);
|
||||||
(GCallback)fd_source_cancelled_cb,
|
|
||||||
NULL, NULL);
|
g_source_set_dummy_callback (cancellable_source);
|
||||||
|
g_source_add_child_source (source, cancellable_source);
|
||||||
|
g_source_unref (cancellable_source);
|
||||||
|
}
|
||||||
|
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <io.h>
|
#include <io.h>
|
||||||
#endif
|
#endif
|
||||||
#include "gcancellable.h"
|
#include "gcancellable.h"
|
||||||
|
#include "gio-marshal.h"
|
||||||
#include "glibintl.h"
|
#include "glibintl.h"
|
||||||
|
|
||||||
|
|
||||||
@ -770,3 +771,118 @@ g_cancellable_disconnect (GCancellable *cancellable,
|
|||||||
g_signal_handler_disconnect (cancellable, handler_id);
|
g_signal_handler_disconnect (cancellable, handler_id);
|
||||||
G_UNLOCK (cancellable);
|
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);
|
GPollFD *pollfd);
|
||||||
void g_cancellable_release_fd (GCancellable *cancellable);
|
void g_cancellable_release_fd (GCancellable *cancellable);
|
||||||
|
|
||||||
|
GSource * g_cancellable_source_new (GCancellable *cancellable);
|
||||||
|
|
||||||
GCancellable *g_cancellable_get_current (void);
|
GCancellable *g_cancellable_get_current (void);
|
||||||
void g_cancellable_push_current (GCancellable *cancellable);
|
void g_cancellable_push_current (GCancellable *cancellable);
|
||||||
void g_cancellable_pop_current (GCancellable *cancellable);
|
void g_cancellable_pop_current (GCancellable *cancellable);
|
||||||
|
@ -193,6 +193,7 @@ g_cancellable_reset
|
|||||||
g_cancellable_cancel
|
g_cancellable_cancel
|
||||||
g_cancellable_connect
|
g_cancellable_connect
|
||||||
g_cancellable_disconnect
|
g_cancellable_disconnect
|
||||||
|
g_cancellable_source_new
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -376,6 +376,21 @@ typedef struct _GDBusPropertyInfo GDBusPropertyInfo;
|
|||||||
typedef struct _GDBusInterfaceInfo GDBusInterfaceInfo;
|
typedef struct _GDBusInterfaceInfo GDBusInterfaceInfo;
|
||||||
typedef struct _GDBusNodeInfo GDBusNodeInfo;
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GIO_TYPES_H__ */
|
#endif /* __GIO_TYPES_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user