early-access version 1350
This commit is contained in:
parent
843abfbd8d
commit
7dcb3821c6
66 changed files with 721 additions and 925 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 1349.
|
This is the source code for early-access 1350.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -101,21 +101,6 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define R_SUCCEEDED(res) (res.IsSuccess())
|
|
||||||
#define R_FAILED(res) (res.IsError())
|
|
||||||
|
|
||||||
/// Evaluates an expression that returns a result, and returns the result if it would fail.
|
|
||||||
#define R_TRY(res_expr) \
|
|
||||||
{ \
|
|
||||||
const auto _tmp_r_try_rc = (res_expr); \
|
|
||||||
if (R_FAILED(_tmp_r_try_rc)) { \
|
|
||||||
return _tmp_r_try_rc; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluates a boolean expression, and succeeds if that expression is true.
|
|
||||||
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), RESULT_SUCCESS)
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
||||||
|
|
|
@ -159,8 +159,6 @@ add_library(core STATIC
|
||||||
hle/kernel/k_affinity_mask.h
|
hle/kernel/k_affinity_mask.h
|
||||||
hle/kernel/k_condition_variable.cpp
|
hle/kernel/k_condition_variable.cpp
|
||||||
hle/kernel/k_condition_variable.h
|
hle/kernel/k_condition_variable.h
|
||||||
hle/kernel/k_light_lock.cpp
|
|
||||||
hle/kernel/k_light_lock.h
|
|
||||||
hle/kernel/k_priority_queue.h
|
hle/kernel/k_priority_queue.h
|
||||||
hle/kernel/k_scheduler.cpp
|
hle/kernel/k_scheduler.cpp
|
||||||
hle/kernel/k_scheduler.h
|
hle/kernel/k_scheduler.h
|
||||||
|
@ -169,9 +167,6 @@ add_library(core STATIC
|
||||||
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
|
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
|
||||||
hle/kernel/k_synchronization_object.cpp
|
hle/kernel/k_synchronization_object.cpp
|
||||||
hle/kernel/k_synchronization_object.h
|
hle/kernel/k_synchronization_object.h
|
||||||
hle/kernel/k_thread.cpp
|
|
||||||
hle/kernel/k_thread.h
|
|
||||||
hle/kernel/k_thread_queue.h
|
|
||||||
hle/kernel/kernel.cpp
|
hle/kernel/kernel.cpp
|
||||||
hle/kernel/kernel.h
|
hle/kernel/kernel.h
|
||||||
hle/kernel/memory/address_space_info.cpp
|
hle/kernel/memory/address_space_info.cpp
|
||||||
|
@ -220,6 +215,8 @@ add_library(core STATIC
|
||||||
hle/kernel/svc_results.h
|
hle/kernel/svc_results.h
|
||||||
hle/kernel/svc_types.h
|
hle/kernel/svc_types.h
|
||||||
hle/kernel/svc_wrap.h
|
hle/kernel/svc_wrap.h
|
||||||
|
hle/kernel/thread.cpp
|
||||||
|
hle/kernel/thread.h
|
||||||
hle/kernel/time_manager.cpp
|
hle/kernel/time_manager.cpp
|
||||||
hle/kernel/time_manager.h
|
hle/kernel/time_manager.h
|
||||||
hle/kernel/transfer_memory.cpp
|
hle/kernel/transfer_memory.cpp
|
||||||
|
|
|
@ -251,16 +251,10 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
|
void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
jit->ChangeProcessorID(new_core_id);
|
jit->ChangeProcessorID(new_core_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
|
void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Dynarmic::A32::Context context;
|
Dynarmic::A32::Context context;
|
||||||
jit->SaveContext(context);
|
jit->SaveContext(context);
|
||||||
ctx.cpu_registers = context.Regs();
|
ctx.cpu_registers = context.Regs();
|
||||||
|
@ -270,9 +264,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
|
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Dynarmic::A32::Context context;
|
Dynarmic::A32::Context context;
|
||||||
context.Regs() = ctx.cpu_registers;
|
context.Regs() = ctx.cpu_registers;
|
||||||
context.ExtRegs() = ctx.extension_registers;
|
context.ExtRegs() = ctx.extension_registers;
|
||||||
|
@ -282,9 +273,6 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_32::PrepareReschedule() {
|
void ARM_Dynarmic_32::PrepareReschedule() {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
jit->HaltExecution();
|
jit->HaltExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,16 +290,10 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
|
void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
jit->ChangeProcessorID(new_core_id);
|
jit->ChangeProcessorID(new_core_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
|
void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.cpu_registers = jit->GetRegisters();
|
ctx.cpu_registers = jit->GetRegisters();
|
||||||
ctx.sp = jit->GetSP();
|
ctx.sp = jit->GetSP();
|
||||||
ctx.pc = jit->GetPC();
|
ctx.pc = jit->GetPC();
|
||||||
|
@ -311,9 +305,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
|
void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
jit->SetRegisters(ctx.cpu_registers);
|
jit->SetRegisters(ctx.cpu_registers);
|
||||||
jit->SetSP(ctx.sp);
|
jit->SetSP(ctx.sp);
|
||||||
jit->SetPC(ctx.pc);
|
jit->SetPC(ctx.pc);
|
||||||
|
@ -325,9 +316,6 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_64::PrepareReschedule() {
|
void ARM_Dynarmic_64::PrepareReschedule() {
|
||||||
if (!jit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
jit->HaltExecution();
|
jit->HaltExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,10 @@
|
||||||
#include "core/hardware_interrupt_manager.h"
|
#include "core/hardware_interrupt_manager.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/physical_core.h"
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/service/am/applets/applets.h"
|
#include "core/hle/service/am/applets/applets.h"
|
||||||
#include "core/hle/service/apm/controller.h"
|
#include "core/hle/service/apm/controller.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/cpu_manager.h"
|
#include "core/cpu_manager.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/physical_core.h"
|
#include "core/hle/kernel/physical_core.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -147,7 +147,7 @@ void CpuManager::MultiCoreRunSuspendThread() {
|
||||||
while (true) {
|
while (true) {
|
||||||
auto core = kernel.GetCurrentHostThreadID();
|
auto core = kernel.GetCurrentHostThreadID();
|
||||||
auto& scheduler = *kernel.CurrentScheduler();
|
auto& scheduler = *kernel.CurrentScheduler();
|
||||||
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
|
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
|
||||||
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
|
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
|
||||||
ASSERT(scheduler.ContextSwitchPending());
|
ASSERT(scheduler.ContextSwitchPending());
|
||||||
ASSERT(core == kernel.GetCurrentHostThreadID());
|
ASSERT(core == kernel.GetCurrentHostThreadID());
|
||||||
|
@ -208,6 +208,7 @@ void CpuManager::SingleCoreRunGuestThread() {
|
||||||
|
|
||||||
void CpuManager::SingleCoreRunGuestLoop() {
|
void CpuManager::SingleCoreRunGuestLoop() {
|
||||||
auto& kernel = system.Kernel();
|
auto& kernel = system.Kernel();
|
||||||
|
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
while (true) {
|
while (true) {
|
||||||
auto* physical_core = &kernel.CurrentPhysicalCore();
|
auto* physical_core = &kernel.CurrentPhysicalCore();
|
||||||
system.EnterDynarmicProfile();
|
system.EnterDynarmicProfile();
|
||||||
|
@ -216,9 +217,9 @@ void CpuManager::SingleCoreRunGuestLoop() {
|
||||||
physical_core = &kernel.CurrentPhysicalCore();
|
physical_core = &kernel.CurrentPhysicalCore();
|
||||||
}
|
}
|
||||||
system.ExitDynarmicProfile();
|
system.ExitDynarmicProfile();
|
||||||
kernel.SetIsPhantomModeForSingleCore(true);
|
thread->SetPhantomMode(true);
|
||||||
system.CoreTiming().Advance();
|
system.CoreTiming().Advance();
|
||||||
kernel.SetIsPhantomModeForSingleCore(false);
|
thread->SetPhantomMode(false);
|
||||||
physical_core->ArmInterface().ClearExclusiveState();
|
physical_core->ArmInterface().ClearExclusiveState();
|
||||||
PreemptSingleCore();
|
PreemptSingleCore();
|
||||||
auto& scheduler = kernel.Scheduler(current_core);
|
auto& scheduler = kernel.Scheduler(current_core);
|
||||||
|
@ -244,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() {
|
||||||
while (true) {
|
while (true) {
|
||||||
auto core = kernel.GetCurrentHostThreadID();
|
auto core = kernel.GetCurrentHostThreadID();
|
||||||
auto& scheduler = *kernel.CurrentScheduler();
|
auto& scheduler = *kernel.CurrentScheduler();
|
||||||
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
|
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
|
||||||
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
|
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
|
||||||
ASSERT(scheduler.ContextSwitchPending());
|
ASSERT(scheduler.ContextSwitchPending());
|
||||||
ASSERT(core == kernel.GetCurrentHostThreadID());
|
ASSERT(core == kernel.GetCurrentHostThreadID());
|
||||||
|
@ -254,23 +255,22 @@ void CpuManager::SingleCoreRunSuspendThread() {
|
||||||
|
|
||||||
void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
|
void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
|
||||||
{
|
{
|
||||||
auto& kernel = system.Kernel();
|
auto& scheduler = system.Kernel().Scheduler(current_core);
|
||||||
auto& scheduler = kernel.Scheduler(current_core);
|
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
|
||||||
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
|
|
||||||
if (idle_count >= 4 || from_running_enviroment) {
|
if (idle_count >= 4 || from_running_enviroment) {
|
||||||
if (!from_running_enviroment) {
|
if (!from_running_enviroment) {
|
||||||
system.CoreTiming().Idle();
|
system.CoreTiming().Idle();
|
||||||
idle_count = 0;
|
idle_count = 0;
|
||||||
}
|
}
|
||||||
kernel.SetIsPhantomModeForSingleCore(true);
|
current_thread->SetPhantomMode(true);
|
||||||
system.CoreTiming().Advance();
|
system.CoreTiming().Advance();
|
||||||
kernel.SetIsPhantomModeForSingleCore(false);
|
current_thread->SetPhantomMode(false);
|
||||||
}
|
}
|
||||||
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
|
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
|
||||||
system.CoreTiming().ResetTicks();
|
system.CoreTiming().ResetTicks();
|
||||||
scheduler.Unload(scheduler.GetCurrentThread());
|
scheduler.Unload(scheduler.GetCurrentThread());
|
||||||
|
|
||||||
auto& next_scheduler = kernel.Scheduler(current_core);
|
auto& next_scheduler = system.Kernel().Scheduler(current_core);
|
||||||
Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
|
Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +278,8 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
|
||||||
{
|
{
|
||||||
auto& scheduler = system.Kernel().Scheduler(current_core);
|
auto& scheduler = system.Kernel().Scheduler(current_core);
|
||||||
scheduler.Reload(scheduler.GetCurrentThread());
|
scheduler.Reload(scheduler.GetCurrentThread());
|
||||||
if (!scheduler.IsIdle()) {
|
auto* currrent_thread2 = scheduler.GetCurrentThread();
|
||||||
|
if (!currrent_thread2->IsIdleThread()) {
|
||||||
idle_count = 0;
|
idle_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -20,12 +18,34 @@ constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz u
|
||||||
constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed
|
constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed
|
||||||
constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
|
constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
|
||||||
|
|
||||||
// Virtual to Physical core map.
|
|
||||||
constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
|
|
||||||
0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Hardware
|
} // namespace Hardware
|
||||||
|
|
||||||
|
constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
struct EmuThreadHandle {
|
||||||
|
u32 host_handle;
|
||||||
|
u32 guest_handle;
|
||||||
|
|
||||||
|
u64 GetRaw() const {
|
||||||
|
return (static_cast<u64>(host_handle) << 32) | guest_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const EmuThreadHandle& rhs) const {
|
||||||
|
return std::tie(host_handle, guest_handle) == std::tie(rhs.host_handle, rhs.guest_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const EmuThreadHandle& rhs) const {
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr EmuThreadHandle InvalidHandle() {
|
||||||
|
constexpr u32 invalid_handle = 0xFFFFFFFF;
|
||||||
|
return {invalid_handle, invalid_handle};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInvalid() const {
|
||||||
|
return (*this) == InvalidHandle();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -51,8 +51,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void ConnectionClosed();
|
void ConnectionClosed();
|
||||||
|
|
||||||
void Finalize() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
||||||
u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
|
u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/server_session.h"
|
#include "core/hle/kernel/server_session.h"
|
||||||
#include "core/hle/kernel/session.h"
|
#include "core/hle/kernel/session.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -38,7 +38,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kern
|
||||||
return MakeResult(std::move(client_session));
|
return MakeResult(std::move(client_session));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread,
|
ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread,
|
||||||
Core::Memory::Memory& memory,
|
Core::Memory::Memory& memory,
|
||||||
Core::Timing::CoreTiming& core_timing) {
|
Core::Timing::CoreTiming& core_timing) {
|
||||||
// Keep ServerSession alive until we're done working with it.
|
// Keep ServerSession alive until we're done working with it.
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Kernel {
|
||||||
|
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class Session;
|
class Session;
|
||||||
class KThread;
|
class Thread;
|
||||||
|
|
||||||
class ClientSession final : public KSynchronizationObject {
|
class ClientSession final : public KSynchronizationObject {
|
||||||
public:
|
public:
|
||||||
|
@ -46,13 +46,11 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SendSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
|
ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
|
||||||
Core::Timing::CoreTiming& core_timing);
|
Core::Timing::CoreTiming& core_timing);
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Finalize() override{};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
|
static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
|
||||||
std::shared_ptr<Session> parent,
|
std::shared_ptr<Session> parent,
|
||||||
|
|
|
@ -17,12 +17,12 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
|
||||||
|
|
||||||
GlobalSchedulerContext::~GlobalSchedulerContext() = default;
|
GlobalSchedulerContext::~GlobalSchedulerContext() = default;
|
||||||
|
|
||||||
void GlobalSchedulerContext::AddThread(std::shared_ptr<KThread> thread) {
|
void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) {
|
||||||
std::scoped_lock lock{global_list_guard};
|
std::scoped_lock lock{global_list_guard};
|
||||||
thread_list.push_back(std::move(thread));
|
thread_list.push_back(std::move(thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalSchedulerContext::RemoveThread(std::shared_ptr<KThread> thread) {
|
void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) {
|
||||||
std::scoped_lock lock{global_list_guard};
|
std::scoped_lock lock{global_list_guard};
|
||||||
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
|
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
|
||||||
thread_list.end());
|
thread_list.end());
|
||||||
|
|
|
@ -12,8 +12,7 @@
|
||||||
#include "core/hardware_properties.h"
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/k_priority_queue.h"
|
#include "core/hle/kernel/k_priority_queue.h"
|
||||||
#include "core/hle/kernel/k_scheduler_lock.h"
|
#include "core/hle/kernel/k_scheduler_lock.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/svc_types.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -21,12 +20,8 @@ class KernelCore;
|
||||||
class SchedulerLock;
|
class SchedulerLock;
|
||||||
|
|
||||||
using KSchedulerPriorityQueue =
|
using KSchedulerPriorityQueue =
|
||||||
KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority,
|
KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>;
|
||||||
Svc::HighestThreadPriority>;
|
constexpr s32 HighestCoreMigrationAllowedPriority = 2;
|
||||||
|
|
||||||
static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
|
|
||||||
static_assert(Svc::LowestThreadPriority >= HighestCoreMigrationAllowedPriority);
|
|
||||||
static_assert(Svc::HighestThreadPriority <= HighestCoreMigrationAllowedPriority);
|
|
||||||
|
|
||||||
class GlobalSchedulerContext final {
|
class GlobalSchedulerContext final {
|
||||||
friend class KScheduler;
|
friend class KScheduler;
|
||||||
|
@ -38,13 +33,13 @@ public:
|
||||||
~GlobalSchedulerContext();
|
~GlobalSchedulerContext();
|
||||||
|
|
||||||
/// Adds a new thread to the scheduler
|
/// Adds a new thread to the scheduler
|
||||||
void AddThread(std::shared_ptr<KThread> thread);
|
void AddThread(std::shared_ptr<Thread> thread);
|
||||||
|
|
||||||
/// Removes a thread from the scheduler
|
/// Removes a thread from the scheduler
|
||||||
void RemoveThread(std::shared_ptr<KThread> thread);
|
void RemoveThread(std::shared_ptr<Thread> thread);
|
||||||
|
|
||||||
/// Returns a list of all threads managed by the scheduler
|
/// Returns a list of all threads managed by the scheduler
|
||||||
[[nodiscard]] const std::vector<std::shared_ptr<KThread>>& GetThreadList() const {
|
[[nodiscard]] const std::vector<std::shared_ptr<Thread>>& GetThreadList() const {
|
||||||
return thread_list;
|
return thread_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +74,7 @@ private:
|
||||||
LockType scheduler_lock;
|
LockType scheduler_lock;
|
||||||
|
|
||||||
/// Lists all thread ids that aren't deleted/etc.
|
/// Lists all thread ids that aren't deleted/etc.
|
||||||
std::vector<std::shared_ptr<KThread>> thread_list;
|
std::vector<std::shared_ptr<Thread>> thread_list;
|
||||||
Common::SpinLock global_list_guard{};
|
Common::SpinLock global_list_guard{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -89,10 +89,6 @@ ResultCode HandleTable::Close(Handle handle) {
|
||||||
|
|
||||||
const u16 slot = GetSlot(handle);
|
const u16 slot = GetSlot(handle);
|
||||||
|
|
||||||
if (objects[slot].use_count() == 1) {
|
|
||||||
objects[slot]->Finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
objects[slot] = nullptr;
|
objects[slot] = nullptr;
|
||||||
|
|
||||||
generations[slot] = next_free_slot;
|
generations[slot] = next_free_slot;
|
||||||
|
|
|
@ -19,12 +19,12 @@
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#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/server_session.h"
|
#include "core/hle/kernel/server_session.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
@ -48,7 +48,7 @@ void SessionRequestHandler::ClientDisconnected(
|
||||||
|
|
||||||
HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
||||||
std::shared_ptr<ServerSession> server_session,
|
std::shared_ptr<ServerSession> server_session,
|
||||||
std::shared_ptr<KThread> thread)
|
std::shared_ptr<Thread> thread)
|
||||||
: server_session(std::move(server_session)),
|
: server_session(std::move(server_session)),
|
||||||
thread(std::move(thread)), kernel{kernel}, memory{memory} {
|
thread(std::move(thread)), kernel{kernel}, memory{memory} {
|
||||||
cmd_buf[0] = 0;
|
cmd_buf[0] = 0;
|
||||||
|
@ -182,7 +182,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) {
|
ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
|
||||||
auto& owner_process = *thread.GetOwnerProcess();
|
auto& owner_process = *thread.GetOwnerProcess();
|
||||||
auto& handle_table = owner_process.GetHandleTable();
|
auto& handle_table = owner_process.GetHandleTable();
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class HLERequestContext;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class Process;
|
class Process;
|
||||||
class ServerSession;
|
class ServerSession;
|
||||||
class KThread;
|
class Thread;
|
||||||
class ReadableEvent;
|
class ReadableEvent;
|
||||||
class WritableEvent;
|
class WritableEvent;
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ class HLERequestContext {
|
||||||
public:
|
public:
|
||||||
explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
|
||||||
std::shared_ptr<ServerSession> session,
|
std::shared_ptr<ServerSession> session,
|
||||||
std::shared_ptr<KThread> thread);
|
std::shared_ptr<Thread> thread);
|
||||||
~HLERequestContext();
|
~HLERequestContext();
|
||||||
|
|
||||||
/// Returns a pointer to the IPC command buffer for this request.
|
/// Returns a pointer to the IPC command buffer for this request.
|
||||||
|
@ -126,12 +126,15 @@ public:
|
||||||
return server_session;
|
return server_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using WakeupCallback = std::function<void(
|
||||||
|
std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
|
||||||
|
|
||||||
/// Populates this context with data from the requesting process/thread.
|
/// Populates this context with data from the requesting process/thread.
|
||||||
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
|
||||||
u32_le* src_cmdbuf);
|
u32_le* src_cmdbuf);
|
||||||
|
|
||||||
/// Writes data from this context back to the requesting process/thread.
|
/// Writes data from this context back to the requesting process/thread.
|
||||||
ResultCode WriteToOutgoingCommandBuffer(KThread& thread);
|
ResultCode WriteToOutgoingCommandBuffer(Thread& thread);
|
||||||
|
|
||||||
u32_le GetCommand() const {
|
u32_le GetCommand() const {
|
||||||
return command;
|
return command;
|
||||||
|
@ -258,11 +261,11 @@ public:
|
||||||
|
|
||||||
std::string Description() const;
|
std::string Description() const;
|
||||||
|
|
||||||
KThread& GetThread() {
|
Thread& GetThread() {
|
||||||
return *thread;
|
return *thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
const KThread& GetThread() const {
|
const Thread& GetThread() const {
|
||||||
return *thread;
|
return *thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +280,7 @@ private:
|
||||||
|
|
||||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||||
std::shared_ptr<Kernel::ServerSession> server_session;
|
std::shared_ptr<Kernel::ServerSession> server_session;
|
||||||
std::shared_ptr<KThread> thread;
|
std::shared_ptr<Thread> thread;
|
||||||
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
||||||
boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
|
boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
|
||||||
boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
|
boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
#include "core/hle/kernel/k_address_arbiter.h"
|
#include "core/hle/kernel/k_address_arbiter.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) {
|
||||||
auto it = thread_tree.nfind_light({addr, -1});
|
auto it = thread_tree.nfind_light({addr, -1});
|
||||||
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||||
(it->GetAddressArbiterKey() == addr)) {
|
(it->GetAddressArbiterKey() == addr)) {
|
||||||
KThread* target_thread = std::addressof(*it);
|
Thread* target_thread = std::addressof(*it);
|
||||||
target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
||||||
|
|
||||||
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
||||||
|
@ -125,7 +125,7 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32
|
||||||
auto it = thread_tree.nfind_light({addr, -1});
|
auto it = thread_tree.nfind_light({addr, -1});
|
||||||
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||||
(it->GetAddressArbiterKey() == addr)) {
|
(it->GetAddressArbiterKey() == addr)) {
|
||||||
KThread* target_thread = std::addressof(*it);
|
Thread* target_thread = std::addressof(*it);
|
||||||
target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
||||||
|
|
||||||
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
||||||
|
@ -215,7 +215,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
|
||||||
|
|
||||||
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||||
(it->GetAddressArbiterKey() == addr)) {
|
(it->GetAddressArbiterKey() == addr)) {
|
||||||
KThread* target_thread = std::addressof(*it);
|
Thread* target_thread = std::addressof(*it);
|
||||||
target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
|
||||||
|
|
||||||
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
||||||
|
@ -231,10 +231,11 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
|
||||||
|
|
||||||
ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
|
ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
|
||||||
// Prepare to wait.
|
// Prepare to wait.
|
||||||
KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
|
Handle timer = InvalidHandle;
|
||||||
|
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
|
KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout);
|
||||||
|
|
||||||
// Check that the thread isn't terminating.
|
// Check that the thread isn't terminating.
|
||||||
if (cur_thread->IsTerminationRequested()) {
|
if (cur_thread->IsTerminationRequested()) {
|
||||||
|
@ -279,7 +280,10 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel the timer wait.
|
// Cancel the timer wait.
|
||||||
kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
|
if (timer != InvalidHandle) {
|
||||||
|
auto& time_manager = kernel.TimeManager();
|
||||||
|
time_manager.UnscheduleTimeEvent(timer);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove from the address arbiter.
|
// Remove from the address arbiter.
|
||||||
{
|
{
|
||||||
|
@ -298,10 +302,11 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
|
||||||
|
|
||||||
ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||||
// Prepare to wait.
|
// Prepare to wait.
|
||||||
KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
|
Handle timer = InvalidHandle;
|
||||||
|
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
|
KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout);
|
||||||
|
|
||||||
// Check that the thread isn't terminating.
|
// Check that the thread isn't terminating.
|
||||||
if (cur_thread->IsTerminationRequested()) {
|
if (cur_thread->IsTerminationRequested()) {
|
||||||
|
@ -339,7 +344,10 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel the timer wait.
|
// Cancel the timer wait.
|
||||||
kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
|
if (timer != InvalidHandle) {
|
||||||
|
auto& time_manager = kernel.TimeManager();
|
||||||
|
time_manager.UnscheduleTimeEvent(timer);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove from the address arbiter.
|
// Remove from the address arbiter.
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/svc_common.h"
|
#include "core/hle/kernel/svc_common.h"
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -66,7 +66,7 @@ KConditionVariable::KConditionVariable(Core::System& system_)
|
||||||
KConditionVariable::~KConditionVariable() = default;
|
KConditionVariable::~KConditionVariable() = default;
|
||||||
|
|
||||||
ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
|
ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
|
||||||
KThread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
Thread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
|
|
||||||
// Signal the address.
|
// Signal the address.
|
||||||
{
|
{
|
||||||
|
@ -74,7 +74,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
|
||||||
|
|
||||||
// Remove waiter thread.
|
// Remove waiter thread.
|
||||||
s32 num_waiters{};
|
s32 num_waiters{};
|
||||||
KThread* next_owner_thread =
|
Thread* next_owner_thread =
|
||||||
owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
|
owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
|
||||||
|
|
||||||
// Determine the next tag.
|
// Determine the next tag.
|
||||||
|
@ -103,11 +103,11 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
|
ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
|
||||||
KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
|
|
||||||
// Wait for the address.
|
// Wait for the address.
|
||||||
{
|
{
|
||||||
std::shared_ptr<KThread> owner_thread;
|
std::shared_ptr<Thread> owner_thread;
|
||||||
ASSERT(!owner_thread);
|
ASSERT(!owner_thread);
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(kernel);
|
||||||
|
@ -126,7 +126,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
|
||||||
R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS);
|
R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS);
|
||||||
|
|
||||||
// Get the lock owner thread.
|
// Get the lock owner thread.
|
||||||
owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle);
|
owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<Thread>(handle);
|
||||||
R_UNLESS(owner_thread, Svc::ResultInvalidHandle);
|
R_UNLESS(owner_thread, Svc::ResultInvalidHandle);
|
||||||
|
|
||||||
// Update the lock.
|
// Update the lock.
|
||||||
|
@ -143,7 +143,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
|
||||||
// Remove the thread as a waiter from the lock owner.
|
// Remove the thread as a waiter from the lock owner.
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(kernel);
|
||||||
KThread* owner_thread = cur_thread->GetLockOwner();
|
Thread* owner_thread = cur_thread->GetLockOwner();
|
||||||
if (owner_thread != nullptr) {
|
if (owner_thread != nullptr) {
|
||||||
owner_thread->RemoveWaiter(cur_thread);
|
owner_thread->RemoveWaiter(cur_thread);
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
|
||||||
return cur_thread->GetWaitResult(std::addressof(dummy));
|
return cur_thread->GetWaitResult(std::addressof(dummy));
|
||||||
}
|
}
|
||||||
|
|
||||||
KThread* KConditionVariable::SignalImpl(KThread* thread) {
|
Thread* KConditionVariable::SignalImpl(Thread* thread) {
|
||||||
// Check pre-conditions.
|
// Check pre-conditions.
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KThread* thread_to_close = nullptr;
|
Thread* thread_to_close = nullptr;
|
||||||
if (can_access) {
|
if (can_access) {
|
||||||
if (prev_tag == InvalidHandle) {
|
if (prev_tag == InvalidHandle) {
|
||||||
// If nobody held the lock previously, we're all good.
|
// If nobody held the lock previously, we're all good.
|
||||||
|
@ -182,7 +182,7 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
|
||||||
thread->Wakeup();
|
thread->Wakeup();
|
||||||
} else {
|
} else {
|
||||||
// Get the previous owner.
|
// Get the previous owner.
|
||||||
auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(
|
auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<Thread>(
|
||||||
prev_tag & ~Svc::HandleWaitMask);
|
prev_tag & ~Svc::HandleWaitMask);
|
||||||
|
|
||||||
if (owner_thread) {
|
if (owner_thread) {
|
||||||
|
@ -210,8 +210,8 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||||
|
|
||||||
// TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using
|
// TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using
|
||||||
// std::shared_ptr.
|
// std::shared_ptr.
|
||||||
std::vector<std::shared_ptr<KThread>> thread_list;
|
std::vector<std::shared_ptr<Thread>> thread_list;
|
||||||
std::array<KThread*, MaxThreads> thread_array;
|
std::array<Thread*, MaxThreads> thread_array;
|
||||||
s32 num_to_close{};
|
s32 num_to_close{};
|
||||||
|
|
||||||
// Perform signaling.
|
// Perform signaling.
|
||||||
|
@ -222,9 +222,9 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||||
auto it = thread_tree.nfind_light({cv_key, -1});
|
auto it = thread_tree.nfind_light({cv_key, -1});
|
||||||
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||||
(it->GetConditionVariableKey() == cv_key)) {
|
(it->GetConditionVariableKey() == cv_key)) {
|
||||||
KThread* target_thread = std::addressof(*it);
|
Thread* target_thread = std::addressof(*it);
|
||||||
|
|
||||||
if (KThread* thread = SignalImpl(target_thread); thread != nullptr) {
|
if (Thread* thread = SignalImpl(target_thread); thread != nullptr) {
|
||||||
if (num_to_close < MaxThreads) {
|
if (num_to_close < MaxThreads) {
|
||||||
thread_array[num_to_close++] = thread;
|
thread_array[num_to_close++] = thread;
|
||||||
} else {
|
} else {
|
||||||
|
@ -257,10 +257,11 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
|
||||||
|
|
||||||
ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
|
||||||
// Prepare to wait.
|
// Prepare to wait.
|
||||||
KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
|
Handle timer = InvalidHandle;
|
||||||
|
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
|
KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout);
|
||||||
|
|
||||||
// Set the synced object.
|
// Set the synced object.
|
||||||
cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
|
cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
|
||||||
|
@ -275,7 +276,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
|
||||||
{
|
{
|
||||||
// Remove waiter thread.
|
// Remove waiter thread.
|
||||||
s32 num_waiters{};
|
s32 num_waiters{};
|
||||||
KThread* next_owner_thread =
|
Thread* next_owner_thread =
|
||||||
cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
|
cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
|
||||||
|
|
||||||
// Update for the next owner thread.
|
// Update for the next owner thread.
|
||||||
|
@ -321,13 +322,16 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel the timer wait.
|
// Cancel the timer wait.
|
||||||
kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
|
if (timer != InvalidHandle) {
|
||||||
|
auto& time_manager = kernel.TimeManager();
|
||||||
|
time_manager.UnscheduleTimeEvent(timer);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove from the condition variable.
|
// Remove from the condition variable.
|
||||||
{
|
{
|
||||||
KScopedSchedulerLock sl(kernel);
|
KScopedSchedulerLock sl(kernel);
|
||||||
|
|
||||||
if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) {
|
if (Thread* owner = cur_thread->GetLockOwner(); owner != nullptr) {
|
||||||
owner->RemoveWaiter(cur_thread);
|
owner->RemoveWaiter(cur_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -20,7 +20,7 @@ namespace Kernel {
|
||||||
|
|
||||||
class KConditionVariable {
|
class KConditionVariable {
|
||||||
public:
|
public:
|
||||||
using ThreadTree = typename KThread::ConditionVariableThreadTreeType;
|
using ThreadTree = typename Thread::ConditionVariableThreadTreeType;
|
||||||
|
|
||||||
explicit KConditionVariable(Core::System& system_);
|
explicit KConditionVariable(Core::System& system_);
|
||||||
~KConditionVariable();
|
~KConditionVariable();
|
||||||
|
@ -34,7 +34,7 @@ public:
|
||||||
[[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout);
|
[[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] KThread* SignalImpl(KThread* thread);
|
[[nodiscard]] Thread* SignalImpl(Thread* thread);
|
||||||
|
|
||||||
ThreadTree thread_tree;
|
ThreadTree thread_tree;
|
||||||
|
|
||||||
|
@ -43,14 +43,14 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
|
inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
|
||||||
KThread* thread) {
|
Thread* thread) {
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
tree->erase(tree->iterator_to(*thread));
|
tree->erase(tree->iterator_to(*thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
|
inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
|
||||||
KThread* thread) {
|
Thread* thread) {
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
tree->insert(*thread);
|
tree->insert(*thread);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class KThread;
|
class Thread;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
|
concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
|
||||||
|
@ -367,7 +367,7 @@ public:
|
||||||
this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
|
this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr KThread* MoveToScheduledBack(Member* member) {
|
constexpr Thread* MoveToScheduledBack(Member* member) {
|
||||||
return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
|
return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
|
||||||
member);
|
member);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,29 +17,25 @@
|
||||||
#include "core/cpu_manager.h"
|
#include "core/cpu_manager.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/physical_core.h"
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
static void IncrementScheduledCount(Kernel::KThread* thread) {
|
static void IncrementScheduledCount(Kernel::Thread* thread) {
|
||||||
if (auto process = thread->GetOwnerProcess(); process) {
|
if (auto process = thread->GetOwnerProcess(); process) {
|
||||||
process->IncrementScheduledCount();
|
process->IncrementScheduledCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule) {
|
void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
|
||||||
auto scheduler = kernel.CurrentScheduler();
|
Core::EmuThreadHandle global_thread) {
|
||||||
|
const u32 current_core = global_thread.host_handle;
|
||||||
u32 current_core{0xF};
|
bool must_context_switch = global_thread.guest_handle != InvalidHandle &&
|
||||||
bool must_context_switch{};
|
(current_core < Core::Hardware::NUM_CPU_CORES);
|
||||||
if (scheduler) {
|
|
||||||
current_core = scheduler->core_id;
|
|
||||||
must_context_switch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (cores_pending_reschedule != 0) {
|
while (cores_pending_reschedule != 0) {
|
||||||
const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule));
|
const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule));
|
||||||
|
@ -60,27 +56,28 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
|
u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) {
|
||||||
std::scoped_lock lock{guard};
|
std::scoped_lock lock{guard};
|
||||||
if (KThread* prev_highest_thread = state.highest_priority_thread;
|
if (Thread* prev_highest_thread = this->state.highest_priority_thread;
|
||||||
prev_highest_thread != highest_thread) {
|
prev_highest_thread != highest_thread) {
|
||||||
if (prev_highest_thread != nullptr) {
|
if (prev_highest_thread != nullptr) {
|
||||||
IncrementScheduledCount(prev_highest_thread);
|
IncrementScheduledCount(prev_highest_thread);
|
||||||
prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks());
|
prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks());
|
||||||
}
|
}
|
||||||
if (state.should_count_idle) {
|
if (this->state.should_count_idle) {
|
||||||
if (highest_thread != nullptr) {
|
if (highest_thread != nullptr) {
|
||||||
if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) {
|
// if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) {
|
||||||
process->SetRunningThread(core_id, highest_thread, state.idle_count);
|
// process->SetRunningThread(this->core_id, highest_thread,
|
||||||
}
|
// this->state.idle_count);
|
||||||
|
//}
|
||||||
} else {
|
} else {
|
||||||
state.idle_count++;
|
this->state.idle_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.highest_priority_thread = highest_thread;
|
this->state.highest_priority_thread = highest_thread;
|
||||||
state.needs_scheduling = true;
|
this->state.needs_scheduling = true;
|
||||||
return (1ULL << core_id);
|
return (1ULL << this->core_id);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -93,29 +90,16 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
||||||
ClearSchedulerUpdateNeeded(kernel);
|
ClearSchedulerUpdateNeeded(kernel);
|
||||||
|
|
||||||
u64 cores_needing_scheduling = 0, idle_cores = 0;
|
u64 cores_needing_scheduling = 0, idle_cores = 0;
|
||||||
KThread* top_threads[Core::Hardware::NUM_CPU_CORES];
|
Thread* top_threads[Core::Hardware::NUM_CPU_CORES];
|
||||||
auto& priority_queue = GetPriorityQueue(kernel);
|
auto& priority_queue = GetPriorityQueue(kernel);
|
||||||
|
|
||||||
/// We want to go over all cores, finding the highest priority thread and determining if
|
/// We want to go over all cores, finding the highest priority thread and determining if
|
||||||
/// scheduling is needed for that core.
|
/// scheduling is needed for that core.
|
||||||
for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
||||||
KThread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id));
|
Thread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id));
|
||||||
if (top_thread != nullptr) {
|
if (top_thread != nullptr) {
|
||||||
// If the thread has no waiters, we need to check if the process has a thread pinned.
|
// If the thread has no waiters, we need to check if the process has a thread pinned.
|
||||||
if (top_thread->GetNumKernelWaiters() == 0) {
|
// TODO(bunnei): Implement thread pinning
|
||||||
if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) {
|
|
||||||
if (KThread* pinned = parent->GetPinnedThread(static_cast<s32>(core_id));
|
|
||||||
pinned != nullptr && pinned != top_thread) {
|
|
||||||
// We prefer our parent's pinned thread if possible. However, we also don't
|
|
||||||
// want to schedule un-runnable threads.
|
|
||||||
if (pinned->GetRawState() == ThreadState::Runnable) {
|
|
||||||
top_thread = pinned;
|
|
||||||
} else {
|
|
||||||
top_thread = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
idle_cores |= (1ULL << core_id);
|
idle_cores |= (1ULL << core_id);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +112,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
||||||
// Idle cores are bad. We're going to try to migrate threads to each idle core in turn.
|
// Idle cores are bad. We're going to try to migrate threads to each idle core in turn.
|
||||||
while (idle_cores != 0) {
|
while (idle_cores != 0) {
|
||||||
const auto core_id = static_cast<u32>(std::countr_zero(idle_cores));
|
const auto core_id = static_cast<u32>(std::countr_zero(idle_cores));
|
||||||
if (KThread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) {
|
if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) {
|
||||||
s32 migration_candidates[Core::Hardware::NUM_CPU_CORES];
|
s32 migration_candidates[Core::Hardware::NUM_CPU_CORES];
|
||||||
size_t num_candidates = 0;
|
size_t num_candidates = 0;
|
||||||
|
|
||||||
|
@ -136,7 +120,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
||||||
while (suggested != nullptr) {
|
while (suggested != nullptr) {
|
||||||
// Check if the suggested thread is the top thread on its core.
|
// Check if the suggested thread is the top thread on its core.
|
||||||
const s32 suggested_core = suggested->GetActiveCore();
|
const s32 suggested_core = suggested->GetActiveCore();
|
||||||
if (KThread* top_thread =
|
if (Thread* top_thread =
|
||||||
(suggested_core >= 0) ? top_threads[suggested_core] : nullptr;
|
(suggested_core >= 0) ? top_threads[suggested_core] : nullptr;
|
||||||
top_thread != suggested) {
|
top_thread != suggested) {
|
||||||
// Make sure we're not dealing with threads too high priority for migration.
|
// Make sure we're not dealing with threads too high priority for migration.
|
||||||
|
@ -168,7 +152,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
||||||
// Check if there's some other thread that can run on the candidate core.
|
// Check if there's some other thread that can run on the candidate core.
|
||||||
const s32 candidate_core = migration_candidates[i];
|
const s32 candidate_core = migration_candidates[i];
|
||||||
suggested = top_threads[candidate_core];
|
suggested = top_threads[candidate_core];
|
||||||
if (KThread* next_on_candidate_core =
|
if (Thread* next_on_candidate_core =
|
||||||
priority_queue.GetScheduledNext(candidate_core, suggested);
|
priority_queue.GetScheduledNext(candidate_core, suggested);
|
||||||
next_on_candidate_core != nullptr) {
|
next_on_candidate_core != nullptr) {
|
||||||
// The candidate core can run some other thread! We'll migrate its current
|
// The candidate core can run some other thread! We'll migrate its current
|
||||||
|
@ -198,20 +182,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
||||||
return cores_needing_scheduling;
|
return cores_needing_scheduling;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) {
|
void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state) {
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
|
||||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; ++i) {
|
|
||||||
// Get an atomic reference to the core scheduler's previous thread.
|
|
||||||
std::atomic_ref<KThread*> prev_thread(kernel.Scheduler(static_cast<s32>(i)).prev_thread);
|
|
||||||
static_assert(std::atomic_ref<KThread*>::is_always_lock_free);
|
|
||||||
|
|
||||||
// Atomically clear the previous thread if it's our target.
|
|
||||||
KThread* compare = thread;
|
|
||||||
prev_thread.compare_exchange_strong(compare, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state) {
|
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
// Check if the state has changed, because if it hasn't there's nothing to do.
|
// Check if the state has changed, because if it hasn't there's nothing to do.
|
||||||
|
@ -234,7 +205,7 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, Threa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority) {
|
void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority) {
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
// If the thread is runnable, we want to change its priority in the queue.
|
// If the thread is runnable, we want to change its priority in the queue.
|
||||||
|
@ -246,7 +217,7 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread,
|
void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread,
|
||||||
const KAffinityMask& old_affinity, s32 old_core) {
|
const KAffinityMask& old_affinity, s32 old_core) {
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
||||||
|
|
||||||
|
@ -266,8 +237,8 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
|
||||||
auto& priority_queue = GetPriorityQueue(kernel);
|
auto& priority_queue = GetPriorityQueue(kernel);
|
||||||
|
|
||||||
// Rotate the front of the queue to the end.
|
// Rotate the front of the queue to the end.
|
||||||
KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority);
|
Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority);
|
||||||
KThread* next_thread = nullptr;
|
Thread* next_thread = nullptr;
|
||||||
if (top_thread != nullptr) {
|
if (top_thread != nullptr) {
|
||||||
next_thread = priority_queue.MoveToScheduledBack(top_thread);
|
next_thread = priority_queue.MoveToScheduledBack(top_thread);
|
||||||
if (next_thread != top_thread) {
|
if (next_thread != top_thread) {
|
||||||
|
@ -278,11 +249,11 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
|
||||||
|
|
||||||
// While we have a suggested thread, try to migrate it!
|
// While we have a suggested thread, try to migrate it!
|
||||||
{
|
{
|
||||||
KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority);
|
Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority);
|
||||||
while (suggested != nullptr) {
|
while (suggested != nullptr) {
|
||||||
// Check if the suggested thread is the top thread on its core.
|
// Check if the suggested thread is the top thread on its core.
|
||||||
const s32 suggested_core = suggested->GetActiveCore();
|
const s32 suggested_core = suggested->GetActiveCore();
|
||||||
if (KThread* top_on_suggested_core =
|
if (Thread* top_on_suggested_core =
|
||||||
(suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
|
(suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
top_on_suggested_core != suggested) {
|
top_on_suggested_core != suggested) {
|
||||||
|
@ -314,7 +285,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
|
||||||
// Now that we might have migrated a thread with the same priority, check if we can do better.
|
// Now that we might have migrated a thread with the same priority, check if we can do better.
|
||||||
|
|
||||||
{
|
{
|
||||||
KThread* best_thread = priority_queue.GetScheduledFront(core_id);
|
Thread* best_thread = priority_queue.GetScheduledFront(core_id);
|
||||||
if (best_thread == GetCurrentThread()) {
|
if (best_thread == GetCurrentThread()) {
|
||||||
best_thread = priority_queue.GetScheduledNext(core_id, best_thread);
|
best_thread = priority_queue.GetScheduledNext(core_id, best_thread);
|
||||||
}
|
}
|
||||||
|
@ -322,7 +293,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
|
||||||
// If the best thread we can choose has a priority the same or worse than ours, try to
|
// If the best thread we can choose has a priority the same or worse than ours, try to
|
||||||
// migrate a higher priority thread.
|
// migrate a higher priority thread.
|
||||||
if (best_thread != nullptr && best_thread->GetPriority() >= priority) {
|
if (best_thread != nullptr && best_thread->GetPriority() >= priority) {
|
||||||
KThread* suggested = priority_queue.GetSuggestedFront(core_id);
|
Thread* suggested = priority_queue.GetSuggestedFront(core_id);
|
||||||
while (suggested != nullptr) {
|
while (suggested != nullptr) {
|
||||||
// If the suggestion's priority is the same as ours, don't bother.
|
// If the suggestion's priority is the same as ours, don't bother.
|
||||||
if (suggested->GetPriority() >= best_thread->GetPriority()) {
|
if (suggested->GetPriority() >= best_thread->GetPriority()) {
|
||||||
|
@ -331,7 +302,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
|
||||||
|
|
||||||
// Check if the suggested thread is the top thread on its core.
|
// Check if the suggested thread is the top thread on its core.
|
||||||
const s32 suggested_core = suggested->GetActiveCore();
|
const s32 suggested_core = suggested->GetActiveCore();
|
||||||
if (KThread* top_on_suggested_core =
|
if (Thread* top_on_suggested_core =
|
||||||
(suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
|
(suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
top_on_suggested_core != suggested) {
|
top_on_suggested_core != suggested) {
|
||||||
|
@ -381,14 +352,12 @@ void KScheduler::DisableScheduling(KernelCore& kernel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) {
|
void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling,
|
||||||
|
Core::EmuThreadHandle global_thread) {
|
||||||
if (auto* scheduler = kernel.CurrentScheduler(); scheduler) {
|
if (auto* scheduler = kernel.CurrentScheduler(); scheduler) {
|
||||||
ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1);
|
|
||||||
if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) {
|
|
||||||
scheduler->GetCurrentThread()->EnableDispatch();
|
scheduler->GetCurrentThread()->EnableDispatch();
|
||||||
}
|
}
|
||||||
}
|
RescheduleCores(kernel, cores_needing_scheduling, global_thread);
|
||||||
RescheduleCores(kernel, cores_needing_scheduling);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
|
u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
|
||||||
|
@ -403,13 +372,15 @@ KSchedulerPriorityQueue& KScheduler::GetPriorityQueue(KernelCore& kernel) {
|
||||||
return kernel.GlobalSchedulerContext().priority_queue;
|
return kernel.GlobalSchedulerContext().priority_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
|
void KScheduler::YieldWithoutCoreMigration() {
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
|
||||||
// Validate preconditions.
|
// Validate preconditions.
|
||||||
ASSERT(CanSchedule(kernel));
|
ASSERT(CanSchedule(kernel));
|
||||||
ASSERT(kernel.CurrentProcess() != nullptr);
|
ASSERT(kernel.CurrentProcess() != nullptr);
|
||||||
|
|
||||||
// Get the current thread and process.
|
// Get the current thread and process.
|
||||||
KThread& cur_thread = Kernel::GetCurrentThread(kernel);
|
Thread& cur_thread = *GetCurrentThread();
|
||||||
Process& cur_process = *kernel.CurrentProcess();
|
Process& cur_process = *kernel.CurrentProcess();
|
||||||
|
|
||||||
// If the thread's yield count matches, there's nothing for us to do.
|
// If the thread's yield count matches, there's nothing for us to do.
|
||||||
|
@ -427,7 +398,7 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
|
||||||
const auto cur_state = cur_thread.GetRawState();
|
const auto cur_state = cur_thread.GetRawState();
|
||||||
if (cur_state == ThreadState::Runnable) {
|
if (cur_state == ThreadState::Runnable) {
|
||||||
// Put the current thread at the back of the queue.
|
// Put the current thread at the back of the queue.
|
||||||
KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
|
Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
|
||||||
IncrementScheduledCount(std::addressof(cur_thread));
|
IncrementScheduledCount(std::addressof(cur_thread));
|
||||||
|
|
||||||
// If the next thread is different, we have an update to perform.
|
// If the next thread is different, we have an update to perform.
|
||||||
|
@ -442,13 +413,15 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
|
void KScheduler::YieldWithCoreMigration() {
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
|
||||||
// Validate preconditions.
|
// Validate preconditions.
|
||||||
ASSERT(CanSchedule(kernel));
|
ASSERT(CanSchedule(kernel));
|
||||||
ASSERT(kernel.CurrentProcess() != nullptr);
|
ASSERT(kernel.CurrentProcess() != nullptr);
|
||||||
|
|
||||||
// Get the current thread and process.
|
// Get the current thread and process.
|
||||||
KThread& cur_thread = Kernel::GetCurrentThread(kernel);
|
Thread& cur_thread = *GetCurrentThread();
|
||||||
Process& cur_process = *kernel.CurrentProcess();
|
Process& cur_process = *kernel.CurrentProcess();
|
||||||
|
|
||||||
// If the thread's yield count matches, there's nothing for us to do.
|
// If the thread's yield count matches, there's nothing for us to do.
|
||||||
|
@ -469,17 +442,17 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
|
||||||
const s32 core_id = cur_thread.GetActiveCore();
|
const s32 core_id = cur_thread.GetActiveCore();
|
||||||
|
|
||||||
// Put the current thread at the back of the queue.
|
// Put the current thread at the back of the queue.
|
||||||
KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
|
Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
|
||||||
IncrementScheduledCount(std::addressof(cur_thread));
|
IncrementScheduledCount(std::addressof(cur_thread));
|
||||||
|
|
||||||
// While we have a suggested thread, try to migrate it!
|
// While we have a suggested thread, try to migrate it!
|
||||||
bool recheck = false;
|
bool recheck = false;
|
||||||
KThread* suggested = priority_queue.GetSuggestedFront(core_id);
|
Thread* suggested = priority_queue.GetSuggestedFront(core_id);
|
||||||
while (suggested != nullptr) {
|
while (suggested != nullptr) {
|
||||||
// Check if the suggested thread is the thread running on its core.
|
// Check if the suggested thread is the thread running on its core.
|
||||||
const s32 suggested_core = suggested->GetActiveCore();
|
const s32 suggested_core = suggested->GetActiveCore();
|
||||||
|
|
||||||
if (KThread* running_on_suggested_core =
|
if (Thread* running_on_suggested_core =
|
||||||
(suggested_core >= 0)
|
(suggested_core >= 0)
|
||||||
? kernel.Scheduler(suggested_core).state.highest_priority_thread
|
? kernel.Scheduler(suggested_core).state.highest_priority_thread
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
@ -530,13 +503,15 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::YieldToAnyThread(KernelCore& kernel) {
|
void KScheduler::YieldToAnyThread() {
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
|
||||||
// Validate preconditions.
|
// Validate preconditions.
|
||||||
ASSERT(CanSchedule(kernel));
|
ASSERT(CanSchedule(kernel));
|
||||||
ASSERT(kernel.CurrentProcess() != nullptr);
|
ASSERT(kernel.CurrentProcess() != nullptr);
|
||||||
|
|
||||||
// Get the current thread and process.
|
// Get the current thread and process.
|
||||||
KThread& cur_thread = Kernel::GetCurrentThread(kernel);
|
Thread& cur_thread = *GetCurrentThread();
|
||||||
Process& cur_process = *kernel.CurrentProcess();
|
Process& cur_process = *kernel.CurrentProcess();
|
||||||
|
|
||||||
// If the thread's yield count matches, there's nothing for us to do.
|
// If the thread's yield count matches, there's nothing for us to do.
|
||||||
|
@ -564,11 +539,11 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
|
||||||
// If there's nothing scheduled, we can try to perform a migration.
|
// If there's nothing scheduled, we can try to perform a migration.
|
||||||
if (priority_queue.GetScheduledFront(core_id) == nullptr) {
|
if (priority_queue.GetScheduledFront(core_id) == nullptr) {
|
||||||
// While we have a suggested thread, try to migrate it!
|
// While we have a suggested thread, try to migrate it!
|
||||||
KThread* suggested = priority_queue.GetSuggestedFront(core_id);
|
Thread* suggested = priority_queue.GetSuggestedFront(core_id);
|
||||||
while (suggested != nullptr) {
|
while (suggested != nullptr) {
|
||||||
// Check if the suggested thread is the top thread on its core.
|
// Check if the suggested thread is the top thread on its core.
|
||||||
const s32 suggested_core = suggested->GetActiveCore();
|
const s32 suggested_core = suggested->GetActiveCore();
|
||||||
if (KThread* top_on_suggested_core =
|
if (Thread* top_on_suggested_core =
|
||||||
(suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
|
(suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
top_on_suggested_core != suggested) {
|
top_on_suggested_core != suggested) {
|
||||||
|
@ -606,19 +581,20 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) {
|
KScheduler::KScheduler(Core::System& system, std::size_t core_id)
|
||||||
|
: system(system), core_id(core_id) {
|
||||||
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
|
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
|
||||||
state.needs_scheduling = true;
|
this->state.needs_scheduling = true;
|
||||||
state.interrupt_task_thread_runnable = false;
|
this->state.interrupt_task_thread_runnable = false;
|
||||||
state.should_count_idle = false;
|
this->state.should_count_idle = false;
|
||||||
state.idle_count = 0;
|
this->state.idle_count = 0;
|
||||||
state.idle_thread_stack = nullptr;
|
this->state.idle_thread_stack = nullptr;
|
||||||
state.highest_priority_thread = nullptr;
|
this->state.highest_priority_thread = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
KScheduler::~KScheduler() = default;
|
KScheduler::~KScheduler() = default;
|
||||||
|
|
||||||
KThread* KScheduler::GetCurrentThread() const {
|
Thread* KScheduler::GetCurrentThread() const {
|
||||||
if (current_thread) {
|
if (current_thread) {
|
||||||
return current_thread;
|
return current_thread;
|
||||||
}
|
}
|
||||||
|
@ -637,7 +613,7 @@ void KScheduler::RescheduleCurrentCore() {
|
||||||
phys_core.ClearInterrupt();
|
phys_core.ClearInterrupt();
|
||||||
}
|
}
|
||||||
guard.lock();
|
guard.lock();
|
||||||
if (state.needs_scheduling) {
|
if (this->state.needs_scheduling) {
|
||||||
Schedule();
|
Schedule();
|
||||||
} else {
|
} else {
|
||||||
guard.unlock();
|
guard.unlock();
|
||||||
|
@ -648,41 +624,38 @@ void KScheduler::OnThreadStart() {
|
||||||
SwitchContextStep2();
|
SwitchContextStep2();
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::Unload(KThread* thread) {
|
void KScheduler::Unload(Thread* thread) {
|
||||||
LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr");
|
|
||||||
|
|
||||||
if (thread) {
|
if (thread) {
|
||||||
if (thread->IsCallingSvc()) {
|
thread->SetIsRunning(false);
|
||||||
|
if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) {
|
||||||
system.ArmInterface(core_id).ExceptionalExit();
|
system.ArmInterface(core_id).ExceptionalExit();
|
||||||
thread->ClearIsCallingSvc();
|
thread->SetContinuousOnSVC(false);
|
||||||
}
|
}
|
||||||
if (!thread->IsTerminationRequested()) {
|
if (!thread->IsHLEThread() && !thread->HasExited()) {
|
||||||
prev_thread = thread;
|
|
||||||
|
|
||||||
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
|
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
|
||||||
cpu_core.SaveContext(thread->GetContext32());
|
cpu_core.SaveContext(thread->GetContext32());
|
||||||
cpu_core.SaveContext(thread->GetContext64());
|
cpu_core.SaveContext(thread->GetContext64());
|
||||||
// Save the TPIDR_EL0 system register in case it was modified.
|
// Save the TPIDR_EL0 system register in case it was modified.
|
||||||
thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
|
thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
|
||||||
cpu_core.ClearExclusiveState();
|
cpu_core.ClearExclusiveState();
|
||||||
} else {
|
|
||||||
prev_thread = nullptr;
|
|
||||||
}
|
}
|
||||||
thread->context_guard.unlock();
|
thread->context_guard.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::Reload(KThread* thread) {
|
void KScheduler::Reload(Thread* thread) {
|
||||||
LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread ? thread->GetName() : "nullptr");
|
|
||||||
|
|
||||||
if (thread) {
|
if (thread) {
|
||||||
ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable.");
|
ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable.");
|
||||||
|
|
||||||
|
// Cancel any outstanding wakeup events for this thread
|
||||||
|
thread->SetIsRunning(true);
|
||||||
|
thread->SetWasRunning(false);
|
||||||
|
|
||||||
auto* const thread_owner_process = thread->GetOwnerProcess();
|
auto* const thread_owner_process = thread->GetOwnerProcess();
|
||||||
if (thread_owner_process != nullptr) {
|
if (thread_owner_process != nullptr) {
|
||||||
system.Kernel().MakeCurrentProcess(thread_owner_process);
|
system.Kernel().MakeCurrentProcess(thread_owner_process);
|
||||||
}
|
}
|
||||||
|
if (!thread->IsHLEThread()) {
|
||||||
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
|
Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
|
||||||
cpu_core.LoadContext(thread->GetContext32());
|
cpu_core.LoadContext(thread->GetContext32());
|
||||||
cpu_core.LoadContext(thread->GetContext64());
|
cpu_core.LoadContext(thread->GetContext64());
|
||||||
|
@ -691,6 +664,7 @@ void KScheduler::Reload(KThread* thread) {
|
||||||
cpu_core.ClearExclusiveState();
|
cpu_core.ClearExclusiveState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void KScheduler::SwitchContextStep2() {
|
void KScheduler::SwitchContextStep2() {
|
||||||
// Load context of new thread
|
// Load context of new thread
|
||||||
|
@ -700,24 +674,16 @@ void KScheduler::SwitchContextStep2() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::ScheduleImpl() {
|
void KScheduler::ScheduleImpl() {
|
||||||
KThread* previous_thread = current_thread;
|
Thread* previous_thread = current_thread;
|
||||||
KThread* next_thread = state.highest_priority_thread;
|
current_thread = state.highest_priority_thread;
|
||||||
|
|
||||||
state.needs_scheduling = false;
|
this->state.needs_scheduling = false;
|
||||||
|
|
||||||
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
|
if (current_thread == previous_thread) {
|
||||||
if (next_thread == nullptr) {
|
|
||||||
next_thread = idle_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're not actually switching thread, there's nothing to do.
|
|
||||||
if (next_thread == current_thread) {
|
|
||||||
guard.unlock();
|
guard.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread = next_thread;
|
|
||||||
|
|
||||||
Process* const previous_process = system.Kernel().CurrentProcess();
|
Process* const previous_process = system.Kernel().CurrentProcess();
|
||||||
|
|
||||||
UpdateLastContextSwitchTime(previous_thread, previous_process);
|
UpdateLastContextSwitchTime(previous_thread, previous_process);
|
||||||
|
@ -749,20 +715,20 @@ void KScheduler::SwitchToCurrent() {
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{guard};
|
std::scoped_lock lock{guard};
|
||||||
current_thread = state.highest_priority_thread;
|
current_thread = state.highest_priority_thread;
|
||||||
state.needs_scheduling = false;
|
this->state.needs_scheduling = false;
|
||||||
}
|
}
|
||||||
const auto is_switch_pending = [this] {
|
const auto is_switch_pending = [this] {
|
||||||
std::scoped_lock lock{guard};
|
std::scoped_lock lock{guard};
|
||||||
return state.needs_scheduling.load(std::memory_order_relaxed);
|
return state.needs_scheduling.load(std::memory_order_relaxed);
|
||||||
};
|
};
|
||||||
do {
|
do {
|
||||||
if (current_thread != nullptr) {
|
if (current_thread != nullptr && !current_thread->IsHLEThread()) {
|
||||||
current_thread->context_guard.lock();
|
current_thread->context_guard.lock();
|
||||||
if (current_thread->GetRawState() != ThreadState::Runnable) {
|
if (current_thread->GetRawState() != ThreadState::Runnable) {
|
||||||
current_thread->context_guard.unlock();
|
current_thread->context_guard.unlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (current_thread->GetActiveCore() != core_id) {
|
if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) {
|
||||||
current_thread->context_guard.unlock();
|
current_thread->context_guard.unlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -778,13 +744,13 @@ void KScheduler::SwitchToCurrent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) {
|
void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
|
||||||
const u64 prev_switch_ticks = last_context_switch_time;
|
const u64 prev_switch_ticks = last_context_switch_time;
|
||||||
const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks();
|
const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks();
|
||||||
const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
|
const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
|
||||||
|
|
||||||
if (thread != nullptr) {
|
if (thread != nullptr) {
|
||||||
thread->AddCpuTime(core_id, update_ticks);
|
thread->UpdateCPUTimeTicks(update_ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process != nullptr) {
|
if (process != nullptr) {
|
||||||
|
@ -798,10 +764,15 @@ void KScheduler::Initialize() {
|
||||||
std::string name = "Idle Thread Id:" + std::to_string(core_id);
|
std::string name = "Idle Thread Id:" + std::to_string(core_id);
|
||||||
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::Main, name, 0,
|
ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE);
|
||||||
KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
|
auto thread_res = Thread::Create(system, type, name, 0, 64, 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();
|
||||||
|
|
||||||
|
{
|
||||||
|
KScopedSchedulerLock lock{system.Kernel()};
|
||||||
|
idle_thread->SetState(ThreadState::Runnable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
|
KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
|
||||||
|
|
|
@ -29,33 +29,29 @@ namespace Kernel {
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class Process;
|
class Process;
|
||||||
class SchedulerLock;
|
class SchedulerLock;
|
||||||
class KThread;
|
class Thread;
|
||||||
|
|
||||||
class KScheduler final {
|
class KScheduler final {
|
||||||
public:
|
public:
|
||||||
explicit KScheduler(Core::System& system, s32 core_id);
|
explicit KScheduler(Core::System& system, std::size_t core_id);
|
||||||
~KScheduler();
|
~KScheduler();
|
||||||
|
|
||||||
/// Reschedules to the next available thread (call after current thread is suspended)
|
/// Reschedules to the next available thread (call after current thread is suspended)
|
||||||
void RescheduleCurrentCore();
|
void RescheduleCurrentCore();
|
||||||
|
|
||||||
/// Reschedules cores pending reschedule, to be called on EnableScheduling.
|
/// Reschedules cores pending reschedule, to be called on EnableScheduling.
|
||||||
static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule);
|
static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
|
||||||
|
Core::EmuThreadHandle global_thread);
|
||||||
|
|
||||||
/// The next two are for SingleCore Only.
|
/// The next two are for SingleCore Only.
|
||||||
/// Unload current thread before preempting core.
|
/// Unload current thread before preempting core.
|
||||||
void Unload(KThread* thread);
|
void Unload(Thread* thread);
|
||||||
|
|
||||||
/// Reload current thread after core preemption.
|
/// Reload current thread after core preemption.
|
||||||
void Reload(KThread* thread);
|
void Reload(Thread* thread);
|
||||||
|
|
||||||
/// Gets the current running thread
|
/// Gets the current running thread
|
||||||
[[nodiscard]] KThread* GetCurrentThread() const;
|
[[nodiscard]] Thread* GetCurrentThread() const;
|
||||||
|
|
||||||
/// Returns true if the scheduler is idle
|
|
||||||
[[nodiscard]] bool IsIdle() const {
|
|
||||||
return GetCurrentThread() == idle_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the timestamp for the last context switch in ticks.
|
/// Gets the timestamp for the last context switch in ticks.
|
||||||
[[nodiscard]] u64 GetLastContextSwitchTicks() const;
|
[[nodiscard]] u64 GetLastContextSwitchTicks() const;
|
||||||
|
@ -76,14 +72,14 @@ public:
|
||||||
return switch_fiber;
|
return switch_fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] u64 UpdateHighestPriorityThread(KThread* highest_thread);
|
[[nodiscard]] u64 UpdateHighestPriorityThread(Thread* highest_thread);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a thread and moves it to the back of the it's priority list.
|
* Takes a thread and moves it to the back of the it's priority list.
|
||||||
*
|
*
|
||||||
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
||||||
*/
|
*/
|
||||||
static void YieldWithoutCoreMigration(KernelCore& kernel);
|
void YieldWithoutCoreMigration();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a thread and moves it to the back of the it's priority list.
|
* Takes a thread and moves it to the back of the it's priority list.
|
||||||
|
@ -92,7 +88,7 @@ public:
|
||||||
*
|
*
|
||||||
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
||||||
*/
|
*/
|
||||||
static void YieldWithCoreMigration(KernelCore& kernel);
|
void YieldWithCoreMigration();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a thread and moves it out of the scheduling queue.
|
* Takes a thread and moves it out of the scheduling queue.
|
||||||
|
@ -101,18 +97,16 @@ public:
|
||||||
*
|
*
|
||||||
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
* @note This operation can be redundant and no scheduling is changed if marked as so.
|
||||||
*/
|
*/
|
||||||
static void YieldToAnyThread(KernelCore& kernel);
|
void YieldToAnyThread();
|
||||||
|
|
||||||
static void ClearPreviousThread(KernelCore& kernel, KThread* thread);
|
|
||||||
|
|
||||||
/// Notify the scheduler a thread's status has changed.
|
/// Notify the scheduler a thread's status has changed.
|
||||||
static void OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state);
|
static void OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state);
|
||||||
|
|
||||||
/// Notify the scheduler a thread's priority has changed.
|
/// Notify the scheduler a thread's priority has changed.
|
||||||
static void OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority);
|
static void OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority);
|
||||||
|
|
||||||
/// Notify the scheduler a thread's core and/or affinity mask has changed.
|
/// Notify the scheduler a thread's core and/or affinity mask has changed.
|
||||||
static void OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread,
|
static void OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread,
|
||||||
const KAffinityMask& old_affinity, s32 old_core);
|
const KAffinityMask& old_affinity, s32 old_core);
|
||||||
|
|
||||||
static bool CanSchedule(KernelCore& kernel);
|
static bool CanSchedule(KernelCore& kernel);
|
||||||
|
@ -120,7 +114,8 @@ public:
|
||||||
static void SetSchedulerUpdateNeeded(KernelCore& kernel);
|
static void SetSchedulerUpdateNeeded(KernelCore& kernel);
|
||||||
static void ClearSchedulerUpdateNeeded(KernelCore& kernel);
|
static void ClearSchedulerUpdateNeeded(KernelCore& kernel);
|
||||||
static void DisableScheduling(KernelCore& kernel);
|
static void DisableScheduling(KernelCore& kernel);
|
||||||
static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling);
|
static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling,
|
||||||
|
Core::EmuThreadHandle global_thread);
|
||||||
[[nodiscard]] static u64 UpdateHighestPriorityThreads(KernelCore& kernel);
|
[[nodiscard]] static u64 UpdateHighestPriorityThreads(KernelCore& kernel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -168,14 +163,13 @@ private:
|
||||||
* most recent tick count retrieved. No special arithmetic is
|
* most recent tick count retrieved. No special arithmetic is
|
||||||
* applied to it.
|
* applied to it.
|
||||||
*/
|
*/
|
||||||
void UpdateLastContextSwitchTime(KThread* thread, Process* process);
|
void UpdateLastContextSwitchTime(Thread* thread, Process* process);
|
||||||
|
|
||||||
static void OnSwitch(void* this_scheduler);
|
static void OnSwitch(void* this_scheduler);
|
||||||
void SwitchToCurrent();
|
void SwitchToCurrent();
|
||||||
|
|
||||||
KThread* prev_thread{};
|
Thread* current_thread{};
|
||||||
KThread* current_thread{};
|
Thread* idle_thread{};
|
||||||
KThread* idle_thread{};
|
|
||||||
|
|
||||||
std::shared_ptr<Common::Fiber> switch_fiber{};
|
std::shared_ptr<Common::Fiber> switch_fiber{};
|
||||||
|
|
||||||
|
@ -184,7 +178,7 @@ private:
|
||||||
bool interrupt_task_thread_runnable{};
|
bool interrupt_task_thread_runnable{};
|
||||||
bool should_count_idle{};
|
bool should_count_idle{};
|
||||||
u64 idle_count{};
|
u64 idle_count{};
|
||||||
KThread* highest_priority_thread{};
|
Thread* highest_priority_thread{};
|
||||||
void* idle_thread_stack{};
|
void* idle_thread_stack{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -192,7 +186,7 @@ private:
|
||||||
|
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
u64 last_context_switch_time{};
|
u64 last_context_switch_time{};
|
||||||
const s32 core_id;
|
const std::size_t core_id;
|
||||||
|
|
||||||
Common::SpinLock guard{};
|
Common::SpinLock guard{};
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
|
|
||||||
// For debug, ensure that our state is valid.
|
// For debug, ensure that our state is valid.
|
||||||
ASSERT(this->lock_count == 0);
|
ASSERT(this->lock_count == 0);
|
||||||
ASSERT(this->owner_thread == EmuThreadHandleInvalid);
|
ASSERT(this->owner_thread == Core::EmuThreadHandle::InvalidHandle());
|
||||||
|
|
||||||
// Increment count, take ownership.
|
// Increment count, take ownership.
|
||||||
this->lock_count = 1;
|
this->lock_count = 1;
|
||||||
|
@ -54,13 +54,14 @@ public:
|
||||||
// We're no longer going to hold the lock. Take note of what cores need scheduling.
|
// We're no longer going to hold the lock. Take note of what cores need scheduling.
|
||||||
const u64 cores_needing_scheduling =
|
const u64 cores_needing_scheduling =
|
||||||
SchedulerType::UpdateHighestPriorityThreads(kernel);
|
SchedulerType::UpdateHighestPriorityThreads(kernel);
|
||||||
|
Core::EmuThreadHandle leaving_thread = owner_thread;
|
||||||
|
|
||||||
// Note that we no longer hold the lock, and unlock the spinlock.
|
// Note that we no longer hold the lock, and unlock the spinlock.
|
||||||
this->owner_thread = EmuThreadHandleInvalid;
|
this->owner_thread = Core::EmuThreadHandle::InvalidHandle();
|
||||||
this->spin_lock.unlock();
|
this->spin_lock.unlock();
|
||||||
|
|
||||||
// Enable scheduling, and perform a rescheduling operation.
|
// Enable scheduling, and perform a rescheduling operation.
|
||||||
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
|
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling, leaving_thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ private:
|
||||||
KernelCore& kernel;
|
KernelCore& kernel;
|
||||||
Common::SpinLock spin_lock{};
|
Common::SpinLock spin_lock{};
|
||||||
s32 lock_count{};
|
s32 lock_count{};
|
||||||
EmuThreadHandle owner_thread{EmuThreadHandleInvalid};
|
Core::EmuThreadHandle owner_thread{Core::EmuThreadHandle::InvalidHandle()};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -9,24 +9,27 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class KScopedSchedulerLockAndSleep {
|
class KScopedSchedulerLockAndSleep {
|
||||||
public:
|
public:
|
||||||
explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout)
|
explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* t,
|
||||||
: kernel(kernel), thread(t), timeout_tick(timeout) {
|
s64 timeout)
|
||||||
|
: kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) {
|
||||||
|
event_handle = InvalidHandle;
|
||||||
|
|
||||||
// Lock the scheduler.
|
// Lock the scheduler.
|
||||||
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
|
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
~KScopedSchedulerLockAndSleep() {
|
~KScopedSchedulerLockAndSleep() {
|
||||||
// Register the sleep.
|
// Register the sleep.
|
||||||
if (timeout_tick > 0) {
|
if (this->timeout_tick > 0) {
|
||||||
kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick);
|
kernel.TimeManager().ScheduleTimeEvent(event_handle, this->thread, this->timeout_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock the scheduler.
|
// Unlock the scheduler.
|
||||||
|
@ -34,12 +37,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void CancelSleep() {
|
void CancelSleep() {
|
||||||
timeout_tick = 0;
|
this->timeout_tick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KernelCore& kernel;
|
KernelCore& kernel;
|
||||||
KThread* thread{};
|
Handle& event_handle;
|
||||||
|
Thread* thread{};
|
||||||
s64 timeout_tick{};
|
s64 timeout_tick{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -20,11 +20,12 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
|
||||||
std::vector<ThreadListNode> thread_nodes(num_objects);
|
std::vector<ThreadListNode> thread_nodes(num_objects);
|
||||||
|
|
||||||
// Prepare for wait.
|
// Prepare for wait.
|
||||||
KThread* thread = kernel.CurrentScheduler()->GetCurrentThread();
|
Thread* thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
|
Handle timer = InvalidHandle;
|
||||||
|
|
||||||
{
|
{
|
||||||
// Setup the scheduling lock and sleep.
|
// Setup the scheduling lock and sleep.
|
||||||
KScopedSchedulerLockAndSleep slp{kernel, thread, timeout};
|
KScopedSchedulerLockAndSleep slp(kernel, timer, thread, timeout);
|
||||||
|
|
||||||
// Check if any of the objects are already signaled.
|
// Check if any of the objects are already signaled.
|
||||||
for (auto i = 0; i < num_objects; ++i) {
|
for (auto i = 0; i < num_objects; ++i) {
|
||||||
|
@ -89,7 +90,10 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
|
||||||
thread->SetWaitObjectsForDebugging({});
|
thread->SetWaitObjectsForDebugging({});
|
||||||
|
|
||||||
// Cancel the timer as needed.
|
// Cancel the timer as needed.
|
||||||
kernel.TimeManager().UnscheduleTimeEvent(thread);
|
if (timer != InvalidHandle) {
|
||||||
|
auto& time_manager = kernel.TimeManager();
|
||||||
|
time_manager.UnscheduleTimeEvent(timer);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the wait result.
|
// Get the wait result.
|
||||||
ResultCode wait_result{RESULT_SUCCESS};
|
ResultCode wait_result{RESULT_SUCCESS};
|
||||||
|
@ -144,7 +148,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) {
|
||||||
|
|
||||||
// Iterate over each thread.
|
// Iterate over each thread.
|
||||||
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
|
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
|
||||||
KThread* thread = cur_node->thread;
|
Thread* thread = cur_node->thread;
|
||||||
if (thread->GetState() == ThreadState::Waiting) {
|
if (thread->GetState() == ThreadState::Waiting) {
|
||||||
thread->SetSyncedObject(this, result);
|
thread->SetSyncedObject(this, result);
|
||||||
thread->SetState(ThreadState::Runnable);
|
thread->SetState(ThreadState::Runnable);
|
||||||
|
@ -152,8 +156,8 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<KThread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const {
|
std::vector<Thread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const {
|
||||||
std::vector<KThread*> threads;
|
std::vector<Thread*> threads;
|
||||||
|
|
||||||
// If debugging, dump the list of waiters.
|
// If debugging, dump the list of waiters.
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,14 +13,14 @@ namespace Kernel {
|
||||||
|
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class Synchronization;
|
class Synchronization;
|
||||||
class KThread;
|
class Thread;
|
||||||
|
|
||||||
/// Class that represents a Kernel object that a thread can be waiting on
|
/// Class that represents a Kernel object that a thread can be waiting on
|
||||||
class KSynchronizationObject : public Object {
|
class KSynchronizationObject : public Object {
|
||||||
public:
|
public:
|
||||||
struct ThreadListNode {
|
struct ThreadListNode {
|
||||||
ThreadListNode* next{};
|
ThreadListNode* next{};
|
||||||
KThread* thread{};
|
Thread* thread{};
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index,
|
[[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index,
|
||||||
|
@ -29,7 +29,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] virtual bool IsSignaled() const = 0;
|
[[nodiscard]] virtual bool IsSignaled() const = 0;
|
||||||
|
|
||||||
[[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
|
[[nodiscard]] std::vector<Thread*> GetWaitingThreadsForDebugging() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit KSynchronizationObject(KernelCore& kernel);
|
explicit KSynchronizationObject(KernelCore& kernel);
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/memory/memory_layout.h"
|
#include "core/hle/kernel/memory/memory_layout.h"
|
||||||
#include "core/hle/kernel/memory/memory_manager.h"
|
#include "core/hle/kernel/memory/memory_manager.h"
|
||||||
|
@ -39,6 +38,7 @@
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/kernel/service_thread.h"
|
#include "core/hle/kernel/service_thread.h"
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
@ -62,7 +62,6 @@ struct KernelCore::Impl {
|
||||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||||
service_thread_manager =
|
service_thread_manager =
|
||||||
std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
|
std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
|
||||||
is_phantom_mode_for_singlecore = false;
|
|
||||||
|
|
||||||
InitializePhysicalCores();
|
InitializePhysicalCores();
|
||||||
InitializeSystemResourceLimit(kernel);
|
InitializeSystemResourceLimit(kernel);
|
||||||
|
@ -117,14 +116,14 @@ struct KernelCore::Impl {
|
||||||
void InitializePhysicalCores() {
|
void InitializePhysicalCores() {
|
||||||
exclusive_monitor =
|
exclusive_monitor =
|
||||||
Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
|
Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
|
||||||
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||||
schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i);
|
schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i);
|
||||||
cores.emplace_back(i, system, *schedulers[i], interrupts);
|
cores.emplace_back(i, system, *schedulers[i], interrupts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeSchedulers() {
|
void InitializeSchedulers() {
|
||||||
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||||
cores[i].Scheduler().Initialize();
|
cores[i].Scheduler().Initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,9 +168,11 @@ struct KernelCore::Impl {
|
||||||
std::string name = "Suspend Thread Id:" + std::to_string(i);
|
std::string name = "Suspend Thread Id:" + std::to_string(i);
|
||||||
std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
|
std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
|
||||||
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
|
void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
|
||||||
auto thread_res = KThread::Create(system, ThreadType::HighPriority, std::move(name), 0,
|
const auto type =
|
||||||
0, 0, static_cast<u32>(i), 0, nullptr,
|
static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND);
|
||||||
std::move(init_func), init_func_parameter);
|
auto thread_res =
|
||||||
|
Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
|
||||||
|
nullptr, std::move(init_func), init_func_parameter);
|
||||||
|
|
||||||
suspend_threads[i] = std::move(thread_res).Unwrap();
|
suspend_threads[i] = std::move(thread_res).Unwrap();
|
||||||
}
|
}
|
||||||
|
@ -228,22 +229,20 @@ struct KernelCore::Impl {
|
||||||
return this_id;
|
return this_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPhantomModeForSingleCore() const {
|
[[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() {
|
||||||
return is_phantom_mode_for_singlecore;
|
Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
|
||||||
|
result.host_handle = GetCurrentHostThreadID();
|
||||||
|
if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler();
|
||||||
void SetIsPhantomModeForSingleCore(bool value) {
|
const Kernel::Thread* current = sched.GetCurrentThread();
|
||||||
ASSERT(!is_multicore);
|
if (current != nullptr && !current->IsPhantomMode()) {
|
||||||
is_phantom_mode_for_singlecore = value;
|
result.guest_handle = current->GetGlobalHandle();
|
||||||
|
} else {
|
||||||
|
result.guest_handle = InvalidHandle;
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
[[nodiscard]] EmuThreadHandle GetCurrentEmuThreadID() {
|
|
||||||
const auto thread_id = GetCurrentHostThreadID();
|
|
||||||
if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
|
|
||||||
// Reserved value for HLE threads
|
|
||||||
return EmuThreadHandleReserved + (static_cast<u64>(thread_id) << 1);
|
|
||||||
}
|
|
||||||
return reinterpret_cast<uintptr_t>(schedulers[thread_id].get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeMemoryLayout() {
|
void InitializeMemoryLayout() {
|
||||||
|
@ -259,7 +258,7 @@ struct KernelCore::Impl {
|
||||||
constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
|
constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
|
||||||
|
|
||||||
// Initialize memory manager
|
// Initialize memory manager
|
||||||
memory_manager = std::make_unique<Memory::MemoryManager>(system.Kernel());
|
memory_manager = std::make_unique<Memory::MemoryManager>();
|
||||||
memory_manager->InitializeManager(Memory::MemoryManager::Pool::Application,
|
memory_manager->InitializeManager(Memory::MemoryManager::Pool::Application,
|
||||||
layout.Application().StartAddress(),
|
layout.Application().StartAddress(),
|
||||||
layout.Application().EndAddress());
|
layout.Application().EndAddress());
|
||||||
|
@ -343,12 +342,11 @@ struct KernelCore::Impl {
|
||||||
// the release of itself
|
// the release of itself
|
||||||
std::unique_ptr<Common::ThreadWorker> service_thread_manager;
|
std::unique_ptr<Common::ThreadWorker> service_thread_manager;
|
||||||
|
|
||||||
std::array<std::shared_ptr<KThread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
|
std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
|
||||||
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
||||||
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
||||||
|
|
||||||
bool is_multicore{};
|
bool is_multicore{};
|
||||||
bool is_phantom_mode_for_singlecore{};
|
|
||||||
u32 single_core_thread_id{};
|
u32 single_core_thread_id{};
|
||||||
|
|
||||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
|
std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
|
||||||
|
@ -382,8 +380,8 @@ std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
|
||||||
return impl->system_resource_limit;
|
return impl->system_resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
|
std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
|
||||||
return impl->global_handle_table.Get<KThread>(handle);
|
return impl->global_handle_table.Get<Thread>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
|
void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
|
||||||
|
@ -548,7 +546,7 @@ u32 KernelCore::GetCurrentHostThreadID() const {
|
||||||
return impl->GetCurrentHostThreadID();
|
return impl->GetCurrentHostThreadID();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
|
Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
|
||||||
return impl->GetCurrentEmuThreadID();
|
return impl->GetCurrentEmuThreadID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,12 +645,4 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KernelCore::IsPhantomModeForSingleCore() const {
|
|
||||||
return impl->IsPhantomModeForSingleCore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KernelCore::SetIsPhantomModeForSingleCore(bool value) {
|
|
||||||
impl->SetIsPhantomModeForSingleCore(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -43,13 +43,9 @@ class KScheduler;
|
||||||
class SharedMemory;
|
class SharedMemory;
|
||||||
class ServiceThread;
|
class ServiceThread;
|
||||||
class Synchronization;
|
class Synchronization;
|
||||||
class KThread;
|
class Thread;
|
||||||
class TimeManager;
|
class TimeManager;
|
||||||
|
|
||||||
using EmuThreadHandle = uintptr_t;
|
|
||||||
constexpr EmuThreadHandle EmuThreadHandleInvalid{};
|
|
||||||
constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
|
|
||||||
|
|
||||||
/// Represents a single instance of the kernel.
|
/// Represents a single instance of the kernel.
|
||||||
class KernelCore {
|
class KernelCore {
|
||||||
private:
|
private:
|
||||||
|
@ -88,7 +84,7 @@ public:
|
||||||
std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
|
std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
|
||||||
|
|
||||||
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
||||||
std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
std::shared_ptr<Thread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
||||||
|
|
||||||
/// Adds the given shared pointer to an internal list of active processes.
|
/// Adds the given shared pointer to an internal list of active processes.
|
||||||
void AppendNewProcess(std::shared_ptr<Process> process);
|
void AppendNewProcess(std::shared_ptr<Process> process);
|
||||||
|
@ -166,7 +162,7 @@ public:
|
||||||
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
|
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
|
||||||
|
|
||||||
/// Gets the current host_thread/guest_thread handle.
|
/// Gets the current host_thread/guest_thread handle.
|
||||||
EmuThreadHandle GetCurrentEmuThreadID() const;
|
Core::EmuThreadHandle GetCurrentEmuThreadID() const;
|
||||||
|
|
||||||
/// Gets the current host_thread handle.
|
/// Gets the current host_thread handle.
|
||||||
u32 GetCurrentHostThreadID() const;
|
u32 GetCurrentHostThreadID() const;
|
||||||
|
@ -241,14 +237,10 @@ public:
|
||||||
*/
|
*/
|
||||||
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
|
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
|
||||||
|
|
||||||
/// Workaround for single-core mode when preempting threads while idle.
|
|
||||||
bool IsPhantomModeForSingleCore() const;
|
|
||||||
void SetIsPhantomModeForSingleCore(bool value);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Object;
|
friend class Object;
|
||||||
friend class Process;
|
friend class Process;
|
||||||
friend class KThread;
|
friend class Thread;
|
||||||
|
|
||||||
/// Creates a new object ID, incrementing the internal object ID counter.
|
/// Creates a new object ID, incrementing the internal object ID counter.
|
||||||
u32 CreateNewObjectID();
|
u32 CreateNewObjectID();
|
||||||
|
|
|
@ -41,9 +41,6 @@ std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u6
|
||||||
return total_metadata_size;
|
return total_metadata_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryManager::MemoryManager(KernelCore& kernel)
|
|
||||||
: pool_lock_0{kernel}, pool_lock_1{kernel}, pool_lock_2{kernel}, pool_lock_3{kernel} {}
|
|
||||||
|
|
||||||
void MemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) {
|
void MemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) {
|
||||||
ASSERT(pool < Pool::Count);
|
ASSERT(pool < Pool::Count);
|
||||||
managers[static_cast<std::size_t>(pool)].Initialize(pool, start_address, end_address);
|
managers[static_cast<std::size_t>(pool)].Initialize(pool, start_address, end_address);
|
||||||
|
@ -58,7 +55,7 @@ VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align
|
||||||
|
|
||||||
// Lock the pool that we're allocating from
|
// Lock the pool that we're allocating from
|
||||||
const auto pool_index{static_cast<std::size_t>(pool)};
|
const auto pool_index{static_cast<std::size_t>(pool)};
|
||||||
KScopedLightLock lk{PoolLock(pool_index)};
|
std::lock_guard lock{pool_locks[pool_index]};
|
||||||
|
|
||||||
// Choose a heap based on our page size request
|
// Choose a heap based on our page size request
|
||||||
const s32 heap_index{PageHeap::GetAlignedBlockIndex(num_pages, align_pages)};
|
const s32 heap_index{PageHeap::GetAlignedBlockIndex(num_pages, align_pages)};
|
||||||
|
@ -93,7 +90,7 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa
|
||||||
|
|
||||||
// Lock the pool that we're allocating from
|
// Lock the pool that we're allocating from
|
||||||
const auto pool_index{static_cast<std::size_t>(pool)};
|
const auto pool_index{static_cast<std::size_t>(pool)};
|
||||||
KScopedLightLock lk{PoolLock(pool_index)};
|
std::lock_guard lock{pool_locks[pool_index]};
|
||||||
|
|
||||||
// Choose a heap based on our page size request
|
// Choose a heap based on our page size request
|
||||||
const s32 heap_index{PageHeap::GetBlockIndex(num_pages)};
|
const s32 heap_index{PageHeap::GetBlockIndex(num_pages)};
|
||||||
|
@ -160,7 +157,7 @@ ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages,
|
||||||
|
|
||||||
// Lock the pool that we're freeing from
|
// Lock the pool that we're freeing from
|
||||||
const auto pool_index{static_cast<std::size_t>(pool)};
|
const auto pool_index{static_cast<std::size_t>(pool)};
|
||||||
KScopedLightLock lk{PoolLock(pool_index)};
|
std::lock_guard lock{pool_locks[pool_index]};
|
||||||
|
|
||||||
// TODO (bunnei): Support multiple managers
|
// TODO (bunnei): Support multiple managers
|
||||||
Impl& chosen_manager{managers[pool_index]};
|
Impl& chosen_manager{managers[pool_index]};
|
||||||
|
|
|
@ -7,16 +7,10 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/k_light_lock.h"
|
|
||||||
#include "core/hle/kernel/memory/page_heap.h"
|
#include "core/hle/kernel/memory/page_heap.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
class KernelCore;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Kernel::Memory {
|
namespace Kernel::Memory {
|
||||||
|
|
||||||
class PageLinkedList;
|
class PageLinkedList;
|
||||||
|
@ -43,7 +37,7 @@ public:
|
||||||
Mask = (0xF << Shift),
|
Mask = (0xF << Shift),
|
||||||
};
|
};
|
||||||
|
|
||||||
MemoryManager(KernelCore& kernel);
|
MemoryManager() = default;
|
||||||
|
|
||||||
constexpr std::size_t GetSize(Pool pool) const {
|
constexpr std::size_t GetSize(Pool pool) const {
|
||||||
return managers[static_cast<std::size_t>(pool)].GetSize();
|
return managers[static_cast<std::size_t>(pool)].GetSize();
|
||||||
|
@ -95,24 +89,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KLightLock pool_lock_0;
|
std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks;
|
||||||
KLightLock pool_lock_1;
|
|
||||||
KLightLock pool_lock_2;
|
|
||||||
KLightLock pool_lock_3;
|
|
||||||
|
|
||||||
KLightLock& PoolLock(std::size_t index) {
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
return pool_lock_0;
|
|
||||||
case 1:
|
|
||||||
return pool_lock_1;
|
|
||||||
case 2:
|
|
||||||
return pool_lock_2;
|
|
||||||
}
|
|
||||||
ASSERT(index == 3);
|
|
||||||
return pool_lock_3;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<Impl, MaxManagerCount> managers;
|
std::array<Impl, MaxManagerCount> managers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ constexpr std::size_t GetSizeInRange(const MemoryInfo& info, VAddr start, VAddr
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PageTable::PageTable(Core::System& system) : general_lock{system.Kernel()}, system{system} {}
|
PageTable::PageTable(Core::System& system) : system{system} {}
|
||||||
|
|
||||||
ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
|
ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
|
||||||
bool enable_aslr, VAddr code_addr, std::size_t code_size,
|
bool enable_aslr, VAddr code_addr, std::size_t code_size,
|
||||||
|
@ -272,7 +272,7 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t
|
||||||
|
|
||||||
ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, MemoryState state,
|
ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, MemoryState state,
|
||||||
MemoryPermission perm) {
|
MemoryPermission perm) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
const u64 size{num_pages * PageSize};
|
const u64 size{num_pages * PageSize};
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, MemorySt
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
const std::size_t num_pages{size / PageSize};
|
const std::size_t num_pages{size / PageSize};
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
if (!size) {
|
if (!size) {
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
@ -394,7 +394,7 @@ void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start,
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
std::size_t mapped_size{};
|
std::size_t mapped_size{};
|
||||||
const VAddr end_addr{addr + size};
|
const VAddr end_addr{addr + size};
|
||||||
|
@ -444,7 +444,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
|
ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
const VAddr end_addr{addr + size};
|
const VAddr end_addr{addr + size};
|
||||||
ResultCode result{RESULT_SUCCESS};
|
ResultCode result{RESULT_SUCCESS};
|
||||||
|
@ -481,7 +481,7 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) {
|
ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
const VAddr end_addr{addr + size};
|
const VAddr end_addr{addr + size};
|
||||||
ResultCode result{RESULT_SUCCESS};
|
ResultCode result{RESULT_SUCCESS};
|
||||||
|
@ -517,7 +517,7 @@ ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryState src_state{};
|
MemoryState src_state{};
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
|
@ -555,7 +555,7 @@ ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryState src_state{};
|
MemoryState src_state{};
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
|
@ -620,7 +620,7 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
|
||||||
|
|
||||||
ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state,
|
ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state,
|
||||||
MemoryPermission perm) {
|
MemoryPermission perm) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
const std::size_t num_pages{page_linked_list.GetNumPages()};
|
const std::size_t num_pages{page_linked_list.GetNumPages()};
|
||||||
const std::size_t size{num_pages * PageSize};
|
const std::size_t size{num_pages * PageSize};
|
||||||
|
@ -642,7 +642,7 @@ ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, Mem
|
||||||
|
|
||||||
ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm) {
|
ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm) {
|
||||||
|
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryState prev_state{};
|
MemoryState prev_state{};
|
||||||
MemoryPermission prev_perm{};
|
MemoryPermission prev_perm{};
|
||||||
|
@ -688,7 +688,7 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryInfo PageTable::QueryInfoImpl(VAddr addr) {
|
MemoryInfo PageTable::QueryInfoImpl(VAddr addr) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
return block_manager->FindBlock(addr).GetMemoryInfo();
|
return block_manager->FindBlock(addr).GetMemoryInfo();
|
||||||
}
|
}
|
||||||
|
@ -703,7 +703,7 @@ MemoryInfo PageTable::QueryInfo(VAddr addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm) {
|
ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryState state{};
|
MemoryState state{};
|
||||||
MemoryAttribute attribute{};
|
MemoryAttribute attribute{};
|
||||||
|
@ -721,7 +721,7 @@ ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
ResultCode PageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryState state{};
|
MemoryState state{};
|
||||||
|
|
||||||
|
@ -739,7 +739,7 @@ ResultCode PageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||||
|
|
||||||
ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask,
|
ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask,
|
||||||
MemoryAttribute value) {
|
MemoryAttribute value) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryState state{};
|
MemoryState state{};
|
||||||
MemoryPermission perm{};
|
MemoryPermission perm{};
|
||||||
|
@ -760,7 +760,7 @@ ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAtt
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::SetHeapCapacity(std::size_t new_heap_capacity) {
|
ResultCode PageTable::SetHeapCapacity(std::size_t new_heap_capacity) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
heap_capacity = new_heap_capacity;
|
heap_capacity = new_heap_capacity;
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -777,7 +777,7 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) {
|
||||||
|
|
||||||
// Increase the heap size
|
// Increase the heap size
|
||||||
{
|
{
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
const u64 delta{size - previous_heap_size};
|
const u64 delta{size - previous_heap_size};
|
||||||
|
|
||||||
|
@ -813,7 +813,7 @@ ResultVal<VAddr> PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s
|
||||||
bool is_map_only, VAddr region_start,
|
bool is_map_only, VAddr region_start,
|
||||||
std::size_t region_num_pages, MemoryState state,
|
std::size_t region_num_pages, MemoryState state,
|
||||||
MemoryPermission perm, PAddr map_addr) {
|
MemoryPermission perm, PAddr map_addr) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
if (!CanContain(region_start, region_num_pages * PageSize, state)) {
|
if (!CanContain(region_start, region_num_pages * PageSize, state)) {
|
||||||
return ERR_INVALID_ADDRESS_STATE;
|
return ERR_INVALID_ADDRESS_STATE;
|
||||||
|
@ -844,7 +844,7 @@ ResultVal<VAddr> PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryPermission perm{};
|
MemoryPermission perm{};
|
||||||
if (const ResultCode result{CheckMemoryState(
|
if (const ResultCode result{CheckMemoryState(
|
||||||
|
@ -867,7 +867,7 @@ ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
MemoryPermission perm{};
|
MemoryPermission perm{};
|
||||||
if (const ResultCode result{CheckMemoryState(
|
if (const ResultCode result{CheckMemoryState(
|
||||||
|
@ -937,7 +937,7 @@ VAddr PageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages
|
||||||
|
|
||||||
ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group,
|
ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group,
|
||||||
OperationType operation) {
|
OperationType operation) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
ASSERT(Common::IsAligned(addr, PageSize));
|
ASSERT(Common::IsAligned(addr, PageSize));
|
||||||
ASSERT(num_pages > 0);
|
ASSERT(num_pages > 0);
|
||||||
|
@ -962,7 +962,7 @@ ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinke
|
||||||
|
|
||||||
ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm,
|
ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm,
|
||||||
OperationType operation, PAddr map_addr) {
|
OperationType operation, PAddr map_addr) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
ASSERT(num_pages > 0);
|
ASSERT(num_pages > 0);
|
||||||
ASSERT(Common::IsAligned(addr, PageSize));
|
ASSERT(Common::IsAligned(addr, PageSize));
|
||||||
|
@ -1123,7 +1123,7 @@ ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission*
|
||||||
MemoryPermission perm_mask, MemoryPermission perm,
|
MemoryPermission perm_mask, MemoryPermission perm,
|
||||||
MemoryAttribute attr_mask, MemoryAttribute attr,
|
MemoryAttribute attr_mask, MemoryAttribute attr,
|
||||||
MemoryAttribute ignore_attr) {
|
MemoryAttribute ignore_attr) {
|
||||||
KScopedLightLock lk{general_lock};
|
std::lock_guard lock{page_table_lock};
|
||||||
|
|
||||||
// Get information about the first block
|
// Get information about the first block
|
||||||
const VAddr last_addr{addr + size - 1};
|
const VAddr last_addr{addr + size - 1};
|
||||||
|
|
|
@ -111,7 +111,7 @@ private:
|
||||||
perm, attr_mask, attr, ignore_attr);
|
perm, attr_mask, attr, ignore_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
KLightLock general_lock;
|
std::recursive_mutex page_table_lock;
|
||||||
std::unique_ptr<MemoryBlockManager> block_manager;
|
std::unique_ptr<MemoryBlockManager> block_manager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -61,8 +61,6 @@ public:
|
||||||
*/
|
*/
|
||||||
bool IsWaitable() const;
|
bool IsWaitable() const;
|
||||||
|
|
||||||
virtual void Finalize() = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// The kernel instance this object was created under.
|
/// The kernel instance this object was created under.
|
||||||
KernelCore& kernel;
|
KernelCore& kernel;
|
||||||
|
|
|
@ -16,13 +16,13 @@
|
||||||
#include "core/hle/kernel/code_set.h"
|
#include "core/hle/kernel/code_set.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/memory/memory_block_manager.h"
|
#include "core/hle/kernel/memory/memory_block_manager.h"
|
||||||
#include "core/hle/kernel/memory/page_table.h"
|
#include "core/hle/kernel/memory/page_table.h"
|
||||||
#include "core/hle/kernel/memory/slab_heap.h"
|
#include "core/hle/kernel/memory/slab_heap.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
@ -38,10 +38,11 @@ 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,
|
ThreadType type = THREADTYPE_USER;
|
||||||
owner_process.GetIdealCoreId(), stack_top, &owner_process);
|
auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0,
|
||||||
|
owner_process.GetIdealCore(), stack_top, &owner_process);
|
||||||
|
|
||||||
std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
|
std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
|
||||||
|
|
||||||
// Register 1 must be a handle to the main thread
|
// Register 1 must be a handle to the main thread
|
||||||
const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
|
const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
|
||||||
|
@ -136,23 +137,6 @@ std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
|
||||||
return resource_limit;
|
return resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::IncrementThreadCount() {
|
|
||||||
ASSERT(num_threads >= 0);
|
|
||||||
++num_created_threads;
|
|
||||||
|
|
||||||
if (const auto count = ++num_threads; count > peak_num_threads) {
|
|
||||||
peak_num_threads = count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::DecrementThreadCount() {
|
|
||||||
ASSERT(num_threads > 0);
|
|
||||||
|
|
||||||
if (const auto count = --num_threads; count == 0) {
|
|
||||||
UNIMPLEMENTED_MSG("Process termination is not implemented!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 Process::GetTotalPhysicalMemoryAvailable() const {
|
u64 Process::GetTotalPhysicalMemoryAvailable() const {
|
||||||
const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
|
const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
|
||||||
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
|
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
|
||||||
|
@ -178,66 +162,11 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
|
||||||
return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
|
return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process::ReleaseUserException(KThread* thread) {
|
void Process::RegisterThread(const Thread* thread) {
|
||||||
KScopedSchedulerLock sl{kernel};
|
|
||||||
|
|
||||||
if (exception_thread == thread) {
|
|
||||||
exception_thread = nullptr;
|
|
||||||
|
|
||||||
// Remove waiter thread.
|
|
||||||
s32 num_waiters{};
|
|
||||||
KThread* next = thread->RemoveWaiterByKey(
|
|
||||||
std::addressof(num_waiters),
|
|
||||||
reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
|
|
||||||
if (next != nullptr) {
|
|
||||||
if (next->GetState() == ThreadState::Waiting) {
|
|
||||||
next->SetState(ThreadState::Runnable);
|
|
||||||
} else {
|
|
||||||
KScheduler::SetSchedulerUpdateNeeded(kernel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::PinCurrentThread() {
|
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
|
||||||
|
|
||||||
// Get the current thread.
|
|
||||||
const s32 core_id = GetCurrentCoreId(kernel);
|
|
||||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
|
||||||
|
|
||||||
// Pin it.
|
|
||||||
PinThread(core_id, cur_thread);
|
|
||||||
cur_thread->Pin();
|
|
||||||
|
|
||||||
// An update is needed.
|
|
||||||
KScheduler::SetSchedulerUpdateNeeded(kernel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::UnpinCurrentThread() {
|
|
||||||
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
|
|
||||||
|
|
||||||
// Get the current thread.
|
|
||||||
const s32 core_id = GetCurrentCoreId(kernel);
|
|
||||||
KThread* cur_thread = GetCurrentThreadPointer(kernel);
|
|
||||||
|
|
||||||
// Unpin it.
|
|
||||||
cur_thread->Unpin();
|
|
||||||
UnpinThread(core_id, cur_thread);
|
|
||||||
|
|
||||||
// An update is needed.
|
|
||||||
KScheduler::SetSchedulerUpdateNeeded(kernel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::RegisterThread(const KThread* thread) {
|
|
||||||
thread_list.push_back(thread);
|
thread_list.push_back(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::UnregisterThread(const KThread* thread) {
|
void Process::UnregisterThread(const Thread* thread) {
|
||||||
thread_list.remove(thread);
|
thread_list.remove(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +267,7 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
|
||||||
void Process::PrepareForTermination() {
|
void Process::PrepareForTermination() {
|
||||||
ChangeStatus(ProcessStatus::Exiting);
|
ChangeStatus(ProcessStatus::Exiting);
|
||||||
|
|
||||||
const auto stop_threads = [this](const std::vector<std::shared_ptr<KThread>>& thread_list) {
|
const auto stop_threads = [this](const std::vector<std::shared_ptr<Thread>>& thread_list) {
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
if (thread->GetOwnerProcess() != this)
|
if (thread->GetOwnerProcess() != this)
|
||||||
continue;
|
continue;
|
||||||
|
@ -350,7 +279,7 @@ void Process::PrepareForTermination() {
|
||||||
ASSERT_MSG(thread->GetState() == ThreadState::Waiting,
|
ASSERT_MSG(thread->GetState() == ThreadState::Waiting,
|
||||||
"Exiting processes with non-waiting threads is currently unimplemented");
|
"Exiting processes with non-waiting threads is currently unimplemented");
|
||||||
|
|
||||||
thread->Exit();
|
thread->Stop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace Kernel {
|
||||||
|
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class ResourceLimit;
|
class ResourceLimit;
|
||||||
class KThread;
|
class Thread;
|
||||||
class TLSPage;
|
class TLSPage;
|
||||||
|
|
||||||
struct CodeSet;
|
struct CodeSet;
|
||||||
|
@ -173,15 +173,10 @@ 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 GetIdealCoreId() const {
|
u8 GetIdealCore() 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();
|
||||||
|
@ -217,14 +212,6 @@ public:
|
||||||
return is_64bit_process;
|
return is_64bit_process;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool IsSuspended() const {
|
|
||||||
return is_suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSuspended(bool suspended) {
|
|
||||||
is_suspended = suspended;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the total running time of the process instance in ticks.
|
/// Gets the total running time of the process instance in ticks.
|
||||||
u64 GetCPUTimeTicks() const {
|
u64 GetCPUTimeTicks() const {
|
||||||
return total_process_running_time_ticks;
|
return total_process_running_time_ticks;
|
||||||
|
@ -245,33 +232,6 @@ public:
|
||||||
++schedule_count;
|
++schedule_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncrementThreadCount();
|
|
||||||
void DecrementThreadCount();
|
|
||||||
|
|
||||||
void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
|
|
||||||
running_threads[core] = thread;
|
|
||||||
running_thread_idle_counts[core] = idle_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearRunningThread(KThread* thread) {
|
|
||||||
for (size_t i = 0; i < running_threads.size(); ++i) {
|
|
||||||
if (running_threads[i] == thread) {
|
|
||||||
running_threads[i] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] KThread* GetRunningThread(s32 core) const {
|
|
||||||
return running_threads[core];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReleaseUserException(KThread* thread);
|
|
||||||
|
|
||||||
[[nodiscard]] KThread* GetPinnedThread(s32 core_id) const {
|
|
||||||
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
||||||
return pinned_threads[core_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
|
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
|
||||||
u64 GetRandomEntropy(std::size_t index) const {
|
u64 GetRandomEntropy(std::size_t index) const {
|
||||||
return random_entropy.at(index);
|
return random_entropy.at(index);
|
||||||
|
@ -292,17 +252,17 @@ public:
|
||||||
u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const;
|
u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const;
|
||||||
|
|
||||||
/// Gets the list of all threads created with this process as their owner.
|
/// Gets the list of all threads created with this process as their owner.
|
||||||
const std::list<const KThread*>& GetThreadList() const {
|
const std::list<const Thread*>& GetThreadList() const {
|
||||||
return thread_list;
|
return thread_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a thread as being created under this process,
|
/// Registers a thread as being created under this process,
|
||||||
/// adding it to this process' thread list.
|
/// adding it to this process' thread list.
|
||||||
void RegisterThread(const KThread* thread);
|
void RegisterThread(const Thread* thread);
|
||||||
|
|
||||||
/// Unregisters a thread from this process, removing it
|
/// Unregisters a thread from this process, removing it
|
||||||
/// from this process' thread list.
|
/// from this process' thread list.
|
||||||
void UnregisterThread(const KThread* thread);
|
void UnregisterThread(const Thread* thread);
|
||||||
|
|
||||||
/// Clears the signaled state of the process if and only if it's signaled.
|
/// Clears the signaled state of the process if and only if it's signaled.
|
||||||
///
|
///
|
||||||
|
@ -343,11 +303,6 @@ public:
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Finalize() override{};
|
|
||||||
|
|
||||||
void PinCurrentThread();
|
|
||||||
void UnpinCurrentThread();
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Thread-local storage management
|
// Thread-local storage management
|
||||||
|
|
||||||
|
@ -358,20 +313,6 @@ public:
|
||||||
void FreeTLSRegion(VAddr tls_address);
|
void FreeTLSRegion(VAddr tls_address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PinThread(s32 core_id, KThread* thread) {
|
|
||||||
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
||||||
ASSERT(thread != nullptr);
|
|
||||||
ASSERT(pinned_threads[core_id] == nullptr);
|
|
||||||
pinned_threads[core_id] = thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnpinThread(s32 core_id, KThread* thread) {
|
|
||||||
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
|
|
||||||
ASSERT(thread != nullptr);
|
|
||||||
ASSERT(pinned_threads[core_id] == thread);
|
|
||||||
pinned_threads[core_id] = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Changes the process status. If the status is different
|
/// Changes the process status. If the status is different
|
||||||
/// from the current process status, then this will trigger
|
/// from the current process status, then this will trigger
|
||||||
/// a process signal.
|
/// a process signal.
|
||||||
|
@ -439,7 +380,7 @@ private:
|
||||||
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
|
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
|
||||||
|
|
||||||
/// List of threads that are running with this process as their owner.
|
/// List of threads that are running with this process as their owner.
|
||||||
std::list<const KThread*> thread_list;
|
std::list<const Thread*> thread_list;
|
||||||
|
|
||||||
/// Address of the top of the main thread's stack
|
/// Address of the top of the main thread's stack
|
||||||
VAddr main_thread_stack_top{};
|
VAddr main_thread_stack_top{};
|
||||||
|
@ -460,17 +401,6 @@ private:
|
||||||
s64 schedule_count{};
|
s64 schedule_count{};
|
||||||
|
|
||||||
bool is_signaled{};
|
bool is_signaled{};
|
||||||
bool is_suspended{};
|
|
||||||
|
|
||||||
std::atomic<s32> num_created_threads{};
|
|
||||||
std::atomic<u16> num_threads{};
|
|
||||||
u16 peak_num_threads{};
|
|
||||||
|
|
||||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{};
|
|
||||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{};
|
|
||||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{};
|
|
||||||
|
|
||||||
KThread* exception_thread{};
|
|
||||||
|
|
||||||
/// System context
|
/// System context
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,6 @@ public:
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Finalize() override{};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ReadableEvent(KernelCore& kernel);
|
explicit ReadableEvent(KernelCore& kernel);
|
||||||
|
|
||||||
|
|
|
@ -85,8 +85,6 @@ public:
|
||||||
*/
|
*/
|
||||||
ResultCode SetLimitValue(ResourceType resource, s64 value);
|
ResultCode SetLimitValue(ResourceType resource, s64 value);
|
||||||
|
|
||||||
void Finalize() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
|
// TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
|
||||||
// functions
|
// functions
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/server_port.h"
|
#include "core/hle/kernel/server_port.h"
|
||||||
#include "core/hle/kernel/server_session.h"
|
#include "core/hle/kernel/server_session.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,6 @@ public:
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Finalize() override{};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// ServerSessions waiting to be accepted by the port
|
/// ServerSessions waiting to be accepted by the port
|
||||||
std::vector<std::shared_ptr<ServerSession>> pending_sessions;
|
std::vector<std::shared_ptr<ServerSession>> pending_sessions;
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/server_session.h"
|
#include "core/hle/kernel/server_session.h"
|
||||||
#include "core/hle/kernel/session.h"
|
#include "core/hle/kernel/session.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -116,7 +116,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<KThread> thread,
|
ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
|
||||||
Core::Memory::Memory& memory) {
|
Core::Memory::Memory& memory) {
|
||||||
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
|
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
|
||||||
auto context =
|
auto context =
|
||||||
|
@ -154,14 +154,14 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock lock(kernel);
|
||||||
if (!context.IsThreadWaiting()) {
|
if (!context.IsThreadWaiting()) {
|
||||||
context.GetThread().Wakeup();
|
context.GetThread().Wakeup();
|
||||||
context.GetThread().SetSyncedObject(nullptr, result);
|
context.GetThread().SetSynchronizationResults(nullptr, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<KThread> thread,
|
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
|
||||||
Core::Memory::Memory& memory,
|
Core::Memory::Memory& memory,
|
||||||
Core::Timing::CoreTiming& core_timing) {
|
Core::Timing::CoreTiming& core_timing) {
|
||||||
return QueueSyncRequest(std::move(thread), memory);
|
return QueueSyncRequest(std::move(thread), memory);
|
||||||
|
|
|
@ -29,7 +29,7 @@ class HLERequestContext;
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class Session;
|
class Session;
|
||||||
class SessionRequestHandler;
|
class SessionRequestHandler;
|
||||||
class KThread;
|
class Thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
|
* Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
|
||||||
|
@ -95,7 +95,7 @@ public:
|
||||||
*
|
*
|
||||||
* @returns ResultCode from the operation.
|
* @returns ResultCode from the operation.
|
||||||
*/
|
*/
|
||||||
ResultCode HandleSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
|
ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
|
||||||
Core::Timing::CoreTiming& core_timing);
|
Core::Timing::CoreTiming& core_timing);
|
||||||
|
|
||||||
/// Called when a client disconnection occurs.
|
/// Called when a client disconnection occurs.
|
||||||
|
@ -126,11 +126,9 @@ public:
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Finalize() override{};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Queues a sync request from the emulated application.
|
/// Queues a sync request from the emulated application.
|
||||||
ResultCode QueueSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory);
|
ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
|
||||||
|
|
||||||
/// Completes a sync request from the emulated application.
|
/// Completes a sync request from the emulated application.
|
||||||
ResultCode CompleteSyncRequest(HLERequestContext& context);
|
ResultCode CompleteSyncRequest(HLERequestContext& context);
|
||||||
|
@ -151,12 +149,12 @@ private:
|
||||||
/// List of threads that are pending a response after a sync request. This list is processed in
|
/// List of threads that are pending a response after a sync request. This list is processed in
|
||||||
/// a LIFO manner, thus, the last request will be dispatched first.
|
/// a LIFO manner, thus, the last request will be dispatched first.
|
||||||
/// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test.
|
/// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test.
|
||||||
std::vector<std::shared_ptr<KThread>> pending_requesting_threads;
|
std::vector<std::shared_ptr<Thread>> pending_requesting_threads;
|
||||||
|
|
||||||
/// Thread whose request is currently being handled. A request is considered "handled" when a
|
/// Thread whose request is currently being handled. A request is considered "handled" when a
|
||||||
/// response is sent via svcReplyAndReceive.
|
/// response is sent via svcReplyAndReceive.
|
||||||
/// TODO(Subv): Find a better name for this.
|
/// TODO(Subv): Find a better name for this.
|
||||||
std::shared_ptr<KThread> currently_handling;
|
std::shared_ptr<Thread> currently_handling;
|
||||||
|
|
||||||
/// When set to True, converts the session to a domain at the end of the command
|
/// When set to True, converts the session to a domain at the end of the command
|
||||||
bool convert_to_domain{};
|
bool convert_to_domain{};
|
||||||
|
|
|
@ -39,8 +39,6 @@ public:
|
||||||
|
|
||||||
bool IsSignaled() const override;
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Finalize() override{};
|
|
||||||
|
|
||||||
std::shared_ptr<ClientSession> Client() {
|
std::shared_ptr<ClientSession> Client() {
|
||||||
if (auto result{client.lock()}) {
|
if (auto result{client.lock()}) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -71,8 +71,6 @@ public:
|
||||||
return device_memory.GetPointer(physical_address + offset);
|
return device_memory.GetPointer(physical_address + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Core::DeviceMemory& device_memory;
|
Core::DeviceMemory& device_memory;
|
||||||
Process* owner_process{};
|
Process* owner_process{};
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/memory/memory_block.h"
|
#include "core/hle/kernel/memory/memory_block.h"
|
||||||
#include "core/hle/kernel/memory/memory_layout.h"
|
#include "core/hle/kernel/memory/memory_layout.h"
|
||||||
|
@ -43,6 +42,7 @@
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
#include "core/hle/kernel/svc_types.h"
|
#include "core/hle/kernel/svc_types.h"
|
||||||
#include "core/hle/kernel/svc_wrap.h"
|
#include "core/hle/kernel/svc_wrap.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/kernel/transfer_memory.h"
|
#include "core/hle/kernel/transfer_memory.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
|
@ -351,8 +351,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
|
||||||
session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
|
session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
|
||||||
}
|
}
|
||||||
|
|
||||||
KSynchronizationObject* dummy{};
|
return thread->GetSignalingResult();
|
||||||
return thread->GetWaitResult(std::addressof(dummy));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
||||||
|
@ -360,26 +359,27 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the ID for the specified thread.
|
/// Get the ID for the specified thread.
|
||||||
static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
|
static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
||||||
|
|
||||||
// Get the thread from its handle.
|
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
if (!thread) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the thread's id.
|
*thread_id = thread->GetThreadID();
|
||||||
*out_thread_id = thread->GetThreadID();
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low,
|
static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high,
|
||||||
u32* out_thread_id_high, Handle thread_handle) {
|
Handle thread_handle) {
|
||||||
u64 out_thread_id{};
|
u64 thread_id{};
|
||||||
const ResultCode result{GetThreadId(system, &out_thread_id, thread_handle)};
|
const ResultCode result{GetThreadId(system, &thread_id, thread_handle)};
|
||||||
|
|
||||||
*out_thread_id_low = static_cast<u32>(out_thread_id >> 32);
|
*thread_id_low = static_cast<u32>(thread_id >> 32);
|
||||||
*out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max());
|
*thread_id_high = static_cast<u32>(thread_id & std::numeric_limits<u32>::max());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
|
const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle);
|
||||||
if (thread) {
|
if (thread) {
|
||||||
const Process* const owner_process = thread->GetOwnerProcess();
|
const Process* const owner_process = thread->GetOwnerProcess();
|
||||||
if (!owner_process) {
|
if (!owner_process) {
|
||||||
|
@ -473,13 +473,15 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u
|
||||||
static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) {
|
static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
|
||||||
|
|
||||||
// Get the thread from its handle.
|
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||||
std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
if (!thread) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||||
|
thread_handle);
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Cancel the thread's wait.
|
thread->CancelWait();
|
||||||
thread->WaitCancel();
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,7 +630,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
||||||
handle_debug_buffer(info1, info2);
|
handle_debug_buffer(info1, info2);
|
||||||
|
|
||||||
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
||||||
const auto thread_processor_id = current_thread->GetActiveCore();
|
const auto thread_processor_id = current_thread->GetProcessorID();
|
||||||
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
|
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -870,7 +872,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
|
||||||
return ERR_INVALID_COMBINATION;
|
return ERR_INVALID_COMBINATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>(
|
const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<Thread>(
|
||||||
static_cast<Handle>(handle));
|
static_cast<Handle>(handle));
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
|
||||||
|
@ -886,7 +888,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
|
||||||
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
|
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
|
||||||
u64 out_ticks = 0;
|
u64 out_ticks = 0;
|
||||||
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
||||||
const u64 thread_ticks = current_thread->GetCpuTime();
|
const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
|
||||||
|
|
||||||
out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
|
out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
|
||||||
} else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
|
} else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
|
||||||
|
@ -1023,109 +1025,129 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
|
||||||
return UnmapPhysicalMemory(system, addr, size);
|
return UnmapPhysicalMemory(system, addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
|
|
||||||
switch (thread_activity) {
|
|
||||||
case Svc::ThreadActivity::Runnable:
|
|
||||||
case Svc::ThreadActivity::Paused:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the thread activity
|
/// Sets the thread activity
|
||||||
static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
|
static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) {
|
||||||
Svc::ThreadActivity thread_activity) {
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity);
|
||||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
|
if (activity > static_cast<u32>(ThreadActivity::Paused)) {
|
||||||
thread_activity);
|
return ERR_INVALID_ENUM_VALUE;
|
||||||
|
|
||||||
// Validate the activity.
|
|
||||||
R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue);
|
|
||||||
|
|
||||||
// Get the thread from its handle.
|
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
|
||||||
|
|
||||||
// Check that the activity is being set on a non-current thread for the current process.
|
|
||||||
R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle);
|
|
||||||
R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy);
|
|
||||||
|
|
||||||
// Set the activity.
|
|
||||||
R_TRY(thread->SetActivity(thread_activity));
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode SetThreadActivity32(Core::System& system, Handle thread_handle,
|
const auto* current_process = system.Kernel().CurrentProcess();
|
||||||
Svc::ThreadActivity thread_activity) {
|
const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
|
||||||
return SetThreadActivity(system, thread_handle, thread_activity);
|
if (!thread) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread->GetOwnerProcess() != current_process) {
|
||||||
|
LOG_ERROR(Kernel_SVC,
|
||||||
|
"The current process does not own the current thread, thread_handle={:08X} "
|
||||||
|
"thread_pid={}, "
|
||||||
|
"current_process_pid={}",
|
||||||
|
handle, thread->GetOwnerProcess()->GetProcessID(),
|
||||||
|
current_process->GetProcessID());
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
|
||||||
|
return ERR_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return thread->SetActivity(static_cast<ThreadActivity>(activity));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) {
|
||||||
|
return SetThreadActivity(system, handle, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the thread context
|
/// Gets the thread context
|
||||||
static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) {
|
static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
|
LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
|
||||||
thread_handle);
|
|
||||||
|
|
||||||
// Get the thread from its handle.
|
|
||||||
const auto* current_process = system.Kernel().CurrentProcess();
|
const auto* current_process = system.Kernel().CurrentProcess();
|
||||||
const std::shared_ptr<KThread> thread =
|
const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
|
||||||
current_process->GetHandleTable().Get<KThread>(thread_handle);
|
if (!thread) {
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Require the handle be to a non-current thread in the current process.
|
if (thread->GetOwnerProcess() != current_process) {
|
||||||
R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle);
|
LOG_ERROR(Kernel_SVC,
|
||||||
R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(),
|
"The current process does not own the current thread, thread_handle={:08X} "
|
||||||
Svc::ResultBusy);
|
"thread_pid={}, "
|
||||||
|
"current_process_pid={}",
|
||||||
|
handle, thread->GetOwnerProcess()->GetProcessID(),
|
||||||
|
current_process->GetProcessID());
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the thread context.
|
if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
|
||||||
std::vector<u8> context;
|
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
|
||||||
R_TRY(thread->GetThreadContext3(context));
|
return ERR_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the thread context to user space.
|
Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64();
|
||||||
system.Memory().WriteBlock(out_context, context.data(), context.size());
|
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||||
|
ctx.pstate &= 0xFF0FFE20;
|
||||||
|
|
||||||
|
// If 64-bit, we can just write the context registers directly and we're good.
|
||||||
|
// However, if 32-bit, we have to ensure some registers are zeroed out.
|
||||||
|
if (!current_process->Is64BitProcess()) {
|
||||||
|
std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0);
|
||||||
|
std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
|
||||||
|
}
|
||||||
|
|
||||||
|
system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) {
|
static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) {
|
||||||
return GetThreadContext(system, out_context, thread_handle);
|
return GetThreadContext(system, thread_context, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the priority for the specified thread
|
/// Gets the priority for the specified thread
|
||||||
static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) {
|
static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called");
|
LOG_TRACE(Kernel_SVC, "called");
|
||||||
|
|
||||||
// Get the thread from its handle.
|
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
|
const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle);
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
if (!thread) {
|
||||||
|
*priority = 0;
|
||||||
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the thread's priority.
|
*priority = thread->GetPriority();
|
||||||
*out_priority = thread->GetPriority();
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) {
|
static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) {
|
||||||
return GetThreadPriority(system, out_priority, handle);
|
return GetThreadPriority(system, priority, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the priority for the specified thread
|
/// Sets the priority for the specified thread
|
||||||
static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) {
|
static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) {
|
||||||
LOG_TRACE(Kernel_SVC, "called");
|
LOG_TRACE(Kernel_SVC, "called");
|
||||||
|
|
||||||
// Validate the priority.
|
if (priority > THREADPRIO_LOWEST) {
|
||||||
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
|
LOG_ERROR(
|
||||||
Svc::ResultInvalidPriority);
|
Kernel_SVC,
|
||||||
|
"An invalid priority was specified, expected {} but got {} for thread_handle={:08X}",
|
||||||
|
THREADPRIO_LOWEST, priority, handle);
|
||||||
|
return ERR_INVALID_THREAD_PRIORITY;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the thread from its handle.
|
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
|
std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
if (!thread) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the thread priority.
|
|
||||||
thread->SetBasePriority(priority);
|
thread->SetBasePriority(priority);
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1416,47 +1438,62 @@ static void ExitProcess(Core::System& system) {
|
||||||
current_process->PrepareForTermination();
|
current_process->PrepareForTermination();
|
||||||
|
|
||||||
// Kill the current thread
|
// Kill the current thread
|
||||||
system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit();
|
system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExitProcess32(Core::System& system) {
|
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_bottom, u32 priority, s32 core_id) {
|
VAddr stack_top, u32 priority, s32 processor_id) {
|
||||||
LOG_DEBUG(Kernel_SVC,
|
LOG_DEBUG(Kernel_SVC,
|
||||||
"called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, "
|
"called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
|
||||||
"priority=0x{:08X}, core_id=0x{:08X}",
|
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
|
||||||
entry_point, arg, stack_bottom, priority, core_id);
|
entry_point, arg, stack_top, priority, processor_id, *out_handle);
|
||||||
|
|
||||||
// Adjust core id, if it's the default magic.
|
auto* const current_process = system.Kernel().CurrentProcess();
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
auto& process = *kernel.CurrentProcess();
|
if (processor_id == THREADPROCESSORID_IDEAL) {
|
||||||
if (core_id == Svc::IdealCoreUseProcessValue) {
|
// Set the target CPU to the one specified by the process.
|
||||||
core_id = process.GetIdealCoreId();
|
processor_id = current_process->GetIdealCore();
|
||||||
|
ASSERT(processor_id != THREADPROCESSORID_IDEAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate arguments.
|
if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) {
|
||||||
R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId);
|
LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
|
||||||
R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId);
|
return ERR_INVALID_PROCESSOR_ID;
|
||||||
|
}
|
||||||
|
|
||||||
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
|
const u64 core_mask = current_process->GetCoreMask();
|
||||||
Svc::ResultInvalidPriority);
|
if ((core_mask | (1ULL << processor_id)) != core_mask) {
|
||||||
R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
|
LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id);
|
||||||
|
return ERR_INVALID_PROCESSOR_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priority > THREADPRIO_LOWEST) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
|
|
||||||
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
|
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
|
||||||
|
|
||||||
CASCADE_RESULT(std::shared_ptr<KThread> thread,
|
ThreadType type = THREADTYPE_USER;
|
||||||
KThread::Create(system, ThreadType::User, "", entry_point, priority, arg,
|
CASCADE_RESULT(std::shared_ptr<Thread> thread,
|
||||||
core_id, stack_bottom, &process));
|
Thread::Create(system, type, "", entry_point, priority, arg, processor_id,
|
||||||
|
stack_top, current_process));
|
||||||
|
|
||||||
const auto new_thread_handle = process.GetHandleTable().Create(thread);
|
const auto new_thread_handle = current_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);
|
||||||
|
@ -1480,15 +1517,17 @@ static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 p
|
||||||
static ResultCode StartThread(Core::System& system, Handle thread_handle) {
|
static ResultCode StartThread(Core::System& system, Handle thread_handle) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
||||||
|
|
||||||
// Get the thread from its handle.
|
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
if (!thread) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||||
|
thread_handle);
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Try to start the thread.
|
ASSERT(thread->GetState() == ThreadState::Initialized);
|
||||||
R_TRY(thread->Run());
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return thread->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode StartThread32(Core::System& system, Handle thread_handle) {
|
static ResultCode StartThread32(Core::System& system, Handle thread_handle) {
|
||||||
|
@ -1501,7 +1540,7 @@ static void ExitThread(Core::System& system) {
|
||||||
|
|
||||||
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
||||||
system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread));
|
system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread));
|
||||||
current_thread->Exit();
|
current_thread->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExitThread32(Core::System& system) {
|
static void ExitThread32(Core::System& system) {
|
||||||
|
@ -1510,31 +1549,35 @@ static void ExitThread32(Core::System& system) {
|
||||||
|
|
||||||
/// Sleep the current thread
|
/// Sleep the current thread
|
||||||
static void SleepThread(Core::System& system, s64 nanoseconds) {
|
static void SleepThread(Core::System& system, s64 nanoseconds) {
|
||||||
auto& kernel = system.Kernel();
|
|
||||||
const auto yield_type = static_cast<Svc::YieldType>(nanoseconds);
|
|
||||||
|
|
||||||
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
|
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
|
||||||
|
|
||||||
// When the input tick is positive, sleep.
|
enum class SleepType : s64 {
|
||||||
if (nanoseconds > 0) {
|
YieldWithoutCoreMigration = 0,
|
||||||
// Convert the timeout from nanoseconds to ticks.
|
YieldWithCoreMigration = -1,
|
||||||
// NOTE: Nintendo does not use this conversion logic in WaitSynchronization...
|
YieldAndWaitForLoadBalancing = -2,
|
||||||
s64 timeout{};
|
};
|
||||||
|
|
||||||
// Sleep.
|
|
||||||
// NOTE: Nintendo does not check the result of this sleep.
|
|
||||||
auto& scheduler = *system.Kernel().CurrentScheduler();
|
auto& scheduler = *system.Kernel().CurrentScheduler();
|
||||||
static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds));
|
if (nanoseconds <= 0) {
|
||||||
} else if (yield_type == Svc::YieldType::WithoutCoreMigration) {
|
switch (static_cast<SleepType>(nanoseconds)) {
|
||||||
KScheduler::YieldWithoutCoreMigration(kernel);
|
case SleepType::YieldWithoutCoreMigration: {
|
||||||
} else if (yield_type == Svc::YieldType::WithCoreMigration) {
|
scheduler.YieldWithoutCoreMigration();
|
||||||
KScheduler::YieldWithCoreMigration(kernel);
|
break;
|
||||||
} else if (yield_type == Svc::YieldType::ToAnyThread) {
|
}
|
||||||
KScheduler::YieldToAnyThread(kernel);
|
case SleepType::YieldWithCoreMigration: {
|
||||||
} else {
|
scheduler.YieldWithCoreMigration();
|
||||||
// Nintendo does nothing at all if an otherwise invalid value is passed.
|
break;
|
||||||
|
}
|
||||||
|
case SleepType::YieldAndWaitForLoadBalancing: {
|
||||||
|
scheduler.YieldToAnyThread();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
scheduler.GetCurrentThread()->Sleep(nanoseconds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) {
|
static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) {
|
||||||
|
@ -1796,72 +1839,95 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u
|
||||||
return CreateTransferMemory(system, handle, addr, size, permissions);
|
return CreateTransferMemory(system, handle, addr, size, permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
|
static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core,
|
||||||
u64* out_affinity_mask) {
|
u64* mask) {
|
||||||
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
||||||
|
|
||||||
// Get the thread from its handle.
|
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
if (!thread) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||||
|
thread_handle);
|
||||||
|
*core = 0;
|
||||||
|
*mask = 0;
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the core mask.
|
*core = thread->GetIdealCore();
|
||||||
R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
|
*mask = thread->GetAffinityMask().GetAffinityMask();
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id,
|
static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core,
|
||||||
u32* out_affinity_mask_low, u32* out_affinity_mask_high) {
|
u32* mask_low, u32* mask_high) {
|
||||||
u64 out_affinity_mask{};
|
u64 mask{};
|
||||||
const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask);
|
const auto result = GetThreadCoreMask(system, thread_handle, core, &mask);
|
||||||
*out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32);
|
*mask_high = static_cast<u32>(mask >> 32);
|
||||||
*out_affinity_mask_low = static_cast<u32>(out_affinity_mask);
|
*mask_low = static_cast<u32>(mask);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
|
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core,
|
||||||
u64 affinity_mask) {
|
u64 affinity_mask) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}",
|
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}",
|
||||||
thread_handle, core_id, affinity_mask);
|
thread_handle, core, affinity_mask);
|
||||||
|
|
||||||
const auto& current_process = *system.Kernel().CurrentProcess();
|
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||||
|
|
||||||
// Determine the core id/affinity mask.
|
if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) {
|
||||||
if (core_id == Svc::IdealCoreUseProcessValue) {
|
const u8 ideal_cpu_core = current_process->GetIdealCore();
|
||||||
core_id = current_process.GetIdealCoreId();
|
|
||||||
affinity_mask = (1ULL << core_id);
|
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 {
|
} else {
|
||||||
// Validate the affinity mask.
|
const u64 core_mask = current_process->GetCoreMask();
|
||||||
const u64 process_core_mask = current_process.GetCoreMask();
|
|
||||||
R_UNLESS((affinity_mask | process_core_mask) == process_core_mask,
|
|
||||||
Svc::ResultInvalidCoreId);
|
|
||||||
R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination);
|
|
||||||
|
|
||||||
// Validate the core id.
|
if ((core_mask | affinity_mask) != core_mask) {
|
||||||
if (IsValidCoreId(core_id)) {
|
LOG_ERROR(
|
||||||
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination);
|
Kernel_SVC,
|
||||||
} else {
|
"Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})",
|
||||||
R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare,
|
core_mask, affinity_mask);
|
||||||
Svc::ResultInvalidCoreId);
|
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::Hardware::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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the thread from its handle.
|
const auto& handle_table = current_process->GetHandleTable();
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
|
||||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
if (!thread) {
|
||||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||||
|
thread_handle);
|
||||||
// Set the core mask.
|
return ERR_INVALID_HANDLE;
|
||||||
R_TRY(thread->SetCoreMask(core_id, affinity_mask));
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id,
|
return thread->SetCoreAndAffinityMask(core, affinity_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core,
|
||||||
u32 affinity_mask_low, u32 affinity_mask_high) {
|
u32 affinity_mask_low, u32 affinity_mask_high) {
|
||||||
const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32);
|
const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32);
|
||||||
return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask);
|
return SetThreadCoreMask(system, thread_handle, core, affinity_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
|
static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
|
||||||
|
@ -2425,7 +2491,7 @@ void Call(Core::System& system, u32 immediate) {
|
||||||
kernel.EnterSVCProfile();
|
kernel.EnterSVCProfile();
|
||||||
|
|
||||||
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
|
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||||
thread->SetIsCallingSvc();
|
thread->SetContinuousOnSVC(true);
|
||||||
|
|
||||||
const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
|
const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
|
||||||
: GetSVCInfo32(immediate);
|
: GetSVCInfo32(immediate);
|
||||||
|
@ -2441,7 +2507,7 @@ void Call(Core::System& system, u32 immediate) {
|
||||||
|
|
||||||
kernel.ExitSVCProfile();
|
kernel.ExitSVCProfile();
|
||||||
|
|
||||||
if (!thread->IsCallingSvc()) {
|
if (!thread->IsContinuousOnSVC()) {
|
||||||
auto* host_context = thread->GetHostContext().get();
|
auto* host_context = thread->GetHostContext().get();
|
||||||
host_context->Rewind();
|
host_context->Rewind();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,13 @@
|
||||||
|
|
||||||
namespace Kernel::Svc {
|
namespace Kernel::Svc {
|
||||||
|
|
||||||
constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
|
|
||||||
constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
|
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 ResultInvalidCoreId{ErrorModule::Kernel, 113};
|
|
||||||
constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
|
constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
|
||||||
constexpr ResultCode ResultInvalidCombination{ErrorModule::Kernel, 116};
|
|
||||||
constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
|
constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
|
||||||
constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
|
constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
|
||||||
constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120};
|
constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120};
|
||||||
constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};
|
|
||||||
constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};
|
constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};
|
||||||
|
|
||||||
} // namespace Kernel::Svc
|
} // namespace Kernel::Svc
|
||||||
|
|
|
@ -77,22 +77,4 @@ enum class ArbitrationType : u32 {
|
||||||
WaitIfEqual = 2,
|
WaitIfEqual = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class YieldType : s64 {
|
|
||||||
WithoutCoreMigration = 0,
|
|
||||||
WithCoreMigration = -1,
|
|
||||||
ToAnyThread = -2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ThreadActivity : u32 {
|
|
||||||
Runnable = 0,
|
|
||||||
Paused = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr inline s32 IdealCoreDontCare = -1;
|
|
||||||
constexpr inline s32 IdealCoreUseProcessValue = -2;
|
|
||||||
constexpr inline s32 IdealCoreNoUpdate = -3;
|
|
||||||
|
|
||||||
constexpr inline s32 LowestThreadPriority = 63;
|
|
||||||
constexpr inline s32 HighestThreadPriority = 0;
|
|
||||||
|
|
||||||
} // namespace Kernel::Svc
|
} // namespace Kernel::Svc
|
||||||
|
|
|
@ -58,14 +58,6 @@ void SvcWrap64(Core::System& system) {
|
||||||
func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
|
func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by SetThreadActivity
|
|
||||||
template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)>
|
|
||||||
void SvcWrap64(Core::System& system) {
|
|
||||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
|
|
||||||
static_cast<Svc::ThreadActivity>(Param(system, 1)))
|
|
||||||
.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <ResultCode func(Core::System&, u32, u64, u64, u64)>
|
template <ResultCode func(Core::System&, u32, u64, u64, u64)>
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
|
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
|
||||||
|
@ -166,18 +158,9 @@ void SvcWrap64(Core::System& system) {
|
||||||
.raw);
|
.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by SetThreadCoreMask
|
template <ResultCode func(Core::System&, u32, u32*, u64*)>
|
||||||
template <ResultCode func(Core::System&, Handle, s32, u64)>
|
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
|
u32 param_1 = 0;
|
||||||
static_cast<s32>(Param(system, 1)), Param(system, 2))
|
|
||||||
.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by GetThreadCoreMask
|
|
||||||
template <ResultCode func(Core::System&, Handle, s32*, u64*)>
|
|
||||||
void SvcWrap64(Core::System& system) {
|
|
||||||
s32 param_1 = 0;
|
|
||||||
u64 param_2 = 0;
|
u64 param_2 = 0;
|
||||||
const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), ¶m_1, ¶m_2);
|
const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), ¶m_1, ¶m_2);
|
||||||
|
|
||||||
|
@ -490,35 +473,12 @@ void SvcWrap32(Core::System& system) {
|
||||||
FuncReturn(system, retval);
|
FuncReturn(system, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by GetThreadCoreMask32
|
|
||||||
template <ResultCode func(Core::System&, Handle, s32*, u32*, u32*)>
|
|
||||||
void SvcWrap32(Core::System& system) {
|
|
||||||
s32 param_1 = 0;
|
|
||||||
u32 param_2 = 0;
|
|
||||||
u32 param_3 = 0;
|
|
||||||
|
|
||||||
const u32 retval = func(system, Param32(system, 2), ¶m_1, ¶m_2, ¶m_3).raw;
|
|
||||||
system.CurrentArmInterface().SetReg(1, param_1);
|
|
||||||
system.CurrentArmInterface().SetReg(2, param_2);
|
|
||||||
system.CurrentArmInterface().SetReg(3, param_3);
|
|
||||||
FuncReturn(system, retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by SignalProcessWideKey32
|
// Used by SignalProcessWideKey32
|
||||||
template <void func(Core::System&, u32, s32)>
|
template <void func(Core::System&, u32, s32)>
|
||||||
void SvcWrap32(Core::System& system) {
|
void SvcWrap32(Core::System& system) {
|
||||||
func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1)));
|
func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by SetThreadActivity32
|
|
||||||
template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)>
|
|
||||||
void SvcWrap32(Core::System& system) {
|
|
||||||
const u32 retval = func(system, static_cast<Handle>(Param(system, 0)),
|
|
||||||
static_cast<Svc::ThreadActivity>(Param(system, 1)))
|
|
||||||
.raw;
|
|
||||||
FuncReturn(system, retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by SetThreadPriority32
|
// Used by SetThreadPriority32
|
||||||
template <ResultCode func(Core::System&, Handle, u32)>
|
template <ResultCode func(Core::System&, Handle, u32)>
|
||||||
void SvcWrap32(Core::System& system) {
|
void SvcWrap32(Core::System& system) {
|
||||||
|
@ -527,7 +487,7 @@ void SvcWrap32(Core::System& system) {
|
||||||
FuncReturn(system, retval);
|
FuncReturn(system, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by SetMemoryAttribute32
|
// Used by SetThreadCoreMask32
|
||||||
template <ResultCode func(Core::System&, Handle, u32, u32, u32)>
|
template <ResultCode func(Core::System&, Handle, u32, u32, u32)>
|
||||||
void SvcWrap32(Core::System& system) {
|
void SvcWrap32(Core::System& system) {
|
||||||
const u32 retval =
|
const u32 retval =
|
||||||
|
@ -537,16 +497,6 @@ void SvcWrap32(Core::System& system) {
|
||||||
FuncReturn(system, retval);
|
FuncReturn(system, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by SetThreadCoreMask32
|
|
||||||
template <ResultCode func(Core::System&, Handle, s32, u32, u32)>
|
|
||||||
void SvcWrap32(Core::System& system) {
|
|
||||||
const u32 retval =
|
|
||||||
func(system, static_cast<Handle>(Param(system, 0)), static_cast<s32>(Param(system, 1)),
|
|
||||||
static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
|
|
||||||
.raw;
|
|
||||||
FuncReturn(system, retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by WaitProcessWideKeyAtomic32
|
// Used by WaitProcessWideKeyAtomic32
|
||||||
template <ResultCode func(Core::System&, u32, u32, Handle, u32, u32)>
|
template <ResultCode func(Core::System&, u32, u32, Handle, u32, u32)>
|
||||||
void SvcWrap32(Core::System& system) {
|
void SvcWrap32(Core::System& system) {
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -18,30 +18,50 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
|
||||||
time_manager_event_type = Core::Timing::CreateEvent(
|
time_manager_event_type = Core::Timing::CreateEvent(
|
||||||
"Kernel::TimeManagerCallback",
|
"Kernel::TimeManagerCallback",
|
||||||
[this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
|
[this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
|
||||||
std::shared_ptr<KThread> thread;
|
std::shared_ptr<Thread> thread;
|
||||||
{
|
{
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
thread = SharedFrom<KThread>(reinterpret_cast<KThread*>(thread_handle));
|
const auto proper_handle = static_cast<Handle>(thread_handle);
|
||||||
|
if (cancelled_events[proper_handle]) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
thread = system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread) {
|
||||||
|
// Thread can be null if process has exited
|
||||||
thread->Wakeup();
|
thread->Wakeup();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
|
void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) {
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
|
event_handle = timetask->GetGlobalHandle();
|
||||||
if (nanoseconds > 0) {
|
if (nanoseconds > 0) {
|
||||||
ASSERT(thread);
|
ASSERT(timetask);
|
||||||
ASSERT(thread->GetState() != ThreadState::Runnable);
|
ASSERT(timetask->GetState() != ThreadState::Runnable);
|
||||||
system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds},
|
system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds},
|
||||||
time_manager_event_type,
|
time_manager_event_type, event_handle);
|
||||||
reinterpret_cast<uintptr_t>(thread));
|
} else {
|
||||||
|
event_handle = InvalidHandle;
|
||||||
}
|
}
|
||||||
|
cancelled_events[event_handle] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeManager::UnscheduleTimeEvent(KThread* thread) {
|
void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
|
||||||
std::lock_guard lock{mutex};
|
std::lock_guard lock{mutex};
|
||||||
system.CoreTiming().UnscheduleEvent(time_manager_event_type,
|
if (event_handle == InvalidHandle) {
|
||||||
reinterpret_cast<uintptr_t>(thread));
|
return;
|
||||||
|
}
|
||||||
|
system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
|
||||||
|
cancelled_events[event_handle] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeManager::CancelTimeEvent(Thread* time_task) {
|
||||||
|
std::lock_guard lock{mutex};
|
||||||
|
const Handle event_handle = time_task->GetGlobalHandle();
|
||||||
|
UnscheduleTimeEvent(event_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct EventType;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class KThread;
|
class Thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp
|
* The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp
|
||||||
|
@ -31,14 +31,18 @@ public:
|
||||||
explicit TimeManager(Core::System& system);
|
explicit TimeManager(Core::System& system);
|
||||||
|
|
||||||
/// Schedule a time event on `timetask` thread that will expire in 'nanoseconds'
|
/// Schedule a time event on `timetask` thread that will expire in 'nanoseconds'
|
||||||
void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds);
|
/// returns a non-invalid handle in `event_handle` if correctly scheduled
|
||||||
|
void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds);
|
||||||
|
|
||||||
/// Unschedule an existing time event
|
/// Unschedule an existing time event
|
||||||
void UnscheduleTimeEvent(KThread* thread);
|
void UnscheduleTimeEvent(Handle event_handle);
|
||||||
|
|
||||||
|
void CancelTimeEvent(Thread* time_task);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
|
std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
|
||||||
|
std::unordered_map<Handle, bool> cancelled_events;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,6 @@ public:
|
||||||
/// is closed.
|
/// is closed.
|
||||||
ResultCode Reset();
|
ResultCode Reset();
|
||||||
|
|
||||||
void Finalize() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The base address for the memory managed by this instance.
|
/// The base address for the memory managed by this instance.
|
||||||
VAddr base_address{};
|
VAddr base_address{};
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -38,4 +38,8 @@ void WritableEvent::Clear() {
|
||||||
readable->Clear();
|
readable->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WritableEvent::IsSignaled() const {
|
||||||
|
return readable->IsSignaled();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -46,8 +46,7 @@ public:
|
||||||
|
|
||||||
void Signal();
|
void Signal();
|
||||||
void Clear();
|
void Clear();
|
||||||
|
bool IsSignaled() const;
|
||||||
void Finalize() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit WritableEvent(KernelCore& kernel);
|
explicit WritableEvent(KernelCore& kernel);
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
#include "core/hle/service/nfp/nfp.h"
|
#include "core/hle/service/nfp/nfp.h"
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/hle/service/nvdrv/interface.h"
|
#include "core/hle/service/nvdrv/interface.h"
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
|
|
|
@ -11,10 +11,10 @@
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/server_port.h"
|
#include "core/hle/kernel/server_port.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/service/acc/acc.h"
|
#include "core/hle/service/acc/acc.h"
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/aoc/aoc_u.h"
|
#include "core/hle/service/aoc/aoc_u.h"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/service/sockets/bsd.h"
|
#include "core/hle/service/sockets/bsd.h"
|
||||||
#include "core/hle/service/sockets/sockets_translate.h"
|
#include "core/hle/service/sockets/sockets_translate.h"
|
||||||
#include "core/network/network.h"
|
#include "core/network/network.h"
|
||||||
|
|
|
@ -121,7 +121,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
|
ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
|
||||||
Kernel::KThread* thread, Clock::SystemClockContext user_context,
|
Kernel::Thread* thread, Clock::SystemClockContext user_context,
|
||||||
Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
|
Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
|
||||||
|
|
||||||
auto& time_manager{system.GetTimeManager()};
|
auto& time_manager{system.GetTimeManager()};
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResultCode GetClockSnapshotFromSystemClockContextInternal(
|
ResultCode GetClockSnapshotFromSystemClockContextInternal(
|
||||||
Kernel::KThread* thread, Clock::SystemClockContext user_context,
|
Kernel::Thread* thread, Clock::SystemClockContext user_context,
|
||||||
Clock::SystemClockContext network_context, u8 type,
|
Clock::SystemClockContext network_context, u8 type,
|
||||||
Clock::ClockSnapshot& cloc_snapshot);
|
Clock::ClockSnapshot& cloc_snapshot);
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/uuid.h"
|
#include "common/uuid.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/service/time/clock_types.h"
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
|
||||||
namespace Service::Time {
|
namespace Service::Time {
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
#include "core/file_sys/romfs_factory.h"
|
#include "core/file_sys/romfs_factory.h"
|
||||||
#include "core/file_sys/vfs_offset.h"
|
#include "core/file_sys/vfs_offset.h"
|
||||||
#include "core/hle/kernel/code_set.h"
|
#include "core/hle/kernel/code_set.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/memory/page_table.h"
|
#include "core/hle/kernel/memory/page_table.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/loader/nro.h"
|
#include "core/loader/nro.h"
|
||||||
#include "core/loader/nso.h"
|
#include "core/loader/nso.h"
|
||||||
|
@ -219,8 +219,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::Sy
|
||||||
}
|
}
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority,
|
return {ResultStatus::Success,
|
||||||
Core::Memory::DEFAULT_STACK_SIZE}};
|
LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
|
ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/hle/kernel/code_set.h"
|
#include "core/hle/kernel/code_set.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#include "core/hle/kernel/memory/page_table.h"
|
#include "core/hle/kernel/memory/page_table.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/loader/nso.h"
|
#include "core/loader/nso.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
@ -179,8 +179,8 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::Sy
|
||||||
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
|
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority,
|
return {ResultStatus::Success,
|
||||||
Core::Memory::DEFAULT_STACK_SIZE}};
|
LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) {
|
ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) {
|
||||||
|
|
|
@ -1334,7 +1334,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto comment = std::get_if<CommentNode>(&*node)) {
|
if (const auto comment = std::get_if<CommentNode>(&*node)) {
|
||||||
Name(OpUndef(t_void), comment->GetText());
|
if (device.HasDebuggingToolAttached()) {
|
||||||
|
// We should insert comments with OpString instead of using named variables
|
||||||
|
Name(OpUndef(t_int), comment->GetText());
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,10 @@
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/k_scheduler.h"
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
|
||||||
#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/hle/kernel/thread.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -91,10 +90,12 @@ std::size_t WaitTreeItem::Row() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() {
|
std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() {
|
||||||
std::vector<std::unique_ptr<WaitTreeThread>> item_list;
|
std::vector<std::unique_ptr<WaitTreeThread>> item_list;
|
||||||
std::size_t row = 0;
|
std::size_t row = 0;
|
||||||
auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) {
|
auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::Thread>>& threads) {
|
||||||
for (std::size_t i = 0; i < threads.size(); ++i) {
|
for (std::size_t i = 0; i < threads.size(); ++i) {
|
||||||
|
if (!threads[i]->IsHLEThread()) {
|
||||||
item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
|
item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
|
||||||
item_list.back()->row = row;
|
item_list.back()->row = row;
|
||||||
|
}
|
||||||
++row;
|
++row;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -116,7 +117,7 @@ WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTa
|
||||||
: mutex_address(mutex_address) {
|
: mutex_address(mutex_address) {
|
||||||
mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
|
mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
|
||||||
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
|
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
|
||||||
owner = handle_table.Get<Kernel::KThread>(owner_handle);
|
owner = handle_table.Get<Kernel::Thread>(owner_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeMutexInfo::~WaitTreeMutexInfo() = default;
|
WaitTreeMutexInfo::~WaitTreeMutexInfo() = default;
|
||||||
|
@ -138,7 +139,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() cons
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread) : thread(thread) {}
|
WaitTreeCallstack::WaitTreeCallstack(const Kernel::Thread& thread) : thread(thread) {}
|
||||||
WaitTreeCallstack::~WaitTreeCallstack() = default;
|
WaitTreeCallstack::~WaitTreeCallstack() = default;
|
||||||
|
|
||||||
QString WaitTreeCallstack::GetText() const {
|
QString WaitTreeCallstack::GetText() const {
|
||||||
|
@ -148,6 +149,10 @@ QString WaitTreeCallstack::GetText() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> list;
|
std::vector<std::unique_ptr<WaitTreeItem>> list;
|
||||||
|
|
||||||
|
if (thread.IsHLEThread()) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) {
|
if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +194,7 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma
|
||||||
case Kernel::HandleType::ReadableEvent:
|
case Kernel::HandleType::ReadableEvent:
|
||||||
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
|
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
|
||||||
case Kernel::HandleType::Thread:
|
case Kernel::HandleType::Thread:
|
||||||
return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object));
|
return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object));
|
||||||
default:
|
default:
|
||||||
return std::make_unique<WaitTreeSynchronizationObject>(object);
|
return std::make_unique<WaitTreeSynchronizationObject>(object);
|
||||||
}
|
}
|
||||||
|
@ -226,17 +231,21 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() con
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread)
|
WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread)
|
||||||
: WaitTreeSynchronizationObject(thread) {}
|
: WaitTreeSynchronizationObject(thread) {}
|
||||||
WaitTreeThread::~WaitTreeThread() = default;
|
WaitTreeThread::~WaitTreeThread() = default;
|
||||||
|
|
||||||
QString WaitTreeThread::GetText() const {
|
QString WaitTreeThread::GetText() const {
|
||||||
const auto& thread = static_cast<const Kernel::KThread&>(object);
|
const auto& thread = static_cast<const Kernel::Thread&>(object);
|
||||||
QString status;
|
QString status;
|
||||||
switch (thread.GetState()) {
|
switch (thread.GetState()) {
|
||||||
case Kernel::ThreadState::Runnable:
|
case Kernel::ThreadState::Runnable:
|
||||||
if (!thread.IsSuspended()) {
|
if (!thread.IsPaused()) {
|
||||||
status = tr("runnable");
|
if (thread.WasRunning()) {
|
||||||
|
status = tr("running");
|
||||||
|
} else {
|
||||||
|
status = tr("ready");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
status = tr("paused");
|
status = tr("paused");
|
||||||
}
|
}
|
||||||
|
@ -288,11 +297,15 @@ QString WaitTreeThread::GetText() const {
|
||||||
QColor WaitTreeThread::GetColor() const {
|
QColor WaitTreeThread::GetColor() const {
|
||||||
const std::size_t color_index = IsDarkTheme() ? 1 : 0;
|
const std::size_t color_index = IsDarkTheme() ? 1 : 0;
|
||||||
|
|
||||||
const auto& thread = static_cast<const Kernel::KThread&>(object);
|
const auto& thread = static_cast<const Kernel::Thread&>(object);
|
||||||
switch (thread.GetState()) {
|
switch (thread.GetState()) {
|
||||||
case Kernel::ThreadState::Runnable:
|
case Kernel::ThreadState::Runnable:
|
||||||
if (!thread.IsSuspended()) {
|
if (!thread.IsPaused()) {
|
||||||
|
if (thread.WasRunning()) {
|
||||||
return QColor(WaitTreeColors[0][color_index]);
|
return QColor(WaitTreeColors[0][color_index]);
|
||||||
|
} else {
|
||||||
|
return QColor(WaitTreeColors[1][color_index]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return QColor(WaitTreeColors[2][color_index]);
|
return QColor(WaitTreeColors[2][color_index]);
|
||||||
}
|
}
|
||||||
|
@ -323,21 +336,27 @@ QColor WaitTreeThread::GetColor() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren());
|
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren());
|
||||||
|
|
||||||
const auto& thread = static_cast<const Kernel::KThread&>(object);
|
const auto& thread = static_cast<const Kernel::Thread&>(object);
|
||||||
|
|
||||||
QString processor;
|
QString processor;
|
||||||
switch (thread.GetActiveCore()) {
|
switch (thread.GetProcessorID()) {
|
||||||
case Kernel::Svc::IdealCoreUseProcessValue:
|
case Kernel::ThreadProcessorId::THREADPROCESSORID_IDEAL:
|
||||||
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("core %1").arg(thread.GetActiveCore());
|
processor = tr("Unknown processor %1").arg(thread.GetProcessorID());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor)));
|
list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor)));
|
||||||
list.push_back(std::make_unique<WaitTreeText>(
|
list.push_back(
|
||||||
tr("ideal core = %1").arg(thread.GetIdealCoreForDebugging())));
|
std::make_unique<WaitTreeText>(tr("ideal core = %1").arg(thread.GetIdealCore())));
|
||||||
list.push_back(std::make_unique<WaitTreeText>(
|
list.push_back(std::make_unique<WaitTreeText>(
|
||||||
tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask())));
|
tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask())));
|
||||||
list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadID())));
|
list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadID())));
|
||||||
|
@ -371,7 +390,7 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object)
|
||||||
: WaitTreeSynchronizationObject(object) {}
|
: WaitTreeSynchronizationObject(object) {}
|
||||||
WaitTreeEvent::~WaitTreeEvent() = default;
|
WaitTreeEvent::~WaitTreeEvent() = default;
|
||||||
|
|
||||||
WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::KThread*>& list)
|
WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::Thread*>& list)
|
||||||
: thread_list(list) {}
|
: thread_list(list) {}
|
||||||
WaitTreeThreadList::~WaitTreeThreadList() = default;
|
WaitTreeThreadList::~WaitTreeThreadList() = default;
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ class EmuThread;
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class HandleTable;
|
class HandleTable;
|
||||||
class KSynchronizationObject;
|
class KSynchronizationObject;
|
||||||
class KThread;
|
|
||||||
class ReadableEvent;
|
class ReadableEvent;
|
||||||
|
class Thread;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
class WaitTreeThread;
|
class WaitTreeThread;
|
||||||
|
@ -83,20 +83,20 @@ private:
|
||||||
VAddr mutex_address;
|
VAddr mutex_address;
|
||||||
u32 mutex_value;
|
u32 mutex_value;
|
||||||
Kernel::Handle owner_handle;
|
Kernel::Handle owner_handle;
|
||||||
std::shared_ptr<Kernel::KThread> owner;
|
std::shared_ptr<Kernel::Thread> owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeCallstack : public WaitTreeExpandableItem {
|
class WaitTreeCallstack : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeCallstack(const Kernel::KThread& thread);
|
explicit WaitTreeCallstack(const Kernel::Thread& thread);
|
||||||
~WaitTreeCallstack() override;
|
~WaitTreeCallstack() override;
|
||||||
|
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Kernel::KThread& thread;
|
const Kernel::Thread& thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
|
class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
|
||||||
|
@ -131,7 +131,7 @@ private:
|
||||||
class WaitTreeThread : public WaitTreeSynchronizationObject {
|
class WaitTreeThread : public WaitTreeSynchronizationObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeThread(const Kernel::KThread& thread);
|
explicit WaitTreeThread(const Kernel::Thread& thread);
|
||||||
~WaitTreeThread() override;
|
~WaitTreeThread() override;
|
||||||
|
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
|
@ -149,14 +149,14 @@ public:
|
||||||
class WaitTreeThreadList : public WaitTreeExpandableItem {
|
class WaitTreeThreadList : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeThreadList(const std::vector<Kernel::KThread*>& list);
|
explicit WaitTreeThreadList(const std::vector<Kernel::Thread*>& list);
|
||||||
~WaitTreeThreadList() override;
|
~WaitTreeThreadList() override;
|
||||||
|
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<Kernel::KThread*>& thread_list;
|
const std::vector<Kernel::Thread*>& thread_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeModel : public QAbstractItemModel {
|
class WaitTreeModel : public QAbstractItemModel {
|
||||||
|
|
Loading…
Reference in a new issue