diff --git a/src/core/linux/SDL_threadprio.c b/src/core/linux/SDL_threadprio.c index 9009d5dfc..73abbc8f3 100644 --- a/src/core/linux/SDL_threadprio.c +++ b/src/core/linux/SDL_threadprio.c @@ -30,6 +30,7 @@ #include #include #include +#include #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; }