mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-28 22:18:28 +00:00
Make some changes to SDL_SetThreadPriority to try and have SDL transparently handle more of the work.
1. Comment that SDL_SetThreadPriority will make any necessary system changes when applying priority. 2. Add a hint to override SDL's default behavior for scheduler policy. 3. Modify the pthreads SDL_SetThreadPriority so that instead of just using the current thread scheduler policy it will change it to a policy that should work best for the requested priority. 4. Add hint checks in SDL_SetThreadPriority so that #3 can be overridden if desired. 5. Modify the Linux SDL_SetThreadPriority so that in the case that policy, either by SDL defaults or from the hint, is a realtime policy it uses the realtime rtkit API. 6. Prior to calling rtkit on Linux make the necessary thread state changes that rtkit requires. Currently this is done every time as it isn't expected that SDL_SetThreadPriority will be called repeatedly for a thread.
This commit is contained in:
@@ -34,6 +34,8 @@
|
||||
#include "SDL_dbus.h"
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
#include <sched.h>
|
||||
|
||||
/* d-bus queries to org.freedesktop.RealtimeKit1. */
|
||||
#define RTKIT_DBUS_NODE "org.freedesktop.RealtimeKit1"
|
||||
#define RTKIT_DBUS_PATH "/org/freedesktop/RealtimeKit1"
|
||||
@@ -41,6 +43,7 @@
|
||||
|
||||
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 void
|
||||
rtkit_initialize()
|
||||
@@ -52,10 +55,76 @@ rtkit_initialize()
|
||||
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",
|
||||
DBUS_TYPE_INT32, &rtkit_max_realtime_priority)) {
|
||||
rtkit_max_realtime_priority = 99;
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
rtkit_setpriority(pid_t thread, int nice_level)
|
||||
rtkit_initialize_thread()
|
||||
{
|
||||
// Following is an excerpt from rtkit README that outlines the requirements
|
||||
// a thread must meet before making rtkit requests:
|
||||
//
|
||||
// * Only clients with RLIMIT_RTTIME set will get RT scheduling
|
||||
//
|
||||
// * RT scheduling will only be handed out to processes with
|
||||
// SCHED_RESET_ON_FORK set to guarantee that the scheduling
|
||||
// settings cannot 'leak' to child processes, thus making sure
|
||||
// that 'RT fork bombs' cannot be used to bypass RLIMIT_RTTIME
|
||||
// and take the system down.
|
||||
//
|
||||
// * Limits are enforced on all user controllable resources, only
|
||||
// a maximum number of users, processes, threads can request RT
|
||||
// scheduling at the same time.
|
||||
//
|
||||
// * Only a limited number of threads may be made RT in a
|
||||
// specific time frame.
|
||||
//
|
||||
// * Client authorization is verified with PolicyKit
|
||||
|
||||
int err;
|
||||
struct rlimit rlimit;
|
||||
int nLimit = RLIMIT_RTTIME;
|
||||
pid_t nPid = 0; //self
|
||||
int nSchedPolicy = sched_getscheduler(nPid) | SCHED_RESET_ON_FORK;
|
||||
struct sched_param schedParam = {};
|
||||
|
||||
// Requirement #1: Set RLIMIT_RTTIME
|
||||
err = getrlimit(nLimit, &rlimit);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
rlimit.rlim_cur = rlimit.rlim_max;
|
||||
err = setrlimit(nLimit, &rlimit);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
// Requirement #2: Add SCHED_RESET_ON_FORK to the scheduler policy
|
||||
err = sched_getparam(nPid, &schedParam);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
err = sched_setscheduler(nPid, nSchedPolicy, &schedParam);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
rtkit_setpriority_nice(pid_t thread, int nice_level)
|
||||
{
|
||||
Uint64 ui64 = (Uint64)thread;
|
||||
Sint32 si32 = (Sint32)nice_level;
|
||||
@@ -66,6 +135,14 @@ rtkit_setpriority(pid_t thread, int nice_level)
|
||||
if (si32 < rtkit_min_nice_level)
|
||||
si32 = rtkit_min_nice_level;
|
||||
|
||||
// We always perform the thread state changes necessary for rtkit.
|
||||
// This wastes some system calls if the state is already set but
|
||||
// typically code sets a thread priority and leaves it so it's
|
||||
// not expected that this wasted effort will be an issue.
|
||||
// We also do not quit if this fails, we let the rtkit request
|
||||
// go through to determine whether it really needs to fail or not.
|
||||
rtkit_initialize_thread();
|
||||
|
||||
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,
|
||||
@@ -74,10 +151,38 @@ rtkit_setpriority(pid_t thread, int nice_level)
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
rtkit_setpriority_realtime(pid_t thread, int rt_priority)
|
||||
{
|
||||
Uint64 ui64 = (Uint64)thread;
|
||||
Sint32 si32 = (Sint32)rt_priority;
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
pthread_once(&rtkit_initialize_once, rtkit_initialize);
|
||||
|
||||
if (si32 > rtkit_max_realtime_priority)
|
||||
si32 = 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
|
||||
// typically code sets a thread priority and leaves it so it's
|
||||
// not expected that this wasted effort will be an issue.
|
||||
// We also do not quit if this fails, we let the rtkit request
|
||||
// go through to determine whether it really needs to fail or not.
|
||||
rtkit_initialize_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_INT32, &si32, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
#endif /* dbus */
|
||||
#endif /* threads */
|
||||
|
||||
|
||||
/* this is a public symbol, so it has to exist even if threads are disabled. */
|
||||
int
|
||||
SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
|
||||
@@ -102,7 +207,7 @@ SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
|
||||
|
||||
README and sample code at: http://git.0pointer.net/rtkit.git
|
||||
*/
|
||||
if (rtkit_setpriority((pid_t)threadID, priority)) {
|
||||
if (rtkit_setpriority_nice((pid_t)threadID, priority)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -111,6 +216,69 @@ SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* this is a public symbol, so it has to exist even if threads are disabled. */
|
||||
int
|
||||
SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy)
|
||||
{
|
||||
#if SDL_THREADS_DISABLED
|
||||
return SDL_Unsupported();
|
||||
#else
|
||||
if (schedPolicy != SCHED_RR && schedPolicy != SCHED_FIFO && setpriority(PRIO_PROCESS, (id_t)threadID, priority) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
/* Note that this fails you most likely:
|
||||
* Have your process's scheduler incorrectly configured.
|
||||
See the requirements at:
|
||||
http://git.0pointer.net/rtkit.git/tree/README#n16
|
||||
* Encountered dbus/polkit security restrictions. Note
|
||||
that the RealtimeKit1 dbus endpoint is inaccessible
|
||||
over ssh connections for most common distro configs.
|
||||
You might want to check your local config for details:
|
||||
/usr/share/polkit-1/actions/org.freedesktop.RealtimeKit1.policy
|
||||
|
||||
README and sample code at: http://git.0pointer.net/rtkit.git
|
||||
*/
|
||||
if (schedPolicy == SCHED_RR || schedPolicy == SCHED_FIFO) {
|
||||
int rtPriority;
|
||||
|
||||
if (sdlPriority == SDL_THREAD_PRIORITY_LOW) {
|
||||
rtPriority = 1;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_HIGH) {
|
||||
rtPriority = rtkit_max_realtime_priority * 3 / 4;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
|
||||
rtPriority = rtkit_max_realtime_priority;
|
||||
} else {
|
||||
rtPriority = rtkit_max_realtime_priority / 2;
|
||||
}
|
||||
|
||||
if (rtkit_setpriority_realtime((pid_t)threadID, rtPriority)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
int niceLevel;
|
||||
|
||||
if (sdlPriority == SDL_THREAD_PRIORITY_LOW) {
|
||||
niceLevel = 19;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_HIGH) {
|
||||
niceLevel = -10;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
|
||||
niceLevel = -20;
|
||||
} else {
|
||||
niceLevel = 0;
|
||||
}
|
||||
|
||||
if (rtkit_setpriority_nice((pid_t)threadID, niceLevel)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return SDL_SetError("setpriority() failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __LINUX__ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
Reference in New Issue
Block a user