summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h43
-rw-r--r--src/core/hle/kernel/k_light_lock.cpp19
-rw-r--r--src/core/hle/kernel/k_process.cpp16
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp2
4 files changed, 43 insertions, 37 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_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index f974022e8..0896e705f 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -59,11 +59,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
59 owner_thread->AddWaiter(cur_thread); 59 owner_thread->AddWaiter(cur_thread);
60 60
61 // Set thread states. 61 // Set thread states.
62 if (cur_thread->GetState() == ThreadState::Runnable) { 62 cur_thread->SetState(ThreadState::Waiting);
63 cur_thread->SetState(ThreadState::Waiting);
64 } else {
65 KScheduler::SetSchedulerUpdateNeeded(kernel);
66 }
67 63
68 if (owner_thread->IsSuspended()) { 64 if (owner_thread->IsSuspended()) {
69 owner_thread->ContinueIfHasKernelWaiters(); 65 owner_thread->ContinueIfHasKernelWaiters();
@@ -73,10 +69,9 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
73 // We're no longer waiting on the lock owner. 69 // We're no longer waiting on the lock owner.
74 { 70 {
75 KScopedSchedulerLock sl{kernel}; 71 KScopedSchedulerLock sl{kernel};
76 KThread* owner_thread = cur_thread->GetLockOwner(); 72
77 if (owner_thread) { 73 if (KThread* owner_thread = cur_thread->GetLockOwner(); owner_thread != nullptr) {
78 owner_thread->RemoveWaiter(cur_thread); 74 owner_thread->RemoveWaiter(cur_thread);
79 KScheduler::SetSchedulerUpdateNeeded(kernel);
80 } 75 }
81 } 76 }
82} 77}
@@ -95,17 +90,13 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
95 90
96 // Pass the lock to the next owner. 91 // Pass the lock to the next owner.
97 uintptr_t next_tag = 0; 92 uintptr_t next_tag = 0;
98 if (next_owner) { 93 if (next_owner != nullptr) {
99 next_tag = reinterpret_cast<uintptr_t>(next_owner); 94 next_tag = reinterpret_cast<uintptr_t>(next_owner);
100 if (num_waiters > 1) { 95 if (num_waiters > 1) {
101 next_tag |= 0x1; 96 next_tag |= 0x1;
102 } 97 }
103 98
104 if (next_owner->GetState() == ThreadState::Waiting) { 99 next_owner->SetState(ThreadState::Runnable);
105 next_owner->SetState(ThreadState::Runnable);
106 } else {
107 KScheduler::SetSchedulerUpdateNeeded(kernel);
108 }
109 100
110 if (next_owner->IsSuspended()) { 101 if (next_owner->IsSuspended()) {
111 next_owner->ContinueIfHasKernelWaiters(); 102 next_owner->ContinueIfHasKernelWaiters();
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 06b8ce151..d1bd98051 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -201,17 +201,15 @@ bool KProcess::ReleaseUserException(KThread* thread) {
201 201
202 // Remove waiter thread. 202 // Remove waiter thread.
203 s32 num_waiters{}; 203 s32 num_waiters{};
204 KThread* next = thread->RemoveWaiterByKey( 204 if (KThread* next = thread->RemoveWaiterByKey(
205 std::addressof(num_waiters), 205 std::addressof(num_waiters),
206 reinterpret_cast<uintptr_t>(std::addressof(exception_thread))); 206 reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
207 if (next != nullptr) { 207 next != nullptr) {
208 if (next->GetState() == ThreadState::Waiting) { 208 next->SetState(ThreadState::Runnable);
209 next->SetState(ThreadState::Runnable);
210 } else {
211 KScheduler::SetSchedulerUpdateNeeded(kernel);
212 }
213 } 209 }
214 210
211 KScheduler::SetSchedulerUpdateNeeded(kernel);
212
215 return true; 213 return true;
216 } else { 214 } else {
217 return false; 215 return false;
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;