forked from suyu/suyu
hle: kernel: KThread: Clean up thread priorities.
This commit is contained in:
parent
1e55498110
commit
4dbf3f4880
10 changed files with 46 additions and 85 deletions
|
@ -21,7 +21,7 @@ class KernelCore;
|
||||||
class SchedulerLock;
|
class SchedulerLock;
|
||||||
|
|
||||||
using KSchedulerPriorityQueue =
|
using KSchedulerPriorityQueue =
|
||||||
KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority,
|
KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority + 1,
|
||||||
Svc::HighestThreadPriority>;
|
Svc::HighestThreadPriority>;
|
||||||
|
|
||||||
static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
|
static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
|
||||||
|
|
|
@ -764,7 +764,7 @@ void KScheduler::Initialize() {
|
||||||
std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
|
std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
|
||||||
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
|
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
|
||||||
auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0,
|
auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0,
|
||||||
Svc::LowestThreadPriority, 0, static_cast<u32>(core_id), 0,
|
KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
|
||||||
nullptr, std::move(init_func), init_func_parameter);
|
nullptr, std::move(init_func), init_func_parameter);
|
||||||
idle_thread = thread_res.Unwrap().get();
|
idle_thread = thread_res.Unwrap().get();
|
||||||
|
|
||||||
|
|
|
@ -127,14 +127,6 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
|
||||||
void* thread_start_parameter) {
|
void* thread_start_parameter) {
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
|
|
||||||
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
|
|
||||||
Svc::ResultInvalidPriority);
|
|
||||||
|
|
||||||
if (processor_id > THREADPROCESSORID_MAX) {
|
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
|
|
||||||
return ERR_INVALID_PROCESSOR_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (owner_process) {
|
if (owner_process) {
|
||||||
if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) {
|
if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) {
|
||||||
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
|
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
|
||||||
|
@ -423,7 +415,7 @@ ResultCode KThread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask)
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool use_override = affinity_override_count != 0;
|
const bool use_override = affinity_override_count != 0;
|
||||||
if (new_core == THREADPROCESSORID_DONT_UPDATE) {
|
if (new_core == Svc::IdealCoreNoUpdate) {
|
||||||
new_core = use_override ? ideal_core_override : ideal_core;
|
new_core = use_override ? ideal_core_override : ideal_core;
|
||||||
if ((new_affinity_mask & (1ULL << new_core)) == 0) {
|
if ((new_affinity_mask & (1ULL << new_core)) == 0) {
|
||||||
LOG_ERROR(Kernel, "New affinity mask is incorrect! new_core={}, new_affinity_mask={}",
|
LOG_ERROR(Kernel, "New affinity mask is incorrect! new_core={}, new_affinity_mask={}",
|
||||||
|
|
|
@ -47,28 +47,6 @@ enum class ThreadType : u32 {
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(ThreadType);
|
DECLARE_ENUM_FLAG_OPERATORS(ThreadType);
|
||||||
|
|
||||||
enum ThreadProcessorId : s32 {
|
|
||||||
/// Indicates that no particular processor core is preferred.
|
|
||||||
THREADPROCESSORID_DONT_CARE = -1,
|
|
||||||
|
|
||||||
/// Run thread on the ideal core specified by the process.
|
|
||||||
THREADPROCESSORID_IDEAL = -2,
|
|
||||||
|
|
||||||
/// Indicates that the preferred processor ID shouldn't be updated in
|
|
||||||
/// a core mask setting operation.
|
|
||||||
THREADPROCESSORID_DONT_UPDATE = -3,
|
|
||||||
|
|
||||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0
|
|
||||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1
|
|
||||||
THREADPROCESSORID_2 = 2, ///< Run thread on core 2
|
|
||||||
THREADPROCESSORID_3 = 3, ///< Run thread on core 3
|
|
||||||
THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this
|
|
||||||
|
|
||||||
/// Allowed CPU mask
|
|
||||||
THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) |
|
|
||||||
(1 << THREADPROCESSORID_2) | (1 << THREADPROCESSORID_3)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ThreadState : u16 {
|
enum class ThreadState : u16 {
|
||||||
Initialized = 0,
|
Initialized = 0,
|
||||||
Waiting = 1,
|
Waiting = 1,
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace {
|
||||||
void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
|
void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
|
||||||
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
|
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
|
||||||
auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0,
|
auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0,
|
||||||
owner_process.GetIdealCore(), stack_top, &owner_process);
|
owner_process.GetIdealCoreId(), stack_top, &owner_process);
|
||||||
|
|
||||||
std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
|
std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
|
||||||
|
|
||||||
|
|
|
@ -173,10 +173,15 @@ public:
|
||||||
std::shared_ptr<ResourceLimit> GetResourceLimit() const;
|
std::shared_ptr<ResourceLimit> GetResourceLimit() const;
|
||||||
|
|
||||||
/// Gets the ideal CPU core ID for this process
|
/// Gets the ideal CPU core ID for this process
|
||||||
u8 GetIdealCore() const {
|
u8 GetIdealCoreId() const {
|
||||||
return ideal_core;
|
return ideal_core;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the specified thread priority is valid.
|
||||||
|
bool CheckThreadPriority(s32 prio) const {
|
||||||
|
return ((1ULL << prio) & GetPriorityMask()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the bitmask of allowed cores that this process' threads can run on.
|
/// Gets the bitmask of allowed cores that this process' threads can run on.
|
||||||
u64 GetCoreMask() const {
|
u64 GetCoreMask() const {
|
||||||
return capabilities.GetCoreMask();
|
return capabilities.GetCoreMask();
|
||||||
|
|
|
@ -1443,54 +1443,40 @@ static void ExitProcess32(Core::System& system) {
|
||||||
ExitProcess(system);
|
ExitProcess(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr bool IsValidCoreId(int32_t core_id) {
|
||||||
|
return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new thread
|
/// Creates a new thread
|
||||||
static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
|
static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
|
||||||
VAddr stack_top, u32 priority, s32 processor_id) {
|
VAddr stack_bottom, u32 priority, s32 core_id) {
|
||||||
LOG_DEBUG(Kernel_SVC,
|
LOG_DEBUG(Kernel_SVC,
|
||||||
"called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
|
"called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, "
|
||||||
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
|
"priority=0x{:08X}, core_id=0x{:08X}",
|
||||||
entry_point, arg, stack_top, priority, processor_id, *out_handle);
|
entry_point, arg, stack_bottom, priority, core_id);
|
||||||
|
|
||||||
auto* const current_process = system.Kernel().CurrentProcess();
|
|
||||||
|
|
||||||
if (processor_id == THREADPROCESSORID_IDEAL) {
|
|
||||||
// Set the target CPU to the one specified by the process.
|
|
||||||
processor_id = current_process->GetIdealCore();
|
|
||||||
ASSERT(processor_id != THREADPROCESSORID_IDEAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) {
|
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
|
|
||||||
return ERR_INVALID_PROCESSOR_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u64 core_mask = current_process->GetCoreMask();
|
|
||||||
if ((core_mask | (1ULL << processor_id)) != core_mask) {
|
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id);
|
|
||||||
return ERR_INVALID_PROCESSOR_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priority > Svc::LowestThreadPriority) {
|
|
||||||
LOG_ERROR(Kernel_SVC,
|
|
||||||
"Invalid thread priority specified ({}). Must be within the range 0-64",
|
|
||||||
priority);
|
|
||||||
return ERR_INVALID_THREAD_PRIORITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((1ULL << priority) & current_process->GetPriorityMask()) == 0) {
|
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid thread priority specified ({})", priority);
|
|
||||||
return ERR_INVALID_THREAD_PRIORITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Adjust core id, if it's the default magic.
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
|
auto& process = *kernel.CurrentProcess();
|
||||||
|
if (core_id == Svc::IdealCoreUseProcessValue) {
|
||||||
|
core_id = process.GetIdealCoreId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate arguments.
|
||||||
|
R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId);
|
||||||
|
R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId);
|
||||||
|
|
||||||
|
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
|
||||||
|
Svc::ResultInvalidPriority);
|
||||||
|
R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
|
||||||
|
|
||||||
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
|
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
|
||||||
|
|
||||||
CASCADE_RESULT(std::shared_ptr<KThread> thread,
|
CASCADE_RESULT(std::shared_ptr<KThread> thread,
|
||||||
KThread::Create(system, ThreadType::User, "", entry_point, priority, arg,
|
KThread::Create(system, ThreadType::User, "", entry_point, priority, arg,
|
||||||
processor_id, stack_top, current_process));
|
core_id, stack_bottom, &process));
|
||||||
|
|
||||||
const auto new_thread_handle = current_process->GetHandleTable().Create(thread);
|
const auto new_thread_handle = process.GetHandleTable().Create(thread);
|
||||||
if (new_thread_handle.Failed()) {
|
if (new_thread_handle.Failed()) {
|
||||||
LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
|
LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
|
||||||
new_thread_handle.Code().raw);
|
new_thread_handle.Code().raw);
|
||||||
|
@ -1872,10 +1858,10 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
|
||||||
|
|
||||||
const auto* const current_process = system.Kernel().CurrentProcess();
|
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||||
|
|
||||||
if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) {
|
if (core == static_cast<u32>(Svc::IdealCoreUseProcessValue)) {
|
||||||
const u8 ideal_cpu_core = current_process->GetIdealCore();
|
const u8 ideal_cpu_core = current_process->GetIdealCoreId();
|
||||||
|
|
||||||
ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL));
|
ASSERT(ideal_cpu_core != static_cast<u8>(Svc::IdealCoreUseProcessValue));
|
||||||
|
|
||||||
// Set the target CPU to the ideal core specified by the process.
|
// Set the target CPU to the ideal core specified by the process.
|
||||||
core = ideal_cpu_core;
|
core = ideal_cpu_core;
|
||||||
|
@ -1903,8 +1889,8 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
|
||||||
affinity_mask);
|
affinity_mask);
|
||||||
return ERR_INVALID_COMBINATION;
|
return ERR_INVALID_COMBINATION;
|
||||||
}
|
}
|
||||||
} else if (core != static_cast<u32>(THREADPROCESSORID_DONT_CARE) &&
|
} else if (core != static_cast<u32>(Svc::IdealCoreDontCare) &&
|
||||||
core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) {
|
core != static_cast<u32>(Svc::IdealCoreNoUpdate)) {
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core);
|
LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core);
|
||||||
return ERR_INVALID_PROCESSOR_ID;
|
return ERR_INVALID_PROCESSOR_ID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
|
||||||
constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
|
constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
|
||||||
constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
|
constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
|
||||||
constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
|
constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
|
||||||
|
constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
|
||||||
constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
|
constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
|
||||||
constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
|
constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
|
||||||
constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
|
constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
|
||||||
|
|
|
@ -77,6 +77,10 @@ enum class ArbitrationType : u32 {
|
||||||
WaitIfEqual = 2,
|
WaitIfEqual = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr inline s32 IdealCoreDontCare = -1;
|
||||||
|
constexpr inline s32 IdealCoreUseProcessValue = -2;
|
||||||
|
constexpr inline s32 IdealCoreNoUpdate = -3;
|
||||||
|
|
||||||
constexpr inline s32 LowestThreadPriority = 63;
|
constexpr inline s32 LowestThreadPriority = 63;
|
||||||
constexpr inline s32 HighestThreadPriority = 0;
|
constexpr inline s32 HighestThreadPriority = 0;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
#include "core/hle/kernel/svc_common.h"
|
#include "core/hle/kernel/svc_common.h"
|
||||||
|
#include "core/hle/kernel/svc_types.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -334,17 +335,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||||
|
|
||||||
QString processor;
|
QString processor;
|
||||||
switch (thread.GetProcessorID()) {
|
switch (thread.GetProcessorID()) {
|
||||||
case Kernel::ThreadProcessorId::THREADPROCESSORID_IDEAL:
|
case Kernel::Svc::IdealCoreUseProcessValue:
|
||||||
processor = tr("ideal");
|
processor = tr("ideal");
|
||||||
break;
|
break;
|
||||||
case Kernel::ThreadProcessorId::THREADPROCESSORID_0:
|
|
||||||
case Kernel::ThreadProcessorId::THREADPROCESSORID_1:
|
|
||||||
case Kernel::ThreadProcessorId::THREADPROCESSORID_2:
|
|
||||||
case Kernel::ThreadProcessorId::THREADPROCESSORID_3:
|
|
||||||
processor = tr("core %1").arg(thread.GetProcessorID());
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
processor = tr("Unknown processor %1").arg(thread.GetProcessorID());
|
processor = tr("core %1").arg(thread.GetProcessorID());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue