summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorGravatar bunnei2018-05-23 10:28:23 -0400
committerGravatar GitHub2018-05-23 10:28:23 -0400
commit3825b703fa26c85e0bde7e99713eab988619c166 (patch)
tree857f20f69d0ee9d6656775d328705c86f8937cc9 /src/core/hle/kernel
parentImplemented NVHOST_IOCTL_CHANNEL_GET_WAITBASE (#440) (diff)
parentKernel/SVC: Signal the highest priority threads first in svcSignalProcessWide... (diff)
downloadyuzu-3825b703fa26c85e0bde7e99713eab988619c166.tar.gz
yuzu-3825b703fa26c85e0bde7e99713eab988619c166.tar.xz
yuzu-3825b703fa26c85e0bde7e99713eab988619c166.zip
Merge pull request #454 from Subv/signal_processwide
Kernel/SVC: Signal the highest priority threads first in svcSignalProcessWideKey
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/svc.cpp157
1 files changed, 74 insertions, 83 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 1ae530c90..0811a16b8 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -145,36 +145,6 @@ static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thr
145 return true; 145 return true;
146}; 146};
147 147
148/// Wait for a kernel object to synchronize, timeout after the specified nanoseconds
149static ResultCode WaitSynchronization1(
150 SharedPtr<WaitObject> object, Thread* thread, s64 nano_seconds = -1,
151 std::function<Thread::WakeupCallback> wakeup_callback = DefaultThreadWakeupCallback) {
152
153 if (!object) {
154 return ERR_INVALID_HANDLE;
155 }
156
157 if (object->ShouldWait(thread)) {
158 if (nano_seconds == 0) {
159 return RESULT_TIMEOUT;
160 }
161
162 thread->wait_objects = {object};
163 object->AddWaitingThread(thread);
164 thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
165
166 // Create an event to wake the thread up after the specified nanosecond delay has passed
167 thread->WakeAfterDelay(nano_seconds);
168 thread->wakeup_callback = wakeup_callback;
169
170 Core::System::GetInstance().PrepareReschedule();
171 } else {
172 object->Acquire(thread);
173 }
174
175 return RESULT_SUCCESS;
176}
177
178/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 148/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
179static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count, 149static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count,
180 s64 nano_seconds) { 150 s64 nano_seconds) {
@@ -232,7 +202,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
232 thread->WakeAfterDelay(nano_seconds); 202 thread->WakeAfterDelay(nano_seconds);
233 thread->wakeup_callback = DefaultThreadWakeupCallback; 203 thread->wakeup_callback = DefaultThreadWakeupCallback;
234 204
235 Core::System::GetInstance().PrepareReschedule(); 205 Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
236 206
237 return RESULT_TIMEOUT; 207 return RESULT_TIMEOUT;
238} 208}
@@ -395,7 +365,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
395 365
396 thread->SetPriority(priority); 366 thread->SetPriority(priority);
397 367
398 Core::System::GetInstance().PrepareReschedule(); 368 Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
399 return RESULT_SUCCESS; 369 return RESULT_SUCCESS;
400} 370}
401 371
@@ -552,6 +522,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
552 *out_handle = thread->guest_handle; 522 *out_handle = thread->guest_handle;
553 523
554 Core::System::GetInstance().PrepareReschedule(); 524 Core::System::GetInstance().PrepareReschedule();
525 Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
555 526
556 NGLOG_TRACE(Kernel_SVC, 527 NGLOG_TRACE(Kernel_SVC,
557 "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " 528 "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
@@ -570,7 +541,10 @@ static ResultCode StartThread(Handle thread_handle) {
570 return ERR_INVALID_HANDLE; 541 return ERR_INVALID_HANDLE;
571 } 542 }
572 543
544 ASSERT(thread->status == THREADSTATUS_DORMANT);
545
573 thread->ResumeFromWait(); 546 thread->ResumeFromWait();
547 Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
574 548
575 return RESULT_SUCCESS; 549 return RESULT_SUCCESS;
576} 550}
@@ -634,61 +608,78 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
634 NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", 608 NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}",
635 condition_variable_addr, target); 609 condition_variable_addr, target);
636 610
637 u32 processed = 0; 611 auto RetrieveWaitingThreads =
612 [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr condvar_addr) {
613 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
614 auto& thread_list = scheduler->GetThreadList();
638 615
639 auto signal_process_wide_key = [&](size_t core_index) { 616 for (auto& thread : thread_list) {
640 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); 617 if (thread->condvar_wait_address == condvar_addr)
641 for (auto& thread : scheduler->GetThreadList()) { 618 waiting_threads.push_back(thread);
642 if (thread->condvar_wait_address != condition_variable_addr)
643 continue;
644
645 // Only process up to 'target' threads, unless 'target' is -1, in which case process
646 // them all.
647 if (target != -1 && processed >= target)
648 break;
649
650 // If the mutex is not yet acquired, acquire it.
651 u32 mutex_val = Memory::Read32(thread->mutex_wait_address);
652
653 if (mutex_val == 0) {
654 // We were able to acquire the mutex, resume this thread.
655 Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
656 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
657 thread->ResumeFromWait();
658
659 auto lock_owner = thread->lock_owner;
660 if (lock_owner)
661 lock_owner->RemoveMutexWaiter(thread);
662
663 thread->lock_owner = nullptr;
664 thread->mutex_wait_address = 0;
665 thread->condvar_wait_address = 0;
666 thread->wait_handle = 0;
667 } else {
668 // Couldn't acquire the mutex, block the thread.
669 Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
670 auto owner = g_handle_table.Get<Thread>(owner_handle);
671 ASSERT(owner);
672 ASSERT(thread->status != THREADSTATUS_RUNNING);
673 thread->status = THREADSTATUS_WAIT_MUTEX;
674 thread->wakeup_callback = nullptr;
675
676 // Signal that the mutex now has a waiting thread.
677 Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag);
678
679 owner->AddMutexWaiter(thread);
680
681 Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
682 } 619 }
620 };
621
622 // Retrieve a list of all threads that are waiting for this condition variable.
623 std::vector<SharedPtr<Thread>> waiting_threads;
624 RetrieveWaitingThreads(0, waiting_threads, condition_variable_addr);
625 RetrieveWaitingThreads(1, waiting_threads, condition_variable_addr);
626 RetrieveWaitingThreads(2, waiting_threads, condition_variable_addr);
627 RetrieveWaitingThreads(3, waiting_threads, condition_variable_addr);
628 // Sort them by priority, such that the highest priority ones come first.
629 std::sort(waiting_threads.begin(), waiting_threads.end(),
630 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
631 return lhs->current_priority < rhs->current_priority;
632 });
633
634 // Only process up to 'target' threads, unless 'target' is -1, in which case process
635 // them all.
636 size_t last = waiting_threads.size();
637 if (target != -1)
638 last = target;
639
640 // If there are no threads waiting on this condition variable, just exit
641 if (last > waiting_threads.size())
642 return RESULT_SUCCESS;
683 643
684 ++processed; 644 for (size_t index = 0; index < last; ++index) {
685 } 645 auto& thread = waiting_threads[index];
686 }; 646
647 ASSERT(thread->condvar_wait_address == condition_variable_addr);
648
649 // If the mutex is not yet acquired, acquire it.
650 u32 mutex_val = Memory::Read32(thread->mutex_wait_address);
687 651
688 signal_process_wide_key(0); 652 if (mutex_val == 0) {
689 signal_process_wide_key(1); 653 // We were able to acquire the mutex, resume this thread.
690 signal_process_wide_key(2); 654 Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
691 signal_process_wide_key(3); 655 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
656 thread->ResumeFromWait();
657
658 auto lock_owner = thread->lock_owner;
659 if (lock_owner)
660 lock_owner->RemoveMutexWaiter(thread);
661
662 thread->lock_owner = nullptr;
663 thread->mutex_wait_address = 0;
664 thread->condvar_wait_address = 0;
665 thread->wait_handle = 0;
666 } else {
667 // Couldn't acquire the mutex, block the thread.
668 Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
669 auto owner = g_handle_table.Get<Thread>(owner_handle);
670 ASSERT(owner);
671 ASSERT(thread->status != THREADSTATUS_RUNNING);
672 thread->status = THREADSTATUS_WAIT_MUTEX;
673 thread->wakeup_callback = nullptr;
674
675 // Signal that the mutex now has a waiting thread.
676 Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag);
677
678 owner->AddMutexWaiter(thread);
679
680 Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
681 }
682 }
692 683
693 return RESULT_SUCCESS; 684 return RESULT_SUCCESS;
694} 685}