diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 42 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.h | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 28 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 8 |
5 files changed, 74 insertions, 22 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f94ac150d..9d3b309b3 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -64,8 +64,11 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ | |||
| 64 | } else if (thread->GetStatus() == ThreadStatus::WaitMutex || | 64 | } else if (thread->GetStatus() == ThreadStatus::WaitMutex || |
| 65 | thread->GetStatus() == ThreadStatus::WaitCondVar) { | 65 | thread->GetStatus() == ThreadStatus::WaitCondVar) { |
| 66 | thread->SetMutexWaitAddress(0); | 66 | thread->SetMutexWaitAddress(0); |
| 67 | thread->SetCondVarWaitAddress(0); | ||
| 68 | thread->SetWaitHandle(0); | 67 | thread->SetWaitHandle(0); |
| 68 | if (thread->GetStatus() == ThreadStatus::WaitCondVar) { | ||
| 69 | thread->GetOwnerProcess()->RemoveConditionVariableThread(thread); | ||
| 70 | thread->SetCondVarWaitAddress(0); | ||
| 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..a4e0dd385 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -142,6 +142,48 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { | |||
| 142 | return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); | 142 | return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | void Process::InsertConditionVariableThread(SharedPtr<Thread> thread) { | ||
| 146 | VAddr cond_var_addr = thread->GetCondVarWaitAddress(); | ||
| 147 | std::list<SharedPtr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; | ||
| 148 | auto it = thread_list.begin(); | ||
| 149 | while (it != thread_list.end()) { | ||
| 150 | const SharedPtr<Thread> current_thread = *it; | ||
| 151 | if (current_thread->GetPriority() > thread->GetPriority()) { | ||
| 152 | thread_list.insert(it, thread); | ||
| 153 | return; | ||
| 154 | } | ||
| 155 | ++it; | ||
| 156 | } | ||
| 157 | thread_list.push_back(thread); | ||
| 158 | } | ||
| 159 | |||
| 160 | void Process::RemoveConditionVariableThread(SharedPtr<Thread> thread) { | ||
| 161 | VAddr cond_var_addr = thread->GetCondVarWaitAddress(); | ||
| 162 | std::list<SharedPtr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; | ||
| 163 | auto it = thread_list.begin(); | ||
| 164 | while (it != thread_list.end()) { | ||
| 165 | const SharedPtr<Thread> current_thread = *it; | ||
| 166 | if (current_thread.get() == thread.get()) { | ||
| 167 | thread_list.erase(it); | ||
| 168 | return; | ||
| 169 | } | ||
| 170 | ++it; | ||
| 171 | } | ||
| 172 | UNREACHABLE(); | ||
| 173 | } | ||
| 174 | |||
| 175 | std::vector<SharedPtr<Thread>> Process::GetConditionVariableThreads(const VAddr cond_var_addr) { | ||
| 176 | std::vector<SharedPtr<Thread>> result{}; | ||
| 177 | std::list<SharedPtr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; | ||
| 178 | auto it = thread_list.begin(); | ||
| 179 | while (it != thread_list.end()) { | ||
| 180 | SharedPtr<Thread> current_thread = *it; | ||
| 181 | result.push_back(current_thread); | ||
| 182 | ++it; | ||
| 183 | } | ||
| 184 | return result; | ||
| 185 | } | ||
| 186 | |||
| 145 | void Process::RegisterThread(const Thread* thread) { | 187 | void Process::RegisterThread(const Thread* thread) { |
| 146 | thread_list.push_back(thread); | 188 | thread_list.push_back(thread); |
| 147 | } | 189 | } |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index c2df451f3..e2eda26b9 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <list> | 9 | #include <list> |
| 10 | #include <string> | 10 | #include <string> |
| 11 | #include <unordered_map> | ||
| 11 | #include <vector> | 12 | #include <vector> |
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | #include "core/hle/kernel/address_arbiter.h" | 14 | #include "core/hle/kernel/address_arbiter.h" |
| @@ -232,6 +233,15 @@ public: | |||
| 232 | return thread_list; | 233 | return thread_list; |
| 233 | } | 234 | } |
| 234 | 235 | ||
| 236 | /// Insert a thread into the condition variable wait container | ||
| 237 | void InsertConditionVariableThread(SharedPtr<Thread> thread); | ||
| 238 | |||
| 239 | /// Remove a thread from the condition variable wait container | ||
| 240 | void RemoveConditionVariableThread(SharedPtr<Thread> thread); | ||
| 241 | |||
| 242 | /// Obtain all condition variable threads waiting for some address | ||
| 243 | std::vector<SharedPtr<Thread>> GetConditionVariableThreads(VAddr cond_var_addr); | ||
| 244 | |||
| 235 | /// Registers a thread as being created under this process, | 245 | /// Registers a thread as being created under this process, |
| 236 | /// adding it to this process' thread list. | 246 | /// adding it to this process' thread list. |
| 237 | void RegisterThread(const Thread* thread); | 247 | void RegisterThread(const Thread* thread); |
| @@ -375,6 +385,9 @@ private: | |||
| 375 | /// List of threads that are running with this process as their owner. | 385 | /// List of threads that are running with this process as their owner. |
| 376 | std::list<const Thread*> thread_list; | 386 | std::list<const Thread*> thread_list; |
| 377 | 387 | ||
| 388 | /// List of threads waiting for a condition variable | ||
| 389 | std::unordered_map<VAddr, std::list<SharedPtr<Thread>>> cond_var_threads; | ||
| 390 | |||
| 378 | /// System context | 391 | /// System context |
| 379 | Core::System& system; | 392 | Core::System& system; |
| 380 | 393 | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b2cef3be9..8c67ada43 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -1631,6 +1631,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add | |||
| 1631 | current_thread->SetWaitHandle(thread_handle); | 1631 | current_thread->SetWaitHandle(thread_handle); |
| 1632 | current_thread->SetStatus(ThreadStatus::WaitCondVar); | 1632 | current_thread->SetStatus(ThreadStatus::WaitCondVar); |
| 1633 | current_thread->InvalidateWakeupCallback(); | 1633 | current_thread->InvalidateWakeupCallback(); |
| 1634 | current_process->InsertConditionVariableThread(current_thread); | ||
| 1634 | 1635 | ||
| 1635 | current_thread->WakeAfterDelay(nano_seconds); | 1636 | current_thread->WakeAfterDelay(nano_seconds); |
| 1636 | 1637 | ||
| @@ -1649,38 +1650,23 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var | |||
| 1649 | ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); | 1650 | ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); |
| 1650 | 1651 | ||
| 1651 | // Retrieve a list of all threads that are waiting for this condition variable. | 1652 | // Retrieve a list of all threads that are waiting for this condition variable. |
| 1652 | std::vector<SharedPtr<Thread>> waiting_threads; | 1653 | auto* const current_process = system.Kernel().CurrentProcess(); |
| 1653 | const auto& scheduler = system.GlobalScheduler(); | 1654 | std::vector<SharedPtr<Thread>> waiting_threads = |
| 1654 | const auto& thread_list = scheduler.GetThreadList(); | 1655 | current_process->GetConditionVariableThreads(condition_variable_addr); |
| 1655 | |||
| 1656 | for (const auto& thread : thread_list) { | ||
| 1657 | if (thread->GetCondVarWaitAddress() == condition_variable_addr) { | ||
| 1658 | waiting_threads.push_back(thread); | ||
| 1659 | } | ||
| 1660 | } | ||
| 1661 | |||
| 1662 | // Sort them by priority, such that the highest priority ones come first. | ||
| 1663 | std::sort(waiting_threads.begin(), waiting_threads.end(), | ||
| 1664 | [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { | ||
| 1665 | return lhs->GetPriority() < rhs->GetPriority(); | ||
| 1666 | }); | ||
| 1667 | 1656 | ||
| 1668 | // Only process up to 'target' threads, unless 'target' is -1, in which case process | 1657 | // Only process up to 'target' threads, unless 'target' is less equal 0, in which case process |
| 1669 | // them all. | 1658 | // them all. |
| 1670 | std::size_t last = waiting_threads.size(); | 1659 | std::size_t last = waiting_threads.size(); |
| 1671 | if (target != -1) | 1660 | if (target > 0) |
| 1672 | last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); | 1661 | last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); |
| 1673 | 1662 | ||
| 1674 | // If there are no threads waiting on this condition variable, just exit | ||
| 1675 | if (last == 0) | ||
| 1676 | return RESULT_SUCCESS; | ||
| 1677 | |||
| 1678 | for (std::size_t index = 0; index < last; ++index) { | 1663 | for (std::size_t index = 0; index < last; ++index) { |
| 1679 | auto& thread = waiting_threads[index]; | 1664 | auto& thread = waiting_threads[index]; |
| 1680 | 1665 | ||
| 1681 | ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); | 1666 | ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); |
| 1682 | 1667 | ||
| 1683 | // liberate Cond Var Thread. | 1668 | // liberate Cond Var Thread. |
| 1669 | current_process->RemoveConditionVariableThread(thread); | ||
| 1684 | thread->SetCondVarWaitAddress(0); | 1670 | thread->SetCondVarWaitAddress(0); |
| 1685 | 1671 | ||
| 1686 | const std::size_t current_core = system.CurrentCoreIndex(); | 1672 | const std::size_t current_core = system.CurrentCoreIndex(); |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ab0e82ac2..7166e9b07 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -309,8 +309,16 @@ void Thread::UpdatePriority() { | |||
| 309 | return; | 309 | return; |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | if (GetStatus() == ThreadStatus::WaitCondVar) { | ||
| 313 | owner_process->RemoveConditionVariableThread(this); | ||
| 314 | } | ||
| 315 | |||
| 312 | SetCurrentPriority(new_priority); | 316 | SetCurrentPriority(new_priority); |
| 313 | 317 | ||
| 318 | if (GetStatus() == ThreadStatus::WaitCondVar) { | ||
| 319 | owner_process->InsertConditionVariableThread(this); | ||
| 320 | } | ||
| 321 | |||
| 314 | if (!lock_owner) { | 322 | if (!lock_owner) { |
| 315 | return; | 323 | return; |
| 316 | } | 324 | } |