summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-01-20 20:53:52 -0500
committerGravatar bunnei2015-01-21 20:48:46 -0500
commit68ddaaa2f5726e3619accee77b488ec285f3a2d7 (patch)
treef9d349d09c66efe768fbb4aed67b7b163c3ffec7 /src
parentThread: Use std::find in CheckWait_WaitObject. (diff)
downloadyuzu-68ddaaa2f5726e3619accee77b488ec285f3a2d7.tar.gz
yuzu-68ddaaa2f5726e3619accee77b488ec285f3a2d7.tar.xz
yuzu-68ddaaa2f5726e3619accee77b488ec285f3a2d7.zip
Thread: Fix WaitSynchronization1 to not set register 1 on thread wakeup.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/thread.cpp43
-rw-r--r--src/core/hle/kernel/thread.h21
-rw-r--r--src/core/hle/svc.cpp6
3 files changed, 45 insertions, 25 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 58523e145..03b492c75 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -205,25 +205,24 @@ static Thread* NextThread() {
205 205
206void WaitCurrentThread_Sleep() { 206void WaitCurrentThread_Sleep() {
207 Thread* thread = GetCurrentThread(); 207 Thread* thread = GetCurrentThread();
208 thread->wait_all = false;
209 thread->wait_address = 0;
210 thread->wait_objects.clear();
211 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); 208 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
212} 209}
213 210
214void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_all) { 211void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all) {
215 Thread* thread = GetCurrentThread(); 212 Thread* thread = GetCurrentThread();
213 thread->wait_set_output = wait_set_output;
216 thread->wait_all = wait_all; 214 thread->wait_all = wait_all;
217 thread->wait_address = 0; 215
218 thread->wait_objects.push_back(wait_object); 216 // It's possible to call WaitSynchronizationN without any objects passed in...
217 if (wait_object != nullptr)
218 thread->wait_objects.push_back(wait_object);
219
219 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); 220 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
220} 221}
221 222
222void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { 223void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
223 Thread* thread = GetCurrentThread(); 224 Thread* thread = GetCurrentThread();
224 thread->wait_all = false;
225 thread->wait_address = wait_address; 225 thread->wait_address = wait_address;
226 thread->wait_objects.clear();
227 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); 226 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
228} 227}
229 228
@@ -239,8 +238,11 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) {
239 return; 238 return;
240 } 239 }
241 240
242 thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, 241 thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
243 ErrorSummary::StatusChanged, ErrorLevel::Info), -1); 242 ErrorSummary::StatusChanged, ErrorLevel::Info));
243
244 if (thread->wait_set_output)
245 thread->SetWaitSynchronizationOutput(-1);
244 246
245 thread->ResumeFromWait(); 247 thread->ResumeFromWait();
246} 248}
@@ -282,12 +284,18 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) {
282 if (wait_all) { 284 if (wait_all) {
283 // Resume the thread only if all are available... 285 // Resume the thread only if all are available...
284 if (!wait_all_failed) { 286 if (!wait_all_failed) {
285 SetReturnValue(RESULT_SUCCESS, -1); 287 SetWaitSynchronizationResult(RESULT_SUCCESS);
288 SetWaitSynchronizationOutput(-1);
289
286 ResumeFromWait(); 290 ResumeFromWait();
287 } 291 }
288 } else { 292 } else {
289 // Otherwise, resume 293 // Otherwise, resume
290 SetReturnValue(RESULT_SUCCESS, index); 294 SetWaitSynchronizationResult(RESULT_SUCCESS);
295
296 if (wait_set_output)
297 SetWaitSynchronizationOutput(index);
298
291 ResumeFromWait(); 299 ResumeFromWait();
292 } 300 }
293} 301}
@@ -303,6 +311,7 @@ void Thread::ResumeFromWait() {
303 wait_object->RemoveWaitingThread(this); 311 wait_object->RemoveWaitingThread(this);
304 312
305 wait_objects.clear(); 313 wait_objects.clear();
314 wait_set_output = false;
306 wait_all = false; 315 wait_all = false;
307 wait_address = 0; 316 wait_address = 0;
308 317
@@ -371,6 +380,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
371 thread->stack_size = stack_size; 380 thread->stack_size = stack_size;
372 thread->initial_priority = thread->current_priority = priority; 381 thread->initial_priority = thread->current_priority = priority;
373 thread->processor_id = processor_id; 382 thread->processor_id = processor_id;
383 thread->wait_set_output = false;
374 thread->wait_all = false; 384 thread->wait_all = false;
375 thread->wait_objects.clear(); 385 thread->wait_objects.clear();
376 thread->wait_address = 0; 386 thread->wait_address = 0;
@@ -462,9 +472,12 @@ void Reschedule() {
462 } 472 }
463} 473}
464 474
465void Thread::SetReturnValue(ResultCode return_val, s32 out_val) { 475void Thread::SetWaitSynchronizationResult(ResultCode result) {
466 context.cpu_registers[0] = return_val.raw; 476 context.cpu_registers[0] = result.raw;
467 context.cpu_registers[1] = out_val; 477}
478
479void Thread::SetWaitSynchronizationOutput(s32 output) {
480 context.cpu_registers[1] = output;
468} 481}
469 482
470//////////////////////////////////////////////////////////////////////////////////////////////////// 483////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index bed9f714a..5fab1ab58 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -78,11 +78,16 @@ public:
78 void ResumeFromWait(); 78 void ResumeFromWait();
79 79
80 /** 80 /**
81 * Sets the output values after the thread awakens from WaitSynchronization 81 * Sets the result after the thread awakens (from either WaitSynchronization SVC)
82 * @param return_val Value returned 82 * @param result Value to set to the returned result
83 * @param out_val Value to set to the output parameter
84 */ 83 */
85 void SetReturnValue(ResultCode return_val, s32 out_val); 84 void SetWaitSynchronizationResult(ResultCode result);
85
86 /**
87 * Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only)
88 * @param output Value to set to the output parameter
89 */
90 void SetWaitSynchronizationOutput(s32 output);
86 91
87 Core::ThreadContext context; 92 Core::ThreadContext context;
88 93
@@ -100,8 +105,9 @@ public:
100 105
101 std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on 106 std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
102 107
103 VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address 108 VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
104 bool wait_all; ///< True if the thread is waiting on all objects before resuming 109 bool wait_all; ///< True if the thread is waiting on all objects before resuming
110 bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
105 111
106 std::string name; 112 std::string name;
107 113
@@ -134,9 +140,10 @@ void WaitCurrentThread_Sleep();
134/** 140/**
135 * Waits the current thread from a WaitSynchronization call 141 * Waits the current thread from a WaitSynchronization call
136 * @param wait_object Kernel object that we are waiting on 142 * @param wait_object Kernel object that we are waiting on
143 * @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only)
137 * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) 144 * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
138 */ 145 */
139void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_all = false); 146void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_set_output, bool wait_all);
140 147
141/** 148/**
142 * Waits the current thread from an ArbitrateAddress call 149 * Waits the current thread from an ArbitrateAddress call
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index f6c912502..89095ac91 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -126,7 +126,7 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
126 if (object->ShouldWait()) { 126 if (object->ShouldWait()) {
127 127
128 object->AddWaitingThread(Kernel::GetCurrentThread()); 128 object->AddWaitingThread(Kernel::GetCurrentThread());
129 Kernel::WaitCurrentThread_WaitSynchronization(object); 129 Kernel::WaitCurrentThread_WaitSynchronization(object, false, false);
130 130
131 // Create an event to wake the thread up after the specified nanosecond delay has passed 131 // Create an event to wake the thread up after the specified nanosecond delay has passed
132 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); 132 Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds);
@@ -187,7 +187,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
187 // NOTE: This should deadlock the current thread if no timeout was specified 187 // NOTE: This should deadlock the current thread if no timeout was specified
188 if (!wait_all) { 188 if (!wait_all) {
189 wait_thread = true; 189 wait_thread = true;
190 Kernel::WaitCurrentThread_Sleep(); 190 Kernel::WaitCurrentThread_WaitSynchronization(nullptr, true, wait_all);
191 } 191 }
192 } 192 }
193 193
@@ -198,7 +198,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
198 for (int i = 0; i < handle_count; ++i) { 198 for (int i = 0; i < handle_count; ++i) {
199 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); 199 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
200 object->AddWaitingThread(Kernel::GetCurrentThread()); 200 object->AddWaitingThread(Kernel::GetCurrentThread());
201 Kernel::WaitCurrentThread_WaitSynchronization(object, wait_all); 201 Kernel::WaitCurrentThread_WaitSynchronization(object, true, wait_all);
202 } 202 }
203 203
204 // Create an event to wake the thread up after the specified nanosecond delay has passed 204 // Create an event to wake the thread up after the specified nanosecond delay has passed