kern: update KLightConditionVariable

This commit is contained in:
Michael Scire 2021-04-07 14:35:26 -07:00 committed by SciresM
parent b4498734e4
commit c62a7381f8
3 changed files with 35 additions and 12 deletions

View file

@ -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);
}
}

View file

@ -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));
}
}

View file

@ -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;
}