diff options
| author | 2015-01-20 20:53:52 -0500 | |
|---|---|---|
| committer | 2015-01-21 20:48:46 -0500 | |
| commit | 68ddaaa2f5726e3619accee77b488ec285f3a2d7 (patch) | |
| tree | f9d349d09c66efe768fbb4aed67b7b163c3ffec7 /src/core | |
| parent | Thread: Use std::find in CheckWait_WaitObject. (diff) | |
| download | yuzu-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/core')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 43 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 21 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 6 |
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 | ||
| 206 | void WaitCurrentThread_Sleep() { | 206 | void 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 | ||
| 214 | void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_all) { | 211 | void 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 | ||
| 222 | void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { | 223 | void 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 | ||
| 465 | void Thread::SetReturnValue(ResultCode return_val, s32 out_val) { | 475 | void 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 | |||
| 479 | void 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 | */ |
| 139 | void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bool wait_all = false); | 146 | void 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 |