[glib/glib-2-62: 4/5] GMainContext - Add tests for !1353 and related situations
- From: Sebastian Dröge <sdroege src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/glib-2-62: 4/5] GMainContext - Add tests for !1353 and related situations
- Date: Wed, 12 Feb 2020 17:00:34 +0000 (UTC)
commit 3c517fb0f741fe82fbcc570dd47d58f8350718d5
Author: Sebastian Dröge <sebastian centricular com>
Date: Mon Feb 3 18:00:12 2020 +0200
GMainContext - Add tests for !1353 and related situations
glib/tests/mainloop.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 174 insertions(+)
---
diff --git a/glib/tests/mainloop.c b/glib/tests/mainloop.c
index a7778153b..a1a37a09b 100644
--- a/glib/tests/mainloop.c
+++ b/glib/tests/mainloop.c
@@ -1746,13 +1746,187 @@ test_nfds (void)
g_main_context_unref (ctx);
}
+/* GSource implementation which optionally keeps a strong reference to another
+ * GSource until finalization, when it destroys and unrefs the other source.
+ */
+typedef struct {
+ GSource source;
+
+ GSource *other_source;
+} SourceWithSource;
+
+static void
+finalize_source_with_source (GSource *source)
+{
+ SourceWithSource *s = (SourceWithSource *) source;
+
+ if (s->other_source)
+ {
+ g_source_destroy (s->other_source);
+ g_source_unref (s->other_source);
+ s->other_source = NULL;
+ }
+}
+
+static GSourceFuncs source_with_source_funcs = {
+ NULL,
+ NULL,
+ NULL,
+ finalize_source_with_source
+};
+
+static void
+test_maincontext_source_finalization_from_source (gconstpointer user_data)
+{
+ GMainContext *c = g_main_context_new ();
+ GSource *s1, *s2;
+
+ g_test_summary ("Tests if freeing a GSource as part of another GSource "
+ "during main context destruction works.");
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/merge_requests/1353");
+
+ s1 = g_source_new (&source_with_source_funcs, sizeof (SourceWithSource));
+ s2 = g_source_new (&source_with_source_funcs, sizeof (SourceWithSource));
+ ((SourceWithSource *)s1)->other_source = g_source_ref (s2);
+
+ /* Attach sources in a different order so they end up being destroyed
+ * in a different order by the main context */
+ if (GPOINTER_TO_INT (user_data) < 5)
+ {
+ g_source_attach (s1, c);
+ g_source_attach (s2, c);
+ }
+ else
+ {
+ g_source_attach (s2, c);
+ g_source_attach (s1, c);
+ }
+
+ /* Test a few different permutations here */
+ if (GPOINTER_TO_INT (user_data) % 5 == 0)
+ {
+ /* Get rid of our references so that destroying the context
+ * will unref them immediately */
+ g_source_unref (s1);
+ g_source_unref (s2);
+ g_main_context_unref (c);
+ }
+ else if (GPOINTER_TO_INT (user_data) % 5 == 1)
+ {
+ /* Destroy and free the sources before the context */
+ g_source_destroy (s1);
+ g_source_unref (s1);
+ g_source_destroy (s2);
+ g_source_unref (s2);
+ g_main_context_unref (c);
+ }
+ else if (GPOINTER_TO_INT (user_data) % 5 == 2)
+ {
+ /* Destroy and free the sources before the context */
+ g_source_destroy (s2);
+ g_source_unref (s2);
+ g_source_destroy (s1);
+ g_source_unref (s1);
+ g_main_context_unref (c);
+ }
+ else if (GPOINTER_TO_INT (user_data) % 5 == 3)
+ {
+ /* Destroy and free the context before the sources */
+ g_main_context_unref (c);
+ g_source_unref (s2);
+ g_source_unref (s1);
+ }
+ else if (GPOINTER_TO_INT (user_data) % 5 == 4)
+ {
+ /* Destroy and free the context before the sources */
+ g_main_context_unref (c);
+ g_source_unref (s1);
+ g_source_unref (s2);
+ }
+}
+
+static gboolean
+dispatch_source_with_source (GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ return G_SOURCE_REMOVE;
+}
+
+static GSourceFuncs source_with_source_funcs_dispatch = {
+ NULL,
+ NULL,
+ dispatch_source_with_source,
+ finalize_source_with_source
+};
+
+static void
+test_maincontext_source_finalization_from_dispatch (gconstpointer user_data)
+{
+ GMainContext *c = g_main_context_new ();
+ GSource *s1, *s2;
+
+ g_test_summary ("Tests if freeing a GSource as part of another GSource "
+ "during main context iteration works.");
+
+ s1 = g_source_new (&source_with_source_funcs_dispatch, sizeof (SourceWithSource));
+ s2 = g_source_new (&source_with_source_funcs_dispatch, sizeof (SourceWithSource));
+ ((SourceWithSource *)s1)->other_source = g_source_ref (s2);
+
+ g_source_attach (s1, c);
+ g_source_attach (s2, c);
+
+ if (GPOINTER_TO_INT (user_data) == 0)
+ {
+ /* This finalizes s1 as part of the iteration, which then destroys and
+ * frees s2 too */
+ g_source_set_ready_time (s1, 0);
+ }
+ else if (GPOINTER_TO_INT (user_data) == 1)
+ {
+ /* This destroys s2 as part of the iteration but does not free it as
+ * it's still referenced by s1 */
+ g_source_set_ready_time (s2, 0);
+ }
+ else if (GPOINTER_TO_INT (user_data) == 2)
+ {
+ /* This destroys both s1 and s2 as part of the iteration */
+ g_source_set_ready_time (s1, 0);
+ g_source_set_ready_time (s2, 0);
+ }
+
+ /* Get rid of our references so only the main context has one now */
+ g_source_unref (s1);
+ g_source_unref (s2);
+
+ /* Iterate as long as there are sources to dispatch */
+ while (g_main_context_iteration (c, FALSE))
+ {
+ /* Do nothing here */
+ }
+
+ g_main_context_unref (c);
+}
+
int
main (int argc, char *argv[])
{
+ gint i;
+
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugzilla.gnome.org/");
g_test_add_func ("/maincontext/basic", test_maincontext_basic);
+ for (i = 0; i < 10; i++)
+ {
+ gchar *name = g_strdup_printf ("/maincontext/source_finalization_from_source/%d", i);
+ g_test_add_data_func (name, GINT_TO_POINTER (i), test_maincontext_source_finalization_from_source);
+ g_free (name);
+ }
+ for (i = 0; i < 3; i++)
+ {
+ gchar *name = g_strdup_printf ("/maincontext/source_finalization_from_dispatch/%d", i);
+ g_test_add_data_func (name, GINT_TO_POINTER (i), test_maincontext_source_finalization_from_dispatch);
+ g_free (name);
+ }
g_test_add_func ("/mainloop/basic", test_mainloop_basic);
g_test_add_func ("/mainloop/timeouts", test_timeouts);
g_test_add_func ("/mainloop/priorities", test_priorities);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]