summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
authorGravatar Sebastian Valle2017-01-05 12:55:01 -0500
committerGravatar GitHub2017-01-05 12:55:01 -0500
commitf20d872643654c574f73a263f032613046900f07 (patch)
tree021284c18034d053c81928fa19d2efb6658451fb /src/core/hle/kernel/thread.cpp
parentMerge pull request #2407 from jroweboy/nightly-deploy (diff)
parentKernel: Add some asserts to enforce the invariants in the scheduler. (diff)
downloadyuzu-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.cpp50
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
28static int ThreadWakeupEventType; 28static int ThreadWakeupEventType;
29 29
30bool Thread::ShouldWait() { 30bool Thread::ShouldWait(Thread* thread) const {
31 return status != THREADSTATUS_DEAD; 31 return status != THREADSTATUS_DEAD;
32} 32}
33 33
34void Thread::Acquire() { 34void 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 */
74static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { 74static 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
92void Thread::Stop() { 93void 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
259void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { 260void 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
307void Thread::ResumeFromWait() { 309void 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
523void 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
518void Thread::BoostPriority(s32 priority) { 532void 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
584s32 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
568void ThreadingInit() { 592void ThreadingInit() {