1
0
Fork 0
forked from suyu/suyu

Merge pull request #6443 from Morph1984/k-light-condition-variable

kernel: KLightConditionVariable: Update implementation to 12.x
This commit is contained in:
bunnei 2021-06-11 11:03:55 -07:00 committed by GitHub
commit 0c0c1a039e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 37 deletions

View file

@ -18,41 +18,58 @@ class KernelCore;
class KLightConditionVariable { class KLightConditionVariable {
public: public:
explicit KLightConditionVariable(KernelCore& kernel_) explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
: thread_queue(kernel_), kernel(kernel_) {}
void Wait(KLightLock* lock, s64 timeout = -1) { void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) {
WaitImpl(lock, timeout); WaitImpl(lock, timeout, allow_terminating_thread);
lock->Lock();
} }
void Broadcast() { void Broadcast() {
KScopedSchedulerLock lk{kernel}; KScopedSchedulerLock lk{kernel};
while (thread_queue.WakeupFrontThread() != nullptr) {
// We want to signal all threads, and so should continue waking up until there's nothing // Signal all threads.
// to wake. for (auto& thread : wait_list) {
thread.SetState(ThreadState::Runnable);
} }
} }
private: private:
void WaitImpl(KLightLock* lock, s64 timeout) { void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
KThread* owner = GetCurrentThreadPointer(kernel); KThread* owner = GetCurrentThreadPointer(kernel);
// Sleep the thread. // Sleep the thread.
{ {
KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); KScopedSchedulerLockAndSleep lk{kernel, owner, timeout};
lock->Unlock();
if (!thread_queue.SleepThread(owner)) { if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep(); lk.CancelSleep();
return; return;
} }
lock->Unlock();
// Set the thread as waiting.
GetCurrentThread(kernel).SetState(ThreadState::Waiting);
// Add the thread to the queue.
wait_list.push_back(GetCurrentThread(kernel));
}
// Remove the thread from the wait list.
{
KScopedSchedulerLock sl{kernel};
wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel)));
} }
// Cancel the task that the sleep setup. // Cancel the task that the sleep setup.
kernel.TimeManager().UnscheduleTimeEvent(owner); kernel.TimeManager().UnscheduleTimeEvent(owner);
// Re-acquire the lock.
lock->Lock();
} }
KThreadQueue thread_queue;
KernelCore& kernel; KernelCore& kernel;
KThread::WaiterList wait_list{};
}; };
} // namespace Kernel } // namespace Kernel

View file

@ -59,11 +59,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
owner_thread->AddWaiter(cur_thread); owner_thread->AddWaiter(cur_thread);
// Set thread states. // Set thread states.
if (cur_thread->GetState() == ThreadState::Runnable) {
cur_thread->SetState(ThreadState::Waiting); cur_thread->SetState(ThreadState::Waiting);
} else {
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
if (owner_thread->IsSuspended()) { if (owner_thread->IsSuspended()) {
owner_thread->ContinueIfHasKernelWaiters(); owner_thread->ContinueIfHasKernelWaiters();
@ -73,10 +69,9 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
// We're no longer waiting on the lock owner. // We're no longer waiting on the lock owner.
{ {
KScopedSchedulerLock sl{kernel}; KScopedSchedulerLock sl{kernel};
KThread* owner_thread = cur_thread->GetLockOwner();
if (owner_thread) { if (KThread* owner_thread = cur_thread->GetLockOwner(); owner_thread != nullptr) {
owner_thread->RemoveWaiter(cur_thread); owner_thread->RemoveWaiter(cur_thread);
KScheduler::SetSchedulerUpdateNeeded(kernel);
} }
} }
} }
@ -95,17 +90,13 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
// Pass the lock to the next owner. // Pass the lock to the next owner.
uintptr_t next_tag = 0; uintptr_t next_tag = 0;
if (next_owner) { if (next_owner != nullptr) {
next_tag = reinterpret_cast<uintptr_t>(next_owner); next_tag = reinterpret_cast<uintptr_t>(next_owner);
if (num_waiters > 1) { if (num_waiters > 1) {
next_tag |= 0x1; next_tag |= 0x1;
} }
if (next_owner->GetState() == ThreadState::Waiting) {
next_owner->SetState(ThreadState::Runnable); next_owner->SetState(ThreadState::Runnable);
} else {
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
if (next_owner->IsSuspended()) { if (next_owner->IsSuspended()) {
next_owner->ContinueIfHasKernelWaiters(); next_owner->ContinueIfHasKernelWaiters();

View file

@ -201,16 +201,14 @@ bool KProcess::ReleaseUserException(KThread* thread) {
// Remove waiter thread. // Remove waiter thread.
s32 num_waiters{}; s32 num_waiters{};
KThread* next = thread->RemoveWaiterByKey( if (KThread* next = thread->RemoveWaiterByKey(
std::addressof(num_waiters), std::addressof(num_waiters),
reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
if (next != nullptr) { next != nullptr) {
if (next->GetState() == ThreadState::Waiting) {
next->SetState(ThreadState::Runnable); next->SetState(ThreadState::Runnable);
} else { }
KScheduler::SetSchedulerUpdateNeeded(kernel); KScheduler::SetSchedulerUpdateNeeded(kernel);
}
}
return true; return true;
} else { } else {

View file

@ -117,7 +117,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
if (current_hints[index] + value <= limit_values[index] && if (current_hints[index] + value <= limit_values[index] &&
(timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) { (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
waiter_count++; waiter_count++;
cond_var.Wait(&lock, timeout); cond_var.Wait(&lock, timeout, false);
waiter_count--; waiter_count--;
} else { } else {
break; break;