thread: Flush tasks and callbacks on finalize

This will make sure no tasks or callbacks are unexpectedly dropped,
potentially leaking or leaving things in an unexpected state.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2777>
This commit is contained in:
Jonas Ådahl 2021-06-11 17:51:50 +02:00
parent 261624538c
commit 251722ec4e
4 changed files with 46 additions and 5 deletions

View File

@ -454,7 +454,7 @@ invoke_task_feedback (MetaThread *thread,
task->feedback_func (task->retval, task->error, task->feedback_user_data); task->feedback_func (task->retval, task->error, task->feedback_user_data);
} }
void int
meta_thread_impl_dispatch (MetaThreadImpl *thread_impl) meta_thread_impl_dispatch (MetaThreadImpl *thread_impl)
{ {
MetaThreadImplPrivate *priv = MetaThreadImplPrivate *priv =
@ -463,7 +463,9 @@ meta_thread_impl_dispatch (MetaThreadImpl *thread_impl)
gpointer retval; gpointer retval;
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
task = g_async_queue_pop (priv->task_queue); task = g_async_queue_try_pop (priv->task_queue);
if (!task)
return 0;
priv->in_impl_task = TRUE; priv->in_impl_task = TRUE;
retval = task->func (thread_impl, task->user_data, &error); retval = task->func (thread_impl, task->user_data, &error);
@ -489,6 +491,8 @@ meta_thread_impl_dispatch (MetaThreadImpl *thread_impl)
g_clear_pointer (&task, meta_thread_task_free); g_clear_pointer (&task, meta_thread_task_free);
priv->in_impl_task = FALSE; priv->in_impl_task = FALSE;
return 1;
} }
void void

View File

@ -65,7 +65,7 @@ GSource * meta_thread_impl_register_fd (MetaThreadImpl *thread_impl,
void meta_thread_impl_queue_task (MetaThreadImpl *thread_impl, void meta_thread_impl_queue_task (MetaThreadImpl *thread_impl,
MetaThreadTask *task); MetaThreadTask *task);
void meta_thread_impl_dispatch (MetaThreadImpl *thread_impl); int meta_thread_impl_dispatch (MetaThreadImpl *thread_impl);
gboolean meta_thread_impl_is_in_impl (MetaThreadImpl *thread_impl); gboolean meta_thread_impl_is_in_impl (MetaThreadImpl *thread_impl);

View File

@ -156,8 +156,8 @@ meta_thread_finalize (GObject *object)
MetaThread *thread = META_THREAD (object); MetaThread *thread = META_THREAD (object);
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread); MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
g_clear_list (&priv->pending_callbacks, while (meta_thread_impl_dispatch (priv->impl) > 0);
(GDestroyNotify) meta_thread_callback_data_free); meta_thread_flush_callbacks (thread);
g_clear_handle_id (&priv->callbacks_source_id, g_source_remove); g_clear_handle_id (&priv->callbacks_source_id, g_source_remove);
g_clear_object (&priv->impl); g_clear_object (&priv->impl);

View File

@ -566,11 +566,48 @@ meta_test_thread_user_common (void)
test_thread = NULL; test_thread = NULL;
} }
static gpointer
late_callback (MetaThreadImpl *thread_impl,
gpointer user_data,
GError **error)
{
gboolean *done = user_data;
*done = TRUE;
return NULL;
}
static void
meta_test_thread_user_late_callbacks (void)
{
MetaBackend *backend = meta_context_get_backend (test_context);
MetaThread *thread;
g_autoptr (GError) error = NULL;
gboolean done = FALSE;
thread = g_initable_new (META_TYPE_THREAD_TEST,
NULL, &error,
"backend", backend,
NULL);
g_object_add_weak_pointer (G_OBJECT (thread), (gpointer *) &thread);
g_assert_nonnull (thread);
g_assert_null (error);
meta_thread_post_impl_task (thread, late_callback, &done, NULL, NULL);
g_object_unref (thread);
g_assert_null (thread);
g_assert_true (done);
}
static void static void
init_tests (void) init_tests (void)
{ {
g_test_add_func ("/backends/native/thread/user/common", g_test_add_func ("/backends/native/thread/user/common",
meta_test_thread_user_common); meta_test_thread_user_common);
g_test_add_func ("/backends/native/thread/user/late-callbacks",
meta_test_thread_user_late_callbacks);
} }
int int