Disable realtime scheduling during modesets (#2240457)
This commit is contained in:
parent
7d552b76c5
commit
11f29e2c83
57
0001-thread-Fix-preexisting-uncrustify-problem.patch
Normal file
57
0001-thread-Fix-preexisting-uncrustify-problem.patch
Normal 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
|
||||
|
149
0002-thread-For-consistency-s-real_time-realtime.patch
Normal file
149
0002-thread-For-consistency-s-real_time-realtime.patch
Normal 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
|
||||
|
630
0003-thread-Allow-turnning-off-rt-scheduling-for-running-.patch
Normal file
630
0003-thread-Allow-turnning-off-rt-scheduling-for-running-.patch
Normal 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
|
||||
|
183
0004-kms-impl-device-Inhibit-real-time-scheduling-when-mo.patch
Normal file
183
0004-kms-impl-device-Inhibit-real-time-scheduling-when-mo.patch
Normal 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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user