Merge branch 'cancellable-test-fix' into 'master'

tests: Speed up the cancellable test

See merge request GNOME/glib!1506
This commit is contained in:
Sebastian Dröge 2020-05-22 10:36:11 +00:00
commit 743bbb90da

View File

@ -232,7 +232,8 @@ typedef struct
{ {
GCond cond; GCond cond;
GMutex mutex; GMutex mutex;
GSource *cancellable_source; /* (owned) */ gboolean thread_ready;
GAsyncQueue *cancellable_source_queue; /* (owned) (element-type GCancellableSource) */
} ThreadedDisposeData; } ThreadedDisposeData;
static gboolean static gboolean
@ -247,14 +248,18 @@ static gpointer
threaded_dispose_thread_cb (gpointer user_data) threaded_dispose_thread_cb (gpointer user_data)
{ {
ThreadedDisposeData *data = user_data; ThreadedDisposeData *data = user_data;
GSource *cancellable_source;
/* Synchronise with the main thread before trying to reproduce the race. */
g_mutex_lock (&data->mutex); g_mutex_lock (&data->mutex);
data->thread_ready = TRUE;
g_cond_broadcast (&data->cond); g_cond_broadcast (&data->cond);
g_mutex_unlock (&data->mutex); g_mutex_unlock (&data->mutex);
/* Race with cancellation of the cancellable. */ while ((cancellable_source = g_async_queue_pop (data->cancellable_source_queue)) != (gpointer) 1)
g_source_unref (data->cancellable_source); {
/* Race with cancellation of the cancellable. */
g_source_unref (cancellable_source);
}
return NULL; return NULL;
} }
@ -262,6 +267,8 @@ threaded_dispose_thread_cb (gpointer user_data)
static void static void
test_cancellable_source_threaded_dispose (void) test_cancellable_source_threaded_dispose (void)
{ {
ThreadedDisposeData data;
GThread *thread = NULL;
guint i; guint i;
g_test_summary ("Test a thread race between disposing of a GCancellableSource " g_test_summary ("Test a thread race between disposing of a GCancellableSource "
@ -269,12 +276,25 @@ test_cancellable_source_threaded_dispose (void)
"to (in another thread)"); "to (in another thread)");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1841"); g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1841");
/* Create a new thread and wait until its ready to execute. Each iteration of
* the test will pass it a new #GCancellableSource. */
g_cond_init (&data.cond);
g_mutex_init (&data.mutex);
data.cancellable_source_queue = g_async_queue_new_full ((GDestroyNotify) g_source_unref);
data.thread_ready = FALSE;
g_mutex_lock (&data.mutex);
thread = g_thread_new ("/cancellable-source/threaded-dispose",
threaded_dispose_thread_cb, &data);
while (!data.thread_ready)
g_cond_wait (&data.cond, &data.mutex);
g_mutex_unlock (&data.mutex);
for (i = 0; i < 100000; i++) for (i = 0; i < 100000; i++)
{ {
GCancellable *cancellable = NULL; GCancellable *cancellable = NULL;
GSource *cancellable_source = NULL; GSource *cancellable_source = NULL;
ThreadedDisposeData data;
GThread *thread = NULL;
/* Create a cancellable and a cancellable source for it. For this test, /* Create a cancellable and a cancellable source for it. For this test,
* theres no need to attach the source to a #GMainContext. */ * theres no need to attach the source to a #GMainContext. */
@ -282,26 +302,26 @@ test_cancellable_source_threaded_dispose (void)
cancellable_source = g_cancellable_source_new (cancellable); cancellable_source = g_cancellable_source_new (cancellable);
g_source_set_callback (cancellable_source, G_SOURCE_FUNC (cancelled_cb), NULL, NULL); g_source_set_callback (cancellable_source, G_SOURCE_FUNC (cancelled_cb), NULL, NULL);
/* Create a new thread and wait until its ready to execute before /* Send it to the thread and wait until its ready to execute before
* cancelling our cancellable. */ * cancelling our cancellable. */
g_cond_init (&data.cond); g_async_queue_push (data.cancellable_source_queue, g_steal_pointer (&cancellable_source));
g_mutex_init (&data.mutex);
data.cancellable_source = g_steal_pointer (&cancellable_source);
g_mutex_lock (&data.mutex);
thread = g_thread_new ("/cancellable-source/threaded-dispose",
threaded_dispose_thread_cb, &data);
g_cond_wait (&data.cond, &data.mutex);
g_mutex_unlock (&data.mutex);
/* Race with disposal of the cancellable source. */ /* Race with disposal of the cancellable source. */
g_cancellable_cancel (cancellable); g_cancellable_cancel (cancellable);
g_thread_join (g_steal_pointer (&thread));
g_mutex_clear (&data.mutex);
g_cond_clear (&data.cond);
g_object_unref (cancellable); g_object_unref (cancellable);
} }
/* Indicate that the test has finished. Cant use %NULL as #GAsyncQueue
* doesnt allow that.*/
g_async_queue_push (data.cancellable_source_queue, (gpointer) 1);
g_thread_join (g_steal_pointer (&thread));
g_assert (g_async_queue_length (data.cancellable_source_queue) == 0);
g_async_queue_unref (data.cancellable_source_queue);
g_mutex_clear (&data.mutex);
g_cond_clear (&data.cond);
} }
int int