[glib: 2/3] gmain: Add GMainContextPusher convenience API
- From: Sebastian Dröge <sdroege src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 2/3] gmain: Add GMainContextPusher convenience API
- Date: Thu, 24 Oct 2019 11:59:08 +0000 (UTC)
commit 21f8f8982020dfd65d8d20a5fd0ace67a6dee856
Author: Philip Withnall <withnall endlessm com>
Date: Wed Oct 23 11:35:58 2019 +0100
gmain: Add GMainContextPusher convenience API
This is like `GMutexLocker`, in that if you are able to use
`g_autoptr()`, it makes popping a `GMainContext` off the thread-default
main context stack easier when exiting a function.
A few uses of `G_GNUC_{BEGIN,END}_IGNORE_DEPRECATIONS` are needed to
avoid warnings when building apps against GLib with
`GLIB_VERSION_MAX_ALLOWED < GLIB_VERSION_2_64`.
Signed-off-by: Philip Withnall <withnall endlessm com>
docs/reference/glib/glib-sections.txt | 5 +++
glib/glib-autocleanups.h | 1 +
glib/gmain.h | 83 +++++++++++++++++++++++++++++++++++
glib/tests/autoptr.c | 25 +++++++++++
4 files changed, 114 insertions(+)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index eea025c92..e9dfa73e9 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -781,6 +781,11 @@ g_main_set_poll_func
g_main_context_invoke
g_main_context_invoke_full
+<SUBSECTION>
+GMainContextPusher
+g_main_context_pusher_new
+g_main_context_pusher_free
+
<SUBSECTION>
g_main_context_get_thread_default
g_main_context_ref_thread_default
diff --git a/glib/glib-autocleanups.h b/glib/glib-autocleanups.h
index 91b4be566..b71101f2d 100644
--- a/glib/glib-autocleanups.h
+++ b/glib/glib-autocleanups.h
@@ -58,6 +58,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GArray, g_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPtrArray, g_ptr_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GByteArray, g_byte_array_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContext, g_main_context_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContextPusher, g_main_context_pusher_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainLoop, g_main_loop_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSource, g_source_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMappedFile, g_mapped_file_unref)
diff --git a/glib/gmain.h b/glib/gmain.h
index 6325ecbe3..ceb30cbd0 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -430,6 +430,89 @@ GMainContext *g_main_context_get_thread_default (void);
GLIB_AVAILABLE_IN_ALL
GMainContext *g_main_context_ref_thread_default (void);
+/**
+ * GMainContextPusher:
+ *
+ * Opaque type. See g_main_context_pusher_new() for details.
+ *
+ * Since: 2.64
+ */
+typedef void GMainContextPusher GLIB_AVAILABLE_TYPE_IN_2_64;
+
+/**
+ * g_main_context_pusher_new:
+ * @main_context: (transfer none): a main context to push
+ *
+ * Push @main_context as the new thread-default main context for the current
+ * thread, using g_main_context_push_thread_default(), and return a new
+ * #GMainContextPusher. Pop with g_main_context_pusher_free(). Using
+ * g_main_context_pop_thread_default() on @main_context while a
+ * #GMainContextPusher exists for it can lead to undefined behaviour.
+ *
+ * Using two #GMainContextPushers in the same scope is not allowed, as it leads
+ * to an undefined pop order.
+ *
+ * This is intended to be used with g_autoptr(). Note that g_autoptr()
+ * is only available when using GCC or clang, so the following example
+ * will only work with those compilers:
+ * |[
+ * typedef struct
+ * {
+ * ...
+ * GMainContext *context;
+ * ...
+ * } MyObject;
+ *
+ * static void
+ * my_object_do_stuff (MyObject *self)
+ * {
+ * g_autoptr(GMainContextPusher) pusher = g_main_context_pusher_new (self->context);
+ *
+ * // Code with main context as the thread default here
+ *
+ * if (cond)
+ * // No need to pop
+ * return;
+ *
+ * // Optionally early pop
+ * g_clear_pointer (&pusher, g_main_context_pusher_free);
+ *
+ * // Code with main context no longer the thread default here
+ * }
+ * ]|
+ *
+ * Returns: (transfer full): a #GMainContextPusher
+ * Since: 2.64
+ */
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+static inline GMainContextPusher *
+g_main_context_pusher_new (GMainContext *main_context)
+{
+ g_main_context_push_thread_default (main_context);
+ return (GMainContextPusher *) main_context;
+}
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+/**
+ * g_main_context_pusher_free:
+ * @pusher: (transfer full): a #GMainContextPusher
+ *
+ * Pop @pusher’s main context as the thread default main context.
+ * See g_main_context_pusher_new() for details.
+ *
+ * This will pop the #GMainContext as the current thread-default main context,
+ * but will not call g_main_context_unref() on it.
+ *
+ * Since: 2.64
+ */
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+static inline void
+g_main_context_pusher_free (GMainContextPusher *pusher)
+{
+ g_main_context_pop_thread_default ((GMainContext *) pusher);
+}
+G_GNUC_END_IGNORE_DEPRECATIONS
+
/* GMainLoop: */
GLIB_AVAILABLE_IN_ALL
diff --git a/glib/tests/autoptr.c b/glib/tests/autoptr.c
index 4eed862af..14b95a9cc 100644
--- a/glib/tests/autoptr.c
+++ b/glib/tests/autoptr.c
@@ -161,6 +161,30 @@ test_g_main_context (void)
g_assert_nonnull (val);
}
+static void
+test_g_main_context_pusher (void)
+{
+ GMainContext *context, *old_thread_default;
+
+ context = g_main_context_new ();
+ old_thread_default = g_main_context_get_thread_default ();
+ g_assert_false (old_thread_default == context);
+
+ if (TRUE)
+ {
+ g_autoptr(GMainContextPusher) val = g_main_context_pusher_new (context);
+
+ /* Check it’s now the thread-default main context */
+ g_assert_true (g_main_context_get_thread_default () == context);
+ }
+
+ /* Check it’s now the old thread-default main context */
+ g_assert_false (g_main_context_get_thread_default () == context);
+ g_assert_true (g_main_context_get_thread_default () == old_thread_default);
+
+ g_main_context_unref (context);
+}
+
static void
test_g_main_loop (void)
{
@@ -692,6 +716,7 @@ main (int argc, gchar *argv[])
g_test_add_func ("/autoptr/g_ptr_array", test_g_ptr_array);
g_test_add_func ("/autoptr/g_byte_array", test_g_byte_array);
g_test_add_func ("/autoptr/g_main_context", test_g_main_context);
+ g_test_add_func ("/autoptr/g_main_context_pusher", test_g_main_context_pusher);
g_test_add_func ("/autoptr/g_main_loop", test_g_main_loop);
g_test_add_func ("/autoptr/g_source", test_g_source);
g_test_add_func ("/autoptr/g_mapped_file", test_g_mapped_file);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]