summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h43
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp2
2 files changed, 31 insertions, 14 deletions
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h
index ca2e539a7..a95fa41f3 100644
--- a/src/core/hle/kernel/k_light_condition_variable.h
+++ b/src/core/hle/kernel/k_light_condition_variable.h
@@ -18,41 +18,58 @@ class KernelCore;
18 18
19class KLightConditionVariable { 19class KLightConditionVariable {
20public: 20public:
21 explicit KLightConditionVariable(KernelCore& kernel_) 21 explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
22 : thread_queue(kernel_), kernel(kernel_) {}
23 22
24 void Wait(KLightLock* lock, s64 timeout = -1) { 23 void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) {
25 WaitImpl(lock, timeout); 24 WaitImpl(lock, timeout, allow_terminating_thread);
26 lock->Lock();
27 } 25 }
28 26
29 void Broadcast() { 27 void Broadcast() {
30 KScopedSchedulerLock lk{kernel}; 28 KScopedSchedulerLock lk{kernel};
31 while (thread_queue.WakeupFrontThread() != nullptr) { 29
32 // We want to signal all threads, and so should continue waking up until there's nothing 30 // Signal all threads.
33 // to wake. 31 for (auto& thread : wait_list) {
32 thread.SetState(ThreadState::Runnable);
34 } 33 }
35 } 34 }
36 35
37private: 36private:
38 void WaitImpl(KLightLock* lock, s64 timeout) { 37 void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
39 KThread* owner = GetCurrentThreadPointer(kernel); 38 KThread* owner = GetCurrentThreadPointer(kernel);
40 39
41 // Sleep the thread. 40 // Sleep the thread.
42 { 41 {
43 KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); 42 KScopedSchedulerLockAndSleep lk{kernel, owner, timeout};
44 lock->Unlock();
45 43
46 if (!thread_queue.SleepThread(owner)) { 44 if (!allow_terminating_thread && owner->IsTerminationRequested()) {
47 lk.CancelSleep(); 45 lk.CancelSleep();
48 return; 46 return;
49 } 47 }
48
49 lock->Unlock();
50
51 // Set the thread as waiting.
52 GetCurrentThread(kernel).SetState(ThreadState::Waiting);
53
54 // Add the thread to the queue.
55 wait_list.push_back(GetCurrentThread(kernel));
56 }
57
58 // Remove the thread from the wait list.
59 {
60 KScopedSchedulerLock sl{kernel};
61
62 wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel)));
50 } 63 }
51 64
52 // Cancel the task that the sleep setup. 65 // Cancel the task that the sleep setup.
53 kernel.TimeManager().UnscheduleTimeEvent(owner); 66 kernel.TimeManager().UnscheduleTimeEvent(owner);
67
68 // Re-acquire the lock.
69 lock->Lock();
54 } 70 }
55 KThreadQueue thread_queue; 71
56 KernelCore& kernel; 72 KernelCore& kernel;
73 KThread::WaiterList wait_list{};
57}; 74};
58} // namespace Kernel 75} // namespace Kernel
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
index f91cb65dc..da88f35bc 100644
--- a/src/core/hle/kernel/k_resource_limit.cpp
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -117,7 +117,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
117 if (current_hints[index] + value <= limit_values[index] && 117 if (current_hints[index] + value <= limit_values[index] &&
118 (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) { 118 (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
119 waiter_count++; 119 waiter_count++;
120 cond_var.Wait(&lock, timeout); 120 cond_var.Wait(&lock, timeout, false);
121 waiter_count--; 121 waiter_count--;
122 } else { 122 } else {
123 break; 123 break;