kernel/svc: Reorganize svcSetThreadCoreMask()
Makes the code much nicer to follow in terms of behavior and control flow. It also fixes a few bugs in the implementation. Notably, the thread's owner process shouldn't be accessed in order to retrieve the core mask or ideal core. This should be done through the current running process. The only reason this bug wasn't encountered yet is because we currently only support running one process, and thus every owner process will be the current process. We also weren't checking against the process' CPU core mask to see if an allowed core is specified or not. With this out of the way, it'll be less noisy to implement proper handling of the affinity flags internally within the kernel thread instances.
This commit is contained in:
parent
69a2003a8e
commit
d672c6e759
|
@ -1744,11 +1744,51 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core,
|
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core,
|
||||||
u64 mask) {
|
u64 affinity_mask) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle,
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}",
|
||||||
mask, core);
|
thread_handle, core, affinity_mask);
|
||||||
|
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||||
|
|
||||||
|
if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) {
|
||||||
|
const u8 ideal_cpu_core = current_process->GetIdealCore();
|
||||||
|
|
||||||
|
ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL));
|
||||||
|
|
||||||
|
// Set the target CPU to the ideal core specified by the process.
|
||||||
|
core = ideal_cpu_core;
|
||||||
|
affinity_mask = 1ULL << core;
|
||||||
|
} else {
|
||||||
|
const u64 core_mask = current_process->GetCoreMask();
|
||||||
|
|
||||||
|
if ((core_mask | affinity_mask) != core_mask) {
|
||||||
|
LOG_ERROR(
|
||||||
|
Kernel_SVC,
|
||||||
|
"Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})",
|
||||||
|
core_mask, affinity_mask);
|
||||||
|
return ERR_INVALID_PROCESSOR_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (affinity_mask == 0) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero.");
|
||||||
|
return ERR_INVALID_COMBINATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (core < Core::NUM_CPU_CORES) {
|
||||||
|
if ((affinity_mask & (1ULL << core)) == 0) {
|
||||||
|
LOG_ERROR(Kernel_SVC,
|
||||||
|
"Core is not enabled for the current mask, core={}, mask={:016X}", core,
|
||||||
|
affinity_mask);
|
||||||
|
return ERR_INVALID_COMBINATION;
|
||||||
|
}
|
||||||
|
} else if (core != static_cast<u32>(THREADPROCESSORID_DONT_CARE) &&
|
||||||
|
core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core);
|
||||||
|
return ERR_INVALID_PROCESSOR_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& handle_table = current_process->GetHandleTable();
|
||||||
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||||
|
@ -1756,40 +1796,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) {
|
thread->ChangeCore(core, affinity_mask);
|
||||||
const u8 ideal_cpu_core = thread->GetOwnerProcess()->GetIdealCore();
|
|
||||||
|
|
||||||
ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL));
|
|
||||||
|
|
||||||
// Set the target CPU to the ideal core specified by the process.
|
|
||||||
core = ideal_cpu_core;
|
|
||||||
mask = 1ULL << core;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mask == 0) {
|
|
||||||
LOG_ERROR(Kernel_SVC, "Mask is 0");
|
|
||||||
return ERR_INVALID_COMBINATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This value is used to only change the affinity mask without changing the current ideal core.
|
|
||||||
static constexpr u32 OnlyChangeMask = static_cast<u32>(-3);
|
|
||||||
|
|
||||||
if (core == OnlyChangeMask) {
|
|
||||||
core = thread->GetIdealCore();
|
|
||||||
} else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) {
|
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core);
|
|
||||||
return ERR_INVALID_PROCESSOR_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error out if the input core isn't enabled in the input mask.
|
|
||||||
if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
|
|
||||||
LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}",
|
|
||||||
core, mask);
|
|
||||||
return ERR_INVALID_COMBINATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->ChangeCore(core, mask);
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue