From 92974b80fc10f494b33ed6760b5417bbbbb83473 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Sun, 3 Oct 2010 17:26:37 -0400 Subject: [PATCH] Bug 618737 - "dispatch to context" functionality Adds a new function g_main_context_invoke() (and _full() variant). This function takes a main context, a function and a user_data. If the main context is already acquired in the current thread, the function is invoked directly. If the main context is the default main context of the current thread and it can be acquired then the function is invoked directly while the context is owned. Otherwise, the function is scheduled as an idle on the context. --- glib/glib.symbols | 2 + glib/gmain.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ glib/gmain.h | 9 +++++ 3 files changed, 121 insertions(+) diff --git a/glib/glib.symbols b/glib/glib.symbols index 52d0519..226a9ff 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -708,6 +708,8 @@ g_main_context_set_poll_func g_main_context_unref g_main_context_wait g_main_context_wakeup +g_main_context_invoke +g_main_context_invoke_full g_main_depth g_main_current_source g_main_loop_get_context diff --git a/glib/gmain.c b/glib/gmain.c index 91e2a8e..da5bfea 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -4356,3 +4356,113 @@ g_idle_remove_by_data (gpointer data) { return g_source_remove_by_funcs_user_data (&g_idle_funcs, data); } + +/** + * g_main_context_invoke: + * @context: a #GMainContext, or %NULL + * @function: function to call + * @data: data to pass to @function + * + * Invokes a function in such a way that @context is owned during the + * invocation of @function. + * + * If @context is %NULL then the global default main context — as + * returned by g_main_context_default() — is used. + * + * If @context is owned by the current thread, @function is called + * directly. Otherwise, if @context is the thread-default main context + * of the current thread and g_main_context_acquire() succeeds, then + * @function is called and g_main_context_release() is called + * afterwards. + * + * In any other case, an idle source is created to call @function and + * that source is attached to @context (presumably to be run in another + * thread). The idle source is attached with #G_PRIORITY_DEFAULT + * priority. If you want a different priority, use + * g_main_context_invoke_full(). + * + * Note that, as with normal idle functions, @function should probably + * return %FALSE. If it returns %TRUE, it will be continuously run in a + * loop (and may prevent this call from returning). + * + * Since: 2.28 + **/ +void +g_main_context_invoke (GMainContext *context, + GSourceFunc function, + gpointer data) +{ + g_main_context_invoke_full (context, + G_PRIORITY_DEFAULT, + function, data, NULL); +} + +/** + * g_main_context_invoke_full: + * @context: a #GMainContext, or %NULL + * @priority: the priority at which to run @function + * @function: function to call + * @data: data to pass to @function + * @notify: a function to call when @data is no longer in use, or %NULL. + * + * Invokes a function in such a way that @context is owned during the + * invocation of @function. + * + * This function is the same as g_main_context_invoke() except that it + * lets you specify the priority incase @function ends up being + * scheduled as an idle and also lets you give a #GDestroyNotify for @data. + * + * @notify should not assume that it is called from any particular + * thread or with any particular context acquired. + * + * Since: 2.28 + **/ +void +g_main_context_invoke_full (GMainContext *context, + gint priority, + GSourceFunc function, + gpointer data, + GDestroyNotify notify) +{ + g_return_if_fail (function != NULL); + + if (!context) + context = g_main_context_default (); + + if (g_main_context_is_owner (context)) + { + while (function (data)); + if (notify != NULL) + notify (data); + } + + else + { + GMainContext *thread_default; + + thread_default = g_main_context_get_thread_default (); + + if (!thread_default) + thread_default = g_main_context_default (); + + if (thread_default == context && g_main_context_acquire (context)) + { + while (function (data)); + + g_main_context_release (context); + + if (notify != NULL) + notify (data); + } + else + { + GSource *source; + + source = g_idle_source_new (); + g_source_set_priority (source, priority); + g_source_set_callback (source, function, data, notify); + g_source_attach (source, context); + g_source_unref (source); + } + } +} diff --git a/glib/gmain.h b/glib/gmain.h index 24c6171..b221a63 100644 --- a/glib/gmain.h +++ b/glib/gmain.h @@ -521,6 +521,15 @@ guint g_idle_add_full (gint priority, GDestroyNotify notify); gboolean g_idle_remove_by_data (gpointer data); +void g_main_context_invoke_full (GMainContext *context, + gint priority, + GSourceFunc function, + gpointer data, + GDestroyNotify notify); +void g_main_context_invoke (GMainContext *context, + GSourceFunc function, + gpointer data); + /* Hook for GClosure / GSource integration. Don't touch */ GLIB_VAR GSourceFuncs g_timeout_funcs; GLIB_VAR GSourceFuncs g_child_watch_funcs; -- 2.7.4