From 763b160c7aefb0d8fb34911986716351adfcf829 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:23:27 +0900 Subject: [PATCH] [Threading/Linux] Add fallback to nice values SCHED_FIFO requires CAP_SYS_NICE or root, try SCHED_FIFO first for real-time priority control, then fall back to setpriority() nice values if permission is denied. --- src/xenia/base/threading_posix.cc | 60 +++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/src/xenia/base/threading_posix.cc b/src/xenia/base/threading_posix.cc index 630e822a3..565a39a5f 100644 --- a/src/xenia/base/threading_posix.cc +++ b/src/xenia/base/threading_posix.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -611,6 +612,7 @@ class PosixCondition final : public PosixConditionBase { /// Thread::GetCurrentThread() on the main thread explicit PosixCondition(pthread_t thread) : thread_(thread), + tid_(static_cast(syscall(SYS_gettid))), signaled_(false), exit_code_(0), state_(State::kRunning), @@ -742,31 +744,48 @@ class PosixCondition final : public PosixConditionBase { int priority() const { WaitStarted(); - int policy; - sched_param param{}; - int ret = pthread_getschedparam(thread_, &policy, ¶m); - if (ret != 0) { - return -1; + if (!fifo_failed_) { + int policy; + sched_param param{}; + int ret = pthread_getschedparam(thread_, &policy, ¶m); + if (ret != 0) { + return -1; + } + return param.sched_priority; } - - return param.sched_priority; + // When using nice values, map back to the SCHED_FIFO range (1-32) + // so callers see a consistent priority space. + int nice_val = getpriority(PRIO_PROCESS, tid_); + // nice -19..19 → fifo 32..1 + return 16 - nice_val; } void set_priority(int new_priority) const { WaitStarted(); - sched_param param{}; - param.sched_priority = new_priority; - int res = pthread_setschedparam(thread_, SCHED_FIFO, ¶m); - if (res != 0) { - switch (res) { - case EPERM: - XELOGW("Permission denied while setting priority"); - break; - case EINVAL: - assert_always(); - default: - XELOGW("Unknown error while setting priority"); + if (!fifo_failed_) { + // Try real-time SCHED_FIFO for best priority control. + sched_param param{}; + param.sched_priority = new_priority; + int res = pthread_setschedparam(thread_, SCHED_FIFO, ¶m); + if (res == 0) { + return; } + if (res == EPERM) { + fifo_failed_ = true; + } else { + XELOGW("Unexpected error {} while setting SCHED_FIFO priority", res); + fifo_failed_ = true; + } + } + // Fall back to nice values under SCHED_OTHER. + // Map SCHED_FIFO range (1-32) to nice range (19 to -19). + // Center: fifo 16 → nice 0. + int nice_val = 16 - new_priority; + // Clamp to valid nice range. + if (nice_val < -20) nice_val = -20; + if (nice_val > 19) nice_val = 19; + if (tid_ > 0) { + setpriority(PRIO_PROCESS, tid_, nice_val); } } @@ -930,6 +949,8 @@ class PosixCondition final : public PosixConditionBase { sem_destroy(&suspend_sem_); } pthread_t thread_; + pid_t tid_ = 0; // Kernel TID for setpriority() fallback + mutable bool fifo_failed_ = false; // True after SCHED_FIFO was rejected bool signaled_; int exit_code_; State state_; // Protected by state_mutex_ @@ -1243,6 +1264,7 @@ void* PosixCondition::ThreadStartRoutine(void* parameter) { delete start_data; current_thread_ = thread; + thread->handle_.tid_ = static_cast(syscall(SYS_gettid)); { std::unique_lock lock(thread->handle_.state_mutex_); thread->handle_.state_ =