1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-11-17 17:36:44 +00:00

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 { class KLightConditionVariable {
private: private:
KThreadQueue m_thread_queue; KThread::WaiterList m_wait_list;
public: public:
constexpr ALWAYS_INLINE KLightConditionVariable() : m_thread_queue() { /* ... */ } constexpr ALWAYS_INLINE KLightConditionVariable() : m_wait_list() { /* ... */ }
private: private:
void WaitImpl(KLightLock *lock, s64 timeout) { void WaitImpl(KLightLock *lock, s64 timeout, bool allow_terminating_thread) {
KThread *owner = GetCurrentThreadPointer(); KThread *owner = GetCurrentThreadPointer();
KHardwareTimer *timer; KHardwareTimer *timer;
/* Sleep the thread. */ /* Sleep the thread. */
{ {
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout); KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
lock->Unlock();
if (!m_thread_queue.SleepThread(owner)) { if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep(); lk.CancelSleep();
return; 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. */ /* Cancel the task that the sleep setup. */
if (timer != nullptr) { if (timer != nullptr) {
timer->CancelTask(owner); timer->CancelTask(owner);
} }
/* Re-acquire the lock. */
lock->Lock();
} }
public: public:
void Wait(KLightLock *lock, s64 timeout = -1ll) { void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true) {
this->WaitImpl(lock, timeout); this->WaitImpl(lock, timeout, allow_terminating_thread);
lock->Lock();
} }
void Broadcast() { void Broadcast() {
KScopedSchedulerLock lk; 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. */ /* Wait for a request. */
{ {
KScopedLightLock lk(g_cv_lock); 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)); 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)) { if (m_current_hints[which] + value <= m_limit_values[which] && (timeout < 0 || KHardwareTimer::GetTick() < timeout)) {
m_waiter_count++; m_waiter_count++;
m_cond_var.Wait(&m_lock, timeout); m_cond_var.Wait(&m_lock, timeout, false);
m_waiter_count--; m_waiter_count--;
if (GetCurrentThread().IsTerminationRequested()) {
return false;
}
} else { } else {
break; break;
} }