mirror of https://github.com/encounter/SDL.git
Fix process randomly getting killed when SDL_THREAD_PRIORITY_HIGH/TIME_CRITICAL is set
When we request realtime priority from rtkit, we have a rttime limit. If we exceed that limit, the kernel will send SIGKILL to the process to terminate it. This isn't something that most high priority processes will want, only processes that selectively opt into SCHED_RR/FIFO through SDL_HINT_THREAD_PRIORITY_POLICY should be subject to this level of scrutiny. This change: * Switches non-apple posix OSs to use SCHED_OTHER instead of SCHED_RR for SDL_THREAD_PRIORITY_HIGH/SDL_THREAD_PRIORITY_TIME_CRITICAL. * Fixes using a hardcoded RLIMIT_RTTIME, instead queries it from rtkit * Only sets RLIMIT_RTTIME for MakeRealtime rtkit requests * Adds a note regarding the possible SIGKILL with SDL_HINT_THREAD_PRIORITY_POLICY * Introduces SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL to allow apps to acquire realtime scheduling policies on Linux
This commit is contained in:
parent
59795822d0
commit
07eae7d670
|
@ -799,9 +799,32 @@ extern "C" {
|
||||||
*
|
*
|
||||||
* pthread hint values are "current", "other", "fifo" and "rr".
|
* pthread hint values are "current", "other", "fifo" and "rr".
|
||||||
* Currently no other platform hint values are defined but may be in the future.
|
* Currently no other platform hint values are defined but may be in the future.
|
||||||
|
*
|
||||||
|
* \note On Linux, the kernel may send SIGKILL to realtime tasks which exceed the distro
|
||||||
|
* configured execution budget for rtkit. This budget is queriably through RLIMIT_RTTIME
|
||||||
|
* after calling SDL_SetThreadPriority().
|
||||||
*/
|
*/
|
||||||
#define SDL_HINT_THREAD_PRIORITY_POLICY "SDL_THREAD_PRIORITY_POLICY"
|
#define SDL_HINT_THREAD_PRIORITY_POLICY "SDL_THREAD_PRIORITY_POLICY"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Specifies whether SDL_THREAD_PRIORITY_TIME_CRITICAL should be treated as realtime.
|
||||||
|
*
|
||||||
|
* On some platforms, like Linux, a realtime priority thread may be subject to restrictions
|
||||||
|
* that require special handling by the application. This hint exists to let SDL know that
|
||||||
|
* the app is prepared to handle said restrictions.
|
||||||
|
*
|
||||||
|
* On Linux, SDL will apply the following configuration to any thread that becomes realtime:
|
||||||
|
* * The SCHED_RESET_ON_FORK bit will be set on the scheduling policy,
|
||||||
|
* * An RLIMIT_RTTIME budget will be configured to the rtkit specified limit.
|
||||||
|
* * Exceeding this limit will result in the kernel sending SIGKILL to the app,
|
||||||
|
* * Refer to the man pages for more information.
|
||||||
|
*
|
||||||
|
* This variable can be set to the following values:
|
||||||
|
* "0" - default platform specific behaviour
|
||||||
|
* "1" - Force SDL_THREAD_PRIORITY_TIME_CRITICAL to a realtime scheduling policy
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL "SDL_THREAD_FORCE_REALTIME_TIME_CRITICAL"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac and iOS)
|
* \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac and iOS)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
static pthread_once_t rtkit_initialize_once = PTHREAD_ONCE_INIT;
|
static pthread_once_t rtkit_initialize_once = PTHREAD_ONCE_INIT;
|
||||||
static Sint32 rtkit_min_nice_level = -20;
|
static Sint32 rtkit_min_nice_level = -20;
|
||||||
static Sint32 rtkit_max_realtime_priority = 99;
|
static Sint32 rtkit_max_realtime_priority = 99;
|
||||||
|
static Sint64 rtkit_max_rttime_usec = 200000;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rtkit_initialize()
|
rtkit_initialize()
|
||||||
|
@ -67,10 +68,16 @@ rtkit_initialize()
|
||||||
DBUS_TYPE_INT32, &rtkit_max_realtime_priority)) {
|
DBUS_TYPE_INT32, &rtkit_max_realtime_priority)) {
|
||||||
rtkit_max_realtime_priority = 99;
|
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",
|
||||||
|
DBUS_TYPE_INT64, &rtkit_max_rttime_usec)) {
|
||||||
|
rtkit_max_rttime_usec = 200000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
rtkit_initialize_thread()
|
rtkit_initialize_realtime_thread()
|
||||||
{
|
{
|
||||||
// Following is an excerpt from rtkit README that outlines the requirements
|
// Following is an excerpt from rtkit README that outlines the requirements
|
||||||
// a thread must meet before making rtkit requests:
|
// a thread must meet before making rtkit requests:
|
||||||
|
@ -107,7 +114,8 @@ rtkit_initialize_thread()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current rtkit allows a max of 200ms right now
|
// Current rtkit allows a max of 200ms right now
|
||||||
rlimit.rlim_cur = rlimit.rlim_max = 100000;
|
rlimit.rlim_max = rtkit_max_rttime_usec;
|
||||||
|
rlimit.rlim_cur = rlimit.rlim_max / 2;
|
||||||
err = setrlimit(nLimit, &rlimit);
|
err = setrlimit(nLimit, &rlimit);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
@ -142,14 +150,6 @@ rtkit_setpriority_nice(pid_t thread, int nice_level)
|
||||||
if (si32 < rtkit_min_nice_level)
|
if (si32 < rtkit_min_nice_level)
|
||||||
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,
|
if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn,
|
||||||
RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadHighPriority",
|
RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadHighPriority",
|
||||||
DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_INT32, &si32, DBUS_TYPE_INVALID,
|
DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_INT32, &si32, DBUS_TYPE_INVALID,
|
||||||
|
@ -177,7 +177,7 @@ rtkit_setpriority_realtime(pid_t thread, int rt_priority)
|
||||||
// not expected that this wasted effort will be an issue.
|
// not expected that this wasted effort will be an issue.
|
||||||
// We also do not quit if this fails, we let the rtkit request
|
// 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.
|
// go through to determine whether it really needs to fail or not.
|
||||||
rtkit_initialize_thread();
|
rtkit_initialize_realtime_thread();
|
||||||
|
|
||||||
if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn,
|
if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn,
|
||||||
RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadRealtime",
|
RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadRealtime",
|
||||||
|
|
|
@ -208,6 +208,7 @@ SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
|
||||||
int pri_policy;
|
int pri_policy;
|
||||||
pthread_t thread = pthread_self();
|
pthread_t thread = pthread_self();
|
||||||
const char *policyhint = SDL_GetHint(SDL_HINT_THREAD_PRIORITY_POLICY);
|
const char *policyhint = SDL_GetHint(SDL_HINT_THREAD_PRIORITY_POLICY);
|
||||||
|
const SDL_bool allow_realtime_hint = SDL_GetHintBoolean(SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL, SDL_FALSE);
|
||||||
|
|
||||||
if (pthread_getschedparam(thread, &policy, &sched) != 0) {
|
if (pthread_getschedparam(thread, &policy, &sched) != 0) {
|
||||||
return SDL_SetError("pthread_getschedparam() failed");
|
return SDL_SetError("pthread_getschedparam() failed");
|
||||||
|
@ -223,8 +224,14 @@ SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
|
||||||
break;
|
break;
|
||||||
case SDL_THREAD_PRIORITY_HIGH:
|
case SDL_THREAD_PRIORITY_HIGH:
|
||||||
case SDL_THREAD_PRIORITY_TIME_CRITICAL:
|
case SDL_THREAD_PRIORITY_TIME_CRITICAL:
|
||||||
|
#if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)
|
||||||
|
/* Apple requires SCHED_RR for high priority threads */
|
||||||
pri_policy = SCHED_RR;
|
pri_policy = SCHED_RR;
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
pri_policy = allow_realtime_hint ? SCHED_RR : SCHED_OTHER;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
pri_policy = policy;
|
pri_policy = policy;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue