mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-05 08:56:16 +01:00
gmain: allow g_source_get_context() on destroyed sources
g_source_get_context() was checking that the source wasn't destroyed (since a source doesn't hold a ref on its context, and so source->context might point to garbage in that case). However, it's useful to be allowed to call g_source_get_context() on a source that is destroyed-but-currently-running. So instead, let g_source_get_context() return the context whenever it's non-NULL, and clear the source->context of any sources that are still in a context's sources list when the context is freed. Since sources are only removed from the list when the source is freed (not when it is destroyed), this means that now whenever a source has a non-NULL context pointer, then that pointer is valid. This also means that g_source_get_time() will now return-if-fail rather than crashing if it is called on a source whose context has been destroyed. Add tests to glib/tests/mainloop to verify that g_source_get_context() and g_source_get_time() work on destroyed sources. https://bugzilla.gnome.org/show_bug.cgi?id=661767
This commit is contained in:
parent
6881e743ee
commit
26056558be
15
glib/gmain.c
15
glib/gmain.c
@ -512,7 +512,10 @@ g_main_context_unref (GMainContext *context)
|
|||||||
|
|
||||||
g_source_iter_init (&iter, context, TRUE);
|
g_source_iter_init (&iter, context, TRUE);
|
||||||
while (g_source_iter_next (&iter, &source))
|
while (g_source_iter_next (&iter, &source))
|
||||||
g_source_destroy_internal (source, context, FALSE);
|
{
|
||||||
|
source->context = NULL;
|
||||||
|
g_source_destroy_internal (source, context, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
g_mutex_clear (&context->mutex);
|
g_mutex_clear (&context->mutex);
|
||||||
|
|
||||||
@ -1203,7 +1206,13 @@ g_source_get_id (GSource *source)
|
|||||||
* @source: a #GSource
|
* @source: a #GSource
|
||||||
*
|
*
|
||||||
* Gets the #GMainContext with which the source is associated.
|
* Gets the #GMainContext with which the source is associated.
|
||||||
* Calling this function on a destroyed source is an error.
|
*
|
||||||
|
* You can call this on a source that has been destroyed, provided
|
||||||
|
* that the #GMainContext it was attached to still exists (in which
|
||||||
|
* case it will return that #GMainContext). In particular, you can
|
||||||
|
* always call this function on the source returned from
|
||||||
|
* g_main_current_source(). But calling this function on a source
|
||||||
|
* whose #GMainContext has been destroyed is an error.
|
||||||
*
|
*
|
||||||
* Return value: (transfer none) (allow-none): the #GMainContext with which the
|
* Return value: (transfer none) (allow-none): the #GMainContext with which the
|
||||||
* source is associated, or %NULL if the context has not
|
* source is associated, or %NULL if the context has not
|
||||||
@ -1212,7 +1221,7 @@ g_source_get_id (GSource *source)
|
|||||||
GMainContext *
|
GMainContext *
|
||||||
g_source_get_context (GSource *source)
|
g_source_get_context (GSource *source)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (!SOURCE_DESTROYED (source), NULL);
|
g_return_val_if_fail (source->context != NULL || !SOURCE_DESTROYED (source), NULL);
|
||||||
|
|
||||||
return source->context;
|
return source->context;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,6 @@ test_maincontext_basic (void)
|
|||||||
g_assert (g_main_context_find_source_by_funcs_user_data (ctx, &funcs, NULL) == NULL);
|
g_assert (g_main_context_find_source_by_funcs_user_data (ctx, &funcs, NULL) == NULL);
|
||||||
|
|
||||||
id = g_source_attach (source, ctx);
|
id = g_source_attach (source, ctx);
|
||||||
g_source_unref (source);
|
|
||||||
g_assert_cmpint (g_source_get_id (source), ==, id);
|
g_assert_cmpint (g_source_get_id (source), ==, id);
|
||||||
g_assert (g_main_context_find_source_by_id (ctx, id) == source);
|
g_assert (g_main_context_find_source_by_id (ctx, id) == source);
|
||||||
|
|
||||||
@ -85,6 +84,10 @@ test_maincontext_basic (void)
|
|||||||
g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
|
g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
|
||||||
|
|
||||||
g_source_destroy (source);
|
g_source_destroy (source);
|
||||||
|
g_assert (g_source_get_context (source) == ctx);
|
||||||
|
g_assert (g_main_context_find_source_by_id (ctx, id) == NULL);
|
||||||
|
|
||||||
|
g_source_unref (source);
|
||||||
g_main_context_unref (ctx);
|
g_main_context_unref (ctx);
|
||||||
|
|
||||||
ctx = g_main_context_default ();
|
ctx = g_main_context_default ();
|
||||||
@ -602,7 +605,7 @@ timeout2_callback (gpointer user_data)
|
|||||||
{
|
{
|
||||||
TimeTestData *data = user_data;
|
TimeTestData *data = user_data;
|
||||||
GSource *source;
|
GSource *source;
|
||||||
gint64 time2;
|
gint64 time2, time3;
|
||||||
|
|
||||||
source = g_main_current_source ();
|
source = g_main_current_source ();
|
||||||
g_assert (source == data->timeout2);
|
g_assert (source == data->timeout2);
|
||||||
@ -615,6 +618,13 @@ timeout2_callback (gpointer user_data)
|
|||||||
time2 = g_source_get_time (source);
|
time2 = g_source_get_time (source);
|
||||||
g_assert_cmpint (data->time1, ==, time2);
|
g_assert_cmpint (data->time1, ==, time2);
|
||||||
|
|
||||||
|
/* The source should still have a valid time even after being
|
||||||
|
* destroyed, since it's currently running.
|
||||||
|
*/
|
||||||
|
g_source_destroy (source);
|
||||||
|
time3 = g_source_get_time (source);
|
||||||
|
g_assert_cmpint (time2, ==, time3);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user