mirror of https://git.suyu.dev/suyu/suyu
kernel: convert KConditionVariable, KLightConditionVariable, KLightLock
This commit is contained in:
parent
097c25b164
commit
fdf90c6d75
|
@ -45,7 +45,7 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si
|
||||||
m_is_mapped = false;
|
m_is_mapped = false;
|
||||||
|
|
||||||
// We succeeded.
|
// We succeeded.
|
||||||
return ResultSuccess;
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void KCodeMemory::Finalize() {
|
void KCodeMemory::Finalize() {
|
||||||
|
@ -80,7 +80,7 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
|
||||||
// Mark ourselves as mapped.
|
// Mark ourselves as mapped.
|
||||||
m_is_mapped = true;
|
m_is_mapped = true;
|
||||||
|
|
||||||
return ResultSuccess;
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KCodeMemory::Unmap(VAddr address, size_t size) {
|
Result KCodeMemory::Unmap(VAddr address, size_t size) {
|
||||||
|
@ -97,7 +97,7 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) {
|
||||||
// Mark ourselves as unmapped.
|
// Mark ourselves as unmapped.
|
||||||
m_is_mapped = false;
|
m_is_mapped = false;
|
||||||
|
|
||||||
return ResultSuccess;
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
|
Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
|
||||||
|
@ -131,7 +131,7 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission
|
||||||
// Mark ourselves as mapped.
|
// Mark ourselves as mapped.
|
||||||
m_is_owner_mapped = true;
|
m_is_owner_mapped = true;
|
||||||
|
|
||||||
return ResultSuccess;
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
|
Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
|
||||||
|
@ -147,7 +147,7 @@ Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
|
||||||
// Mark ourselves as unmapped.
|
// Mark ourselves as unmapped.
|
||||||
m_is_owner_mapped = false;
|
m_is_owner_mapped = false;
|
||||||
|
|
||||||
return ResultSuccess;
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -98,17 +98,17 @@ public:
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
KConditionVariable::KConditionVariable(Core::System& system_)
|
KConditionVariable::KConditionVariable(Core::System& system)
|
||||||
: system{system_}, kernel{system.Kernel()} {}
|
: m_system{system}, m_kernel{system.Kernel()} {}
|
||||||
|
|
||||||
KConditionVariable::~KConditionVariable() = default;
|
KConditionVariable::~KConditionVariable() = default;
|
||||||
|
|
||||||
Result KConditionVariable::SignalToAddress(VAddr addr) {
|
Result KConditionVariable::SignalToAddress(VAddr addr) {
|
||||||
KThread* owner_thread = GetCurrentThreadPointer(kernel);
|
KThread* owner_thread = GetCurrentThreadPointer(m_kernel);
|
||||||
|
|
||||||
// Signal the address.
|
// Signal the address.
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(m_kernel);
|
||||||
|
|
||||||
// Remove waiter thread.
|
// Remove waiter thread.
|
||||||
bool has_waiters{};
|
bool has_waiters{};
|
||||||
|
@ -129,7 +129,7 @@ Result KConditionVariable::SignalToAddress(VAddr addr) {
|
||||||
|
|
||||||
// Write the value to userspace.
|
// Write the value to userspace.
|
||||||
Result result{ResultSuccess};
|
Result result{ResultSuccess};
|
||||||
if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
|
if (WriteToUser(m_system, addr, std::addressof(next_value))) [[likely]] {
|
||||||
result = ResultSuccess;
|
result = ResultSuccess;
|
||||||
} else {
|
} else {
|
||||||
result = ResultInvalidCurrentMemory;
|
result = ResultInvalidCurrentMemory;
|
||||||
|
@ -145,26 +145,27 @@ Result KConditionVariable::SignalToAddress(VAddr addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
|
Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
|
||||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
|
||||||
ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel);
|
ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(m_kernel);
|
||||||
|
|
||||||
// Wait for the address.
|
// Wait for the address.
|
||||||
KThread* owner_thread{};
|
KThread* owner_thread{};
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(m_kernel);
|
||||||
|
|
||||||
// Check if the thread should terminate.
|
// Check if the thread should terminate.
|
||||||
R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested);
|
R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested);
|
||||||
|
|
||||||
// Read the tag from userspace.
|
// Read the tag from userspace.
|
||||||
u32 test_tag{};
|
u32 test_tag{};
|
||||||
R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory);
|
R_UNLESS(ReadFromUser(m_system, std::addressof(test_tag), addr),
|
||||||
|
ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
// If the tag isn't the handle (with wait mask), we're done.
|
// If the tag isn't the handle (with wait mask), we're done.
|
||||||
R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask));
|
R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask));
|
||||||
|
|
||||||
// Get the lock owner thread.
|
// Get the lock owner thread.
|
||||||
owner_thread = GetCurrentProcess(kernel)
|
owner_thread = GetCurrentProcess(m_kernel)
|
||||||
.GetHandleTable()
|
.GetHandleTable()
|
||||||
.GetObjectWithoutPseudoHandle<KThread>(handle)
|
.GetObjectWithoutPseudoHandle<KThread>(handle)
|
||||||
.ReleasePointerUnsafe();
|
.ReleasePointerUnsafe();
|
||||||
|
@ -184,12 +185,12 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value)
|
||||||
owner_thread->Close();
|
owner_thread->Close();
|
||||||
|
|
||||||
// Get the wait result.
|
// Get the wait result.
|
||||||
return cur_thread->GetWaitResult();
|
R_RETURN(cur_thread->GetWaitResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
void KConditionVariable::SignalImpl(KThread* thread) {
|
void KConditionVariable::SignalImpl(KThread* thread) {
|
||||||
// Check pre-conditions.
|
// Check pre-conditions.
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
|
||||||
|
|
||||||
// Update the tag.
|
// Update the tag.
|
||||||
VAddr address = thread->GetAddressKey();
|
VAddr address = thread->GetAddressKey();
|
||||||
|
@ -204,7 +205,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
|
||||||
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
||||||
can_access = true;
|
can_access = true;
|
||||||
if (can_access) [[likely]] {
|
if (can_access) [[likely]] {
|
||||||
UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag,
|
UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag,
|
||||||
Svc::HandleWaitMask);
|
Svc::HandleWaitMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +216,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
|
||||||
thread->EndWait(ResultSuccess);
|
thread->EndWait(ResultSuccess);
|
||||||
} else {
|
} else {
|
||||||
// Get the previous owner.
|
// Get the previous owner.
|
||||||
KThread* owner_thread = GetCurrentProcess(kernel)
|
KThread* owner_thread = GetCurrentProcess(m_kernel)
|
||||||
.GetHandleTable()
|
.GetHandleTable()
|
||||||
.GetObjectWithoutPseudoHandle<KThread>(
|
.GetObjectWithoutPseudoHandle<KThread>(
|
||||||
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
|
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
|
||||||
|
@ -240,14 +241,14 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||||
// Perform signaling.
|
// Perform signaling.
|
||||||
s32 num_waiters{};
|
s32 num_waiters{};
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(m_kernel);
|
||||||
|
|
||||||
auto it = thread_tree.nfind_key({cv_key, -1});
|
auto it = m_tree.nfind_key({cv_key, -1});
|
||||||
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||||
(it->GetConditionVariableKey() == cv_key)) {
|
(it->GetConditionVariableKey() == cv_key)) {
|
||||||
KThread* target_thread = std::addressof(*it);
|
KThread* target_thread = std::addressof(*it);
|
||||||
|
|
||||||
it = thread_tree.erase(it);
|
it = m_tree.erase(it);
|
||||||
target_thread->ClearConditionVariable();
|
target_thread->ClearConditionVariable();
|
||||||
|
|
||||||
this->SignalImpl(target_thread);
|
this->SignalImpl(target_thread);
|
||||||
|
@ -256,27 +257,27 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have no waiters, clear the has waiter flag.
|
// If we have no waiters, clear the has waiter flag.
|
||||||
if (it == thread_tree.end() || it->GetConditionVariableKey() != cv_key) {
|
if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) {
|
||||||
const u32 has_waiter_flag{};
|
const u32 has_waiter_flag{};
|
||||||
WriteToUser(system, cv_key, std::addressof(has_waiter_flag));
|
WriteToUser(m_system, cv_key, std::addressof(has_waiter_flag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
||||||
// Prepare to wait.
|
// Prepare to wait.
|
||||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
|
||||||
KHardwareTimer* timer{};
|
KHardwareTimer* timer{};
|
||||||
ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(
|
ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(m_kernel,
|
||||||
kernel, std::addressof(thread_tree));
|
std::addressof(m_tree));
|
||||||
|
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep slp(kernel, std::addressof(timer), cur_thread, timeout);
|
KScopedSchedulerLockAndSleep slp(m_kernel, std::addressof(timer), cur_thread, timeout);
|
||||||
|
|
||||||
// Check that the thread isn't terminating.
|
// Check that the thread isn't terminating.
|
||||||
if (cur_thread->IsTerminationRequested()) {
|
if (cur_thread->IsTerminationRequested()) {
|
||||||
slp.CancelSleep();
|
slp.CancelSleep();
|
||||||
return ResultTerminationRequested;
|
R_THROW(ResultTerminationRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the value and process for the next owner.
|
// Update the value and process for the next owner.
|
||||||
|
@ -302,14 +303,14 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
||||||
// Write to the cv key.
|
// Write to the cv key.
|
||||||
{
|
{
|
||||||
const u32 has_waiter_flag = 1;
|
const u32 has_waiter_flag = 1;
|
||||||
WriteToUser(system, key, std::addressof(has_waiter_flag));
|
WriteToUser(m_system, key, std::addressof(has_waiter_flag));
|
||||||
// TODO(bunnei): We should call DataMemoryBarrier(..) here.
|
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the value to userspace.
|
// Write the value to userspace.
|
||||||
if (!WriteToUser(system, addr, std::addressof(next_value))) {
|
if (!WriteToUser(m_system, addr, std::addressof(next_value))) {
|
||||||
slp.CancelSleep();
|
slp.CancelSleep();
|
||||||
return ResultInvalidCurrentMemory;
|
R_THROW(ResultInvalidCurrentMemory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,8 +318,8 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
||||||
R_UNLESS(timeout != 0, ResultTimedOut);
|
R_UNLESS(timeout != 0, ResultTimedOut);
|
||||||
|
|
||||||
// Update condition variable tracking.
|
// Update condition variable tracking.
|
||||||
cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value);
|
cur_thread->SetConditionVariable(std::addressof(m_tree), addr, key, value);
|
||||||
thread_tree.insert(*cur_thread);
|
m_tree.insert(*cur_thread);
|
||||||
|
|
||||||
// Begin waiting.
|
// Begin waiting.
|
||||||
wait_queue.SetHardwareTimer(timer);
|
wait_queue.SetHardwareTimer(timer);
|
||||||
|
@ -328,7 +329,7 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the wait result.
|
// Get the wait result.
|
||||||
return cur_thread->GetWaitResult();
|
R_RETURN(cur_thread->GetWaitResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -21,24 +21,24 @@ class KConditionVariable {
|
||||||
public:
|
public:
|
||||||
using ThreadTree = typename KThread::ConditionVariableThreadTreeType;
|
using ThreadTree = typename KThread::ConditionVariableThreadTreeType;
|
||||||
|
|
||||||
explicit KConditionVariable(Core::System& system_);
|
explicit KConditionVariable(Core::System& system);
|
||||||
~KConditionVariable();
|
~KConditionVariable();
|
||||||
|
|
||||||
// Arbitration
|
// Arbitration
|
||||||
[[nodiscard]] Result SignalToAddress(VAddr addr);
|
Result SignalToAddress(VAddr addr);
|
||||||
[[nodiscard]] Result WaitForAddress(Handle handle, VAddr addr, u32 value);
|
Result WaitForAddress(Handle handle, VAddr addr, u32 value);
|
||||||
|
|
||||||
// Condition variable
|
// Condition variable
|
||||||
void Signal(u64 cv_key, s32 count);
|
void Signal(u64 cv_key, s32 count);
|
||||||
[[nodiscard]] Result Wait(VAddr addr, u64 key, u32 value, s64 timeout);
|
Result Wait(VAddr addr, u64 key, u32 value, s64 timeout);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SignalImpl(KThread* thread);
|
void SignalImpl(KThread* thread);
|
||||||
|
|
||||||
ThreadTree thread_tree;
|
private:
|
||||||
|
Core::System& m_system;
|
||||||
Core::System& system;
|
KernelCore& m_kernel;
|
||||||
KernelCore& kernel;
|
ThreadTree m_tree{};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
|
inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
|
||||||
|
|
|
@ -13,9 +13,9 @@ namespace {
|
||||||
|
|
||||||
class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue {
|
class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue {
|
||||||
public:
|
public:
|
||||||
ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl,
|
ThreadQueueImplForKLightConditionVariable(KernelCore& kernel, KThread::WaiterList* wl,
|
||||||
bool term)
|
bool term)
|
||||||
: KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {}
|
: KThreadQueue(kernel), m_wait_list(wl), m_allow_terminating_thread(term) {}
|
||||||
|
|
||||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||||
// Only process waits if we're allowed to.
|
// Only process waits if we're allowed to.
|
||||||
|
@ -39,15 +39,15 @@ private:
|
||||||
|
|
||||||
void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
|
void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
|
||||||
// Create thread queue.
|
// Create thread queue.
|
||||||
KThread* owner = GetCurrentThreadPointer(kernel);
|
KThread* owner = GetCurrentThreadPointer(m_kernel);
|
||||||
KHardwareTimer* timer{};
|
KHardwareTimer* timer{};
|
||||||
|
|
||||||
ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list),
|
ThreadQueueImplForKLightConditionVariable wait_queue(m_kernel, std::addressof(m_wait_list),
|
||||||
allow_terminating_thread);
|
allow_terminating_thread);
|
||||||
|
|
||||||
// Sleep the thread.
|
// Sleep the thread.
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep lk(kernel, std::addressof(timer), owner, timeout);
|
KScopedSchedulerLockAndSleep lk(m_kernel, std::addressof(timer), owner, timeout);
|
||||||
|
|
||||||
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
|
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
|
||||||
lk.CancelSleep();
|
lk.CancelSleep();
|
||||||
|
@ -57,7 +57,7 @@ void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_ter
|
||||||
lock->Unlock();
|
lock->Unlock();
|
||||||
|
|
||||||
// Add the thread to the queue.
|
// Add the thread to the queue.
|
||||||
wait_list.push_back(*owner);
|
m_wait_list.push_back(*owner);
|
||||||
|
|
||||||
// Begin waiting.
|
// Begin waiting.
|
||||||
wait_queue.SetHardwareTimer(timer);
|
wait_queue.SetHardwareTimer(timer);
|
||||||
|
@ -69,10 +69,10 @@ void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_ter
|
||||||
}
|
}
|
||||||
|
|
||||||
void KLightConditionVariable::Broadcast() {
|
void KLightConditionVariable::Broadcast() {
|
||||||
KScopedSchedulerLock lk(kernel);
|
KScopedSchedulerLock lk(m_kernel);
|
||||||
|
|
||||||
// Signal all threads.
|
// Signal all threads.
|
||||||
for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) {
|
for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it = m_wait_list.erase(it)) {
|
||||||
it->EndWait(ResultSuccess);
|
it->EndWait(ResultSuccess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@ class KLightLock;
|
||||||
|
|
||||||
class KLightConditionVariable {
|
class KLightConditionVariable {
|
||||||
public:
|
public:
|
||||||
explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
|
explicit KLightConditionVariable(KernelCore& kernel) : m_kernel{kernel} {}
|
||||||
|
|
||||||
void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true);
|
void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true);
|
||||||
void Broadcast();
|
void Broadcast();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KernelCore& kernel;
|
KernelCore& m_kernel;
|
||||||
KThread::WaiterList wait_list{};
|
KThread::WaiterList m_wait_list{};
|
||||||
};
|
};
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace {
|
||||||
|
|
||||||
class ThreadQueueImplForKLightLock final : public KThreadQueue {
|
class ThreadQueueImplForKLightLock final : public KThreadQueue {
|
||||||
public:
|
public:
|
||||||
explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {}
|
explicit ThreadQueueImplForKLightLock(KernelCore& kernel) : KThreadQueue(kernel) {}
|
||||||
|
|
||||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||||
// Remove the thread as a waiter from its owner.
|
// Remove the thread as a waiter from its owner.
|
||||||
|
@ -29,13 +29,13 @@ public:
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void KLightLock::Lock() {
|
void KLightLock::Lock() {
|
||||||
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
|
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
uintptr_t old_tag = tag.load(std::memory_order_relaxed);
|
uintptr_t old_tag = m_tag.load(std::memory_order_relaxed);
|
||||||
|
|
||||||
while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),
|
while (!m_tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),
|
||||||
std::memory_order_acquire)) {
|
std::memory_order_acquire)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) {
|
if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) {
|
||||||
|
@ -45,30 +45,30 @@ void KLightLock::Lock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KLightLock::Unlock() {
|
void KLightLock::Unlock() {
|
||||||
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
|
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel));
|
||||||
|
|
||||||
uintptr_t expected = cur_thread;
|
uintptr_t expected = cur_thread;
|
||||||
if (!tag.compare_exchange_strong(expected, 0, std::memory_order_release)) {
|
if (!m_tag.compare_exchange_strong(expected, 0, std::memory_order_release)) {
|
||||||
this->UnlockSlowPath(cur_thread);
|
this->UnlockSlowPath(cur_thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
|
bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
|
||||||
KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
|
KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
|
||||||
ThreadQueueImplForKLightLock wait_queue(kernel);
|
ThreadQueueImplForKLightLock wait_queue(m_kernel);
|
||||||
|
|
||||||
// Pend the current thread waiting on the owner thread.
|
// Pend the current thread waiting on the owner thread.
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl{kernel};
|
KScopedSchedulerLock sl{m_kernel};
|
||||||
|
|
||||||
// Ensure we actually have locking to do.
|
// Ensure we actually have locking to do.
|
||||||
if (tag.load(std::memory_order_relaxed) != _owner) {
|
if (m_tag.load(std::memory_order_relaxed) != _owner) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the current thread as a waiter on the owner.
|
// Add the current thread as a waiter on the owner.
|
||||||
KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL);
|
KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL);
|
||||||
cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
|
cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
|
||||||
owner_thread->AddWaiter(cur_thread);
|
owner_thread->AddWaiter(cur_thread);
|
||||||
|
|
||||||
// Begin waiting to hold the lock.
|
// Begin waiting to hold the lock.
|
||||||
|
@ -87,12 +87,12 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
|
||||||
|
|
||||||
// Unlock.
|
// Unlock.
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(m_kernel);
|
||||||
|
|
||||||
// Get the next owner.
|
// Get the next owner.
|
||||||
bool has_waiters;
|
bool has_waiters;
|
||||||
KThread* next_owner = owner_thread->RemoveKernelWaiterByKey(
|
KThread* next_owner = owner_thread->RemoveKernelWaiterByKey(
|
||||||
std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag)));
|
std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
|
||||||
|
|
||||||
// Pass the lock to the next owner.
|
// Pass the lock to the next owner.
|
||||||
uintptr_t next_tag = 0;
|
uintptr_t next_tag = 0;
|
||||||
|
@ -114,12 +114,13 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the new tag value.
|
// Write the new tag value.
|
||||||
tag.store(next_tag, std::memory_order_release);
|
m_tag.store(next_tag, std::memory_order_release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KLightLock::IsLockedByCurrentThread() const {
|
bool KLightLock::IsLockedByCurrentThread() const {
|
||||||
return (tag | 1ULL) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)) | 1ULL);
|
return (m_tag.load() | 1ULL) ==
|
||||||
|
(reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel)) | 1ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -13,7 +13,7 @@ class KernelCore;
|
||||||
|
|
||||||
class KLightLock {
|
class KLightLock {
|
||||||
public:
|
public:
|
||||||
explicit KLightLock(KernelCore& kernel_) : kernel{kernel_} {}
|
explicit KLightLock(KernelCore& kernel) : m_kernel{kernel} {}
|
||||||
|
|
||||||
void Lock();
|
void Lock();
|
||||||
|
|
||||||
|
@ -24,14 +24,14 @@ public:
|
||||||
void UnlockSlowPath(uintptr_t cur_thread);
|
void UnlockSlowPath(uintptr_t cur_thread);
|
||||||
|
|
||||||
bool IsLocked() const {
|
bool IsLocked() const {
|
||||||
return tag != 0;
|
return m_tag.load() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLockedByCurrentThread() const;
|
bool IsLockedByCurrentThread() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<uintptr_t> tag{};
|
std::atomic<uintptr_t> m_tag{};
|
||||||
KernelCore& kernel;
|
KernelCore& m_kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
using KScopedLightLock = KScopedLock<KLightLock>;
|
using KScopedLightLock = KScopedLock<KLightLock>;
|
||||||
|
|
Loading…
Reference in New Issue