mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
Merge branch 'source-attach-trigger-wakeup' into 'main'
Add g_main_context_new_with_flags() and ownerless polling option See merge request GNOME/glib!1960
This commit is contained in:
commit
48af1cbddc
@ -841,7 +841,9 @@ G_SOURCE_REMOVE
|
||||
|
||||
<SUBSECTION>
|
||||
GMainContext
|
||||
GMainContextFlags
|
||||
g_main_context_new
|
||||
g_main_context_new_with_flags
|
||||
g_main_context_ref
|
||||
g_main_context_unref
|
||||
g_main_context_default
|
||||
|
34
glib/gmain.c
34
glib/gmain.c
@ -177,6 +177,15 @@
|
||||
* g_main_context_prepare(), g_main_context_query(),
|
||||
* g_main_context_check() and g_main_context_dispatch().
|
||||
*
|
||||
* If the event loop thread releases #GMainContext ownership until the results
|
||||
* required by g_main_context_check() are ready you must create a context with
|
||||
* the flag %G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING or else you'll lose
|
||||
* g_source_attach() notifications. This happens for instance when you integrate
|
||||
* the GLib event loop into implementations that follow the proactor pattern
|
||||
* (i.e. in these contexts the `poll()` implementation will reclaim the thread for
|
||||
* other tasks until the results are ready). One example of the proactor pattern
|
||||
* is the Boost.Asio library.
|
||||
*
|
||||
* ## State of a Main Context # {#mainloop-states}
|
||||
*
|
||||
* The operation of these functions can best be seen in terms
|
||||
@ -270,6 +279,7 @@ struct _GMainContext
|
||||
GCond cond;
|
||||
GThread *owner;
|
||||
guint owner_count;
|
||||
GMainContextFlags flags;
|
||||
GSList *waiters;
|
||||
|
||||
gint ref_count; /* (atomic) */
|
||||
@ -658,6 +668,23 @@ g_main_context_new_with_next_id (guint next_id)
|
||||
**/
|
||||
GMainContext *
|
||||
g_main_context_new (void)
|
||||
{
|
||||
return g_main_context_new_with_flags (G_MAIN_CONTEXT_FLAGS_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_main_context_new_with_flags:
|
||||
* @flags: a bitwise-OR combination of #GMainContextFlags flags that can only be
|
||||
* set at creation time.
|
||||
*
|
||||
* Creates a new #GMainContext structure.
|
||||
*
|
||||
* Returns: (transfer full): the new #GMainContext
|
||||
*
|
||||
* Since: 2.72
|
||||
*/
|
||||
GMainContext *
|
||||
g_main_context_new_with_flags (GMainContextFlags flags)
|
||||
{
|
||||
static gsize initialised;
|
||||
GMainContext *context;
|
||||
@ -681,6 +708,7 @@ g_main_context_new (void)
|
||||
|
||||
context->sources = g_hash_table_new (NULL, NULL);
|
||||
context->owner = NULL;
|
||||
context->flags = flags;
|
||||
context->waiters = NULL;
|
||||
|
||||
context->ref_count = 1;
|
||||
@ -1248,8 +1276,12 @@ g_source_attach_unlocked (GSource *source,
|
||||
/* If another thread has acquired the context, wake it up since it
|
||||
* might be in poll() right now.
|
||||
*/
|
||||
if (do_wakeup && context->owner && context->owner != G_THREAD_SELF)
|
||||
if (do_wakeup &&
|
||||
(context->flags & G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING ||
|
||||
(context->owner && context->owner != G_THREAD_SELF)))
|
||||
{
|
||||
g_wakeup_signal (context->wakeup);
|
||||
}
|
||||
|
||||
g_trace_mark (G_TRACE_CURRENT_TIME, 0,
|
||||
"GLib", "g_source_attach",
|
||||
|
24
glib/gmain.h
24
glib/gmain.h
@ -38,6 +38,26 @@ typedef enum /*< flags >*/
|
||||
G_IO_NVAL GLIB_SYSDEF_POLLNVAL
|
||||
} GIOCondition;
|
||||
|
||||
/**
|
||||
* GMainContextFlags:
|
||||
* @G_MAIN_CONTEXT_FLAGS_NONE: Default behaviour.
|
||||
* @G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING: Assume that polling for events will
|
||||
* free the thread to process other jobs. That's useful if you're using
|
||||
* `g_main_context_{prepare,query,check,dispatch}` to integrate GMainContext in
|
||||
* other event loops.
|
||||
*
|
||||
* Flags to pass to g_main_context_new_with_flags() which affect the behaviour
|
||||
* of a #GMainContext.
|
||||
*
|
||||
* Since: 2.72
|
||||
*/
|
||||
GLIB_AVAILABLE_TYPE_IN_2_72
|
||||
typedef enum /*< flags >*/
|
||||
{
|
||||
G_MAIN_CONTEXT_FLAGS_NONE = 0,
|
||||
G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING = 1
|
||||
} GMainContextFlags;
|
||||
|
||||
|
||||
/**
|
||||
* GMainContext:
|
||||
@ -358,6 +378,10 @@ struct _GSourceFuncs
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMainContext *g_main_context_new (void);
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
GLIB_AVAILABLE_IN_2_72
|
||||
GMainContext *g_main_context_new_with_flags (GMainContextFlags flags);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GMainContext *g_main_context_ref (GMainContext *context);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
|
@ -158,6 +158,56 @@ test_mainloop_basic (void)
|
||||
g_main_loop_unref (loop);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ownerless_polling (gconstpointer test_data)
|
||||
{
|
||||
gboolean attach_first = GPOINTER_TO_INT (test_data);
|
||||
GMainContext *ctx = g_main_context_new_with_flags (
|
||||
G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING);
|
||||
|
||||
GPollFD fds[20];
|
||||
gint fds_size;
|
||||
gint max_priority;
|
||||
GSource *source = NULL;
|
||||
|
||||
g_assert_true (ctx != g_main_context_default ());
|
||||
|
||||
g_main_context_push_thread_default (ctx);
|
||||
|
||||
/* Drain events */
|
||||
for (;;)
|
||||
{
|
||||
gboolean ready_to_dispatch = g_main_context_prepare (ctx, &max_priority);
|
||||
gint timeout, nready;
|
||||
fds_size = g_main_context_query (ctx, max_priority, &timeout, fds, G_N_ELEMENTS (fds));
|
||||
nready = g_poll (fds, fds_size, /*timeout=*/0);
|
||||
if (!ready_to_dispatch && nready == 0)
|
||||
{
|
||||
if (timeout == -1)
|
||||
break;
|
||||
else
|
||||
g_usleep (timeout * 1000);
|
||||
}
|
||||
ready_to_dispatch = g_main_context_check (ctx, max_priority, fds, fds_size);
|
||||
if (ready_to_dispatch)
|
||||
g_main_context_dispatch (ctx);
|
||||
}
|
||||
|
||||
if (!attach_first)
|
||||
g_main_context_pop_thread_default (ctx);
|
||||
|
||||
source = g_idle_source_new ();
|
||||
g_source_attach (source, ctx);
|
||||
g_source_unref (source);
|
||||
|
||||
if (attach_first)
|
||||
g_main_context_pop_thread_default (ctx);
|
||||
|
||||
g_assert_cmpint (g_poll (fds, fds_size, 0), >, 0);
|
||||
|
||||
g_main_context_unref (ctx);
|
||||
}
|
||||
|
||||
static gint a;
|
||||
static gint b;
|
||||
static gint c;
|
||||
@ -2145,6 +2195,8 @@ main (int argc, char *argv[])
|
||||
#endif
|
||||
g_test_add_func ("/mainloop/nfds", test_nfds);
|
||||
g_test_add_func ("/mainloop/steal-fd", test_steal_fd);
|
||||
g_test_add_data_func ("/mainloop/ownerless-polling/attach-first", GINT_TO_POINTER (TRUE), test_ownerless_polling);
|
||||
g_test_add_data_func ("/mainloop/ownerless-polling/pop-first", GINT_TO_POINTER (FALSE), test_ownerless_polling);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user