summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-11-14 20:13:18 -0400
committerGravatar FernandoS272019-11-21 10:46:55 -0400
commit2d16507f9fa06e868349d6f57a78585aec8628fd (patch)
tree7931e2bb9db6d55e7be760f1a1dcff14de09db78 /src/core/hle/kernel
parentMerge pull request #3142 from ReinUsesLisp/depbar-log (diff)
downloadyuzu-2d16507f9fa06e868349d6f57a78585aec8628fd.tar.gz
yuzu-2d16507f9fa06e868349d6f57a78585aec8628fd.tar.xz
yuzu-2d16507f9fa06e868349d6f57a78585aec8628fd.zip
Kernel: Correct behavior of Condition Variables to be more similar to real hardware.
This commit ensures cond var threads act exactly as they do in the real console. The original implementation uses an RBTree and the behavior of cond var threads is that at the same priority level they act like a FIFO.
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/kernel.cpp3
-rw-r--r--src/core/hle/kernel/process.cpp46
-rw-r--r--src/core/hle/kernel/process.h12
-rw-r--r--src/core/hle/kernel/svc.cpp20
-rw-r--r--src/core/hle/kernel/thread.cpp8
5 files changed, 74 insertions, 15 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f94ac150d..cdf7944f7 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -66,6 +66,9 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
66 thread->SetMutexWaitAddress(0); 66 thread->SetMutexWaitAddress(0);
67 thread->SetCondVarWaitAddress(0); 67 thread->SetCondVarWaitAddress(0);
68 thread->SetWaitHandle(0); 68 thread->SetWaitHandle(0);
69 if (thread->GetStatus() == ThreadStatus::WaitCondVar) {
70 thread->GetOwnerProcess()->RemoveConditionVariableThread(thread);
71 }
69 72
70 auto* const lock_owner = thread->GetLockOwner(); 73 auto* const lock_owner = thread->GetLockOwner();
71 // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance 74 // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 12a900bcc..43576c6ab 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -142,6 +142,52 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
142 return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); 142 return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
143} 143}
144 144
145void Process::InsertConditionVariableThread(SharedPtr<Thread> thread) {
146 auto it = cond_var_threads.begin();
147 while (it != cond_var_threads.end()) {
148 const SharedPtr<Thread> current_thread = *it;
149 if (current_thread->GetCondVarWaitAddress() < thread->GetCondVarWaitAddress()) {
150 if (current_thread->GetCondVarWaitAddress() == thread->GetCondVarWaitAddress()) {
151 if (current_thread->GetPriority() > thread->GetPriority()) {
152 cond_var_threads.insert(it, thread);
153 return;
154 }
155 } else {
156 cond_var_threads.insert(it, thread);
157 return;
158 }
159 }
160 ++it;
161 }
162 cond_var_threads.push_back(thread);
163}
164
165void Process::RemoveConditionVariableThread(SharedPtr<Thread> thread) {
166 auto it = cond_var_threads.begin();
167 while (it != cond_var_threads.end()) {
168 const SharedPtr<Thread> current_thread = *it;
169 if (current_thread.get() == thread.get()) {
170 cond_var_threads.erase(it);
171 return;
172 }
173 ++it;
174 }
175 UNREACHABLE();
176}
177
178std::vector<SharedPtr<Thread>> Process::GetConditionVariableThreads(const VAddr cond_var_addr) {
179 std::vector<SharedPtr<Thread>> result{};
180 auto it = cond_var_threads.begin();
181 while (it != cond_var_threads.end()) {
182 SharedPtr<Thread> current_thread = *it;
183 if (current_thread->GetCondVarWaitAddress() == cond_var_addr) {
184 result.push_back(current_thread);
185 }
186 ++it;
187 }
188 return result;
189}
190
145void Process::RegisterThread(const Thread* thread) { 191void Process::RegisterThread(const Thread* thread) {
146 thread_list.push_back(thread); 192 thread_list.push_back(thread);
147} 193}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index c2df451f3..e8bff709b 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -232,6 +232,15 @@ public:
232 return thread_list; 232 return thread_list;
233 } 233 }
234 234
235 /// Insert a thread into the condition variable wait container
236 void InsertConditionVariableThread(SharedPtr<Thread> thread);
237
238 /// Remove a thread from the condition variable wait container
239 void RemoveConditionVariableThread(SharedPtr<Thread> thread);
240
241 /// Obtain all condition variable threads waiting for some address
242 std::vector<SharedPtr<Thread>> GetConditionVariableThreads(VAddr cond_var_addr);
243
235 /// Registers a thread as being created under this process, 244 /// Registers a thread as being created under this process,
236 /// adding it to this process' thread list. 245 /// adding it to this process' thread list.
237 void RegisterThread(const Thread* thread); 246 void RegisterThread(const Thread* thread);
@@ -375,6 +384,9 @@ private:
375 /// List of threads that are running with this process as their owner. 384 /// List of threads that are running with this process as their owner.
376 std::list<const Thread*> thread_list; 385 std::list<const Thread*> thread_list;
377 386
387 /// List of threads waiting for a condition variable
388 std::list<SharedPtr<Thread>> cond_var_threads;
389
378 /// System context 390 /// System context
379 Core::System& system; 391 Core::System& system;
380 392
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c63a9ba8b..c27529f4d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1626,6 +1626,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
1626 current_thread->SetWaitHandle(thread_handle); 1626 current_thread->SetWaitHandle(thread_handle);
1627 current_thread->SetStatus(ThreadStatus::WaitCondVar); 1627 current_thread->SetStatus(ThreadStatus::WaitCondVar);
1628 current_thread->InvalidateWakeupCallback(); 1628 current_thread->InvalidateWakeupCallback();
1629 current_process->InsertConditionVariableThread(current_thread);
1629 1630
1630 current_thread->WakeAfterDelay(nano_seconds); 1631 current_thread->WakeAfterDelay(nano_seconds);
1631 1632
@@ -1644,21 +1645,9 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1644 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); 1645 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
1645 1646
1646 // Retrieve a list of all threads that are waiting for this condition variable. 1647 // Retrieve a list of all threads that are waiting for this condition variable.
1647 std::vector<SharedPtr<Thread>> waiting_threads; 1648 auto* const current_process = system.Kernel().CurrentProcess();
1648 const auto& scheduler = system.GlobalScheduler(); 1649 std::vector<SharedPtr<Thread>> waiting_threads =
1649 const auto& thread_list = scheduler.GetThreadList(); 1650 current_process->GetConditionVariableThreads(condition_variable_addr);
1650
1651 for (const auto& thread : thread_list) {
1652 if (thread->GetCondVarWaitAddress() == condition_variable_addr) {
1653 waiting_threads.push_back(thread);
1654 }
1655 }
1656
1657 // Sort them by priority, such that the highest priority ones come first.
1658 std::sort(waiting_threads.begin(), waiting_threads.end(),
1659 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
1660 return lhs->GetPriority() < rhs->GetPriority();
1661 });
1662 1651
1663 // Only process up to 'target' threads, unless 'target' is -1, in which case process 1652 // Only process up to 'target' threads, unless 'target' is -1, in which case process
1664 // them all. 1653 // them all.
@@ -1677,6 +1666,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1677 1666
1678 // liberate Cond Var Thread. 1667 // liberate Cond Var Thread.
1679 thread->SetCondVarWaitAddress(0); 1668 thread->SetCondVarWaitAddress(0);
1669 current_process->RemoveConditionVariableThread(thread);
1680 1670
1681 const std::size_t current_core = system.CurrentCoreIndex(); 1671 const std::size_t current_core = system.CurrentCoreIndex();
1682 auto& monitor = system.Monitor(); 1672 auto& monitor = system.Monitor();
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index ee7531f2d..6dafa311d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -306,8 +306,16 @@ void Thread::UpdatePriority() {
306 return; 306 return;
307 } 307 }
308 308
309 if (GetStatus() == ThreadStatus::WaitCondVar) {
310 owner_process->RemoveConditionVariableThread(this);
311 }
312
309 SetCurrentPriority(new_priority); 313 SetCurrentPriority(new_priority);
310 314
315 if (GetStatus() == ThreadStatus::WaitCondVar) {
316 owner_process->InsertConditionVariableThread(this);
317 }
318
311 if (!lock_owner) { 319 if (!lock_owner) {
312 return; 320 return;
313 } 321 }