diff options
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 99 |
1 files changed, 52 insertions, 47 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1fd1a732a..f64236be1 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -516,7 +516,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr thread->WakeAfterDelay(nano_seconds); thread->SetWakeupCallback(DefaultThreadWakeupCallback); - system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.PrepareReschedule(thread->GetProcessorID()); return RESULT_TIMEOUT; } @@ -534,6 +534,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand } thread->CancelWait(); + system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1066,6 +1067,8 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act } thread->SetActivity(static_cast<ThreadActivity>(activity)); + + system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1147,7 +1150,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri thread->SetPriority(priority); - system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1503,7 +1506,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e thread->SetName( fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); - system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1525,7 +1528,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { thread->ResumeFromWait(); if (thread->GetStatus() == ThreadStatus::Ready) { - system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); + system.PrepareReschedule(thread->GetProcessorID()); } return RESULT_SUCCESS; @@ -1537,7 +1540,7 @@ static void ExitThread(Core::System& system) { auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->Stop(); - system.CurrentScheduler().RemoveThread(current_thread); + system.GlobalScheduler().RemoveThread(current_thread); system.PrepareReschedule(); } @@ -1553,17 +1556,18 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { auto& scheduler = system.CurrentScheduler(); auto* const current_thread = scheduler.GetCurrentThread(); + bool is_redundant = false; if (nanoseconds <= 0) { switch (static_cast<SleepType>(nanoseconds)) { case SleepType::YieldWithoutLoadBalancing: - scheduler.YieldWithoutLoadBalancing(current_thread); + is_redundant = current_thread->YieldSimple(); break; case SleepType::YieldWithLoadBalancing: - scheduler.YieldWithLoadBalancing(current_thread); + is_redundant = current_thread->YieldAndBalanceLoad(); break; case SleepType::YieldAndWaitForLoadBalancing: - scheduler.YieldAndWaitForLoadBalancing(current_thread); + is_redundant = current_thread->YieldAndWaitForLoadBalancing(); break; default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); @@ -1572,10 +1576,13 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { current_thread->Sleep(nanoseconds); } - // Reschedule all CPU cores - for (std::size_t i = 0; i < Core::NUM_CPU_CORES; ++i) { - system.CpuCore(i).PrepareReschedule(); + if (is_redundant) { + // If it's redundant, the core is pretty much idle. Some games keep idling + // a core while it's doing nothing, we advance timing to avoid costly continuous + // calls. + system.CoreTiming().AddTicks(2000); } + system.PrepareReschedule(current_thread->GetProcessorID()); } /// Wait process wide key atomic @@ -1601,6 +1608,8 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return ERR_INVALID_ADDRESS; } + ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); + auto* const current_process = system.Kernel().CurrentProcess(); const auto& handle_table = current_process->GetHandleTable(); SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); @@ -1622,7 +1631,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add // Note: Deliberately don't attempt to inherit the lock owner's priority. - system.CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); + system.PrepareReschedule(current_thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1632,24 +1641,19 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", condition_variable_addr, target); - const auto RetrieveWaitingThreads = [&system](std::size_t core_index, - std::vector<SharedPtr<Thread>>& waiting_threads, - VAddr condvar_addr) { - const auto& scheduler = system.Scheduler(core_index); - const auto& thread_list = scheduler.GetThreadList(); - - for (const auto& thread : thread_list) { - if (thread->GetCondVarWaitAddress() == condvar_addr) - waiting_threads.push_back(thread); - } - }; + ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); // Retrieve a list of all threads that are waiting for this condition variable. std::vector<SharedPtr<Thread>> waiting_threads; - RetrieveWaitingThreads(0, waiting_threads, condition_variable_addr); - RetrieveWaitingThreads(1, waiting_threads, condition_variable_addr); - RetrieveWaitingThreads(2, waiting_threads, condition_variable_addr); - RetrieveWaitingThreads(3, waiting_threads, condition_variable_addr); + const auto& scheduler = system.GlobalScheduler(); + const auto& thread_list = scheduler.GetThreadList(); + + for (const auto& thread : thread_list) { + if (thread->GetCondVarWaitAddress() == condition_variable_addr) { + waiting_threads.push_back(thread); + } + } + // Sort them by priority, such that the highest priority ones come first. std::sort(waiting_threads.begin(), waiting_threads.end(), [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { @@ -1679,18 +1683,20 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var // Atomically read the value of the mutex. u32 mutex_val = 0; + u32 update_val = 0; + const VAddr mutex_address = thread->GetMutexWaitAddress(); do { - monitor.SetExclusive(current_core, thread->GetMutexWaitAddress()); + monitor.SetExclusive(current_core, mutex_address); // If the mutex is not yet acquired, acquire it. - mutex_val = Memory::Read32(thread->GetMutexWaitAddress()); + mutex_val = Memory::Read32(mutex_address); if (mutex_val != 0) { - monitor.ClearExclusive(); - break; + update_val = mutex_val | Mutex::MutexHasWaitersFlag; + } else { + update_val = thread->GetWaitHandle(); } - } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(), - thread->GetWaitHandle())); + } while (!monitor.ExclusiveWrite32(current_core, mutex_address, update_val)); if (mutex_val == 0) { // We were able to acquire the mutex, resume this thread. ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); @@ -1704,20 +1710,9 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var thread->SetLockOwner(nullptr); thread->SetMutexWaitAddress(0); thread->SetWaitHandle(0); - system.CpuCore(thread->GetProcessorID()).PrepareReschedule(); + thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + system.PrepareReschedule(thread->GetProcessorID()); } else { - // Atomically signal that the mutex now has a waiting thread. - do { - monitor.SetExclusive(current_core, thread->GetMutexWaitAddress()); - - // Ensure that the mutex value is still what we expect. - u32 value = Memory::Read32(thread->GetMutexWaitAddress()); - // TODO(Subv): When this happens, the kernel just clears the exclusive state and - // retries the initial read for this thread. - ASSERT_MSG(mutex_val == value, "Unhandled synchronization primitive case"); - } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(), - mutex_val | Mutex::MutexHasWaitersFlag)); - // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); @@ -1728,6 +1723,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var thread->SetStatus(ThreadStatus::WaitMutex); owner->AddMutexWaiter(thread); + system.PrepareReschedule(thread->GetProcessorID()); } } @@ -1754,7 +1750,12 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, const auto arbitration_type = static_cast<AddressArbiter::ArbitrationType>(type); auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); - return address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); + const ResultCode result = + address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); + if (result == RESULT_SUCCESS) { + system.PrepareReschedule(); + } + return result; } // Signals to an address (via Address Arbiter) @@ -2040,7 +2041,10 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_HANDLE; } + system.PrepareReschedule(thread->GetProcessorID()); thread->ChangeCore(core, affinity_mask); + system.PrepareReschedule(thread->GetProcessorID()); + return RESULT_SUCCESS; } @@ -2151,6 +2155,7 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) { } writable_event->Signal(); + system.PrepareReschedule(); return RESULT_SUCCESS; } |