From 5a4fc4a5299a3835a57ae8a35c6de51459df70c0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 15 Jan 2021 21:58:44 -0800 Subject: core: hle: kernel: Implement KLightLock. --- src/core/hle/kernel/k_light_lock.cpp | 130 +++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/core/hle/kernel/k_light_lock.cpp (limited to 'src/core/hle/kernel/k_light_lock.cpp') diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp new file mode 100644 index 000000000..08fa65fd5 --- /dev/null +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -0,0 +1,130 @@ +// 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_lock.h" +#include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +void KLightLock::Lock() { + const uintptr_t cur_thread = reinterpret_cast(GetCurrentThreadPointer(kernel)); + const uintptr_t cur_thread_tag = (cur_thread | 1); + + while (true) { + uintptr_t old_tag = tag.load(std::memory_order_relaxed); + + while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1, + std::memory_order_acquire)) { + if ((old_tag | 1) == cur_thread_tag) { + return; + } + } + + if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) { + break; + } + + LockSlowPath(old_tag | 1, cur_thread); + } +} + +void KLightLock::Unlock() { + const uintptr_t cur_thread = reinterpret_cast(GetCurrentThreadPointer(kernel)); + uintptr_t expected = cur_thread; + do { + if (expected != cur_thread) { + return UnlockSlowPath(cur_thread); + } + } while (!tag.compare_exchange_weak(expected, 0, std::memory_order_release)); +} + +void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { + KThread* cur_thread = reinterpret_cast(_cur_thread); + + // Pend the current thread waiting on the owner thread. + { + KScopedSchedulerLock sl{kernel}; + + // Ensure we actually have locking to do. + if (tag.load(std::memory_order_relaxed) != _owner) { + return; + } + + // Add the current thread as a waiter on the owner. + KThread* owner_thread = reinterpret_cast(_owner & ~1ul); + cur_thread->SetAddressKey(reinterpret_cast(std::addressof(tag))); + owner_thread->AddWaiter(cur_thread); + + // Set thread states. + if (cur_thread->GetState() == ThreadState::Runnable) { + cur_thread->SetState(ThreadState::Waiting); + } else { + KScheduler::SetSchedulerUpdateNeeded(kernel); + } + + if (owner_thread->IsSuspended()) { + owner_thread->ContinueIfHasKernelWaiters(); + KScheduler::SetSchedulerUpdateNeeded(kernel); + } + } + + // We're no longer waiting on the lock owner. + { + KScopedSchedulerLock sl{kernel}; + KThread* owner_thread = cur_thread->GetLockOwner(); + if (owner_thread) { + owner_thread->RemoveWaiter(cur_thread); + } + } +} + +void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { + KThread* owner_thread = reinterpret_cast(_cur_thread); + + // Unlock. + { + KScopedSchedulerLock sl{kernel}; + + // Get the next owner. + s32 num_waiters = 0; + KThread* next_owner = owner_thread->RemoveWaiterByKey( + std::addressof(num_waiters), reinterpret_cast(std::addressof(tag))); + + // Pass the lock to the next owner. + uintptr_t next_tag = 0; + if (next_owner) { + next_tag = reinterpret_cast(next_owner); + if (num_waiters > 1) { + next_tag |= 0x1; + } + + if (next_owner->GetState() == ThreadState::Waiting) { + next_owner->SetState(ThreadState::Runnable); + } else { + KScheduler::SetSchedulerUpdateNeeded(kernel); + } + + if (next_owner->IsSuspended()) { + next_owner->ContinueIfHasKernelWaiters(); + } + } + + // We may have unsuspended in the process of acquiring the lock, so we'll re-suspend now if + // so. + if (owner_thread->IsSuspended()) { + owner_thread->TrySuspend(); + } + + // Write the new tag value. + tag.store(next_tag); + } +} + +bool KLightLock::IsLockedByCurrentThread() const { + return (tag | 0x1ul) == (reinterpret_cast(GetCurrentThreadPointer(kernel)) | 0x1ul); +} + +} // namespace Kernel -- cgit v1.2.3 From 1f99f5473c7a03c791ea20256c7fc2f1caba8adc Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 19 Jan 2021 21:07:07 -0800 Subject: kernel: k_light_lock: Simplify EmuThreadHandle implementation. --- src/core/hle/kernel/k_light_lock.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/k_light_lock.cpp') diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 08fa65fd5..1d54ba5df 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -9,6 +9,12 @@ namespace Kernel { +static KThread* ToThread(uintptr_t thread_) { + ASSERT((thread_ & EmuThreadHandleReserved) == 0); + ASSERT((thread_ & 1) == 0); + return reinterpret_cast(thread_); +} + void KLightLock::Lock() { const uintptr_t cur_thread = reinterpret_cast(GetCurrentThreadPointer(kernel)); const uintptr_t cur_thread_tag = (cur_thread | 1); @@ -42,7 +48,7 @@ void KLightLock::Unlock() { } void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { - KThread* cur_thread = reinterpret_cast(_cur_thread); + KThread* cur_thread = ToThread(_cur_thread); // Pend the current thread waiting on the owner thread. { @@ -54,7 +60,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } // Add the current thread as a waiter on the owner. - KThread* owner_thread = reinterpret_cast(_owner & ~1ul); + KThread* owner_thread = ToThread(_owner & ~1ul); cur_thread->SetAddressKey(reinterpret_cast(std::addressof(tag))); owner_thread->AddWaiter(cur_thread); @@ -82,7 +88,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { - KThread* owner_thread = reinterpret_cast(_cur_thread); + KThread* owner_thread = ToThread(_cur_thread); // Unlock. { -- cgit v1.2.3 From 6e953f7f0294d945ba9d6f08350d5dccb0d76075 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 21 Jan 2021 13:00:16 -0800 Subject: hle: kernel: Allocate a dummy KThread for each host thread, and use it for scheduling. --- src/core/hle/kernel/k_light_lock.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel/k_light_lock.cpp') diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 1d54ba5df..08fa65fd5 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -9,12 +9,6 @@ namespace Kernel { -static KThread* ToThread(uintptr_t thread_) { - ASSERT((thread_ & EmuThreadHandleReserved) == 0); - ASSERT((thread_ & 1) == 0); - return reinterpret_cast(thread_); -} - void KLightLock::Lock() { const uintptr_t cur_thread = reinterpret_cast(GetCurrentThreadPointer(kernel)); const uintptr_t cur_thread_tag = (cur_thread | 1); @@ -48,7 +42,7 @@ void KLightLock::Unlock() { } void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { - KThread* cur_thread = ToThread(_cur_thread); + KThread* cur_thread = reinterpret_cast(_cur_thread); // Pend the current thread waiting on the owner thread. { @@ -60,7 +54,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } // Add the current thread as a waiter on the owner. - KThread* owner_thread = ToThread(_owner & ~1ul); + KThread* owner_thread = reinterpret_cast(_owner & ~1ul); cur_thread->SetAddressKey(reinterpret_cast(std::addressof(tag))); owner_thread->AddWaiter(cur_thread); @@ -88,7 +82,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { - KThread* owner_thread = ToThread(_cur_thread); + KThread* owner_thread = reinterpret_cast(_cur_thread); // Unlock. { -- cgit v1.2.3 From 543e2125541aa3c3399dd471cd170153ce67c369 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 28 Jan 2021 21:53:21 -0800 Subject: hle: kernel: KLightLock: Fix several bugs. --- src/core/hle/kernel/k_light_lock.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/k_light_lock.cpp') diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 08fa65fd5..f974022e8 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -54,7 +54,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } // Add the current thread as a waiter on the owner. - KThread* owner_thread = reinterpret_cast(_owner & ~1ul); + KThread* owner_thread = reinterpret_cast(_owner & ~1ULL); cur_thread->SetAddressKey(reinterpret_cast(std::addressof(tag))); owner_thread->AddWaiter(cur_thread); @@ -67,7 +67,6 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { if (owner_thread->IsSuspended()) { owner_thread->ContinueIfHasKernelWaiters(); - KScheduler::SetSchedulerUpdateNeeded(kernel); } } @@ -77,6 +76,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { KThread* owner_thread = cur_thread->GetLockOwner(); if (owner_thread) { owner_thread->RemoveWaiter(cur_thread); + KScheduler::SetSchedulerUpdateNeeded(kernel); } } } @@ -124,7 +124,7 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { } bool KLightLock::IsLockedByCurrentThread() const { - return (tag | 0x1ul) == (reinterpret_cast(GetCurrentThreadPointer(kernel)) | 0x1ul); + return (tag | 1ULL) == (reinterpret_cast(GetCurrentThreadPointer(kernel)) | 1ULL); } } // namespace Kernel -- cgit v1.2.3