From 65ce1c3fcd7f1151aeba0b43715564e30b7d471c Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 23 Oct 2019 11:25:48 +0100 Subject: [PATCH 1/2] glib: Ignore deprecations when declaring autocleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We may need to declare autocleanups for new types, which will be marked as ‘deprecated’ if the code which includes GLib doesn’t declare a high enough `GLIB_VERSION_MAX_ALLOWED`. Despite that, we still need to declare the autocleanups. Signed-off-by: Philip Withnall --- glib/glib-autocleanups.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/glib/glib-autocleanups.h b/glib/glib-autocleanups.h index efa4a99ab..91b4be566 100644 --- a/glib/glib-autocleanups.h +++ b/glib/glib-autocleanups.h @@ -35,6 +35,10 @@ g_autoptr_cleanup_gstring_free (GString *string) g_string_free (string, TRUE); } +/* Ignore deprecations in case we refer to a type which was added in a more + * recent GLib version than the user’s #GLIB_VERSION_MAX_ALLOWED definition. */ +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + /* If adding a cleanup here, please also add a test case to * glib/tests/autoptr.c */ @@ -91,3 +95,5 @@ G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantDict, g_variant_dict_clear) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantType, g_variant_type_free) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL) G_DEFINE_AUTOPTR_CLEANUP_FUNC (GRefString, g_ref_string_release) + +G_GNUC_END_IGNORE_DEPRECATIONS From 21f8f8982020dfd65d8d20a5fd0ace67a6dee856 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 23 Oct 2019 11:35:58 +0100 Subject: [PATCH 2/2] 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 --- 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 + +GMainContextPusher +g_main_context_pusher_new +g_main_context_pusher_free + 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);