mirror of
https://github.com/brl/mutter.git
synced 2025-02-16 21:34:09 +00:00
thread: Introduce kernel thread support
This commit makes it possible to create a MetaThread where the MetaThreadImpl side runs in a real thread, instead of a artificially separated impl context. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2777>
This commit is contained in:
parent
4c317eae07
commit
8b612a6150
@ -436,6 +436,7 @@ meta_kms_new (MetaBackend *backend,
|
||||
NULL, error,
|
||||
"backend", backend,
|
||||
"name", "KMS thread",
|
||||
"thread-type", META_THREAD_TYPE_USER,
|
||||
NULL);
|
||||
kms->flags = flags;
|
||||
|
||||
|
@ -23,7 +23,9 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/native/meta-thread.h"
|
||||
#include "backends/native/meta-thread-private.h"
|
||||
|
||||
#define META_THREAD_IMPL_TERMINATE ((gpointer) 1)
|
||||
|
||||
enum
|
||||
{
|
||||
@ -47,6 +49,8 @@ typedef struct _MetaThreadImplPrivate
|
||||
{
|
||||
MetaThread *thread;
|
||||
|
||||
GMainLoop *loop;
|
||||
|
||||
gboolean in_impl_task;
|
||||
|
||||
GMainContext *thread_context;
|
||||
@ -202,6 +206,7 @@ meta_thread_impl_finalize (GObject *object)
|
||||
MetaThreadImplPrivate *priv =
|
||||
meta_thread_impl_get_instance_private (thread_impl);
|
||||
|
||||
g_clear_pointer (&priv->loop, g_main_loop_unref);
|
||||
g_clear_pointer (&priv->impl_source, g_source_destroy);
|
||||
g_clear_pointer (&priv->task_queue, g_async_queue_unref);
|
||||
g_clear_pointer (&priv->thread_context, g_main_context_unref);
|
||||
@ -444,13 +449,31 @@ meta_thread_impl_register_fd (MetaThreadImpl *thread_impl,
|
||||
return source;
|
||||
}
|
||||
|
||||
void
|
||||
meta_thread_impl_terminate (MetaThreadImpl *thread_impl)
|
||||
{
|
||||
MetaThreadImplPrivate *priv =
|
||||
meta_thread_impl_get_instance_private (thread_impl);
|
||||
|
||||
g_async_queue_push (priv->task_queue, META_THREAD_IMPL_TERMINATE);
|
||||
g_main_context_wakeup (priv->thread_context);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_thread_impl_is_in_impl (MetaThreadImpl *thread_impl)
|
||||
{
|
||||
MetaThreadImplPrivate *priv =
|
||||
meta_thread_impl_get_instance_private (thread_impl);
|
||||
|
||||
return priv->in_impl_task;
|
||||
switch (meta_thread_get_thread_type (priv->thread))
|
||||
{
|
||||
case META_THREAD_TYPE_USER:
|
||||
return priv->in_impl_task;
|
||||
case META_THREAD_TYPE_KERNEL:
|
||||
return meta_thread_get_thread (priv->thread) == g_thread_self ();
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -477,6 +500,13 @@ meta_thread_impl_dispatch (MetaThreadImpl *thread_impl)
|
||||
if (!task)
|
||||
return 0;
|
||||
|
||||
if (task == META_THREAD_IMPL_TERMINATE)
|
||||
{
|
||||
if (priv->loop)
|
||||
g_main_loop_quit (priv->loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv->in_impl_task = TRUE;
|
||||
retval = task->func (thread_impl, task->user_data, &error);
|
||||
|
||||
@ -505,6 +535,18 @@ meta_thread_impl_dispatch (MetaThreadImpl *thread_impl)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
meta_thread_impl_run (MetaThreadImpl *thread_impl)
|
||||
{
|
||||
MetaThreadImplPrivate *priv =
|
||||
meta_thread_impl_get_instance_private (thread_impl);
|
||||
|
||||
meta_assert_in_thread_impl (priv->thread);
|
||||
|
||||
priv->loop = g_main_loop_new (priv->thread_context, FALSE);
|
||||
g_main_loop_run (priv->loop);
|
||||
}
|
||||
|
||||
void
|
||||
meta_thread_impl_queue_task (MetaThreadImpl *thread_impl,
|
||||
MetaThreadTask *task)
|
||||
|
@ -65,6 +65,10 @@ GSource * meta_thread_impl_register_fd (MetaThreadImpl *thread_impl,
|
||||
void meta_thread_impl_queue_task (MetaThreadImpl *thread_impl,
|
||||
MetaThreadTask *task);
|
||||
|
||||
void meta_thread_impl_terminate (MetaThreadImpl *thread_impl);
|
||||
|
||||
void meta_thread_impl_run (MetaThreadImpl *thread_impl);
|
||||
|
||||
int meta_thread_impl_dispatch (MetaThreadImpl *thread_impl);
|
||||
|
||||
gboolean meta_thread_impl_is_in_impl (MetaThreadImpl *thread_impl);
|
||||
|
@ -28,4 +28,9 @@ META_EXPORT_TEST
|
||||
void meta_thread_class_register_impl_type (MetaThreadClass *thread_class,
|
||||
GType impl_type);
|
||||
|
||||
META_EXPORT_TEST
|
||||
MetaThreadType meta_thread_get_thread_type (MetaThread *thread);
|
||||
|
||||
GThread * meta_thread_get_thread (MetaThread *thread);
|
||||
|
||||
#endif /* META_THREAD_PRIVATE_H */
|
||||
|
@ -25,12 +25,15 @@
|
||||
#include "backends/meta-backend-types.h"
|
||||
#include "backends/native/meta-thread-impl.h"
|
||||
|
||||
#include "meta-private-enum-types.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_BACKEND,
|
||||
PROP_NAME,
|
||||
PROP_THREAD_TYPE,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@ -57,6 +60,13 @@ typedef struct _MetaThreadPrivate
|
||||
GMutex callbacks_mutex;
|
||||
GList *pending_callbacks;
|
||||
guint callbacks_source_id;
|
||||
|
||||
MetaThreadType thread_type;
|
||||
|
||||
struct {
|
||||
GThread *thread;
|
||||
GMutex init_mutex;
|
||||
} kernel;
|
||||
} MetaThreadPrivate;
|
||||
|
||||
typedef struct _MetaThreadClassPrivate
|
||||
@ -98,6 +108,9 @@ meta_thread_get_property (GObject *object,
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, priv->name);
|
||||
break;
|
||||
case PROP_THREAD_TYPE:
|
||||
g_value_set_enum (value, priv->thread_type);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -121,12 +134,29 @@ meta_thread_set_property (GObject *object,
|
||||
case PROP_NAME:
|
||||
priv->name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_THREAD_TYPE:
|
||||
priv->thread_type = g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gpointer
|
||||
thread_impl_func (gpointer user_data)
|
||||
{
|
||||
MetaThread *thread = META_THREAD (user_data);
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
g_mutex_lock (&priv->kernel.init_mutex);
|
||||
g_mutex_unlock (&priv->kernel.init_mutex);
|
||||
|
||||
meta_thread_impl_run (priv->impl);
|
||||
|
||||
return GINT_TO_POINTER (TRUE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_thread_initable_init (GInitable *initable,
|
||||
GCancellable *cancellable,
|
||||
@ -142,7 +172,15 @@ meta_thread_initable_init (GInitable *initable,
|
||||
|
||||
priv->main_context = g_main_context_default ();
|
||||
|
||||
thread_context = g_main_context_ref (priv->main_context);
|
||||
switch (priv->thread_type)
|
||||
{
|
||||
case META_THREAD_TYPE_USER:
|
||||
thread_context = g_main_context_ref (priv->main_context);
|
||||
break;
|
||||
case META_THREAD_TYPE_KERNEL:
|
||||
thread_context = g_main_context_new ();
|
||||
break;
|
||||
}
|
||||
|
||||
g_assert (g_type_is_a (class_priv->impl_type, META_TYPE_THREAD_IMPL));
|
||||
priv->impl = g_object_new (class_priv->impl_type,
|
||||
@ -150,6 +188,20 @@ meta_thread_initable_init (GInitable *initable,
|
||||
"main-context", thread_context,
|
||||
NULL);
|
||||
|
||||
switch (priv->thread_type)
|
||||
{
|
||||
case META_THREAD_TYPE_USER:
|
||||
break;
|
||||
case META_THREAD_TYPE_KERNEL:
|
||||
g_mutex_init (&priv->kernel.init_mutex);
|
||||
g_mutex_lock (&priv->kernel.init_mutex);
|
||||
priv->kernel.thread = g_thread_new (priv->name,
|
||||
thread_impl_func,
|
||||
thread);
|
||||
g_mutex_unlock (&priv->kernel.init_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -159,13 +211,42 @@ initable_iface_init (GInitableIface *initable_iface)
|
||||
initable_iface->init = meta_thread_initable_init;
|
||||
}
|
||||
|
||||
static void
|
||||
finalize_thread_user (MetaThread *thread)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
while (meta_thread_impl_dispatch (priv->impl) > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
finalize_thread_kernel (MetaThread *thread)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
meta_thread_impl_terminate (priv->impl);
|
||||
g_thread_join (priv->kernel.thread);
|
||||
priv->kernel.thread = NULL;
|
||||
g_mutex_clear (&priv->kernel.init_mutex);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
meta_thread_finalize (GObject *object)
|
||||
{
|
||||
MetaThread *thread = META_THREAD (object);
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
while (meta_thread_impl_dispatch (priv->impl) > 0);
|
||||
switch (priv->thread_type)
|
||||
{
|
||||
case META_THREAD_TYPE_USER:
|
||||
finalize_thread_user (thread);
|
||||
break;
|
||||
case META_THREAD_TYPE_KERNEL:
|
||||
finalize_thread_kernel (thread);
|
||||
break;
|
||||
}
|
||||
|
||||
meta_thread_flush_callbacks (thread);
|
||||
|
||||
g_clear_object (&priv->impl);
|
||||
@ -203,6 +284,16 @@ meta_thread_class_init (MetaThreadClass *klass)
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
obj_props[PROP_THREAD_TYPE] =
|
||||
g_param_spec_enum ("thread-type",
|
||||
"thread-type",
|
||||
"Type of thread",
|
||||
META_TYPE_THREAD_TYPE,
|
||||
META_THREAD_TYPE_KERNEL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
||||
}
|
||||
|
||||
@ -317,12 +408,16 @@ typedef struct _MetaSyncTaskData
|
||||
gboolean done;
|
||||
GError *error;
|
||||
gpointer retval;
|
||||
struct {
|
||||
GMutex mutex;
|
||||
GCond cond;
|
||||
} kernel;
|
||||
} MetaSyncTaskData;
|
||||
|
||||
static void
|
||||
sync_task_done_in_impl (gpointer retval,
|
||||
const GError *error,
|
||||
gpointer user_data)
|
||||
sync_task_done_user_in_impl (gpointer retval,
|
||||
const GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaSyncTaskData *data = user_data;
|
||||
|
||||
@ -331,18 +426,18 @@ sync_task_done_in_impl (gpointer retval,
|
||||
data->error = error ? g_error_copy (error) : NULL;
|
||||
}
|
||||
|
||||
gpointer
|
||||
meta_thread_run_impl_task_sync (MetaThread *thread,
|
||||
MetaThreadTaskFunc func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
static gpointer
|
||||
run_impl_task_sync_user (MetaThread *thread,
|
||||
MetaThreadTaskFunc func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
MetaThreadTask *task;
|
||||
MetaSyncTaskData data = { 0 };
|
||||
|
||||
task = meta_thread_task_new (func, user_data,
|
||||
sync_task_done_in_impl, &data,
|
||||
sync_task_done_user_in_impl, &data,
|
||||
META_THREAD_TASK_FEEDBACK_TYPE_IMPL);
|
||||
meta_thread_impl_queue_task (priv->impl, task);
|
||||
|
||||
@ -359,6 +454,77 @@ meta_thread_run_impl_task_sync (MetaThread *thread,
|
||||
return data.retval;
|
||||
}
|
||||
|
||||
static void
|
||||
sync_task_done_kernel_in_impl (gpointer retval,
|
||||
const GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaSyncTaskData *data = user_data;
|
||||
|
||||
g_mutex_lock (&data->kernel.mutex);
|
||||
data->done = TRUE;
|
||||
data->retval = retval;
|
||||
data->error = error ? g_error_copy (error) : NULL;
|
||||
g_cond_signal (&data->kernel.cond);
|
||||
g_mutex_unlock (&data->kernel.mutex);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
run_impl_task_sync_kernel (MetaThread *thread,
|
||||
MetaThreadTaskFunc func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
MetaThreadTask *task;
|
||||
MetaSyncTaskData data = { 0 };
|
||||
|
||||
g_mutex_init (&data.kernel.mutex);
|
||||
g_cond_init (&data.kernel.cond);
|
||||
|
||||
g_mutex_lock (&data.kernel.mutex);
|
||||
priv->waiting_for_impl_task = TRUE;
|
||||
|
||||
task = meta_thread_task_new (func, user_data,
|
||||
sync_task_done_kernel_in_impl, &data,
|
||||
META_THREAD_TASK_FEEDBACK_TYPE_IMPL);
|
||||
meta_thread_impl_queue_task (priv->impl, task);
|
||||
|
||||
while (!data.done)
|
||||
g_cond_wait (&data.kernel.cond, &data.kernel.mutex);
|
||||
priv->waiting_for_impl_task = FALSE;
|
||||
g_mutex_unlock (&data.kernel.mutex);
|
||||
|
||||
g_mutex_clear (&data.kernel.mutex);
|
||||
g_cond_clear (&data.kernel.cond);
|
||||
|
||||
if (error)
|
||||
*error = data.error;
|
||||
else
|
||||
g_clear_error (&data.error);
|
||||
|
||||
return data.retval;
|
||||
}
|
||||
|
||||
gpointer
|
||||
meta_thread_run_impl_task_sync (MetaThread *thread,
|
||||
MetaThreadTaskFunc func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
switch (priv->thread_type)
|
||||
{
|
||||
case META_THREAD_TYPE_USER:
|
||||
return run_impl_task_sync_user (thread, func, user_data, error);
|
||||
case META_THREAD_TYPE_KERNEL:
|
||||
return run_impl_task_sync_kernel (thread, func, user_data, error);
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
void
|
||||
meta_thread_post_impl_task (MetaThread *thread,
|
||||
MetaThreadTaskFunc func,
|
||||
@ -391,6 +557,24 @@ meta_thread_get_name (MetaThread *thread)
|
||||
return priv->name;
|
||||
}
|
||||
|
||||
MetaThreadType
|
||||
meta_thread_get_thread_type (MetaThread *thread)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
return priv->thread_type;
|
||||
}
|
||||
|
||||
GThread *
|
||||
meta_thread_get_thread (MetaThread *thread)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
g_assert (priv->thread_type == META_THREAD_TYPE_KERNEL);
|
||||
|
||||
return priv->kernel.thread;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_thread_is_in_impl_task (MetaThread *thread)
|
||||
{
|
||||
|
@ -27,6 +27,12 @@
|
||||
|
||||
typedef struct _MetaThreadImpl MetaThreadImpl;
|
||||
|
||||
typedef enum _MetaThreadType
|
||||
{
|
||||
META_THREAD_TYPE_KERNEL,
|
||||
META_THREAD_TYPE_USER,
|
||||
} MetaThreadType;
|
||||
|
||||
#define META_TYPE_THREAD (meta_thread_get_type ())
|
||||
META_EXPORT_TEST
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaThread, meta_thread,
|
||||
|
@ -840,6 +840,7 @@ if have_native_backend
|
||||
'backends/native/meta-stage-native.h',
|
||||
'backends/native/meta-thread-impl.c',
|
||||
'backends/native/meta-thread-impl.h',
|
||||
'backends/native/meta-thread-private.h',
|
||||
'backends/native/meta-thread.c',
|
||||
'backends/native/meta-thread.h',
|
||||
'backends/native/meta-thread-private.h',
|
||||
|
@ -23,8 +23,8 @@
|
||||
#include <glib.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include "backends/native/meta-thread.h"
|
||||
#include "backends/native/meta-thread-impl.h"
|
||||
#include "backends/native/meta-thread-private.h"
|
||||
#include "meta-test/meta-context-test.h"
|
||||
#include "tests/meta-thread-impl-test.h"
|
||||
#include "tests/meta-thread-test.h"
|
||||
@ -156,6 +156,7 @@ register_fd_func (MetaThreadImpl *thread_impl,
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaThread *thread;
|
||||
GMainLoop *loop;
|
||||
|
||||
int state;
|
||||
@ -186,8 +187,9 @@ idle_data_destroy (gpointer user_data)
|
||||
{
|
||||
IdleData *idle_data = user_data;
|
||||
|
||||
/* XXX: This can only be checked on kernel type threads. */
|
||||
/* meta_assert_in_thread_impl (test_thread); */
|
||||
if (meta_thread_get_thread_type (idle_data->thread) ==
|
||||
META_THREAD_TYPE_KERNEL)
|
||||
meta_assert_in_thread_impl (test_thread);
|
||||
|
||||
g_assert_cmpint (idle_data->state, ==, 2);
|
||||
idle_data->state = 3;
|
||||
@ -471,6 +473,7 @@ run_thread_tests (MetaThread *thread)
|
||||
/* Test idle source */
|
||||
g_debug ("Test idle source");
|
||||
idle_data = (IdleData) { 0 };
|
||||
idle_data.thread = thread;
|
||||
idle_data.loop = g_main_loop_new (NULL, FALSE);
|
||||
meta_thread_run_impl_task_sync (thread, add_idle_func, &idle_data, NULL);
|
||||
g_main_loop_run (idle_data.loop);
|
||||
@ -553,6 +556,7 @@ meta_test_thread_user_common (void)
|
||||
NULL, &error,
|
||||
"backend", backend,
|
||||
"name", "test user thread",
|
||||
"thread-type", META_THREAD_TYPE_USER,
|
||||
NULL);
|
||||
g_object_add_weak_pointer (G_OBJECT (thread), (gpointer *) &thread);
|
||||
g_assert_nonnull (thread);
|
||||
@ -568,6 +572,33 @@ meta_test_thread_user_common (void)
|
||||
test_thread = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_thread_kernel_common (void)
|
||||
{
|
||||
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||
MetaThread *thread;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
thread = g_initable_new (META_TYPE_THREAD_TEST,
|
||||
NULL, &error,
|
||||
"backend", backend,
|
||||
"name", "test kernel thread",
|
||||
"thread-type", META_THREAD_TYPE_KERNEL,
|
||||
NULL);
|
||||
g_object_add_weak_pointer (G_OBJECT (thread), (gpointer *) &thread);
|
||||
g_assert_nonnull (thread);
|
||||
g_assert_null (error);
|
||||
g_assert (meta_thread_get_backend (thread) == backend);
|
||||
g_assert_cmpstr (meta_thread_get_name (thread), ==, "test kernel thread");
|
||||
test_thread = thread;
|
||||
|
||||
run_thread_tests (thread);
|
||||
|
||||
g_object_unref (thread);
|
||||
g_assert_null (thread);
|
||||
test_thread = NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
late_callback (MetaThreadImpl *thread_impl,
|
||||
gpointer user_data,
|
||||
@ -581,7 +612,7 @@ late_callback (MetaThreadImpl *thread_impl,
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_thread_user_late_callbacks (void)
|
||||
meta_test_thread_late_callbacks_common (MetaThreadType thread_type)
|
||||
{
|
||||
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||
MetaThread *thread;
|
||||
@ -592,6 +623,7 @@ meta_test_thread_user_late_callbacks (void)
|
||||
NULL, &error,
|
||||
"backend", backend,
|
||||
"name", "test late callback",
|
||||
"thread-type", thread_type,
|
||||
NULL);
|
||||
g_object_add_weak_pointer (G_OBJECT (thread), (gpointer *) &thread);
|
||||
g_assert_nonnull (thread);
|
||||
@ -604,13 +636,29 @@ meta_test_thread_user_late_callbacks (void)
|
||||
g_assert_true (done);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_thread_user_late_callbacks (void)
|
||||
{
|
||||
meta_test_thread_late_callbacks_common (META_THREAD_TYPE_USER);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_thread_kernel_late_callbacks (void)
|
||||
{
|
||||
meta_test_thread_late_callbacks_common (META_THREAD_TYPE_KERNEL);
|
||||
}
|
||||
|
||||
static void
|
||||
init_tests (void)
|
||||
{
|
||||
g_test_add_func ("/backends/native/thread/user/common",
|
||||
meta_test_thread_user_common);
|
||||
g_test_add_func ("/backends/native/thread/kernel/common",
|
||||
meta_test_thread_kernel_common);
|
||||
g_test_add_func ("/backends/native/thread/user/late-callbacks",
|
||||
meta_test_thread_user_late_callbacks);
|
||||
g_test_add_func ("/backends/native/thread/kernel/late-callbacks",
|
||||
meta_test_thread_kernel_late_callbacks);
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
x
Reference in New Issue
Block a user