631 lines
20 KiB
Diff
631 lines
20 KiB
Diff
From c38064c9614b70e92a38e98df3ebd6b232ea2f55 Mon Sep 17 00:00:00 2001
|
|
From: Ray Strode <rstrode@redhat.com>
|
|
Date: Tue, 10 Oct 2023 14:39:13 -0400
|
|
Subject: [PATCH 3/4] thread: Allow turnning off rt scheduling for running
|
|
thread
|
|
|
|
At the moment if a thread is made real-time there's no going back,
|
|
it stays real-time for the duration of its life.
|
|
|
|
That's suboptimal because real-time threads are expected by RTKit to
|
|
have an rlimit on their CPU time and certain GPU drivers in the kernel
|
|
can exceed that CPU time during certain operations like DPMS off.
|
|
|
|
This commit adds two new ref counted functions:
|
|
|
|
meta_thread_{un,}inhibit_realtime_in_impl
|
|
|
|
that allow turning a thread real-time or normally scheduled. At the same
|
|
time, this commit stores the RTKit proxy as private data on the thread
|
|
so that it can be reused by the above apis.
|
|
|
|
A subsequent commit will use the new APIs.
|
|
---
|
|
src/backends/native/meta-thread.c | 174 ++++++++++++++++++++++++++----
|
|
src/backends/native/meta-thread.h | 6 ++
|
|
2 files changed, 157 insertions(+), 23 deletions(-)
|
|
|
|
diff --git a/src/backends/native/meta-thread.c b/src/backends/native/meta-thread.c
|
|
index 93a84a8a5..f291c0b4a 100644
|
|
--- a/src/backends/native/meta-thread.c
|
|
+++ b/src/backends/native/meta-thread.c
|
|
@@ -56,62 +56,65 @@ typedef struct _MetaThreadCallbackSource
|
|
|
|
GMutex mutex;
|
|
GCond cond;
|
|
|
|
MetaThread *thread;
|
|
GMainContext *main_context;
|
|
GList *callbacks;
|
|
gboolean needs_flush;
|
|
} MetaThreadCallbackSource;
|
|
|
|
typedef struct _MetaThreadPrivate
|
|
{
|
|
MetaBackend *backend;
|
|
char *name;
|
|
|
|
GMainContext *main_context;
|
|
|
|
MetaThreadImpl *impl;
|
|
gboolean wants_realtime;
|
|
gboolean waiting_for_impl_task;
|
|
GSource *wrapper_source;
|
|
|
|
GMutex callbacks_mutex;
|
|
GHashTable *callback_sources;
|
|
|
|
MetaThreadType thread_type;
|
|
|
|
GThread *main_thread;
|
|
|
|
struct {
|
|
+ MetaDBusRealtimeKit1 *rtkit_proxy;
|
|
GThread *thread;
|
|
+ pid_t thread_id;
|
|
GMutex init_mutex;
|
|
+ int realtime_inhibit_count;
|
|
} kernel;
|
|
} MetaThreadPrivate;
|
|
|
|
typedef struct _MetaThreadClassPrivate
|
|
{
|
|
GType impl_type;
|
|
} MetaThreadClassPrivate;
|
|
|
|
static void initable_iface_init (GInitableIface *initable_iface);
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (MetaThread, meta_thread, G_TYPE_OBJECT,
|
|
G_ADD_PRIVATE (MetaThread)
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
|
initable_iface_init)
|
|
g_type_add_class_private (g_define_type_id,
|
|
sizeof (MetaThreadClassPrivate)))
|
|
|
|
static void
|
|
meta_thread_callback_data_free (MetaThreadCallbackData *callback_data)
|
|
{
|
|
if (callback_data->user_data_destroy)
|
|
callback_data->user_data_destroy (callback_data->user_data);
|
|
g_free (callback_data);
|
|
}
|
|
|
|
static void
|
|
meta_thread_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
@@ -175,181 +178,238 @@ get_rtkit_property (MetaDBusRealtimeKit1 *rtkit_proxy,
|
|
{
|
|
GDBusConnection *connection;
|
|
g_autoptr (GVariant) prop_value = NULL;
|
|
g_autoptr (GVariant) property_variant = NULL;
|
|
|
|
/* The following is a fall back path for a RTKit daemon that doesn't support
|
|
* org.freedesktop.DBus.Properties.GetAll. See
|
|
* <https://github.com/heftig/rtkit/pull/30>.
|
|
*/
|
|
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (rtkit_proxy));
|
|
prop_value =
|
|
g_dbus_connection_call_sync (connection,
|
|
"org.freedesktop.RealtimeKit1",
|
|
"/org/freedesktop/RealtimeKit1",
|
|
"org.freedesktop.DBus.Properties",
|
|
"Get",
|
|
g_variant_new ("(ss)",
|
|
"org.freedesktop.RealtimeKit1",
|
|
property_name),
|
|
G_VARIANT_TYPE ("(v)"),
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
-1, NULL, error);
|
|
if (!prop_value)
|
|
return NULL;
|
|
|
|
g_variant_get (prop_value, "(v)", &property_variant);
|
|
return g_steal_pointer (&property_variant);
|
|
}
|
|
|
|
static gboolean
|
|
-request_realtime_scheduling (MetaThread *thread,
|
|
- GError **error)
|
|
+ensure_realtime_kit_proxy (MetaThread *thread,
|
|
+ GError **error)
|
|
{
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
g_autoptr (MetaDBusRealtimeKit1) rtkit_proxy = NULL;
|
|
g_autoptr (GError) local_error = NULL;
|
|
- int64_t rttime;
|
|
- struct rlimit rl;
|
|
- uint32_t priority;
|
|
+
|
|
+ if (priv->kernel.rtkit_proxy)
|
|
+ return TRUE;
|
|
|
|
rtkit_proxy =
|
|
meta_dbus_realtime_kit1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
|
"org.freedesktop.RealtimeKit1",
|
|
"/org/freedesktop/RealtimeKit1",
|
|
NULL,
|
|
&local_error);
|
|
if (!rtkit_proxy)
|
|
{
|
|
g_dbus_error_strip_remote_error (local_error);
|
|
g_propagate_prefixed_error (error, g_steal_pointer (&local_error),
|
|
"Failed to acquire RTKit D-Bus proxy: ");
|
|
return FALSE;
|
|
}
|
|
|
|
- priority = meta_dbus_realtime_kit1_get_max_realtime_priority (rtkit_proxy);
|
|
+ priv->kernel.rtkit_proxy = g_steal_pointer (&rtkit_proxy);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+request_realtime_scheduling (MetaThread *thread,
|
|
+ GError **error)
|
|
+{
|
|
+ MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
+ g_autoptr (GError) local_error = NULL;
|
|
+ int64_t rttime;
|
|
+ struct rlimit rl;
|
|
+ uint32_t priority;
|
|
+
|
|
+ if (!ensure_realtime_kit_proxy (thread, error))
|
|
+ return FALSE;
|
|
+
|
|
+ priority = meta_dbus_realtime_kit1_get_max_realtime_priority (priv->kernel.rtkit_proxy);
|
|
if (priority == 0)
|
|
{
|
|
g_autoptr (GVariant) priority_variant = NULL;
|
|
|
|
- priority_variant = get_rtkit_property (rtkit_proxy,
|
|
+ priority_variant = get_rtkit_property (priv->kernel.rtkit_proxy,
|
|
"MaxRealtimePriority",
|
|
error);
|
|
if (!priority_variant)
|
|
return FALSE;
|
|
|
|
priority = g_variant_get_int32 (priority_variant);
|
|
}
|
|
|
|
if (priority == 0)
|
|
g_warning ("Maximum real time scheduling priority is 0");
|
|
|
|
- rttime = meta_dbus_realtime_kit1_get_rttime_usec_max (rtkit_proxy);
|
|
+ rttime = meta_dbus_realtime_kit1_get_rttime_usec_max (priv->kernel.rtkit_proxy);
|
|
if (rttime == 0)
|
|
{
|
|
g_autoptr (GVariant) rttime_variant = NULL;
|
|
|
|
- rttime_variant = get_rtkit_property (rtkit_proxy,
|
|
+ rttime_variant = get_rtkit_property (priv->kernel.rtkit_proxy,
|
|
"RTTimeUSecMax",
|
|
error);
|
|
if (!rttime_variant)
|
|
return FALSE;
|
|
|
|
rttime = g_variant_get_int64 (rttime_variant);
|
|
}
|
|
|
|
meta_topic (META_DEBUG_BACKEND,
|
|
"Setting soft and hard RLIMIT_RTTIME limit to %lu", rttime);
|
|
rl.rlim_cur = rttime;
|
|
rl.rlim_max = rttime;
|
|
|
|
if (setrlimit (RLIMIT_RTTIME, &rl) != 0)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
"Failed to set RLIMIT_RTTIME: %s", g_strerror (errno));
|
|
return FALSE;
|
|
}
|
|
|
|
meta_topic (META_DEBUG_BACKEND, "Setting '%s' thread real time priority to %d",
|
|
priv->name, priority);
|
|
- if (!meta_dbus_realtime_kit1_call_make_thread_realtime_sync (rtkit_proxy,
|
|
- gettid (),
|
|
+ if (!meta_dbus_realtime_kit1_call_make_thread_realtime_sync (priv->kernel.rtkit_proxy,
|
|
+ priv->kernel.thread_id,
|
|
priority,
|
|
NULL,
|
|
&local_error))
|
|
{
|
|
g_dbus_error_strip_remote_error (local_error);
|
|
g_propagate_error (error, g_steal_pointer (&local_error));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
+static gboolean
|
|
+request_normal_scheduling (MetaThread *thread,
|
|
+ GError **error)
|
|
+{
|
|
+ MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
+ g_autoptr (GError) local_error = NULL;
|
|
+
|
|
+ if (!ensure_realtime_kit_proxy (thread, error))
|
|
+ return FALSE;
|
|
+
|
|
+ meta_topic (META_DEBUG_BACKEND, "Setting '%s' thread to normal priority", priv->name);
|
|
+ if (!meta_dbus_realtime_kit1_call_make_thread_high_priority_sync (priv->kernel.rtkit_proxy,
|
|
+ priv->kernel.thread_id,
|
|
+ 0 /* "normal" nice value */,
|
|
+ NULL,
|
|
+ &local_error))
|
|
+ {
|
|
+ g_dbus_error_strip_remote_error (local_error);
|
|
+ g_propagate_error (error, g_steal_pointer (&local_error));
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+meta_thread_uses_realtime_scheduling (MetaThread *thread)
|
|
+{
|
|
+ MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
+ gboolean uses_realtime_scheduling = FALSE;
|
|
+
|
|
+ switch (priv->thread_type)
|
|
+ {
|
|
+ case META_THREAD_TYPE_USER:
|
|
+ break;
|
|
+ case META_THREAD_TYPE_KERNEL:
|
|
+ if (priv->kernel.realtime_inhibit_count == 0)
|
|
+ uses_realtime_scheduling = TRUE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return uses_realtime_scheduling;
|
|
+}
|
|
+
|
|
static gpointer
|
|
thread_impl_func (gpointer user_data)
|
|
{
|
|
MetaThread *thread = META_THREAD (user_data);
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
MetaThreadImpl *impl = priv->impl;
|
|
MetaThreadImplRunFlags run_flags = META_THREAD_IMPL_RUN_FLAG_NONE;
|
|
GMainContext *thread_context = meta_thread_impl_get_main_context (impl);
|
|
#ifdef HAVE_PROFILER
|
|
MetaContext *context = meta_backend_get_context (priv->backend);
|
|
MetaProfiler *profiler = meta_context_get_profiler (context);
|
|
#endif
|
|
|
|
g_mutex_lock (&priv->kernel.init_mutex);
|
|
g_mutex_unlock (&priv->kernel.init_mutex);
|
|
|
|
g_main_context_push_thread_default (thread_context);
|
|
|
|
#ifdef HAVE_PROFILER
|
|
meta_profiler_register_thread (profiler, thread_context, priv->name);
|
|
#endif
|
|
|
|
+ priv->kernel.thread_id = gettid ();
|
|
+ priv->kernel.realtime_inhibit_count = 1;
|
|
+
|
|
if (priv->wants_realtime)
|
|
- {
|
|
- g_autoptr (GError) error = NULL;
|
|
+ meta_thread_uninhibit_realtime_in_impl (thread);
|
|
|
|
- if (!request_realtime_scheduling (thread, &error))
|
|
- {
|
|
- g_warning ("Failed to make thread '%s' realtime scheduled: %s",
|
|
- priv->name, error->message);
|
|
- }
|
|
- else
|
|
- {
|
|
- g_message ("Made thread '%s' realtime scheduled", priv->name);
|
|
- run_flags |= META_THREAD_IMPL_RUN_FLAG_REALTIME;
|
|
- }
|
|
+ if (meta_thread_uses_realtime_scheduling (thread))
|
|
+ {
|
|
+ g_message ("Made thread '%s' realtime scheduled", priv->name);
|
|
+ run_flags |= META_THREAD_IMPL_RUN_FLAG_REALTIME;
|
|
}
|
|
|
|
meta_thread_impl_run (impl, run_flags);
|
|
|
|
#ifdef HAVE_PROFILER
|
|
meta_profiler_unregister_thread (profiler, thread_context);
|
|
#endif
|
|
|
|
g_main_context_pop_thread_default (thread_context);
|
|
|
|
return GINT_TO_POINTER (TRUE);
|
|
}
|
|
|
|
typedef struct _WrapperSource
|
|
{
|
|
GSource base;
|
|
|
|
GMainContext *thread_main_context;
|
|
|
|
GPollFD fds[256];
|
|
gpointer fd_tags[256];
|
|
int n_fds;
|
|
int priority;
|
|
} WrapperSource;
|
|
|
|
static gboolean
|
|
wrapper_source_prepare (GSource *source,
|
|
int *timeout)
|
|
{
|
|
WrapperSource *wrapper_source = (WrapperSource *) source;
|
|
@@ -522,60 +582,66 @@ meta_thread_initable_init (GInitable *initable,
|
|
|
|
start_thread (thread);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
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);
|
|
|
|
meta_thread_impl_terminate (priv->impl);
|
|
while (meta_thread_impl_dispatch (priv->impl) > 0);
|
|
unwrap_main_context (thread, meta_thread_impl_get_main_context (priv->impl));
|
|
}
|
|
|
|
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;
|
|
+ priv->kernel.thread_id = 0;
|
|
+
|
|
+ priv->kernel.realtime_inhibit_count = -1;
|
|
+
|
|
+ g_clear_object (&priv->kernel.rtkit_proxy);
|
|
+
|
|
g_mutex_clear (&priv->kernel.init_mutex);
|
|
}
|
|
|
|
static void
|
|
tear_down_thread (MetaThread *thread)
|
|
{
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
meta_thread_finalize (GObject *object)
|
|
{
|
|
MetaThread *thread = META_THREAD (object);
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
|
|
tear_down_thread (thread);
|
|
|
|
meta_thread_unregister_callback_context (thread, priv->main_context);
|
|
@@ -618,60 +684,62 @@ meta_thread_class_init (MetaThreadClass *klass)
|
|
|
|
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);
|
|
|
|
obj_props[PROP_WANTS_REALTIME] =
|
|
g_param_spec_boolean ("wants-realtime",
|
|
"wants-realtime",
|
|
"Wants real-time thread scheduling",
|
|
FALSE,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
|
}
|
|
|
|
static void
|
|
meta_thread_init (MetaThread *thread)
|
|
{
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
|
|
g_mutex_init (&priv->callbacks_mutex);
|
|
priv->main_thread = g_thread_self ();
|
|
+
|
|
+ priv->kernel.realtime_inhibit_count = -1;
|
|
}
|
|
|
|
void
|
|
meta_thread_class_register_impl_type (MetaThreadClass *thread_class,
|
|
GType impl_type)
|
|
{
|
|
MetaThreadClassPrivate *class_priv =
|
|
G_TYPE_CLASS_GET_PRIVATE (thread_class, META_TYPE_THREAD,
|
|
MetaThreadClassPrivate);
|
|
|
|
g_assert (class_priv->impl_type == G_TYPE_INVALID);
|
|
class_priv->impl_type = impl_type;
|
|
}
|
|
|
|
void
|
|
meta_thread_reset_thread_type (MetaThread *thread,
|
|
MetaThreadType thread_type)
|
|
{
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
g_autoptr (GMainContext) thread_context = NULL;
|
|
|
|
if (priv->thread_type == thread_type)
|
|
return;
|
|
|
|
tear_down_thread (thread);
|
|
g_assert (!priv->wrapper_source);
|
|
|
|
priv->thread_type = thread_type;
|
|
|
|
start_thread (thread);
|
|
@@ -1134,30 +1202,90 @@ 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)
|
|
{
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
|
|
return meta_thread_impl_is_in_impl (priv->impl);
|
|
}
|
|
|
|
gboolean
|
|
meta_thread_is_waiting_for_impl_task (MetaThread *thread)
|
|
{
|
|
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
|
|
return priv->waiting_for_impl_task;
|
|
}
|
|
+
|
|
+void
|
|
+meta_thread_inhibit_realtime_in_impl (MetaThread *thread)
|
|
+{
|
|
+ MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
+ g_autoptr (GError) error = NULL;
|
|
+
|
|
+ switch (priv->thread_type)
|
|
+ {
|
|
+ case META_THREAD_TYPE_KERNEL:
|
|
+ priv->kernel.realtime_inhibit_count++;
|
|
+
|
|
+ if (priv->kernel.realtime_inhibit_count == 1)
|
|
+ {
|
|
+ if (!request_normal_scheduling (thread, &error))
|
|
+ {
|
|
+ g_warning ("Failed to make thread '%s' normally scheduled: %s",
|
|
+ priv->name, error->message);
|
|
+ priv->kernel.realtime_inhibit_count--;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ meta_topic (META_DEBUG_BACKEND, "Made thread '%s' normally scheduled", priv->name);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ case META_THREAD_TYPE_USER:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+meta_thread_uninhibit_realtime_in_impl (MetaThread *thread)
|
|
+{
|
|
+ MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
|
+ g_autoptr (GError) error = NULL;
|
|
+
|
|
+ switch (priv->thread_type)
|
|
+ {
|
|
+ case META_THREAD_TYPE_KERNEL:
|
|
+ priv->kernel.realtime_inhibit_count--;
|
|
+
|
|
+ if (priv->kernel.realtime_inhibit_count == 0)
|
|
+ {
|
|
+ if (!request_realtime_scheduling (thread, &error))
|
|
+ {
|
|
+ g_warning ("Failed to make thread '%s' realtime scheduled: %s",
|
|
+ priv->name, error->message);
|
|
+ priv->kernel.realtime_inhibit_count++;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ meta_topic (META_DEBUG_BACKEND, "Made thread '%s' realtime scheduled", priv->name);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ case META_THREAD_TYPE_USER:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
diff --git a/src/backends/native/meta-thread.h b/src/backends/native/meta-thread.h
|
|
index 9fc3588b9..96b79b586 100644
|
|
--- a/src/backends/native/meta-thread.h
|
|
+++ b/src/backends/native/meta-thread.h
|
|
@@ -71,36 +71,42 @@ void meta_thread_queue_callback (MetaThread *thread,
|
|
GDestroyNotify user_data_destroy);
|
|
|
|
META_EXPORT_TEST
|
|
void meta_thread_flush_callbacks (MetaThread *thread);
|
|
|
|
META_EXPORT_TEST
|
|
gpointer meta_thread_run_impl_task_sync (MetaThread *thread,
|
|
MetaThreadTaskFunc func,
|
|
gpointer user_data,
|
|
GError **error);
|
|
|
|
META_EXPORT_TEST
|
|
void meta_thread_post_impl_task (MetaThread *thread,
|
|
MetaThreadTaskFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify user_data_destroy,
|
|
MetaThreadTaskFeedbackFunc feedback_func,
|
|
gpointer feedback_user_data);
|
|
|
|
META_EXPORT_TEST
|
|
MetaBackend * meta_thread_get_backend (MetaThread *thread);
|
|
|
|
META_EXPORT_TEST
|
|
const char * meta_thread_get_name (MetaThread *thread);
|
|
|
|
META_EXPORT_TEST
|
|
gboolean meta_thread_is_in_impl_task (MetaThread *thread);
|
|
|
|
gboolean meta_thread_is_waiting_for_impl_task (MetaThread *thread);
|
|
|
|
+META_EXPORT_TEST
|
|
+void meta_thread_inhibit_realtime_in_impl (MetaThread *thread);
|
|
+
|
|
+META_EXPORT_TEST
|
|
+void meta_thread_uninhibit_realtime_in_impl (MetaThread *thread);
|
|
+
|
|
#define meta_assert_in_thread_impl(thread) \
|
|
g_assert (meta_thread_is_in_impl_task (thread))
|
|
#define meta_assert_not_in_thread_impl(thread) \
|
|
g_assert (!meta_thread_is_in_impl_task (thread))
|
|
#define meta_assert_is_waiting_for_thread_impl_task(thread) \
|
|
g_assert (meta_thread_is_waiting_for_impl_task (thread))
|
|
--
|
|
2.41.0
|
|
|