summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp66
-rw-r--r--src/core/hle/kernel/address_arbiter.h19
-rw-r--r--src/core/hle/kernel/kernel.cpp6
3 files changed, 67 insertions, 24 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 8422d05e0..db189c8e3 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -17,10 +17,10 @@
17#include "core/memory.h" 17#include "core/memory.h"
18 18
19namespace Kernel { 19namespace Kernel {
20namespace { 20
21// Wake up num_to_wake (or all) threads in a vector. 21// Wake up num_to_wake (or all) threads in a vector.
22void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake) { 22void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads,
23 auto& system = Core::System::GetInstance(); 23 s32 num_to_wake) {
24 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process 24 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
25 // them all. 25 // them all.
26 std::size_t last = waiting_threads.size(); 26 std::size_t last = waiting_threads.size();
@@ -32,12 +32,12 @@ void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s3
32 for (std::size_t i = 0; i < last; i++) { 32 for (std::size_t i = 0; i < last; i++) {
33 ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb); 33 ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb);
34 waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); 34 waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS);
35 RemoveThread(waiting_threads[i]);
35 waiting_threads[i]->SetArbiterWaitAddress(0); 36 waiting_threads[i]->SetArbiterWaitAddress(0);
36 waiting_threads[i]->ResumeFromWait(); 37 waiting_threads[i]->ResumeFromWait();
37 system.PrepareReschedule(waiting_threads[i]->GetProcessorID()); 38 system.PrepareReschedule(waiting_threads[i]->GetProcessorID());
38 } 39 }
39} 40}
40} // Anonymous namespace
41 41
42AddressArbiter::AddressArbiter(Core::System& system) : system{system} {} 42AddressArbiter::AddressArbiter(Core::System& system) : system{system} {}
43AddressArbiter::~AddressArbiter() = default; 43AddressArbiter::~AddressArbiter() = default;
@@ -184,6 +184,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
184ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { 184ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) {
185 Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); 185 Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
186 current_thread->SetArbiterWaitAddress(address); 186 current_thread->SetArbiterWaitAddress(address);
187 InsertThread(SharedFrom(current_thread));
187 current_thread->SetStatus(ThreadStatus::WaitArb); 188 current_thread->SetStatus(ThreadStatus::WaitArb);
188 current_thread->InvalidateWakeupCallback(); 189 current_thread->InvalidateWakeupCallback();
189 current_thread->WakeAfterDelay(timeout); 190 current_thread->WakeAfterDelay(timeout);
@@ -192,26 +193,51 @@ ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) {
192 return RESULT_TIMEOUT; 193 return RESULT_TIMEOUT;
193} 194}
194 195
195std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress( 196void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) {
196 VAddr address) const { 197 ASSERT(thread->GetStatus() == ThreadStatus::WaitArb);
197 198 RemoveThread(thread);
198 // Retrieve all threads that are waiting for this address. 199 thread->SetArbiterWaitAddress(0);
199 std::vector<std::shared_ptr<Thread>> threads; 200}
200 const auto& scheduler = system.GlobalScheduler();
201 const auto& thread_list = scheduler.GetThreadList();
202 201
203 for (const auto& thread : thread_list) { 202void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) {
204 if (thread->GetArbiterWaitAddress() == address) { 203 const VAddr arb_addr = thread->GetArbiterWaitAddress();
205 threads.push_back(thread); 204 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
205 auto it = thread_list.begin();
206 while (it != thread_list.end()) {
207 const std::shared_ptr<Thread>& current_thread = *it;
208 if (current_thread->GetPriority() >= thread->GetPriority()) {
209 thread_list.insert(it, thread);
210 return;
206 } 211 }
212 ++it;
207 } 213 }
214 thread_list.push_back(std::move(thread));
215}
208 216
209 // Sort them by priority, such that the highest priority ones come first. 217void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) {
210 std::sort(threads.begin(), threads.end(), 218 const VAddr arb_addr = thread->GetArbiterWaitAddress();
211 [](const std::shared_ptr<Thread>& lhs, const std::shared_ptr<Thread>& rhs) { 219 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
212 return lhs->GetPriority() < rhs->GetPriority(); 220 auto it = thread_list.begin();
213 }); 221 while (it != thread_list.end()) {
222 const std::shared_ptr<Thread>& current_thread = *it;
223 if (current_thread.get() == thread.get()) {
224 thread_list.erase(it);
225 return;
226 }
227 ++it;
228 }
229 UNREACHABLE();
230}
214 231
215 return threads; 232std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) {
233 std::vector<std::shared_ptr<Thread>> result;
234 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[address];
235 auto it = thread_list.begin();
236 while (it != thread_list.end()) {
237 std::shared_ptr<Thread> current_thread = *it;
238 result.push_back(std::move(current_thread));
239 ++it;
240 }
241 return result;
216} 242}
217} // namespace Kernel 243} // namespace Kernel
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 1e1f00e60..386983e54 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <list>
7#include <memory> 8#include <memory>
9#include <unordered_map>
8#include <vector> 10#include <vector>
9 11
10#include "common/common_types.h" 12#include "common/common_types.h"
@@ -48,6 +50,9 @@ public:
48 /// Waits on an address with a particular arbitration type. 50 /// Waits on an address with a particular arbitration type.
49 ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns); 51 ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns);
50 52
53 /// Removes a thread from the container and resets its address arbiter adress to 0
54 void HandleWakeupThread(std::shared_ptr<Thread> thread);
55
51private: 56private:
52 /// Signals an address being waited on. 57 /// Signals an address being waited on.
53 ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake); 58 ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake);
@@ -71,8 +76,20 @@ private:
71 // Waits on the given address with a timeout in nanoseconds 76 // Waits on the given address with a timeout in nanoseconds
72 ResultCode WaitForAddressImpl(VAddr address, s64 timeout); 77 ResultCode WaitForAddressImpl(VAddr address, s64 timeout);
73 78
79 /// Wake up num_to_wake (or all) threads in a vector.
80 void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake);
81
82 /// Insert a thread into the address arbiter container
83 void InsertThread(std::shared_ptr<Thread> thread);
84
85 /// Removes a thread from the address arbiter container
86 void RemoveThread(std::shared_ptr<Thread> thread);
87
74 // Gets the threads waiting on an address. 88 // Gets the threads waiting on an address.
75 std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; 89 std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address);
90
91 /// List of threads waiting for a address arbiter
92 std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> arb_threads;
76 93
77 Core::System& system; 94 Core::System& system;
78}; 95};
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0b149067a..1d0783bd3 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -78,9 +78,9 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
78 } 78 }
79 } 79 }
80 80
81 if (thread->GetArbiterWaitAddress() != 0) { 81 if (thread->GetStatus() == ThreadStatus::WaitArb) {
82 ASSERT(thread->GetStatus() == ThreadStatus::WaitArb); 82 auto& address_arbiter = thread->GetOwnerProcess()->GetAddressArbiter();
83 thread->SetArbiterWaitAddress(0); 83 address_arbiter.HandleWakeupThread(thread);
84 } 84 }
85 85
86 if (resume) { 86 if (resume) {