mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 23:46:15 +01:00
GMainContext - Add tests for !1353 and related situations
This commit is contained in:
parent
730a75fc8e
commit
aaa7640f7c
@ -1832,14 +1832,188 @@ test_maincontext_source_finalization (void)
|
|||||||
g_assert_true (source_finalize_called);
|
g_assert_true (source_finalize_called);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
gint i;
|
||||||
|
|
||||||
g_test_init (&argc, &argv, NULL);
|
g_test_init (&argc, &argv, NULL);
|
||||||
g_test_bug_base ("http://bugzilla.gnome.org/");
|
g_test_bug_base ("http://bugzilla.gnome.org/");
|
||||||
|
|
||||||
g_test_add_func ("/maincontext/basic", test_maincontext_basic);
|
g_test_add_func ("/maincontext/basic", test_maincontext_basic);
|
||||||
g_test_add_func ("/maincontext/source_finalization", test_maincontext_source_finalization);
|
g_test_add_func ("/maincontext/source_finalization", test_maincontext_source_finalization);
|
||||||
|
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/basic", test_mainloop_basic);
|
||||||
g_test_add_func ("/mainloop/timeouts", test_timeouts);
|
g_test_add_func ("/mainloop/timeouts", test_timeouts);
|
||||||
g_test_add_func ("/mainloop/priorities", test_priorities);
|
g_test_add_func ("/mainloop/priorities", test_priorities);
|
||||||
|
Loading…
Reference in New Issue
Block a user