thread: Move context and task management to impl side

It's the impl side that wants to add impl side idle sources, or fd
sources, etc, so make it part of MetaThreadImpl.

This changes things to be GAsyncQueue based. While things are still
technically single threaded, the GAsyncQueue type is used as later we'll
introduce queuing tasks asynchronously, then eventually queuing across
thread barriers.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2777>
This commit is contained in:
Jonas Ådahl
2021-05-27 11:36:35 +02:00
parent 229904cb4b
commit fda883e859
8 changed files with 370 additions and 184 deletions

View File

@ -43,23 +43,6 @@ typedef struct _MetaThreadCallbackData
GDestroyNotify user_data_destroy;
} MetaThreadCallbackData;
typedef struct _MetaThreadSimpleImplSource
{
GSource source;
MetaThread *thread;
} MetaThreadSimpleImplSource;
typedef struct _MetaThreadFdImplSource
{
GSource source;
gpointer fd_tag;
MetaThread *thread;
MetaThreadTaskFunc dispatch;
gpointer user_data;
} MetaThreadFdImplSource;
typedef struct _MetaThreadPrivate
{
MetaBackend *backend;
@ -67,7 +50,6 @@ typedef struct _MetaThreadPrivate
GMainContext *main_context;
MetaThreadImpl *impl;
gboolean in_impl_task;
gboolean waiting_for_impl_task;
GList *pending_callbacks;
@ -147,12 +129,16 @@ meta_thread_initable_init (GInitable *initable,
MetaThreadClassPrivate *class_priv =
G_TYPE_CLASS_GET_PRIVATE (thread_class, META_TYPE_THREAD,
MetaThreadClassPrivate);
g_autoptr (GMainContext) thread_context = NULL;
priv->main_context = g_main_context_get_thread_default ();
priv->main_context = g_main_context_default ();
thread_context = g_main_context_ref (priv->main_context);
g_assert (g_type_is_a (class_priv->impl_type, META_TYPE_THREAD_IMPL));
priv->impl = g_object_new (class_priv->impl_type,
"thread", thread,
"main-context", thread_context,
NULL);
return TRUE;
@ -282,6 +268,25 @@ meta_thread_queue_callback (MetaThread *thread,
}
}
typedef struct _MetaSyncTaskData
{
gboolean done;
GError *error;
gpointer retval;
} MetaSyncTaskData;
static void
sync_task_done_in_impl (gpointer retval,
const GError *error,
gpointer user_data)
{
MetaSyncTaskData *data = user_data;
data->done = TRUE;
data->retval = retval;
data->error = error ? g_error_copy (error) : NULL;
}
gpointer
meta_thread_run_impl_task_sync (MetaThread *thread,
MetaThreadTaskFunc func,
@ -289,129 +294,24 @@ meta_thread_run_impl_task_sync (MetaThread *thread,
GError **error)
{
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
gpointer ret;
MetaThreadTask *task;
MetaSyncTaskData data = { 0 };
task = meta_thread_task_new (func, user_data,
sync_task_done_in_impl, &data);
meta_thread_impl_queue_task (priv->impl, task);
priv->in_impl_task = TRUE;
priv->waiting_for_impl_task = TRUE;
ret = func (priv->impl, user_data, error);
while (!data.done)
meta_thread_impl_dispatch (priv->impl);
priv->waiting_for_impl_task = FALSE;
priv->in_impl_task = FALSE;
return ret;
}
if (error)
*error = data.error;
else
g_clear_error (&data.error);
static gboolean
simple_impl_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
MetaThreadSimpleImplSource *simple_impl_source =
(MetaThreadSimpleImplSource *) source;
MetaThread *thread = simple_impl_source->thread;
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
gboolean ret;
priv->in_impl_task = TRUE;
ret = callback (user_data);
priv->in_impl_task = FALSE;
return ret;
}
static GSourceFuncs simple_impl_source_funcs = {
.dispatch = simple_impl_source_dispatch,
};
GSource *
meta_thread_add_source_in_impl (MetaThread *thread,
GSourceFunc func,
gpointer user_data,
GDestroyNotify user_data_destroy)
{
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
GSource *source;
MetaThreadSimpleImplSource *simple_impl_source;
meta_assert_in_thread_impl (thread);
source = g_source_new (&simple_impl_source_funcs,
sizeof (MetaThreadSimpleImplSource));
g_source_set_name (source, "[mutter] MetaThread simple impl");
simple_impl_source = (MetaThreadSimpleImplSource *) source;
simple_impl_source->thread = thread;
g_source_set_callback (source, func, user_data, user_data_destroy);
g_source_set_ready_time (source, 0);
g_source_attach (source, meta_thread_impl_get_main_context (priv->impl));
return source;
}
static gboolean
meta_thread_fd_impl_source_check (GSource *source)
{
MetaThreadFdImplSource *fd_impl_source = (MetaThreadFdImplSource *) source;
return g_source_query_unix_fd (source, fd_impl_source->fd_tag) & G_IO_IN;
}
static gboolean
meta_thread_fd_impl_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
MetaThreadFdImplSource *fd_impl_source = (MetaThreadFdImplSource *) source;
MetaThread *thread = fd_impl_source->thread;
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
gpointer ret;
GError *error = NULL;
priv->in_impl_task = TRUE;
ret = fd_impl_source->dispatch (priv->impl,
fd_impl_source->user_data,
&error);
priv->in_impl_task = FALSE;
if (!GPOINTER_TO_INT (ret))
{
g_warning ("Failed to dispatch fd source: %s", error->message);
g_error_free (error);
}
return G_SOURCE_CONTINUE;
}
static GSourceFuncs fd_impl_source_funcs = {
NULL,
meta_thread_fd_impl_source_check,
meta_thread_fd_impl_source_dispatch
};
GSource *
meta_thread_register_fd_in_impl (MetaThread *thread,
int fd,
MetaThreadTaskFunc dispatch,
gpointer user_data)
{
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
GSource *source;
MetaThreadFdImplSource *fd_impl_source;
meta_assert_in_thread_impl (thread);
source = g_source_new (&fd_impl_source_funcs,
sizeof (MetaThreadFdImplSource));
g_source_set_name (source, "[mutter] MetaThread fd impl");
fd_impl_source = (MetaThreadFdImplSource *) source;
fd_impl_source->dispatch = dispatch;
fd_impl_source->user_data = user_data;
fd_impl_source->thread = thread;
fd_impl_source->fd_tag = g_source_add_unix_fd (source, fd,
G_IO_IN | G_IO_ERR);
g_source_attach (source, meta_thread_impl_get_main_context (priv->impl));
return source;
return data.retval;
}
MetaBackend *
@ -427,7 +327,7 @@ meta_thread_is_in_impl_task (MetaThread *thread)
{
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
return priv->in_impl_task;
return meta_thread_impl_is_in_impl (priv->impl);
}
gboolean