Просмотр исходного кода

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

kernel: KLightConditionVariable: Update implementation to 12.x
bunnei 5 лет назад
Родитель
Сommit
0c0c1a039e

+ 30 - 13
src/core/hle/kernel/k_light_condition_variable.h

@@ -18,41 +18,58 @@ class KernelCore;
 
 class KLightConditionVariable {
 public:
-    explicit KLightConditionVariable(KernelCore& kernel_)
-        : thread_queue(kernel_), kernel(kernel_) {}
+    explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
 
-    void Wait(KLightLock* lock, s64 timeout = -1) {
-        WaitImpl(lock, timeout);
-        lock->Lock();
+    void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) {
+        WaitImpl(lock, timeout, allow_terminating_thread);
     }
 
     void Broadcast() {
         KScopedSchedulerLock lk{kernel};
-        while (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 : wait_list) {
+            thread.SetState(ThreadState::Runnable);
         }
     }
 
 private:
-    void WaitImpl(KLightLock* lock, s64 timeout) {
+    void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
         KThread* owner = GetCurrentThreadPointer(kernel);
 
         // Sleep the thread.
         {
-            KScopedSchedulerLockAndSleep lk(kernel, owner, timeout);
-            lock->Unlock();
+            KScopedSchedulerLockAndSleep lk{kernel, owner, timeout};
 
-            if (!thread_queue.SleepThread(owner)) {
+            if (!allow_terminating_thread && owner->IsTerminationRequested()) {
                 lk.CancelSleep();
                 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.
         kernel.TimeManager().UnscheduleTimeEvent(owner);
+
+        // Re-acquire the lock.
+        lock->Lock();
     }
-    KThreadQueue thread_queue;
+
     KernelCore& kernel;
+    KThread::WaiterList wait_list{};
 };
 } // namespace Kernel

+ 5 - 14
src/core/hle/kernel/k_light_lock.cpp

@@ -59,11 +59,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
         owner_thread->AddWaiter(cur_thread);
 
         // Set thread states.
-        if (cur_thread->GetState() == ThreadState::Runnable) {
-            cur_thread->SetState(ThreadState::Waiting);
-        } else {
-            KScheduler::SetSchedulerUpdateNeeded(kernel);
-        }
+        cur_thread->SetState(ThreadState::Waiting);
 
         if (owner_thread->IsSuspended()) {
             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.
     {
         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);
-            KScheduler::SetSchedulerUpdateNeeded(kernel);
         }
     }
 }
@@ -95,17 +90,13 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
 
         // Pass the lock to the next owner.
         uintptr_t next_tag = 0;
-        if (next_owner) {
+        if (next_owner != nullptr) {
             next_tag = reinterpret_cast<uintptr_t>(next_owner);
             if (num_waiters > 1) {
                 next_tag |= 0x1;
             }
 
-            if (next_owner->GetState() == ThreadState::Waiting) {
-                next_owner->SetState(ThreadState::Runnable);
-            } else {
-                KScheduler::SetSchedulerUpdateNeeded(kernel);
-            }
+            next_owner->SetState(ThreadState::Runnable);
 
             if (next_owner->IsSuspended()) {
                 next_owner->ContinueIfHasKernelWaiters();

+ 7 - 9
src/core/hle/kernel/k_process.cpp

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

+ 1 - 1
src/core/hle/kernel/k_resource_limit.cpp

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