core: linux: Favor xdg-desktop-portal for elevating thread priority Use the xdg-desktop-portal interface to RealtimeKit1, when available, to set realtime scheduling and elevated priority for threads. This portal allows for the use of rtkit within containers such as Flatpak. It will fall back to using RealtimeKit1 directly if the xdg-desktop-portal interface is too old or not available.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
diff --git a/src/core/linux/SDL_threadprio.c b/src/core/linux/SDL_threadprio.c
index 9009d5d..73abbc8 100644
--- a/src/core/linux/SDL_threadprio.c
+++ b/src/core/linux/SDL_threadprio.c
@@ -30,6 +30,7 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <pthread.h>
+#include <unistd.h>
#include "SDL_system.h"
/* RLIMIT_RTTIME requires kernel >= 2.6.25 and is in glibc >= 2.14 */
@@ -51,30 +52,72 @@
#define RTKIT_DBUS_PATH "/org/freedesktop/RealtimeKit1"
#define RTKIT_DBUS_INTERFACE "org.freedesktop.RealtimeKit1"
+/* d-bus queries to the XDG portal interface to RealtimeKit1 */
+#define XDG_PORTAL_DBUS_NODE "org.freedesktop.portal.Desktop"
+#define XDG_PORTAL_DBUS_PATH "/org/freedesktop/portal/desktop"
+#define XDG_PORTAL_DBUS_INTERFACE "org.freedesktop.portal.Realtime"
+
+static DBusConnection *rtkit_dbus_conn;
+static const char *rtkit_dbus_node;
+static const char *rtkit_dbus_path;
+static const char *rtkit_dbus_interface;
+
static pthread_once_t rtkit_initialize_once = PTHREAD_ONCE_INIT;
static Sint32 rtkit_min_nice_level = -20;
static Sint32 rtkit_max_realtime_priority = 99;
static Sint64 rtkit_max_rttime_usec = 200000;
+/*
+ * Checking that the RTTimeUSecMax property exists and is an int64 confirms that:
+ * - The desktop portal exists and supports the realtime interface.
+ * - The realtime interface is new enough to have the required bug fixes applied.
+ */
+static SDL_bool
+realtime_portal_supported(DBusConnection *conn)
+{
+ Sint64 res;
+ return SDL_DBus_QueryPropertyOnConnection(conn, XDG_PORTAL_DBUS_NODE, XDG_PORTAL_DBUS_PATH, XDG_PORTAL_DBUS_INTERFACE,
+ "RTTimeUSecMax", DBUS_TYPE_INT64, &res);
+}
+
static void
-rtkit_initialize()
+set_rtkit_interface()
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
+ /* xdg-desktop-portal works in all instances, so check for it first. */
+ if (dbus && realtime_portal_supported(dbus->session_conn)) {
+ rtkit_dbus_conn = dbus->session_conn;
+ rtkit_dbus_node = XDG_PORTAL_DBUS_NODE;
+ rtkit_dbus_path = XDG_PORTAL_DBUS_PATH;
+ rtkit_dbus_interface = XDG_PORTAL_DBUS_INTERFACE;
+ } else { /* Fall back to the standard rtkit interface in all other cases. */
+ rtkit_dbus_conn = dbus ? dbus->system_conn : NULL;
+ rtkit_dbus_node = RTKIT_DBUS_NODE;
+ rtkit_dbus_path = RTKIT_DBUS_PATH;
+ rtkit_dbus_interface = RTKIT_DBUS_INTERFACE;
+ }
+}
+
+static void
+rtkit_initialize()
+{
+ set_rtkit_interface();
+
/* Try getting minimum nice level: this is often greater than PRIO_MIN (-20). */
- if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MinNiceLevel",
+ if (!rtkit_dbus_conn || !SDL_DBus_QueryPropertyOnConnection(rtkit_dbus_conn, rtkit_dbus_node, rtkit_dbus_path, rtkit_dbus_interface, "MinNiceLevel",
DBUS_TYPE_INT32, &rtkit_min_nice_level)) {
rtkit_min_nice_level = -20;
}
/* Try getting maximum realtime priority: this can be less than the POSIX default (99). */
- if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MaxRealtimePriority",
+ if (!rtkit_dbus_conn || !SDL_DBus_QueryPropertyOnConnection(rtkit_dbus_conn, rtkit_dbus_node, rtkit_dbus_path, rtkit_dbus_interface, "MaxRealtimePriority",
DBUS_TYPE_INT32, &rtkit_max_realtime_priority)) {
rtkit_max_realtime_priority = 99;
}
/* Try getting maximum rttime allowed by rtkit: exceeding this value will result in SIGKILL */
- if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "RTTimeUSecMax",
+ if (!rtkit_dbus_conn || !SDL_DBus_QueryPropertyOnConnection(rtkit_dbus_conn, rtkit_dbus_node, rtkit_dbus_path, rtkit_dbus_interface, "RTTimeUSecMax",
DBUS_TYPE_INT64, &rtkit_max_rttime_usec)) {
rtkit_max_rttime_usec = 200000;
}
@@ -147,18 +190,18 @@ rtkit_initialize_realtime_thread()
static SDL_bool
rtkit_setpriority_nice(pid_t thread, int nice_level)
{
- Uint64 ui64 = (Uint64)thread;
- Sint32 si32 = (Sint32)nice_level;
- SDL_DBusContext *dbus = SDL_DBus_GetContext();
+ Uint64 pid = (Uint64)getpid();
+ Uint64 tid = (Uint64)thread;
+ Sint32 nice = (Sint32)nice_level;
pthread_once(&rtkit_initialize_once, rtkit_initialize);
- if (si32 < rtkit_min_nice_level)
- si32 = rtkit_min_nice_level;
+ if (nice < rtkit_min_nice_level)
+ nice = rtkit_min_nice_level;
- if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn,
- RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadHighPriority",
- DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_INT32, &si32, DBUS_TYPE_INVALID,
+ if (!rtkit_dbus_conn || !SDL_DBus_CallMethodOnConnection(rtkit_dbus_conn,
+ rtkit_dbus_node, rtkit_dbus_path, rtkit_dbus_interface, "MakeThreadHighPriorityWithPID",
+ DBUS_TYPE_UINT64, &pid, DBUS_TYPE_UINT64, &tid, DBUS_TYPE_INT32, &nice, DBUS_TYPE_INVALID,
DBUS_TYPE_INVALID)) {
return SDL_FALSE;
}
@@ -168,14 +211,14 @@ rtkit_setpriority_nice(pid_t thread, int nice_level)
static SDL_bool
rtkit_setpriority_realtime(pid_t thread, int rt_priority)
{
- Uint64 ui64 = (Uint64)thread;
- Uint32 ui32 = (Uint32)rt_priority;
- SDL_DBusContext *dbus = SDL_DBus_GetContext();
+ Uint64 pid = (Uint64)getpid();
+ Uint64 tid = (Uint64)thread;
+ Uint32 priority = (Uint32)rt_priority;
pthread_once(&rtkit_initialize_once, rtkit_initialize);
- if (ui32 > rtkit_max_realtime_priority)
- ui32 = rtkit_max_realtime_priority;
+ if (priority > rtkit_max_realtime_priority)
+ priority = rtkit_max_realtime_priority;
// We always perform the thread state changes necessary for rtkit.
// This wastes some system calls if the state is already set but
@@ -185,9 +228,9 @@ rtkit_setpriority_realtime(pid_t thread, int rt_priority)
// go through to determine whether it really needs to fail or not.
rtkit_initialize_realtime_thread();
- if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn,
- RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadRealtime",
- DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_UINT32, &ui32, DBUS_TYPE_INVALID,
+ if (!rtkit_dbus_conn || !SDL_DBus_CallMethodOnConnection(rtkit_dbus_conn,
+ rtkit_dbus_node, rtkit_dbus_path, rtkit_dbus_interface, "MakeThreadRealtimeWithPID",
+ DBUS_TYPE_UINT64, &pid, DBUS_TYPE_UINT64, &tid, DBUS_TYPE_UINT32, &priority, DBUS_TYPE_INVALID,
DBUS_TYPE_INVALID)) {
return SDL_FALSE;
}