diff options
| author | 2017-01-05 12:55:01 -0500 | |
|---|---|---|
| committer | 2017-01-05 12:55:01 -0500 | |
| commit | f20d872643654c574f73a263f032613046900f07 (patch) | |
| tree | 021284c18034d053c81928fa19d2efb6658451fb /src/core/hle/kernel/thread.cpp | |
| parent | Merge pull request #2407 from jroweboy/nightly-deploy (diff) | |
| parent | Kernel: Add some asserts to enforce the invariants in the scheduler. (diff) | |
| download | yuzu-f20d872643654c574f73a263f032613046900f07.tar.gz yuzu-f20d872643654c574f73a263f032613046900f07.tar.xz yuzu-f20d872643654c574f73a263f032613046900f07.zip | |
Merge pull request #2393 from Subv/synch
Kernel: Mutex priority inheritance and synchronization improvements.
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 50 |
1 files changed, 37 insertions, 13 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 5fb95dada..9109bd10b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -27,12 +27,12 @@ namespace Kernel { | |||
| 27 | /// Event type for the thread wake up event | 27 | /// Event type for the thread wake up event |
| 28 | static int ThreadWakeupEventType; | 28 | static int ThreadWakeupEventType; |
| 29 | 29 | ||
| 30 | bool Thread::ShouldWait() { | 30 | bool Thread::ShouldWait(Thread* thread) const { |
| 31 | return status != THREADSTATUS_DEAD; | 31 | return status != THREADSTATUS_DEAD; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | void Thread::Acquire() { | 34 | void Thread::Acquire(Thread* thread) { |
| 35 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | 35 | ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing | 38 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing |
| @@ -72,7 +72,8 @@ Thread* GetCurrentThread() { | |||
| 72 | * @return True if the thread is waiting, false otherwise | 72 | * @return True if the thread is waiting, false otherwise |
| 73 | */ | 73 | */ |
| 74 | static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { | 74 | static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { |
| 75 | if (thread->status != THREADSTATUS_WAIT_SYNCH) | 75 | if (thread->status != THREADSTATUS_WAIT_SYNCH_ALL && |
| 76 | thread->status != THREADSTATUS_WAIT_SYNCH_ANY) | ||
| 76 | return false; | 77 | return false; |
| 77 | 78 | ||
| 78 | auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); | 79 | auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); |
| @@ -90,9 +91,6 @@ static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { | |||
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | void Thread::Stop() { | 93 | void Thread::Stop() { |
| 93 | // Release all the mutexes that this thread holds | ||
| 94 | ReleaseThreadMutexes(this); | ||
| 95 | |||
| 96 | // Cancel any outstanding wakeup events for this thread | 94 | // Cancel any outstanding wakeup events for this thread |
| 97 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); | 95 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); |
| 98 | wakeup_callback_handle_table.Close(callback_handle); | 96 | wakeup_callback_handle_table.Close(callback_handle); |
| @@ -114,6 +112,9 @@ void Thread::Stop() { | |||
| 114 | } | 112 | } |
| 115 | wait_objects.clear(); | 113 | wait_objects.clear(); |
| 116 | 114 | ||
| 115 | // Release all the mutexes that this thread holds | ||
| 116 | ReleaseThreadMutexes(this); | ||
| 117 | |||
| 117 | // Mark the TLS slot in the thread's page as free. | 118 | // Mark the TLS slot in the thread's page as free. |
| 118 | u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; | 119 | u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; |
| 119 | u32 tls_slot = | 120 | u32 tls_slot = |
| @@ -199,8 +200,8 @@ static void SwitchContext(Thread* new_thread) { | |||
| 199 | 200 | ||
| 200 | // Load context of new thread | 201 | // Load context of new thread |
| 201 | if (new_thread) { | 202 | if (new_thread) { |
| 202 | DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, | 203 | ASSERT_MSG(new_thread->status == THREADSTATUS_READY, |
| 203 | "Thread must be ready to become running."); | 204 | "Thread must be ready to become running."); |
| 204 | 205 | ||
| 205 | // Cancel any outstanding wakeup events for this thread | 206 | // Cancel any outstanding wakeup events for this thread |
| 206 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); | 207 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); |
| @@ -253,7 +254,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa | |||
| 253 | Thread* thread = GetCurrentThread(); | 254 | Thread* thread = GetCurrentThread(); |
| 254 | thread->wait_set_output = wait_set_output; | 255 | thread->wait_set_output = wait_set_output; |
| 255 | thread->wait_objects = std::move(wait_objects); | 256 | thread->wait_objects = std::move(wait_objects); |
| 256 | thread->status = THREADSTATUS_WAIT_SYNCH; | 257 | thread->status = THREADSTATUS_WAIT_SYNCH_ANY; |
| 257 | } | 258 | } |
| 258 | 259 | ||
| 259 | void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { | 260 | void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { |
| @@ -281,7 +282,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 281 | return; | 282 | return; |
| 282 | } | 283 | } |
| 283 | 284 | ||
| 284 | if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { | 285 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || |
| 286 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { | ||
| 285 | thread->wait_set_output = false; | 287 | thread->wait_set_output = false; |
| 286 | // Remove the thread from each of its waiting objects' waitlists | 288 | // Remove the thread from each of its waiting objects' waitlists |
| 287 | for (auto& object : thread->wait_objects) | 289 | for (auto& object : thread->wait_objects) |
| @@ -305,8 +307,11 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { | |||
| 305 | } | 307 | } |
| 306 | 308 | ||
| 307 | void Thread::ResumeFromWait() { | 309 | void Thread::ResumeFromWait() { |
| 310 | ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); | ||
| 311 | |||
| 308 | switch (status) { | 312 | switch (status) { |
| 309 | case THREADSTATUS_WAIT_SYNCH: | 313 | case THREADSTATUS_WAIT_SYNCH_ALL: |
| 314 | case THREADSTATUS_WAIT_SYNCH_ANY: | ||
| 310 | case THREADSTATUS_WAIT_ARB: | 315 | case THREADSTATUS_WAIT_ARB: |
| 311 | case THREADSTATUS_WAIT_SLEEP: | 316 | case THREADSTATUS_WAIT_SLEEP: |
| 312 | break; | 317 | break; |
| @@ -515,8 +520,21 @@ void Thread::SetPriority(s32 priority) { | |||
| 515 | nominal_priority = current_priority = priority; | 520 | nominal_priority = current_priority = priority; |
| 516 | } | 521 | } |
| 517 | 522 | ||
| 523 | void Thread::UpdatePriority() { | ||
| 524 | s32 best_priority = nominal_priority; | ||
| 525 | for (auto& mutex : held_mutexes) { | ||
| 526 | if (mutex->priority < best_priority) | ||
| 527 | best_priority = mutex->priority; | ||
| 528 | } | ||
| 529 | BoostPriority(best_priority); | ||
| 530 | } | ||
| 531 | |||
| 518 | void Thread::BoostPriority(s32 priority) { | 532 | void Thread::BoostPriority(s32 priority) { |
| 519 | ready_queue.move(this, current_priority, priority); | 533 | // If thread was ready, adjust queues |
| 534 | if (status == THREADSTATUS_READY) | ||
| 535 | ready_queue.move(this, current_priority, priority); | ||
| 536 | else | ||
| 537 | ready_queue.prepare(priority); | ||
| 520 | current_priority = priority; | 538 | current_priority = priority; |
| 521 | } | 539 | } |
| 522 | 540 | ||
| @@ -563,6 +581,12 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { | |||
| 563 | context.cpu_registers[1] = output; | 581 | context.cpu_registers[1] = output; |
| 564 | } | 582 | } |
| 565 | 583 | ||
| 584 | s32 Thread::GetWaitObjectIndex(WaitObject* object) const { | ||
| 585 | ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); | ||
| 586 | auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); | ||
| 587 | return std::distance(match, wait_objects.rend()) - 1; | ||
| 588 | } | ||
| 589 | |||
| 566 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 590 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 567 | 591 | ||
| 568 | void ThreadingInit() { | 592 | void ThreadingInit() { |