diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_light_condition_variable.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_light_condition_variable.hpp index 5fdc7ac85..425714815 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_light_condition_variable.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_light_condition_variable.hpp @@ -24,40 +24,59 @@ namespace ams::kern { class KLightConditionVariable { private: - KThreadQueue m_thread_queue; + KThread::WaiterList m_wait_list; public: - constexpr ALWAYS_INLINE KLightConditionVariable() : m_thread_queue() { /* ... */ } + constexpr ALWAYS_INLINE KLightConditionVariable() : m_wait_list() { /* ... */ } private: - void WaitImpl(KLightLock *lock, s64 timeout) { + void WaitImpl(KLightLock *lock, s64 timeout, bool allow_terminating_thread) { KThread *owner = GetCurrentThreadPointer(); KHardwareTimer *timer; /* Sleep the thread. */ { KScopedSchedulerLockAndSleep lk(&timer, owner, timeout); - lock->Unlock(); - if (!m_thread_queue.SleepThread(owner)) { + if (!allow_terminating_thread && owner->IsTerminationRequested()) { lk.CancelSleep(); return; } + + lock->Unlock(); + + + /* Set the thread as waiting. */ + GetCurrentThread().SetState(KThread::ThreadState_Waiting); + + /* Add the thread to the queue. */ + m_wait_list.push_back(GetCurrentThread()); + } + + /* Remove the thread from the wait list. */ + { + KScopedSchedulerLock sl; + + m_wait_list.erase(m_wait_list.iterator_to(GetCurrentThread())); } /* Cancel the task that the sleep setup. */ if (timer != nullptr) { timer->CancelTask(owner); } + + /* Re-acquire the lock. */ + lock->Lock(); } public: - void Wait(KLightLock *lock, s64 timeout = -1ll) { - this->WaitImpl(lock, timeout); - lock->Lock(); + void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true) { + this->WaitImpl(lock, timeout, allow_terminating_thread); } void Broadcast() { KScopedSchedulerLock lk; - while (m_thread_queue.WakeupFrontThread() != nullptr) { - /* We want to signal all threads, and so should continue waking up until there's nothing to wake. */ + + /* Signal all threads. */ + for (auto &thread : m_wait_list) { + thread.SetState(KThread::ThreadState_Runnable); } } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp index e6860023d..3ad3abb90 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp @@ -492,7 +492,7 @@ namespace ams::kern::board::nintendo::nx { /* Wait for a request. */ { KScopedLightLock lk(g_cv_lock); - while (!(g_sleep_target_cores & target_core_mask)) { + while ((g_sleep_target_cores & target_core_mask) == 0) { g_cv.Wait(std::addressof(g_cv_lock)); } } diff --git a/libraries/libmesosphere/source/kern_k_resource_limit.cpp b/libraries/libmesosphere/source/kern_k_resource_limit.cpp index 04cf4873b..9b4941084 100644 --- a/libraries/libmesosphere/source/kern_k_resource_limit.cpp +++ b/libraries/libmesosphere/source/kern_k_resource_limit.cpp @@ -146,8 +146,12 @@ namespace ams::kern { if (m_current_hints[which] + value <= m_limit_values[which] && (timeout < 0 || KHardwareTimer::GetTick() < timeout)) { m_waiter_count++; - m_cond_var.Wait(&m_lock, timeout); + m_cond_var.Wait(&m_lock, timeout, false); m_waiter_count--; + + if (GetCurrentThread().IsTerminationRequested()) { + return false; + } } else { break; }