Disable realtime scheduling during modesets (#2240457)

This commit is contained in:
Ray Strode 2023-10-10 16:41:15 -04:00
parent 7d552b76c5
commit 11f29e2c83
5 changed files with 1025 additions and 0 deletions

View File

@ -0,0 +1,57 @@
From 372a2ecda4c06170a85936e3b88c7fdd681cdca1 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Oct 2023 16:24:43 -0400
Subject: [PATCH 1/4] thread: Fix preexisting uncrustify problem
uncrustify seems to want a little more indentation, so this
commit gives it what it's asking for.
---
src/backends/native/meta-thread.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/backends/native/meta-thread.h b/src/backends/native/meta-thread.h
index f6c5c94f5..9fc3588b9 100644
--- a/src/backends/native/meta-thread.h
+++ b/src/backends/native/meta-thread.h
@@ -72,35 +72,35 @@ void meta_thread_queue_callback (MetaThread *thread,
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);
#define meta_assert_in_thread_impl(thread) \
- g_assert (meta_thread_is_in_impl_task (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))
+ 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))
+ g_assert (meta_thread_is_waiting_for_impl_task (thread))
--
2.41.0

View File

@ -0,0 +1,149 @@
From 39f55e7af76ee6a6339115a386a4b26f8318fed4 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Oct 2023 14:35:46 -0400
Subject: [PATCH 2/4] thread: For consistency, s/real_time/realtime/
Most of the code writes "real-time" as "realtime" not "real_time".
The only exception is one function `request_real_time_scheduling`.
This commit changes that function for consistency.
---
src/backends/native/meta-thread.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/backends/native/meta-thread.c b/src/backends/native/meta-thread.c
index 08d01144d..93a84a8a5 100644
--- a/src/backends/native/meta-thread.c
+++ b/src/backends/native/meta-thread.c
@@ -175,62 +175,62 @@ 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_real_time_scheduling (MetaThread *thread,
- GError **error)
+request_realtime_scheduling (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;
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);
if (priority == 0)
{
g_autoptr (GVariant) priority_variant = NULL;
priority_variant = get_rtkit_property (rtkit_proxy,
@@ -286,61 +286,61 @@ request_real_time_scheduling (MetaThread *thread,
return TRUE;
}
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
if (priv->wants_realtime)
{
g_autoptr (GError) error = NULL;
- if (!request_real_time_scheduling (thread, &error))
+ 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;
}
}
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];
--
2.41.0

View File

@ -0,0 +1,630 @@
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

View File

@ -0,0 +1,183 @@
From 99be4ed7c3be19969930ce826f48c444e5e9da41 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Oct 2023 14:48:55 -0400
Subject: [PATCH 4/4] kms/impl-device: Inhibit real-time scheduling when mode
setting
Certain kernel drivers can take an unreasonably long time to
complete mode setting operations. That excessive CPU time is charged
to the process's rlimits which can lead to the process getting killed
if the thread is a real-time thread.
This commit inhibits real-time scheduling around mode setting
commits, since those commits are the ones currently presenting as
excessively slow.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3037
---
src/backends/native/meta-kms-impl-device.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
index da372383d..d53552704 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
@@ -1554,141 +1554,154 @@ meta_kms_impl_device_schedule_process (MetaKmsImplDevice *impl_device,
if (crtc_frame->await_flush)
return;
if (!is_using_deadline_timer (impl_device))
goto needs_flush;
if (crtc_frame->pending_page_flip)
return;
if (ensure_deadline_timer_armed (impl_device, crtc_frame, &error))
return;
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
g_warning ("Failed to determine deadline: %s", error->message);
priv = meta_kms_impl_device_get_instance_private (impl_device);
priv->deadline_timer_inhibited = TRUE;
needs_flush:
meta_kms_device_set_needs_flush (meta_kms_crtc_get_device (crtc), crtc);
}
static MetaKmsFeedback *
process_mode_set_update (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update,
MetaKmsUpdateFlag flags)
{
MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device);
+ MetaKmsImpl *kms_impl = meta_kms_impl_device_get_impl (impl_device);
+ MetaThreadImpl *thread_impl = META_THREAD_IMPL (kms_impl);
+ MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
+ MetaKmsFeedback *feedback;
CrtcFrame *crtc_frame;
GList *l;
GHashTableIter iter;
for (l = meta_kms_update_get_mode_sets (update); l; l = l->next)
{
MetaKmsModeSet *mode_set = l->data;
MetaKmsCrtc *crtc = mode_set->crtc;
crtc_frame = get_crtc_frame (impl_device, crtc);
if (!crtc_frame)
continue;
if (!crtc_frame->pending_update)
continue;
meta_kms_update_merge_from (update, crtc_frame->pending_update);
g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
}
g_hash_table_iter_init (&iter, priv->crtc_frames);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &crtc_frame))
{
crtc_frame->deadline.is_deadline_page_flip = FALSE;
crtc_frame->await_flush = FALSE;
crtc_frame->pending_page_flip = FALSE;
g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
disarm_crtc_frame_deadline_timer (crtc_frame);
}
- return do_process (impl_device, NULL, update, flags);
+ meta_thread_inhibit_realtime_in_impl (thread);
+ feedback = do_process (impl_device, NULL, update, flags);
+ meta_thread_uninhibit_realtime_in_impl (thread);
+
+ return feedback;
}
MetaKmsFeedback *
meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device,
MetaKmsUpdate *update,
MetaKmsUpdateFlag flags)
{
g_autoptr (GError) error = NULL;
if (!ensure_device_file (impl_device, &error))
{
MetaKmsFeedback *feedback = NULL;
feedback = meta_kms_feedback_new_failed (NULL, g_steal_pointer (&error));
queue_result_feedback (impl_device, update, feedback);
meta_kms_update_free (update);
return feedback;
}
meta_kms_update_realize (update, impl_device);
if (flags & META_KMS_UPDATE_FLAG_TEST_ONLY)
{
return do_process (impl_device,
meta_kms_update_get_latch_crtc (update),
update, flags);
}
else if (flags & META_KMS_UPDATE_FLAG_MODE_SET)
{
return process_mode_set_update (impl_device, update, flags);
}
else
{
g_assert_not_reached ();
}
}
void
meta_kms_impl_device_disable (MetaKmsImplDevice *impl_device)
{
MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device);
+ MetaKmsImpl *kms_impl = meta_kms_impl_device_get_impl (impl_device);
+ MetaThreadImpl *thread_impl = META_THREAD_IMPL (kms_impl);
+ MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
if (!priv->device_file)
return;
meta_kms_impl_device_hold_fd (impl_device);
+ meta_thread_inhibit_realtime_in_impl (thread);
klass->disable (impl_device);
+ meta_thread_uninhibit_realtime_in_impl (thread);
g_list_foreach (priv->crtcs,
(GFunc) meta_kms_crtc_disable_in_impl, NULL);
g_list_foreach (priv->connectors,
(GFunc) meta_kms_connector_disable_in_impl, NULL);
meta_kms_impl_device_unhold_fd (impl_device);
}
void
meta_kms_impl_device_handle_page_flip_callback (MetaKmsImplDevice *impl_device,
MetaKmsPageFlipData *page_flip_data)
{
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
klass->handle_page_flip_callback (impl_device, page_flip_data);
}
void
meta_kms_impl_device_discard_pending_page_flips (MetaKmsImplDevice *impl_device)
{
MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
klass->discard_pending_page_flips (impl_device);
}
void
meta_kms_impl_device_hold_fd (MetaKmsImplDevice *impl_device)
{
MetaKmsImplDevicePrivate *priv =
meta_kms_impl_device_get_instance_private (impl_device);
MetaKms *kms = meta_kms_device_get_kms (priv->device);
--
2.41.0

View File

@ -48,6 +48,12 @@ Patch: 3306.patch
# to fix *both* problems
Patch: 0001-Revert-x11-Use-input-region-from-frame-window-for-de.patch
# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3324
Patch: 0001-thread-Fix-preexisting-uncrustify-problem.patch
Patch: 0002-thread-For-consistency-s-real_time-realtime.patch
Patch: 0003-thread-Allow-turnning-off-rt-scheduling-for-running-.patch
Patch: 0004-kms-impl-device-Inhibit-real-time-scheduling-when-mo.patch
BuildRequires: pkgconfig(gobject-introspection-1.0) >= 1.41.0
BuildRequires: pkgconfig(polkit-gobject-1)
BuildRequires: pkgconfig(sm)