diff options
| author | 2015-01-17 02:03:44 -0500 | |
|---|---|---|
| committer | 2015-01-21 19:09:03 -0500 | |
| commit | 7faf2d8e06e705d1866fa0d7848ff43541a4b172 (patch) | |
| tree | 7cca6433c6b06a1299af1193df2cedac7ad522c5 /src/core/hle/kernel/thread.cpp | |
| parent | Event: Fixed some bugs and cleanup (Subv) (diff) | |
| download | yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.gz yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.tar.xz yuzu-7faf2d8e06e705d1866fa0d7848ff43541a4b172.zip | |
WaitSynchronizationN: Implement return values
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 94 |
1 files changed, 75 insertions, 19 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 00b72477e..0c9ecc091 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -22,11 +22,11 @@ | |||
| 22 | 22 | ||
| 23 | namespace Kernel { | 23 | namespace Kernel { |
| 24 | 24 | ||
| 25 | ResultVal<bool> Thread::WaitSynchronization() { | 25 | ResultVal<bool> Thread::WaitSynchronization(unsigned index) { |
| 26 | const bool wait = status != THREADSTATUS_DORMANT; | 26 | const bool wait = status != THREADSTATUS_DORMANT; |
| 27 | if (wait) { | 27 | if (wait) { |
| 28 | AddWaitingThread(GetCurrentThread()); | 28 | AddWaitingThread(GetCurrentThread()); |
| 29 | WaitCurrentThread(WAITTYPE_THREADEND, this); | 29 | WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | return MakeResult<bool>(wait); | 32 | return MakeResult<bool>(wait); |
| @@ -92,11 +92,11 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { | |||
| 92 | 92 | ||
| 93 | /// Check if a thread is blocking on a specified wait type with a specified handle | 93 | /// Check if a thread is blocking on a specified wait type with a specified handle |
| 94 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { | 94 | static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { |
| 95 | auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); | 95 | for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { |
| 96 | if (itr == thread->wait_objects.end()) { | 96 | if (itr->first == wait_object) |
| 97 | return false; | 97 | return CheckWaitType(thread, type); |
| 98 | } | 98 | } |
| 99 | return CheckWaitType(thread, type); | 99 | return false; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | /// Check if a thread is blocking on a specified wait type with a specified handle and address | 102 | /// Check if a thread is blocking on a specified wait type with a specified handle and address |
| @@ -111,7 +111,7 @@ void Thread::Stop(const char* reason) { | |||
| 111 | 111 | ||
| 112 | ChangeReadyState(this, false); | 112 | ChangeReadyState(this, false); |
| 113 | status = THREADSTATUS_DORMANT; | 113 | status = THREADSTATUS_DORMANT; |
| 114 | ResumeAllWaitingThreads(); | 114 | ReleaseAllWaitingThreads(); |
| 115 | 115 | ||
| 116 | // Stopped threads are never waiting. | 116 | // Stopped threads are never waiting. |
| 117 | wait_type = WAITTYPE_NONE; | 117 | wait_type = WAITTYPE_NONE; |
| @@ -135,7 +135,7 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { | |||
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | /// Arbitrate the highest priority thread that is waiting | 137 | /// Arbitrate the highest priority thread that is waiting |
| 138 | Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { | 138 | Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { |
| 139 | Thread* highest_priority_thread = nullptr; | 139 | Thread* highest_priority_thread = nullptr; |
| 140 | s32 priority = THREADPRIO_LOWEST; | 140 | s32 priority = THREADPRIO_LOWEST; |
| 141 | 141 | ||
| @@ -155,19 +155,19 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { | |||
| 155 | 155 | ||
| 156 | // If a thread was arbitrated, resume it | 156 | // If a thread was arbitrated, resume it |
| 157 | if (nullptr != highest_priority_thread) { | 157 | if (nullptr != highest_priority_thread) { |
| 158 | highest_priority_thread->ResumeFromWait(); | 158 | highest_priority_thread->ReleaseFromWait(arbiter); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | return highest_priority_thread; | 161 | return highest_priority_thread; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | /// Arbitrate all threads currently waiting | 164 | /// Arbitrate all threads currently waiting |
| 165 | void ArbitrateAllThreads(Object* arbiter, u32 address) { | 165 | void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { |
| 166 | 166 | ||
| 167 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | 167 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |
| 168 | for (auto& thread : thread_list) { | 168 | for (auto& thread : thread_list) { |
| 169 | if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) | 169 | if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) |
| 170 | thread->ResumeFromWait(); | 170 | thread->ReleaseFromWait(arbiter); |
| 171 | } | 171 | } |
| 172 | } | 172 | } |
| 173 | 173 | ||
| @@ -220,19 +220,32 @@ static Thread* NextThread() { | |||
| 220 | return next; | 220 | return next; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) { | 223 | void WaitCurrentThread(WaitType wait_type) { |
| 224 | Thread* thread = GetCurrentThread(); | ||
| 225 | thread->wait_type = wait_type; | ||
| 226 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | ||
| 227 | } | ||
| 228 | |||
| 229 | void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index) { | ||
| 224 | Thread* thread = GetCurrentThread(); | 230 | Thread* thread = GetCurrentThread(); |
| 225 | thread->wait_type = wait_type; | 231 | thread->wait_type = wait_type; |
| 226 | 232 | ||
| 227 | auto res = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); | 233 | bool insert_wait_object = true; |
| 228 | if (res == thread->wait_objects.end()) { | 234 | for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) { |
| 229 | thread->wait_objects.push_back(wait_object); | 235 | if (itr->first == wait_object) { |
| 236 | insert_wait_object = false; | ||
| 237 | break; | ||
| 238 | } | ||
| 230 | } | 239 | } |
| 240 | |||
| 241 | if (insert_wait_object) | ||
| 242 | thread->wait_objects.push_back(std::pair<SharedPtr<WaitObject>, unsigned>(wait_object, index)); | ||
| 243 | |||
| 231 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); | 244 | ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); |
| 232 | } | 245 | } |
| 233 | 246 | ||
| 234 | void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) { | 247 | void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { |
| 235 | WaitCurrentThread(wait_type, wait_object); | 248 | WaitCurrentThread_WaitSynchronization(WaitType::WAITTYPE_ARB, wait_object, 0); |
| 236 | GetCurrentThread()->wait_address = wait_address; | 249 | GetCurrentThread()->wait_address = wait_address; |
| 237 | } | 250 | } |
| 238 | 251 | ||
| @@ -248,6 +261,9 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { | |||
| 248 | return; | 261 | return; |
| 249 | } | 262 | } |
| 250 | 263 | ||
| 264 | thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | ||
| 265 | ErrorSummary::StatusChanged, ErrorLevel::Info), -1); | ||
| 266 | |||
| 251 | thread->ResumeFromWait(); | 267 | thread->ResumeFromWait(); |
| 252 | } | 268 | } |
| 253 | 269 | ||
| @@ -262,7 +278,40 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { | |||
| 262 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); | 278 | CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); |
| 263 | } | 279 | } |
| 264 | 280 | ||
| 265 | /// Resumes a thread from waiting by marking it as "ready" | 281 | void Thread::ReleaseFromWait(WaitObject* wait_object) { |
| 282 | if (wait_objects.empty()) { | ||
| 283 | LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); | ||
| 284 | return; | ||
| 285 | } | ||
| 286 | |||
| 287 | // Remove this thread from the wait_object | ||
| 288 | wait_object->RemoveWaitingThread(this); | ||
| 289 | |||
| 290 | // Find the waiting object | ||
| 291 | auto itr = wait_objects.begin(); | ||
| 292 | for (; itr != wait_objects.end(); ++itr) { | ||
| 293 | if (wait_object == itr->first) | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | unsigned index = itr->second; | ||
| 297 | |||
| 298 | // Remove the wait_object from this thread | ||
| 299 | if (itr != wait_objects.end()) | ||
| 300 | wait_objects.erase(itr); | ||
| 301 | |||
| 302 | // If wait_all=false, resume the thread on a release wait_object from wait | ||
| 303 | if (!wait_all) { | ||
| 304 | SetReturnValue(RESULT_SUCCESS, index); | ||
| 305 | ResumeFromWait(); | ||
| 306 | } else { | ||
| 307 | // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released | ||
| 308 | if (wait_objects.empty()) { | ||
| 309 | SetReturnValue(RESULT_SUCCESS, -1); | ||
| 310 | ResumeFromWait(); | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 266 | void Thread::ResumeFromWait() { | 315 | void Thread::ResumeFromWait() { |
| 267 | // Cancel any outstanding wakeup events | 316 | // Cancel any outstanding wakeup events |
| 268 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); | 317 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); |
| @@ -271,11 +320,12 @@ void Thread::ResumeFromWait() { | |||
| 271 | 320 | ||
| 272 | // Remove this thread from all other WaitObjects | 321 | // Remove this thread from all other WaitObjects |
| 273 | for (auto wait_object : wait_objects) | 322 | for (auto wait_object : wait_objects) |
| 274 | wait_object->RemoveWaitingThread(this); | 323 | wait_object.first->RemoveWaitingThread(this); |
| 275 | 324 | ||
| 276 | wait_objects.clear(); | 325 | wait_objects.clear(); |
| 277 | 326 | ||
| 278 | wait_type = WAITTYPE_NONE; | 327 | wait_type = WAITTYPE_NONE; |
| 328 | wait_all = false; | ||
| 279 | if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | 329 | if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |
| 280 | ChangeReadyState(this, true); | 330 | ChangeReadyState(this, true); |
| 281 | } | 331 | } |
| @@ -342,6 +392,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 342 | thread->initial_priority = thread->current_priority = priority; | 392 | thread->initial_priority = thread->current_priority = priority; |
| 343 | thread->processor_id = processor_id; | 393 | thread->processor_id = processor_id; |
| 344 | thread->wait_type = WAITTYPE_NONE; | 394 | thread->wait_type = WAITTYPE_NONE; |
| 395 | thread->wait_all = false; | ||
| 345 | thread->wait_objects.clear(); | 396 | thread->wait_objects.clear(); |
| 346 | thread->wait_address = 0; | 397 | thread->wait_address = 0; |
| 347 | thread->name = std::move(name); | 398 | thread->name = std::move(name); |
| @@ -432,6 +483,11 @@ void Reschedule() { | |||
| 432 | } | 483 | } |
| 433 | } | 484 | } |
| 434 | 485 | ||
| 486 | void Thread::SetReturnValue(ResultCode return_val, s32 out_val) { | ||
| 487 | context.cpu_registers[0] = return_val.raw; | ||
| 488 | context.cpu_registers[1] = out_val; | ||
| 489 | } | ||
| 490 | |||
| 435 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 491 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 436 | 492 | ||
| 437 | void ThreadingInit() { | 493 | void ThreadingInit() { |