diff options
author | bunnei <bunneidev@gmail.com> | 2021-11-10 05:54:44 +0100 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2021-12-07 01:39:17 +0100 |
commit | 5dff28290fc4fc9bc3db3c32476dd93b2c4414c6 (patch) | |
tree | 45bccef430ad51ccef88b66036f511d8f52964d0 /src/core/hle/kernel/k_light_condition_variable.cpp | |
parent | hle: kernel: KLightLock: Migrate to updated KThreadQueue. (diff) | |
download | yuzu-5dff28290fc4fc9bc3db3c32476dd93b2c4414c6.tar yuzu-5dff28290fc4fc9bc3db3c32476dd93b2c4414c6.tar.gz yuzu-5dff28290fc4fc9bc3db3c32476dd93b2c4414c6.tar.bz2 yuzu-5dff28290fc4fc9bc3db3c32476dd93b2c4414c6.tar.lz yuzu-5dff28290fc4fc9bc3db3c32476dd93b2c4414c6.tar.xz yuzu-5dff28290fc4fc9bc3db3c32476dd93b2c4414c6.tar.zst yuzu-5dff28290fc4fc9bc3db3c32476dd93b2c4414c6.zip |
Diffstat (limited to 'src/core/hle/kernel/k_light_condition_variable.cpp')
-rw-r--r-- | src/core/hle/kernel/k_light_condition_variable.cpp | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp new file mode 100644 index 000000000..9ff710084 --- /dev/null +++ b/src/core/hle/kernel/k_light_condition_variable.cpp @@ -0,0 +1,80 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_light_condition_variable.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_thread_queue.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +namespace { + +class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { +private: + KThread::WaiterList* m_wait_list; + bool m_allow_terminating_thread; + +public: + ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl, + bool term) + : KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {} + + virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, + bool cancel_timer_task) override { + // Only process waits if we're allowed to. + if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) { + return; + } + + // Remove the thread from the waiting thread from the light condition variable. + m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + +} // namespace + +void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { + // Create thread queue. + KThread* owner = GetCurrentThreadPointer(kernel); + + ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list), + allow_terminating_thread); + + // Sleep the thread. + { + KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); + + if (!allow_terminating_thread && owner->IsTerminationRequested()) { + lk.CancelSleep(); + return; + } + + lock->Unlock(); + + // Add the thread to the queue. + wait_list.push_back(*owner); + + // Begin waiting. + owner->BeginWait(std::addressof(wait_queue)); + } + + // Re-acquire the lock. + lock->Lock(); +} + +void KLightConditionVariable::Broadcast() { + KScopedSchedulerLock lk(kernel); + + // Signal all threads. + for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) { + it->EndWait(ResultSuccess); + } +} + +} // namespace Kernel |