summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-03-03 17:19:44 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:35:25 -0400
commite4b175ade205095e7cc89e0f60c902c708d7d767 (patch)
tree7f226dc31d498c7b9ad6921d328346932b4fa1e1 /src
parentScheduler: Correct Select Threads Step 2. (diff)
downloadyuzu-e4b175ade205095e7cc89e0f60c902c708d7d767.tar.gz
yuzu-e4b175ade205095e7cc89e0f60c902c708d7d767.tar.xz
yuzu-e4b175ade205095e7cc89e0f60c902c708d7d767.zip
SVC: Correct svcWaitForAddress and svcSignalToAddress.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp214
-rw-r--r--src/core/hle/kernel/address_arbiter.h3
-rw-r--r--src/core/hle/kernel/svc.cpp3
-rw-r--r--src/core/hle/kernel/thread.h9
4 files changed, 161 insertions, 68 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 8475b698c..ebabde921 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -7,11 +7,15 @@
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/arm/exclusive_monitor.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "core/hle/kernel/address_arbiter.h" 12#include "core/hle/kernel/address_arbiter.h"
12#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
14#include "core/hle/kernel/handle_table.h"
15#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/scheduler.h" 16#include "core/hle/kernel/scheduler.h"
14#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
18#include "core/hle/kernel/time_manager.h"
15#include "core/hle/result.h" 19#include "core/hle/result.h"
16#include "core/memory.h" 20#include "core/memory.h"
17 21
@@ -20,6 +24,7 @@ namespace Kernel {
20// Wake up num_to_wake (or all) threads in a vector. 24// Wake up num_to_wake (or all) threads in a vector.
21void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, 25void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads,
22 s32 num_to_wake) { 26 s32 num_to_wake) {
27 auto& time_manager = system.Kernel().TimeManager();
23 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process 28 // Only process up to 'target' threads, unless 'target' is <= 0, in which case process
24 // them all. 29 // them all.
25 std::size_t last = waiting_threads.size(); 30 std::size_t last = waiting_threads.size();
@@ -29,12 +34,20 @@ void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& wai
29 34
30 // Signal the waiting threads. 35 // Signal the waiting threads.
31 for (std::size_t i = 0; i < last; i++) { 36 for (std::size_t i = 0; i < last; i++) {
37 if (waiting_threads[i]->GetStatus() != ThreadStatus::WaitArb) {
38 last++;
39 last = std::min(waiting_threads.size(), last);
40 continue;
41 }
42
43 time_manager.CancelTimeEvent(waiting_threads[i].get());
44
32 ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb); 45 ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb);
33 waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); 46 waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
34 RemoveThread(waiting_threads[i]); 47 RemoveThread(waiting_threads[i]);
48 waiting_threads[i]->WaitForArbitration(false);
35 waiting_threads[i]->SetArbiterWaitAddress(0); 49 waiting_threads[i]->SetArbiterWaitAddress(0);
36 waiting_threads[i]->ResumeFromWait(); 50 waiting_threads[i]->ResumeFromWait();
37 system.PrepareReschedule(waiting_threads[i]->GetProcessorID());
38 } 51 }
39} 52}
40 53
@@ -56,6 +69,7 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v
56} 69}
57 70
58ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { 71ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
72 SchedulerLock lock(system.Kernel());
59 const std::vector<std::shared_ptr<Thread>> waiting_threads = 73 const std::vector<std::shared_ptr<Thread>> waiting_threads =
60 GetThreadsWaitingOnAddress(address); 74 GetThreadsWaitingOnAddress(address);
61 WakeThreads(waiting_threads, num_to_wake); 75 WakeThreads(waiting_threads, num_to_wake);
@@ -64,6 +78,7 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
64 78
65ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, 79ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value,
66 s32 num_to_wake) { 80 s32 num_to_wake) {
81 SchedulerLock lock(system.Kernel());
67 auto& memory = system.Memory(); 82 auto& memory = system.Memory();
68 83
69 // Ensure that we can write to the address. 84 // Ensure that we can write to the address.
@@ -71,16 +86,25 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
71 return ERR_INVALID_ADDRESS_STATE; 86 return ERR_INVALID_ADDRESS_STATE;
72 } 87 }
73 88
74 if (static_cast<s32>(memory.Read32(address)) != value) { 89 const std::size_t current_core = system.CurrentCoreIndex();
75 return ERR_INVALID_STATE; 90 auto& monitor = system.Monitor();
76 } 91 u32 current_value;
92 do {
93 monitor.SetExclusive(current_core, address);
94 current_value = memory.Read32(address);
95
96 if (current_value != value) {
97 return ERR_INVALID_STATE;
98 }
99 current_value++;
100 } while (!monitor.ExclusiveWrite32(current_core, address, current_value));
77 101
78 memory.Write32(address, static_cast<u32>(value + 1));
79 return SignalToAddressOnly(address, num_to_wake); 102 return SignalToAddressOnly(address, num_to_wake);
80} 103}
81 104
82ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, 105ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
83 s32 num_to_wake) { 106 s32 num_to_wake) {
107 SchedulerLock lock(system.Kernel());
84 auto& memory = system.Memory(); 108 auto& memory = system.Memory();
85 109
86 // Ensure that we can write to the address. 110 // Ensure that we can write to the address.
@@ -92,29 +116,34 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a
92 const std::vector<std::shared_ptr<Thread>> waiting_threads = 116 const std::vector<std::shared_ptr<Thread>> waiting_threads =
93 GetThreadsWaitingOnAddress(address); 117 GetThreadsWaitingOnAddress(address);
94 118
95 // Determine the modified value depending on the waiting count. 119 const std::size_t current_core = system.CurrentCoreIndex();
120 auto& monitor = system.Monitor();
96 s32 updated_value; 121 s32 updated_value;
97 if (num_to_wake <= 0) { 122 do {
98 if (waiting_threads.empty()) { 123 monitor.SetExclusive(current_core, address);
99 updated_value = value + 1; 124 updated_value = memory.Read32(address);
100 } else { 125
101 updated_value = value - 1; 126 if (updated_value != value) {
127 return ERR_INVALID_STATE;
102 } 128 }
103 } else { 129 // Determine the modified value depending on the waiting count.
104 if (waiting_threads.empty()) { 130 if (num_to_wake <= 0) {
105 updated_value = value + 1; 131 if (waiting_threads.empty()) {
106 } else if (waiting_threads.size() <= static_cast<u32>(num_to_wake)) { 132 updated_value = value + 1;
107 updated_value = value - 1; 133 } else {
134 updated_value = value - 1;
135 }
108 } else { 136 } else {
109 updated_value = value; 137 if (waiting_threads.empty()) {
138 updated_value = value + 1;
139 } else if (waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
140 updated_value = value - 1;
141 } else {
142 updated_value = value;
143 }
110 } 144 }
111 } 145 } while (!monitor.ExclusiveWrite32(current_core, address, updated_value));
112 146
113 if (static_cast<s32>(memory.Read32(address)) != value) {
114 return ERR_INVALID_STATE;
115 }
116
117 memory.Write32(address, static_cast<u32>(updated_value));
118 WakeThreads(waiting_threads, num_to_wake); 147 WakeThreads(waiting_threads, num_to_wake);
119 return RESULT_SUCCESS; 148 return RESULT_SUCCESS;
120} 149}
@@ -136,60 +165,121 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s
136ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, 165ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout,
137 bool should_decrement) { 166 bool should_decrement) {
138 auto& memory = system.Memory(); 167 auto& memory = system.Memory();
168 auto& kernel = system.Kernel();
169 Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
139 170
140 // Ensure that we can read the address. 171 Handle event_handle = InvalidHandle;
141 if (!memory.IsValidVirtualAddress(address)) { 172 {
142 return ERR_INVALID_ADDRESS_STATE; 173 SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
143 } 174
175 // Ensure that we can read the address.
176 if (!memory.IsValidVirtualAddress(address)) {
177 lock.CancelSleep();
178 return ERR_INVALID_ADDRESS_STATE;
179 }
180
181 /// TODO(Blinkhawk): Check termination pending.
182
183 s32 current_value = static_cast<s32>(memory.Read32(address));
184 if (current_value >= value) {
185 lock.CancelSleep();
186 return ERR_INVALID_STATE;
187 }
144 188
145 const s32 cur_value = static_cast<s32>(memory.Read32(address)); 189 s32 decrement_value;
146 if (cur_value >= value) { 190
147 return ERR_INVALID_STATE; 191 const std::size_t current_core = system.CurrentCoreIndex();
192 auto& monitor = system.Monitor();
193 do {
194 monitor.SetExclusive(current_core, address);
195 current_value = static_cast<s32>(memory.Read32(address));
196 if (should_decrement) {
197 decrement_value = current_value - 1;
198 } else {
199 decrement_value = current_value;
200 }
201 } while (
202 !monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(decrement_value)));
203
204 // Short-circuit without rescheduling, if timeout is zero.
205 if (timeout == 0) {
206 lock.CancelSleep();
207 return RESULT_TIMEOUT;
208 }
209
210 current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
211 current_thread->SetArbiterWaitAddress(address);
212 InsertThread(SharedFrom(current_thread));
213 current_thread->SetStatus(ThreadStatus::WaitArb);
214 current_thread->WaitForArbitration(true);
148 } 215 }
149 216
150 if (should_decrement) { 217 if (event_handle != InvalidHandle) {
151 memory.Write32(address, static_cast<u32>(cur_value - 1)); 218 auto& time_manager = kernel.TimeManager();
219 time_manager.UnscheduleTimeEvent(event_handle);
152 } 220 }
153 221
154 // Short-circuit without rescheduling, if timeout is zero. 222 {
155 if (timeout == 0) { 223 SchedulerLock lock(kernel);
156 return RESULT_TIMEOUT; 224 if (current_thread->IsWaitingForArbitration()) {
225 RemoveThread(SharedFrom(current_thread));
226 current_thread->WaitForArbitration(false);
227 }
157 } 228 }
158 229
159 return WaitForAddressImpl(address, timeout); 230 return current_thread->GetSignalingResult();
160} 231}
161 232
162ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { 233ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
163 auto& memory = system.Memory(); 234 auto& memory = system.Memory();
235 auto& kernel = system.Kernel();
236 Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
164 237
165 // Ensure that we can read the address. 238 Handle event_handle = InvalidHandle;
166 if (!memory.IsValidVirtualAddress(address)) { 239 {
167 return ERR_INVALID_ADDRESS_STATE; 240 SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
168 } 241
242 // Ensure that we can read the address.
243 if (!memory.IsValidVirtualAddress(address)) {
244 lock.CancelSleep();
245 return ERR_INVALID_ADDRESS_STATE;
246 }
247
248 /// TODO(Blinkhawk): Check termination pending.
169 249
170 // Only wait for the address if equal. 250 s32 current_value = static_cast<s32>(memory.Read32(address));
171 if (static_cast<s32>(memory.Read32(address)) != value) { 251 if (current_value != value) {
172 return ERR_INVALID_STATE; 252 lock.CancelSleep();
253 return ERR_INVALID_STATE;
254 }
255
256 // Short-circuit without rescheduling, if timeout is zero.
257 if (timeout == 0) {
258 lock.CancelSleep();
259 return RESULT_TIMEOUT;
260 }
261
262 current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
263 current_thread->SetArbiterWaitAddress(address);
264 InsertThread(SharedFrom(current_thread));
265 current_thread->SetStatus(ThreadStatus::WaitArb);
266 current_thread->WaitForArbitration(true);
173 } 267 }
174 268
175 // Short-circuit without rescheduling if timeout is zero. 269 if (event_handle != InvalidHandle) {
176 if (timeout == 0) { 270 auto& time_manager = kernel.TimeManager();
177 return RESULT_TIMEOUT; 271 time_manager.UnscheduleTimeEvent(event_handle);
178 } 272 }
179 273
180 return WaitForAddressImpl(address, timeout); 274 {
181} 275 SchedulerLock lock(kernel);
276 if (current_thread->IsWaitingForArbitration()) {
277 RemoveThread(SharedFrom(current_thread));
278 current_thread->WaitForArbitration(false);
279 }
280 }
182 281
183ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { 282 return current_thread->GetSignalingResult();
184 Thread* current_thread = system.CurrentScheduler().GetCurrentThread();
185 current_thread->SetArbiterWaitAddress(address);
186 InsertThread(SharedFrom(current_thread));
187 current_thread->SetStatus(ThreadStatus::WaitArb);
188 current_thread->InvalidateWakeupCallback();
189 current_thread->WakeAfterDelay(timeout);
190
191 system.PrepareReschedule(current_thread->GetProcessorID());
192 return RESULT_TIMEOUT;
193} 283}
194 284
195void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) { 285void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) {
@@ -221,9 +311,9 @@ void AddressArbiter::RemoveThread(std::shared_ptr<Thread> thread) {
221 const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(), 311 const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(),
222 [&thread](const auto& entry) { return thread == entry; }); 312 [&thread](const auto& entry) { return thread == entry; });
223 313
224 ASSERT(iter != thread_list.cend()); 314 if (iter != thread_list.cend()) {
225 315 thread_list.erase(iter);
226 thread_list.erase(iter); 316 }
227} 317}
228 318
229std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress( 319std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index f958eee5a..0b05d533c 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -73,9 +73,6 @@ private:
73 /// Waits on an address if the value passed is equal to the argument value. 73 /// Waits on an address if the value passed is equal to the argument value.
74 ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); 74 ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout);
75 75
76 // Waits on the given address with a timeout in nanoseconds
77 ResultCode WaitForAddressImpl(VAddr address, s64 timeout);
78
79 /// Wake up num_to_wake (or all) threads in a vector. 76 /// 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); 77 void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake);
81 78
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 5e9dd43bf..718462b2b 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1691,7 +1691,6 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type,
1691 LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address, 1691 LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address,
1692 type, value, timeout); 1692 type, value, timeout);
1693 1693
1694 UNIMPLEMENTED();
1695 // If the passed address is a kernel virtual address, return invalid memory state. 1694 // If the passed address is a kernel virtual address, return invalid memory state.
1696 if (Core::Memory::IsKernelVirtualAddress(address)) { 1695 if (Core::Memory::IsKernelVirtualAddress(address)) {
1697 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); 1696 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
@@ -1717,8 +1716,6 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type,
1717 LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", 1716 LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}",
1718 address, type, value, num_to_wake); 1717 address, type, value, num_to_wake);
1719 1718
1720 UNIMPLEMENTED();
1721
1722 // If the passed address is a kernel virtual address, return invalid memory state. 1719 // If the passed address is a kernel virtual address, return invalid memory state.
1723 if (Core::Memory::IsKernelVirtualAddress(address)) { 1720 if (Core::Memory::IsKernelVirtualAddress(address)) {
1724 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); 1721 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 7b6d1b4ec..e8355bbd1 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -548,6 +548,14 @@ public:
548 return global_handle; 548 return global_handle;
549 } 549 }
550 550
551 bool IsWaitingForArbitration() const {
552 return waiting_for_arbitration;
553 }
554
555 void WaitForArbitration(bool set) {
556 waiting_for_arbitration = set;
557 }
558
551private: 559private:
552 friend class GlobalScheduler; 560 friend class GlobalScheduler;
553 friend class Scheduler; 561 friend class Scheduler;
@@ -615,6 +623,7 @@ private:
615 623
616 /// If waiting for an AddressArbiter, this is the address being waited on. 624 /// If waiting for an AddressArbiter, this is the address being waited on.
617 VAddr arb_wait_address{0}; 625 VAddr arb_wait_address{0};
626 bool waiting_for_arbitration{};
618 627
619 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. 628 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
620 Handle global_handle = 0; 629 Handle global_handle = 0;