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>
|
<SUBSECTION>
|
||||||
GMainContext
|
GMainContext
|
||||||
|
GMainContextFlags
|
||||||
g_main_context_new
|
g_main_context_new
|
||||||
|
g_main_context_new_with_flags
|
||||||
g_main_context_ref
|
g_main_context_ref
|
||||||
g_main_context_unref
|
g_main_context_unref
|
||||||
g_main_context_default
|
g_main_context_default
|
||||||
|
36
glib/gmain.c
36
glib/gmain.c
@ -177,6 +177,15 @@
|
|||||||
* g_main_context_prepare(), g_main_context_query(),
|
* g_main_context_prepare(), g_main_context_query(),
|
||||||
* g_main_context_check() and g_main_context_dispatch().
|
* 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}
|
* ## State of a Main Context # {#mainloop-states}
|
||||||
*
|
*
|
||||||
* The operation of these functions can best be seen in terms
|
* The operation of these functions can best be seen in terms
|
||||||
@ -270,6 +279,7 @@ struct _GMainContext
|
|||||||
GCond cond;
|
GCond cond;
|
||||||
GThread *owner;
|
GThread *owner;
|
||||||
guint owner_count;
|
guint owner_count;
|
||||||
|
GMainContextFlags flags;
|
||||||
GSList *waiters;
|
GSList *waiters;
|
||||||
|
|
||||||
gint ref_count; /* (atomic) */
|
gint ref_count; /* (atomic) */
|
||||||
@ -658,6 +668,23 @@ g_main_context_new_with_next_id (guint next_id)
|
|||||||
**/
|
**/
|
||||||
GMainContext *
|
GMainContext *
|
||||||
g_main_context_new (void)
|
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;
|
static gsize initialised;
|
||||||
GMainContext *context;
|
GMainContext *context;
|
||||||
@ -681,6 +708,7 @@ g_main_context_new (void)
|
|||||||
|
|
||||||
context->sources = g_hash_table_new (NULL, NULL);
|
context->sources = g_hash_table_new (NULL, NULL);
|
||||||
context->owner = NULL;
|
context->owner = NULL;
|
||||||
|
context->flags = flags;
|
||||||
context->waiters = NULL;
|
context->waiters = NULL;
|
||||||
|
|
||||||
context->ref_count = 1;
|
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
|
/* If another thread has acquired the context, wake it up since it
|
||||||
* might be in poll() right now.
|
* might be in poll() right now.
|
||||||
*/
|
*/
|
||||||
if (do_wakeup && context->owner && context->owner != G_THREAD_SELF)
|
if (do_wakeup &&
|
||||||
g_wakeup_signal (context->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,
|
g_trace_mark (G_TRACE_CURRENT_TIME, 0,
|
||||||
"GLib", "g_source_attach",
|
"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
|
G_IO_NVAL GLIB_SYSDEF_POLLNVAL
|
||||||
} GIOCondition;
|
} 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:
|
* GMainContext:
|
||||||
@ -358,6 +378,10 @@ struct _GSourceFuncs
|
|||||||
|
|
||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
GMainContext *g_main_context_new (void);
|
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
|
GLIB_AVAILABLE_IN_ALL
|
||||||
GMainContext *g_main_context_ref (GMainContext *context);
|
GMainContext *g_main_context_ref (GMainContext *context);
|
||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
|
@ -158,6 +158,56 @@ test_mainloop_basic (void)
|
|||||||
g_main_loop_unref (loop);
|
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 a;
|
||||||
static gint b;
|
static gint b;
|
||||||
static gint c;
|
static gint c;
|
||||||
@ -2145,6 +2195,8 @@ main (int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
g_test_add_func ("/mainloop/nfds", test_nfds);
|
g_test_add_func ("/mainloop/nfds", test_nfds);
|
||||||
g_test_add_func ("/mainloop/steal-fd", test_steal_fd);
|
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 ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user