summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Michael Scire2018-06-21 04:07:03 -0600
committerGravatar Michael Scire2018-06-21 04:10:11 -0600
commit4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0 (patch)
tree597b478c20184a6c40692b4d7c695c8b1cac362e /src
parentKernel/Arbiters: Implement WaitForAddress (diff)
downloadyuzu-4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0.tar.gz
yuzu-4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0.tar.xz
yuzu-4f81bc4e1bd12e4df7410c6790ba818d8dbba9c0.zip
Kernel/Arbiters: Mostly implement SignalToAddress
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp110
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/svc.cpp2
-rw-r--r--src/core/hle/kernel/thread.h6
-rw-r--r--src/yuzu/debugger/wait_tree.cpp2
5 files changed, 111 insertions, 11 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 367c4520d..4556199ab 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -27,24 +27,122 @@ namespace Kernel {
27 current_thread->WakeAfterDelay(timeout); 27 current_thread->WakeAfterDelay(timeout);
28 28
29 Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule(); 29 Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
30 return RESULT_SUCCESS; 30 return current_thread->arb_wait_result;
31 }
32
33 // Gets the threads waiting on an address.
34 void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>> &waiting_threads, VAddr address) {
35 auto RetrieveWaitingThreads =
36 [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) {
37 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
38 auto& thread_list = scheduler->GetThreadList();
39
40 for (auto& thread : thread_list) {
41 if (thread->arb_wait_address == arb_addr)
42 waiting_threads.push_back(thread);
43 }
44 };
45
46 // Retrieve a list of all threads that are waiting for this address.
47 RetrieveWaitingThreads(0, waiting_threads, address);
48 RetrieveWaitingThreads(1, waiting_threads, address);
49 RetrieveWaitingThreads(2, waiting_threads, address);
50 RetrieveWaitingThreads(3, waiting_threads, address);
51 // Sort them by priority, such that the highest priority ones come first.
52 std::sort(waiting_threads.begin(), waiting_threads.end(),
53 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
54 return lhs->current_priority < rhs->current_priority;
55 });
56 }
57
58 // Wake up num_to_wake (or all) threads in a vector.
59 void WakeThreads(std::vector<SharedPtr<Thread>> &waiting_threads, s32 num_to_wake) {
60 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
61 // them all.
62 size_t last = waiting_threads.size();
63 if (num_to_wake > 0)
64 last = num_to_wake;
65
66 // Signal the waiting threads.
67 // TODO: Rescheduling should not occur while waking threads. How can it be prevented?
68 for (size_t i = 0; i < last; i++) {
69 ASSERT(waiting_threads[i]->status = THREADSTATUS_WAIT_ARB);
70 waiting_threads[i]->arb_wait_result = RESULT_SUCCESS;
71 waiting_threads[i]->ResumeFromWait();
72 }
73
31 } 74 }
32 75
33 // Signals an address being waited on. 76 // Signals an address being waited on.
34 ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) { 77 ResultCode SignalToAddress(VAddr address, s32 num_to_wake) {
35 // TODO 78 // Get threads waiting on the address.
79 std::vector<SharedPtr<Thread>> waiting_threads;
80 GetThreadsWaitingOnAddress(waiting_threads, address);
81
82 WakeThreads(waiting_threads, num_to_wake);
36 return RESULT_SUCCESS; 83 return RESULT_SUCCESS;
37 } 84 }
38 85
39 // Signals an address being waited on and increments its value if equal to the value argument. 86 // Signals an address being waited on and increments its value if equal to the value argument.
40 ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { 87 ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) {
41 // TODO 88 // Ensure that we can write to the address.
42 return RESULT_SUCCESS; 89 if (!Memory::IsValidVirtualAddress(address)) {
90 return ERR_INVALID_ADDRESS_STATE;
91 }
92
93 s32 cur_value;
94 // Get value, incrementing if equal.
95 {
96 // Increment if Equal must be an atomic operation.
97 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
98 cur_value = (s32)Memory::Read32(address);
99 if (cur_value == value) {
100 Memory::Write32(address, (u32)(cur_value + 1));
101 }
102 }
103 if (cur_value != value) {
104 return ERR_INVALID_STATE;
105 }
106
107 return SignalToAddress(address, num_to_wake);
43 } 108 }
44 109
45 // Signals an address being waited on and modifies its value based on waiting thread count if equal to the value argument. 110 // Signals an address being waited on and modifies its value based on waiting thread count if equal to the value argument.
46 ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { 111 ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) {
47 // TODO 112 // Ensure that we can write to the address.
113 if (!Memory::IsValidVirtualAddress(address)) {
114 return ERR_INVALID_ADDRESS_STATE;
115 }
116
117 // Get threads waiting on the address.
118 std::vector<SharedPtr<Thread>> waiting_threads;
119 GetThreadsWaitingOnAddress(waiting_threads, address);
120
121 // Determine the modified value depending on the waiting count.
122 s32 updated_value;
123 if (waiting_threads.size() == 0) {
124 updated_value = value - 1;
125 } else if (num_to_wake <= 0 || waiting_threads.size() <= num_to_wake) {
126 updated_value = value + 1;
127 } else {
128 updated_value = value;
129 }
130 s32 cur_value;
131 // Perform an atomic update if equal.
132 {
133 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
134 cur_value = (s32)Memory::Read32(address);
135 if (cur_value == value) {
136 Memory::Write32(address, (u32)(updated_value));
137 }
138 }
139
140 // Only continue if equal.
141 if (cur_value != value) {
142 return ERR_INVALID_STATE;
143 }
144
145 WakeThreads(waiting_threads, num_to_wake);
48 return RESULT_SUCCESS; 146 return RESULT_SUCCESS;
49 } 147 }
50 148
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 3eba103dd..32d4a77a9 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -21,7 +21,7 @@ namespace Kernel {
21 ModifyByWaitingCountAndSignalIfEqual = 2, 21 ModifyByWaitingCountAndSignalIfEqual = 2,
22 }; 22 };
23 23
24 ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake); 24 ResultCode SignalToAddress(VAddr address, s32 num_to_wake);
25 ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); 25 ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
26 ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); 26 ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake);
27 27
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4b4831c08..24dd50938 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -726,7 +726,7 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
726 726
727 switch ((AddressArbiter::SignalType)type) { 727 switch ((AddressArbiter::SignalType)type) {
728 case AddressArbiter::SignalType::Signal: 728 case AddressArbiter::SignalType::Signal:
729 return AddressArbiter::SignalToAddress(address, value, num_to_wake); 729 return AddressArbiter::SignalToAddress(address, num_to_wake);
730 case AddressArbiter::SignalType::IncrementAndSignalIfEqual: 730 case AddressArbiter::SignalType::IncrementAndSignalIfEqual:
731 return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); 731 return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);
732 case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: 732 case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual:
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 79e5d6e5c..0a76bd222 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -230,8 +230,10 @@ public:
230 VAddr condvar_wait_address; 230 VAddr condvar_wait_address;
231 VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address 231 VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address
232 Handle wait_handle; ///< The handle used to wait for the mutex. 232 Handle wait_handle; ///< The handle used to wait for the mutex.
233 VAddr arb_wait_address; ///< If waiting for an AddressArbiter, this is the address 233
234 ResultCode arb_wait_result; ///< If waiting for an AddressArbiter, this is the result that will be returned. 234 // If waiting for an AddressArbiter, this is the address being waited on.
235 VAddr arb_wait_address;
236 ResultCode arb_wait_result{RESULT_SUCCESS}; ///< Result returned when done waiting on AddressArbiter.
235 237
236 std::string name; 238 std::string name;
237 239
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 800e431bd..7101b381e 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -213,7 +213,7 @@ QString WaitTreeThread::GetText() const {
213 case THREADSTATUS_WAIT_MUTEX: 213 case THREADSTATUS_WAIT_MUTEX:
214 status = tr("waiting for mutex"); 214 status = tr("waiting for mutex");
215 break; 215 break;
216 case THREADSTATUS_WAIT_MUTEX: 216 case THREADSTATUS_WAIT_ARB:
217 status = tr("waiting for address arbiter"); 217 status = tr("waiting for address arbiter");
218 break; 218 break;
219 case THREADSTATUS_DORMANT: 219 case THREADSTATUS_DORMANT: