summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp99
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;
}