From 7dcb3821c639de4b3fee1ed003968f32721dac6f Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Thu, 21 Jan 2021 07:23:23 +0100 Subject: [PATCH] early-access version 1350 --- README.md | 2 +- src/common/common_funcs.h | 15 - src/core/CMakeLists.txt | 7 +- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 12 - src/core/arm/dynarmic/arm_dynarmic_64.cpp | 12 - src/core/core.cpp | 2 +- src/core/cpu_manager.cpp | 25 +- src/core/hardware_properties.h | 36 +- src/core/hle/kernel/client_port.h | 2 - src/core/hle/kernel/client_session.cpp | 4 +- src/core/hle/kernel/client_session.h | 6 +- .../hle/kernel/global_scheduler_context.cpp | 4 +- .../hle/kernel/global_scheduler_context.h | 19 +- src/core/hle/kernel/handle_table.cpp | 6 +- src/core/hle/kernel/hle_ipc.cpp | 6 +- src/core/hle/kernel/hle_ipc.h | 15 +- src/core/hle/kernel/k_address_arbiter.cpp | 28 +- src/core/hle/kernel/k_condition_variable.cpp | 42 +- src/core/hle/kernel/k_condition_variable.h | 10 +- src/core/hle/kernel/k_priority_queue.h | 4 +- src/core/hle/kernel/k_scheduler.cpp | 231 ++++------ src/core/hle/kernel/k_scheduler.h | 48 +- src/core/hle/kernel/k_scheduler_lock.h | 9 +- .../k_scoped_scheduler_lock_and_sleep.h | 18 +- .../hle/kernel/k_synchronization_object.cpp | 20 +- .../hle/kernel/k_synchronization_object.h | 6 +- src/core/hle/kernel/kernel.cpp | 62 ++- src/core/hle/kernel/kernel.h | 16 +- src/core/hle/kernel/memory/memory_manager.cpp | 9 +- src/core/hle/kernel/memory/memory_manager.h | 27 +- src/core/hle/kernel/memory/page_table.cpp | 46 +- src/core/hle/kernel/memory/page_table.h | 2 +- src/core/hle/kernel/object.h | 2 - src/core/hle/kernel/process.cpp | 89 +--- src/core/hle/kernel/process.h | 82 +--- src/core/hle/kernel/readable_event.cpp | 2 +- src/core/hle/kernel/readable_event.h | 2 - src/core/hle/kernel/resource_limit.h | 2 - src/core/hle/kernel/server_port.cpp | 2 +- src/core/hle/kernel/server_port.h | 2 - src/core/hle/kernel/server_session.cpp | 8 +- src/core/hle/kernel/server_session.h | 12 +- src/core/hle/kernel/session.h | 2 - src/core/hle/kernel/shared_memory.h | 2 - src/core/hle/kernel/svc.cpp | 434 ++++++++++-------- src/core/hle/kernel/svc_results.h | 5 - src/core/hle/kernel/svc_types.h | 18 - src/core/hle/kernel/svc_wrap.h | 56 +-- src/core/hle/kernel/time_manager.cpp | 44 +- src/core/hle/kernel/time_manager.h | 10 +- src/core/hle/kernel/transfer_memory.h | 2 - src/core/hle/kernel/writable_event.cpp | 6 +- src/core/hle/kernel/writable_event.h | 3 +- src/core/hle/service/nfp/nfp.cpp | 2 +- src/core/hle/service/nvdrv/interface.cpp | 2 +- src/core/hle/service/service.cpp | 2 +- src/core/hle/service/sockets/bsd.cpp | 2 +- src/core/hle/service/time/time.cpp | 2 +- src/core/hle/service/time/time.h | 2 +- src/core/hle/service/time/time_sharedmemory.h | 2 +- src/core/hle/service/vi/vi.cpp | 2 +- src/core/loader/nro.cpp | 6 +- src/core/loader/nso.cpp | 6 +- .../renderer_vulkan/vk_shader_decompiler.cpp | 5 +- src/yuzu/debugger/wait_tree.cpp | 63 ++- src/yuzu/debugger/wait_tree.h | 14 +- 66 files changed, 721 insertions(+), 925 deletions(-) diff --git a/README.md b/README.md index 9500ff60f..483187f98 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 1349. +This is the source code for early-access 1350. ## Legal Notice diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 1121cdf5e..75f3027fb 100755 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -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 { [[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) { diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 848b7ca7c..f74b581de 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -159,8 +159,6 @@ add_library(core STATIC hle/kernel/k_affinity_mask.h hle/kernel/k_condition_variable.cpp 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_scheduler.cpp 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_synchronization_object.cpp 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.h hle/kernel/memory/address_space_info.cpp @@ -220,6 +215,8 @@ add_library(core STATIC hle/kernel/svc_results.h hle/kernel/svc_types.h hle/kernel/svc_wrap.h + hle/kernel/thread.cpp + hle/kernel/thread.h hle/kernel/time_manager.cpp hle/kernel/time_manager.h hle/kernel/transfer_memory.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 7d7e191ea..6c4c8e9e4 100755 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -251,16 +251,10 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { } void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) { - if (!jit) { - return; - } jit->ChangeProcessorID(new_core_id); } void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { - if (!jit) { - return; - } Dynarmic::A32::Context context; jit->SaveContext(context); ctx.cpu_registers = context.Regs(); @@ -270,9 +264,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { } void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { - if (!jit) { - return; - } Dynarmic::A32::Context context; context.Regs() = ctx.cpu_registers; context.ExtRegs() = ctx.extension_registers; @@ -282,9 +273,6 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { } void ARM_Dynarmic_32::PrepareReschedule() { - if (!jit) { - return; - } jit->HaltExecution(); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index f755a39cf..4c5ebca22 100755 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -290,16 +290,10 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { } void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) { - if (!jit) { - return; - } jit->ChangeProcessorID(new_core_id); } void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { - if (!jit) { - return; - } ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); ctx.pc = jit->GetPC(); @@ -311,9 +305,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { } void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { - if (!jit) { - return; - } jit->SetRegisters(ctx.cpu_registers); jit->SetSP(ctx.sp); jit->SetPC(ctx.pc); @@ -325,9 +316,6 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { } void ARM_Dynarmic_64::PrepareReschedule() { - if (!jit) { - return; - } jit->HaltExecution(); } diff --git a/src/core/core.cpp b/src/core/core.cpp index 30f5e1128..86bdc7f6b 100755 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -28,10 +28,10 @@ #include "core/hardware_interrupt_manager.h" #include "core/hle/kernel/client_port.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/physical_core.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/apm/controller.h" #include "core/hle/service/filesystem/filesystem.h" diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 8f04fb8f5..373395047 100755 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -11,9 +11,9 @@ #include "core/core_timing.h" #include "core/cpu_manager.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/physical_core.h" +#include "core/hle/kernel/thread.h" #include "video_core/gpu.h" namespace Core { @@ -147,7 +147,7 @@ void CpuManager::MultiCoreRunSuspendThread() { while (true) { auto core = kernel.GetCurrentHostThreadID(); 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); ASSERT(scheduler.ContextSwitchPending()); ASSERT(core == kernel.GetCurrentHostThreadID()); @@ -208,6 +208,7 @@ void CpuManager::SingleCoreRunGuestThread() { void CpuManager::SingleCoreRunGuestLoop() { auto& kernel = system.Kernel(); + auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); while (true) { auto* physical_core = &kernel.CurrentPhysicalCore(); system.EnterDynarmicProfile(); @@ -216,9 +217,9 @@ void CpuManager::SingleCoreRunGuestLoop() { physical_core = &kernel.CurrentPhysicalCore(); } system.ExitDynarmicProfile(); - kernel.SetIsPhantomModeForSingleCore(true); + thread->SetPhantomMode(true); system.CoreTiming().Advance(); - kernel.SetIsPhantomModeForSingleCore(false); + thread->SetPhantomMode(false); physical_core->ArmInterface().ClearExclusiveState(); PreemptSingleCore(); auto& scheduler = kernel.Scheduler(current_core); @@ -244,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() { while (true) { auto core = kernel.GetCurrentHostThreadID(); 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); ASSERT(scheduler.ContextSwitchPending()); ASSERT(core == kernel.GetCurrentHostThreadID()); @@ -254,23 +255,22 @@ void CpuManager::SingleCoreRunSuspendThread() { void CpuManager::PreemptSingleCore(bool from_running_enviroment) { { - auto& kernel = system.Kernel(); - auto& scheduler = kernel.Scheduler(current_core); - Kernel::KThread* current_thread = scheduler.GetCurrentThread(); + auto& scheduler = system.Kernel().Scheduler(current_core); + Kernel::Thread* current_thread = scheduler.GetCurrentThread(); if (idle_count >= 4 || from_running_enviroment) { if (!from_running_enviroment) { system.CoreTiming().Idle(); idle_count = 0; } - kernel.SetIsPhantomModeForSingleCore(true); + current_thread->SetPhantomMode(true); system.CoreTiming().Advance(); - kernel.SetIsPhantomModeForSingleCore(false); + current_thread->SetPhantomMode(false); } current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); system.CoreTiming().ResetTicks(); 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()); } @@ -278,7 +278,8 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { { auto& scheduler = system.Kernel().Scheduler(current_core); scheduler.Reload(scheduler.GetCurrentThread()); - if (!scheduler.IsIdle()) { + auto* currrent_thread2 = scheduler.GetCurrentThread(); + if (!currrent_thread2->IsIdleThread()) { idle_count = 0; } } diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 176a72c67..456b41e1b 100755 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -4,10 +4,8 @@ #pragma once -#include #include -#include "common/bit_util.h" #include "common/common_types.h" 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 u32 NUM_CPU_CORES = 4; // Number of CPU Cores -// Virtual to Physical core map. -constexpr std::array()> 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 +constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF; + +struct EmuThreadHandle { + u32 host_handle; + u32 guest_handle; + + u64 GetRaw() const { + return (static_cast(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 diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 77559ebf9..9762bbf0d 100755 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -51,8 +51,6 @@ public: */ void ConnectionClosed(); - void Finalize() override {} - private: std::shared_ptr server_port; ///< ServerPort associated with this client port. u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index a2be1a8f6..e8e52900d 100755 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -5,9 +5,9 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/errors.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/session.h" +#include "core/hle/kernel/thread.h" #include "core/hle/result.h" namespace Kernel { @@ -38,7 +38,7 @@ ResultVal> ClientSession::Create(KernelCore& kern return MakeResult(std::move(client_session)); } -ResultCode ClientSession::SendSyncRequest(std::shared_ptr thread, +ResultCode ClientSession::SendSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing) { // Keep ServerSession alive until we're done working with it. diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index bc50f2505..d5c9ebee8 100755 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -24,7 +24,7 @@ namespace Kernel { class KernelCore; class Session; -class KThread; +class Thread; class ClientSession final : public KSynchronizationObject { public: @@ -46,13 +46,11 @@ public: return HANDLE_TYPE; } - ResultCode SendSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, + ResultCode SendSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing); bool IsSignaled() const override; - void Finalize() override{}; - private: static ResultVal> Create(KernelCore& kernel, std::shared_ptr parent, diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index c6838649f..a133e8ed0 100755 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp @@ -17,12 +17,12 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel) GlobalSchedulerContext::~GlobalSchedulerContext() = default; -void GlobalSchedulerContext::AddThread(std::shared_ptr thread) { +void GlobalSchedulerContext::AddThread(std::shared_ptr thread) { std::scoped_lock lock{global_list_guard}; thread_list.push_back(std::move(thread)); } -void GlobalSchedulerContext::RemoveThread(std::shared_ptr thread) { +void GlobalSchedulerContext::RemoveThread(std::shared_ptr thread) { std::scoped_lock lock{global_list_guard}; thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 11592843e..5c7b89290 100755 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -12,8 +12,7 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/k_priority_queue.h" #include "core/hle/kernel/k_scheduler_lock.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/svc_types.h" +#include "core/hle/kernel/thread.h" namespace Kernel { @@ -21,12 +20,8 @@ class KernelCore; class SchedulerLock; using KSchedulerPriorityQueue = - KPriorityQueue; - -static constexpr s32 HighestCoreMigrationAllowedPriority = 2; -static_assert(Svc::LowestThreadPriority >= HighestCoreMigrationAllowedPriority); -static_assert(Svc::HighestThreadPriority <= HighestCoreMigrationAllowedPriority); + KPriorityQueue; +constexpr s32 HighestCoreMigrationAllowedPriority = 2; class GlobalSchedulerContext final { friend class KScheduler; @@ -38,13 +33,13 @@ public: ~GlobalSchedulerContext(); /// Adds a new thread to the scheduler - void AddThread(std::shared_ptr thread); + void AddThread(std::shared_ptr thread); /// Removes a thread from the scheduler - void RemoveThread(std::shared_ptr thread); + void RemoveThread(std::shared_ptr thread); /// Returns a list of all threads managed by the scheduler - [[nodiscard]] const std::vector>& GetThreadList() const { + [[nodiscard]] const std::vector>& GetThreadList() const { return thread_list; } @@ -79,7 +74,7 @@ private: LockType scheduler_lock; /// Lists all thread ids that aren't deleted/etc. - std::vector> thread_list; + std::vector> thread_list; Common::SpinLock global_list_guard{}; }; diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 1a2fa9cd8..40988b0fd 100755 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -9,9 +9,9 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.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/process.h" +#include "core/hle/kernel/thread.h" namespace Kernel { namespace { @@ -89,10 +89,6 @@ ResultCode HandleTable::Close(Handle handle) { const u16 slot = GetSlot(handle); - if (objects[slot].use_count() == 1) { - objects[slot]->Finalize(); - } - objects[slot] = nullptr; generations[slot] = next_free_slot; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 5c0a5857f..83decf6cf 100755 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -19,12 +19,12 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_scheduler.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/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.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/writable_event.h" #include "core/memory.h" @@ -48,7 +48,7 @@ void SessionRequestHandler::ClientDisconnected( HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, std::shared_ptr server_session, - std::shared_ptr thread) + std::shared_ptr thread) : server_session(std::move(server_session)), thread(std::move(thread)), kernel{kernel}, memory{memory} { cmd_buf[0] = 0; @@ -182,7 +182,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl return RESULT_SUCCESS; } -ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { +ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { auto& owner_process = *thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 3ff55af40..b112e1ebd 100755 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -40,7 +40,7 @@ class HLERequestContext; class KernelCore; class Process; class ServerSession; -class KThread; +class Thread; class ReadableEvent; class WritableEvent; @@ -110,7 +110,7 @@ class HLERequestContext { public: explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, std::shared_ptr session, - std::shared_ptr thread); + std::shared_ptr thread); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. @@ -126,12 +126,15 @@ public: return server_session; } + using WakeupCallback = std::function thread, HLERequestContext& context, ThreadWakeupReason reason)>; + /// Populates this context with data from the requesting process/thread. ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf); /// Writes data from this context back to the requesting process/thread. - ResultCode WriteToOutgoingCommandBuffer(KThread& thread); + ResultCode WriteToOutgoingCommandBuffer(Thread& thread); u32_le GetCommand() const { return command; @@ -258,11 +261,11 @@ public: std::string Description() const; - KThread& GetThread() { + Thread& GetThread() { return *thread; } - const KThread& GetThread() const { + const Thread& GetThread() const { return *thread; } @@ -277,7 +280,7 @@ private: std::array cmd_buf; std::shared_ptr server_session; - std::shared_ptr thread; + std::shared_ptr thread; // TODO(yuriks): Check common usage of this and optimize size accordingly boost::container::small_vector, 8> move_objects; boost::container::small_vector, 8> copy_objects; diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 1685d25bb..d9e702f13 100755 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -7,9 +7,9 @@ #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_scheduler.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/svc_results.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" #include "core/memory.h" @@ -96,7 +96,7 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { auto it = thread_tree.nfind_light({addr, -1}); while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { - KThread* target_thread = std::addressof(*it); + Thread* target_thread = std::addressof(*it); target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); ASSERT(target_thread->IsWaitingForAddressArbiter()); @@ -125,7 +125,7 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 auto it = thread_tree.nfind_light({addr, -1}); while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { - KThread* target_thread = std::addressof(*it); + Thread* target_thread = std::addressof(*it); target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); ASSERT(target_thread->IsWaitingForAddressArbiter()); @@ -215,7 +215,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { - KThread* target_thread = std::addressof(*it); + Thread* target_thread = std::addressof(*it); target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); 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) { // 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. if (cur_thread->IsTerminationRequested()) { @@ -279,7 +280,10 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement } // 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. { @@ -298,10 +302,11 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { // 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. if (cur_thread->IsTerminationRequested()) { @@ -339,7 +344,10 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { } // 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. { diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index f0ad8b390..49a068310 100755 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -10,11 +10,11 @@ #include "core/hle/kernel/k_scheduler.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_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_results.h" +#include "core/hle/kernel/thread.h" #include "core/memory.h" namespace Kernel { @@ -66,7 +66,7 @@ KConditionVariable::KConditionVariable(Core::System& system_) KConditionVariable::~KConditionVariable() = default; ResultCode KConditionVariable::SignalToAddress(VAddr addr) { - KThread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread(); + Thread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread(); // Signal the address. { @@ -74,7 +74,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { // Remove waiter thread. s32 num_waiters{}; - KThread* next_owner_thread = + Thread* next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); // Determine the next tag. @@ -103,11 +103,11 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { } 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. { - std::shared_ptr owner_thread; + std::shared_ptr owner_thread; ASSERT(!owner_thread); { 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); // Get the lock owner thread. - owner_thread = kernel.CurrentProcess()->GetHandleTable().Get(handle); + owner_thread = kernel.CurrentProcess()->GetHandleTable().Get(handle); R_UNLESS(owner_thread, Svc::ResultInvalidHandle); // 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. { KScopedSchedulerLock sl(kernel); - KThread* owner_thread = cur_thread->GetLockOwner(); + Thread* owner_thread = cur_thread->GetLockOwner(); if (owner_thread != nullptr) { 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)); } -KThread* KConditionVariable::SignalImpl(KThread* thread) { +Thread* KConditionVariable::SignalImpl(Thread* thread) { // Check pre-conditions. 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 (prev_tag == InvalidHandle) { // If nobody held the lock previously, we're all good. @@ -182,7 +182,7 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { thread->Wakeup(); } else { // Get the previous owner. - auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get( + auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get( prev_tag & ~Svc::HandleWaitMask); 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 // std::shared_ptr. - std::vector> thread_list; - std::array thread_array; + std::vector> thread_list; + std::array thread_array; s32 num_to_close{}; // Perform signaling. @@ -222,9 +222,9 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { auto it = thread_tree.nfind_light({cv_key, -1}); while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && (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) { thread_array[num_to_close++] = thread; } else { @@ -257,10 +257,11 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { // 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. cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); @@ -275,7 +276,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { // Remove waiter thread. s32 num_waiters{}; - KThread* next_owner_thread = + Thread* next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); // 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. - kernel.TimeManager().UnscheduleTimeEvent(cur_thread); + if (timer != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(timer); + } // Remove from the condition variable. { KScopedSchedulerLock sl(kernel); - if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) { + if (Thread* owner = cur_thread->GetLockOwner(); owner != nullptr) { owner->RemoveWaiter(cur_thread); } diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h index 861dbd420..98ed5b323 100755 --- a/src/core/hle/kernel/k_condition_variable.h +++ b/src/core/hle/kernel/k_condition_variable.h @@ -8,8 +8,8 @@ #include "common/common_types.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/thread.h" #include "core/hle/result.h" namespace Core { @@ -20,7 +20,7 @@ namespace Kernel { class KConditionVariable { public: - using ThreadTree = typename KThread::ConditionVariableThreadTreeType; + using ThreadTree = typename Thread::ConditionVariableThreadTreeType; explicit KConditionVariable(Core::System& system_); ~KConditionVariable(); @@ -34,7 +34,7 @@ public: [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout); private: - [[nodiscard]] KThread* SignalImpl(KThread* thread); + [[nodiscard]] Thread* SignalImpl(Thread* thread); ThreadTree thread_tree; @@ -43,14 +43,14 @@ private: }; inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, - KThread* thread) { + Thread* thread) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); tree->erase(tree->iterator_to(*thread)); } inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, - KThread* thread) { + Thread* thread) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); tree->insert(*thread); diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index 13d628b85..0dc929040 100755 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h @@ -18,7 +18,7 @@ namespace Kernel { -class KThread; +class Thread; template concept KPriorityQueueAffinityMask = !std::is_reference_v && requires(T & t) { @@ -367,7 +367,7 @@ public: 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(), member); } diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index e99122f4c..12b5619fb 100755 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -17,29 +17,25 @@ #include "core/cpu_manager.h" #include "core/hle/kernel/k_scheduler.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/physical_core.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { -static void IncrementScheduledCount(Kernel::KThread* thread) { +static void IncrementScheduledCount(Kernel::Thread* thread) { if (auto process = thread->GetOwnerProcess(); process) { process->IncrementScheduledCount(); } } -void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule) { - auto scheduler = kernel.CurrentScheduler(); - - u32 current_core{0xF}; - bool must_context_switch{}; - if (scheduler) { - current_core = scheduler->core_id; - must_context_switch = true; - } +void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, + Core::EmuThreadHandle global_thread) { + const u32 current_core = global_thread.host_handle; + bool must_context_switch = global_thread.guest_handle != InvalidHandle && + (current_core < Core::Hardware::NUM_CPU_CORES); while (cores_pending_reschedule != 0) { const auto core = static_cast(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}; - if (KThread* prev_highest_thread = state.highest_priority_thread; + if (Thread* prev_highest_thread = this->state.highest_priority_thread; prev_highest_thread != highest_thread) { if (prev_highest_thread != nullptr) { IncrementScheduledCount(prev_highest_thread); prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks()); } - if (state.should_count_idle) { + if (this->state.should_count_idle) { if (highest_thread != nullptr) { - if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { - process->SetRunningThread(core_id, highest_thread, state.idle_count); - } + // if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { + // process->SetRunningThread(this->core_id, highest_thread, + // this->state.idle_count); + //} } else { - state.idle_count++; + this->state.idle_count++; } } - state.highest_priority_thread = highest_thread; - state.needs_scheduling = true; - return (1ULL << core_id); + this->state.highest_priority_thread = highest_thread; + this->state.needs_scheduling = true; + return (1ULL << this->core_id); } else { return 0; } @@ -93,29 +90,16 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { ClearSchedulerUpdateNeeded(kernel); 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); /// We want to go over all cores, finding the highest priority thread and determining if /// scheduling is needed for that core. for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - KThread* top_thread = priority_queue.GetScheduledFront(static_cast(core_id)); + Thread* top_thread = priority_queue.GetScheduledFront(static_cast(core_id)); if (top_thread != nullptr) { // If the thread has no waiters, we need to check if the process has a thread pinned. - if (top_thread->GetNumKernelWaiters() == 0) { - if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) { - if (KThread* pinned = parent->GetPinnedThread(static_cast(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; - } - } - } - } + // TODO(bunnei): Implement thread pinning } else { 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. while (idle_cores != 0) { const auto core_id = static_cast(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]; size_t num_candidates = 0; @@ -136,7 +120,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { while (suggested != nullptr) { // Check if the suggested thread is the top thread on its core. const s32 suggested_core = suggested->GetActiveCore(); - if (KThread* top_thread = + if (Thread* top_thread = (suggested_core >= 0) ? top_threads[suggested_core] : nullptr; top_thread != suggested) { // 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. const s32 candidate_core = migration_candidates[i]; suggested = top_threads[candidate_core]; - if (KThread* next_on_candidate_core = + if (Thread* next_on_candidate_core = priority_queue.GetScheduledNext(candidate_core, suggested); next_on_candidate_core != nullptr) { // 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; } -void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) { - 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 prev_thread(kernel.Scheduler(static_cast(i)).prev_thread); - static_assert(std::atomic_ref::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) { +void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // 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()); // 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) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -266,8 +237,8 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { auto& priority_queue = GetPriorityQueue(kernel); // Rotate the front of the queue to the end. - KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority); - KThread* next_thread = nullptr; + Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority); + Thread* next_thread = nullptr; if (top_thread != nullptr) { next_thread = priority_queue.MoveToScheduledBack(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! { - KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority); + Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority); while (suggested != nullptr) { // Check if the suggested thread is the top thread on its core. 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) : nullptr; 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. { - KThread* best_thread = priority_queue.GetScheduledFront(core_id); + Thread* best_thread = priority_queue.GetScheduledFront(core_id); if (best_thread == GetCurrentThread()) { 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 // migrate a higher priority thread. 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) { // If the suggestion's priority is the same as ours, don't bother. 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. 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) : nullptr; 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) { - ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1); - if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) { - scheduler->GetCurrentThread()->EnableDispatch(); - } + scheduler->GetCurrentThread()->EnableDispatch(); } - RescheduleCores(kernel, cores_needing_scheduling); + RescheduleCores(kernel, cores_needing_scheduling, global_thread); } u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { @@ -403,13 +372,15 @@ KSchedulerPriorityQueue& KScheduler::GetPriorityQueue(KernelCore& kernel) { return kernel.GlobalSchedulerContext().priority_queue; } -void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { +void KScheduler::YieldWithoutCoreMigration() { + auto& kernel = system.Kernel(); + // Validate preconditions. ASSERT(CanSchedule(kernel)); ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = Kernel::GetCurrentThread(kernel); + Thread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // 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(); if (cur_state == ThreadState::Runnable) { // 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)); // 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. ASSERT(CanSchedule(kernel)); ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = Kernel::GetCurrentThread(kernel); + Thread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // 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(); // 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)); // While we have a suggested thread, try to migrate it! bool recheck = false; - KThread* suggested = priority_queue.GetSuggestedFront(core_id); + Thread* suggested = priority_queue.GetSuggestedFront(core_id); while (suggested != nullptr) { // Check if the suggested thread is the thread running on its core. const s32 suggested_core = suggested->GetActiveCore(); - if (KThread* running_on_suggested_core = + if (Thread* running_on_suggested_core = (suggested_core >= 0) ? kernel.Scheduler(suggested_core).state.highest_priority_thread : nullptr; @@ -530,13 +503,15 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { } } -void KScheduler::YieldToAnyThread(KernelCore& kernel) { +void KScheduler::YieldToAnyThread() { + auto& kernel = system.Kernel(); + // Validate preconditions. ASSERT(CanSchedule(kernel)); ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = Kernel::GetCurrentThread(kernel); + Thread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // 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 (priority_queue.GetScheduledFront(core_id) == nullptr) { // 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) { // Check if the suggested thread is the top thread on its core. 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) : nullptr; 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(OnSwitch, this); - state.needs_scheduling = true; - state.interrupt_task_thread_runnable = false; - state.should_count_idle = false; - state.idle_count = 0; - state.idle_thread_stack = nullptr; - state.highest_priority_thread = nullptr; + this->state.needs_scheduling = true; + this->state.interrupt_task_thread_runnable = false; + this->state.should_count_idle = false; + this->state.idle_count = 0; + this->state.idle_thread_stack = nullptr; + this->state.highest_priority_thread = nullptr; } KScheduler::~KScheduler() = default; -KThread* KScheduler::GetCurrentThread() const { +Thread* KScheduler::GetCurrentThread() const { if (current_thread) { return current_thread; } @@ -637,7 +613,7 @@ void KScheduler::RescheduleCurrentCore() { phys_core.ClearInterrupt(); } guard.lock(); - if (state.needs_scheduling) { + if (this->state.needs_scheduling) { Schedule(); } else { guard.unlock(); @@ -648,47 +624,45 @@ void KScheduler::OnThreadStart() { SwitchContextStep2(); } -void KScheduler::Unload(KThread* thread) { - LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); - +void KScheduler::Unload(Thread* thread) { if (thread) { - if (thread->IsCallingSvc()) { + thread->SetIsRunning(false); + if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) { system.ArmInterface(core_id).ExceptionalExit(); - thread->ClearIsCallingSvc(); + thread->SetContinuousOnSVC(false); } - if (!thread->IsTerminationRequested()) { - prev_thread = thread; - + if (!thread->IsHLEThread() && !thread->HasExited()) { Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(thread->GetContext32()); cpu_core.SaveContext(thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); - } else { - prev_thread = nullptr; } thread->context_guard.unlock(); } } -void KScheduler::Reload(KThread* thread) { - LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread ? thread->GetName() : "nullptr"); - +void KScheduler::Reload(Thread* thread) { if (thread) { 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(); if (thread_owner_process != nullptr) { system.Kernel().MakeCurrentProcess(thread_owner_process); } - - Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); - cpu_core.LoadContext(thread->GetContext32()); - cpu_core.LoadContext(thread->GetContext64()); - cpu_core.SetTlsAddress(thread->GetTLSAddress()); - cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); - cpu_core.ClearExclusiveState(); + if (!thread->IsHLEThread()) { + Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); + cpu_core.LoadContext(thread->GetContext32()); + cpu_core.LoadContext(thread->GetContext64()); + cpu_core.SetTlsAddress(thread->GetTLSAddress()); + cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); + } } } @@ -700,24 +674,16 @@ void KScheduler::SwitchContextStep2() { } void KScheduler::ScheduleImpl() { - KThread* previous_thread = current_thread; - KThread* next_thread = state.highest_priority_thread; + Thread* previous_thread = current_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 (next_thread == nullptr) { - next_thread = idle_thread; - } - - // If we're not actually switching thread, there's nothing to do. - if (next_thread == current_thread) { + if (current_thread == previous_thread) { guard.unlock(); return; } - current_thread = next_thread; - Process* const previous_process = system.Kernel().CurrentProcess(); UpdateLastContextSwitchTime(previous_thread, previous_process); @@ -749,20 +715,20 @@ void KScheduler::SwitchToCurrent() { { std::scoped_lock lock{guard}; current_thread = state.highest_priority_thread; - state.needs_scheduling = false; + this->state.needs_scheduling = false; } const auto is_switch_pending = [this] { std::scoped_lock lock{guard}; return state.needs_scheduling.load(std::memory_order_relaxed); }; do { - if (current_thread != nullptr) { + if (current_thread != nullptr && !current_thread->IsHLEThread()) { current_thread->context_guard.lock(); if (current_thread->GetRawState() != ThreadState::Runnable) { current_thread->context_guard.unlock(); break; } - if (current_thread->GetActiveCore() != core_id) { + if (static_cast(current_thread->GetProcessorID()) != core_id) { current_thread->context_guard.unlock(); 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 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; if (thread != nullptr) { - thread->AddCpuTime(core_id, update_ticks); + thread->UpdateCPUTimeTicks(update_ticks); } if (process != nullptr) { @@ -798,10 +764,15 @@ void KScheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, - KThread::IdleThreadPriority, 0, static_cast(core_id), 0, - nullptr, std::move(init_func), init_func_parameter); + ThreadType type = static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); + auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast(core_id), 0, + nullptr, std::move(init_func), init_func_parameter); idle_thread = thread_res.Unwrap().get(); + + { + KScopedSchedulerLock lock{system.Kernel()}; + idle_thread->SetState(ThreadState::Runnable); + } } KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 2308a55be..783665123 100755 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -29,33 +29,29 @@ namespace Kernel { class KernelCore; class Process; class SchedulerLock; -class KThread; +class Thread; class KScheduler final { public: - explicit KScheduler(Core::System& system, s32 core_id); + explicit KScheduler(Core::System& system, std::size_t core_id); ~KScheduler(); /// Reschedules to the next available thread (call after current thread is suspended) void RescheduleCurrentCore(); /// 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. /// Unload current thread before preempting core. - void Unload(KThread* thread); + void Unload(Thread* thread); /// Reload current thread after core preemption. - void Reload(KThread* thread); + void Reload(Thread* thread); /// Gets the current running thread - [[nodiscard]] KThread* GetCurrentThread() const; - - /// Returns true if the scheduler is idle - [[nodiscard]] bool IsIdle() const { - return GetCurrentThread() == idle_thread; - } + [[nodiscard]] Thread* GetCurrentThread() const; /// Gets the timestamp for the last context switch in ticks. [[nodiscard]] u64 GetLastContextSwitchTicks() const; @@ -76,14 +72,14 @@ public: 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. * * @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. @@ -92,7 +88,7 @@ public: * * @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. @@ -101,18 +97,16 @@ public: * * @note This operation can be redundant and no scheduling is changed if marked as so. */ - static void YieldToAnyThread(KernelCore& kernel); - - static void ClearPreviousThread(KernelCore& kernel, KThread* thread); + void YieldToAnyThread(); /// 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. - 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. - static void OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread, + static void OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, const KAffinityMask& old_affinity, s32 old_core); static bool CanSchedule(KernelCore& kernel); @@ -120,7 +114,8 @@ public: static void SetSchedulerUpdateNeeded(KernelCore& kernel); static void ClearSchedulerUpdateNeeded(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); private: @@ -168,14 +163,13 @@ private: * most recent tick count retrieved. No special arithmetic is * applied to it. */ - void UpdateLastContextSwitchTime(KThread* thread, Process* process); + void UpdateLastContextSwitchTime(Thread* thread, Process* process); static void OnSwitch(void* this_scheduler); void SwitchToCurrent(); - KThread* prev_thread{}; - KThread* current_thread{}; - KThread* idle_thread{}; + Thread* current_thread{}; + Thread* idle_thread{}; std::shared_ptr switch_fiber{}; @@ -184,7 +178,7 @@ private: bool interrupt_task_thread_runnable{}; bool should_count_idle{}; u64 idle_count{}; - KThread* highest_priority_thread{}; + Thread* highest_priority_thread{}; void* idle_thread_stack{}; }; @@ -192,7 +186,7 @@ private: Core::System& system; u64 last_context_switch_time{}; - const s32 core_id; + const std::size_t core_id; Common::SpinLock guard{}; }; diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h index 5d48dcf38..9b40bd22c 100755 --- a/src/core/hle/kernel/k_scheduler_lock.h +++ b/src/core/hle/kernel/k_scheduler_lock.h @@ -37,7 +37,7 @@ public: // For debug, ensure that our state is valid. ASSERT(this->lock_count == 0); - ASSERT(this->owner_thread == EmuThreadHandleInvalid); + ASSERT(this->owner_thread == Core::EmuThreadHandle::InvalidHandle()); // Increment count, take ownership. 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. const u64 cores_needing_scheduling = SchedulerType::UpdateHighestPriorityThreads(kernel); + Core::EmuThreadHandle leaving_thread = owner_thread; // 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(); // 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; Common::SpinLock spin_lock{}; s32 lock_count{}; - EmuThreadHandle owner_thread{EmuThreadHandleInvalid}; + Core::EmuThreadHandle owner_thread{Core::EmuThreadHandle::InvalidHandle()}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index f8189e107..2bb3817fa 100755 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h @@ -9,24 +9,27 @@ #include "common/common_types.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/thread.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { class KScopedSchedulerLockAndSleep { public: - explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout) - : kernel(kernel), thread(t), timeout_tick(timeout) { + explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* t, + s64 timeout) + : kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) { + event_handle = InvalidHandle; + // Lock the scheduler. kernel.GlobalSchedulerContext().scheduler_lock.Lock(); } ~KScopedSchedulerLockAndSleep() { // Register the sleep. - if (timeout_tick > 0) { - kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick); + if (this->timeout_tick > 0) { + kernel.TimeManager().ScheduleTimeEvent(event_handle, this->thread, this->timeout_tick); } // Unlock the scheduler. @@ -34,12 +37,13 @@ public: } void CancelSleep() { - timeout_tick = 0; + this->timeout_tick = 0; } private: KernelCore& kernel; - KThread* thread{}; + Handle& event_handle; + Thread* thread{}; s64 timeout_tick{}; }; diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index a3b34f82f..1c508cb55 100755 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp @@ -7,9 +7,9 @@ #include "core/hle/kernel/k_scheduler.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_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" +#include "core/hle/kernel/thread.h" namespace Kernel { @@ -20,11 +20,12 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, std::vector thread_nodes(num_objects); // Prepare for wait. - KThread* thread = kernel.CurrentScheduler()->GetCurrentThread(); + Thread* thread = kernel.CurrentScheduler()->GetCurrentThread(); + Handle timer = InvalidHandle; { // 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. for (auto i = 0; i < num_objects; ++i) { @@ -89,7 +90,10 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, thread->SetWaitObjectsForDebugging({}); // 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. ResultCode wait_result{RESULT_SUCCESS}; @@ -132,7 +136,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} -KSynchronizationObject::~KSynchronizationObject() = default; +KSynchronizationObject ::~KSynchronizationObject() = default; void KSynchronizationObject::NotifyAvailable(ResultCode result) { KScopedSchedulerLock lock(kernel); @@ -144,7 +148,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) { // Iterate over each thread. 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) { thread->SetSyncedObject(this, result); thread->SetState(ThreadState::Runnable); @@ -152,8 +156,8 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) { } } -std::vector KSynchronizationObject::GetWaitingThreadsForDebugging() const { - std::vector threads; +std::vector KSynchronizationObject::GetWaitingThreadsForDebugging() const { + std::vector threads; // If debugging, dump the list of waiters. { diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index f65c71c28..14d80ebf1 100755 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -13,14 +13,14 @@ namespace Kernel { class KernelCore; class Synchronization; -class KThread; +class Thread; /// Class that represents a Kernel object that a thread can be waiting on class KSynchronizationObject : public Object { public: struct ThreadListNode { ThreadListNode* next{}; - KThread* thread{}; + Thread* thread{}; }; [[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index, @@ -29,7 +29,7 @@ public: [[nodiscard]] virtual bool IsSignaled() const = 0; - [[nodiscard]] std::vector GetWaitingThreadsForDebugging() const; + [[nodiscard]] std::vector GetWaitingThreadsForDebugging() const; protected: explicit KSynchronizationObject(KernelCore& kernel); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c41312a0f..c0ff287a6 100755 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -29,7 +29,6 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.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/memory/memory_layout.h" #include "core/hle/kernel/memory/memory_manager.h" @@ -39,6 +38,7 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/lock.h" #include "core/hle/result.h" @@ -62,7 +62,6 @@ struct KernelCore::Impl { global_scheduler_context = std::make_unique(kernel); service_thread_manager = std::make_unique(1, "yuzu:ServiceThreadManager"); - is_phantom_mode_for_singlecore = false; InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); @@ -117,14 +116,14 @@ struct KernelCore::Impl { void InitializePhysicalCores() { exclusive_monitor = 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(system, i); cores.emplace_back(i, system, *schedulers[i], interrupts); } } 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(); } } @@ -169,9 +168,11 @@ struct KernelCore::Impl { std::string name = "Suspend Thread Id:" + std::to_string(i); std::function init_func = Core::CpuManager::GetSuspendThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::Create(system, ThreadType::HighPriority, std::move(name), 0, - 0, 0, static_cast(i), 0, nullptr, - std::move(init_func), init_func_parameter); + const auto type = + static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); + auto thread_res = + Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast(i), 0, + nullptr, std::move(init_func), init_func_parameter); suspend_threads[i] = std::move(thread_res).Unwrap(); } @@ -228,22 +229,20 @@ struct KernelCore::Impl { return this_id; } - bool IsPhantomModeForSingleCore() const { - return is_phantom_mode_for_singlecore; - } - - void SetIsPhantomModeForSingleCore(bool value) { - ASSERT(!is_multicore); - is_phantom_mode_for_singlecore = value; - } - - [[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(thread_id) << 1); + [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() { + Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); + result.host_handle = GetCurrentHostThreadID(); + if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { + return result; } - return reinterpret_cast(schedulers[thread_id].get()); + const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler(); + const Kernel::Thread* current = sched.GetCurrentThread(); + if (current != nullptr && !current->IsPhantomMode()) { + result.guest_handle = current->GetGlobalHandle(); + } else { + result.guest_handle = InvalidHandle; + } + return result; } void InitializeMemoryLayout() { @@ -259,7 +258,7 @@ struct KernelCore::Impl { constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size}; // Initialize memory manager - memory_manager = std::make_unique(system.Kernel()); + memory_manager = std::make_unique(); memory_manager->InitializeManager(Memory::MemoryManager::Pool::Application, layout.Application().StartAddress(), layout.Application().EndAddress()); @@ -343,12 +342,11 @@ struct KernelCore::Impl { // the release of itself std::unique_ptr service_thread_manager; - std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; - bool is_phantom_mode_for_singlecore{}; u32 single_core_thread_id{}; std::array svc_ticks{}; @@ -382,8 +380,8 @@ std::shared_ptr KernelCore::GetSystemResourceLimit() const { return impl->system_resource_limit; } -std::shared_ptr KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { - return impl->global_handle_table.Get(handle); +std::shared_ptr KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { + return impl->global_handle_table.Get(handle); } void KernelCore::AppendNewProcess(std::shared_ptr process) { @@ -548,7 +546,7 @@ u32 KernelCore::GetCurrentHostThreadID() const { return impl->GetCurrentHostThreadID(); } -EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { +Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { return impl->GetCurrentEmuThreadID(); } @@ -647,12 +645,4 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr servi }); } -bool KernelCore::IsPhantomModeForSingleCore() const { - return impl->IsPhantomModeForSingleCore(); -} - -void KernelCore::SetIsPhantomModeForSingleCore(bool value) { - impl->SetIsPhantomModeForSingleCore(value); -} - } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index b92c017f6..933d9a7d6 100755 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -43,13 +43,9 @@ class KScheduler; class SharedMemory; class ServiceThread; class Synchronization; -class KThread; +class Thread; class TimeManager; -using EmuThreadHandle = uintptr_t; -constexpr EmuThreadHandle EmuThreadHandleInvalid{}; -constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63}; - /// Represents a single instance of the kernel. class KernelCore { private: @@ -88,7 +84,7 @@ public: std::shared_ptr GetSystemResourceLimit() const; /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. - std::shared_ptr RetrieveThreadFromGlobalHandleTable(Handle handle) const; + std::shared_ptr RetrieveThreadFromGlobalHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. void AppendNewProcess(std::shared_ptr process); @@ -166,7 +162,7 @@ public: bool IsValidNamedPort(NamedPortTable::const_iterator port) const; /// Gets the current host_thread/guest_thread handle. - EmuThreadHandle GetCurrentEmuThreadID() const; + Core::EmuThreadHandle GetCurrentEmuThreadID() const; /// Gets the current host_thread handle. u32 GetCurrentHostThreadID() const; @@ -241,14 +237,10 @@ public: */ void ReleaseServiceThread(std::weak_ptr service_thread); - /// Workaround for single-core mode when preempting threads while idle. - bool IsPhantomModeForSingleCore() const; - void SetIsPhantomModeForSingleCore(bool value); - private: friend class Object; friend class Process; - friend class KThread; + friend class Thread; /// Creates a new object ID, incrementing the internal object ID counter. u32 CreateNewObjectID(); diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/memory/memory_manager.cpp index 75a8a05b5..acf13585c 100755 --- a/src/core/hle/kernel/memory/memory_manager.cpp +++ b/src/core/hle/kernel/memory/memory_manager.cpp @@ -41,9 +41,6 @@ std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u6 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) { ASSERT(pool < Pool::Count); managers[static_cast(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 const auto pool_index{static_cast(pool)}; - KScopedLightLock lk{PoolLock(pool_index)}; + std::lock_guard lock{pool_locks[pool_index]}; // Choose a heap based on our page size request 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 const auto pool_index{static_cast(pool)}; - KScopedLightLock lk{PoolLock(pool_index)}; + std::lock_guard lock{pool_locks[pool_index]}; // Choose a heap based on our page size request 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 const auto pool_index{static_cast(pool)}; - KScopedLightLock lk{PoolLock(pool_index)}; + std::lock_guard lock{pool_locks[pool_index]}; // TODO (bunnei): Support multiple managers Impl& chosen_manager{managers[pool_index]}; diff --git a/src/core/hle/kernel/memory/memory_manager.h b/src/core/hle/kernel/memory/memory_manager.h index d9f16d15e..3cf444857 100755 --- a/src/core/hle/kernel/memory/memory_manager.h +++ b/src/core/hle/kernel/memory/memory_manager.h @@ -7,16 +7,10 @@ #include #include -#include "common/assert.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/result.h" -namespace Kernel { -class KernelCore; -} - namespace Kernel::Memory { class PageLinkedList; @@ -43,7 +37,7 @@ public: Mask = (0xF << Shift), }; - MemoryManager(KernelCore& kernel); + MemoryManager() = default; constexpr std::size_t GetSize(Pool pool) const { return managers[static_cast(pool)].GetSize(); @@ -95,24 +89,7 @@ private: }; private: - KLightLock pool_lock_0; - 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(Pool::Count)> pool_locks; std::array managers; }; diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 5aa08c654..080886554 100755 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp @@ -57,7 +57,7 @@ constexpr std::size_t GetSizeInRange(const MemoryInfo& info, VAddr start, VAddr } // 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, 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, MemoryPermission perm) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; if (!size) { 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; std::size_t mapped_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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; const VAddr end_addr{addr + size}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; const VAddr end_addr{addr + size}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; MemoryState src_state{}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; MemoryState src_state{}; 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, 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 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; MemoryState prev_state{}; MemoryPermission prev_perm{}; @@ -688,7 +688,7 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo } MemoryInfo PageTable::QueryInfoImpl(VAddr addr) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; MemoryState state{}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; 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, MemoryAttribute value) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; MemoryState state{}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; heap_capacity = new_heap_capacity; return RESULT_SUCCESS; } @@ -777,7 +777,7 @@ ResultVal PageTable::SetHeapSize(std::size_t size) { // Increase the heap size { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; const u64 delta{size - previous_heap_size}; @@ -813,7 +813,7 @@ ResultVal PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s bool is_map_only, VAddr region_start, std::size_t region_num_pages, MemoryState state, 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)) { return ERR_INVALID_ADDRESS_STATE; @@ -844,7 +844,7 @@ ResultVal PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s } ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; MemoryPermission perm{}; 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) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; MemoryPermission perm{}; 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, OperationType operation) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; ASSERT(Common::IsAligned(addr, PageSize)); 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, OperationType operation, PAddr map_addr) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; ASSERT(num_pages > 0); ASSERT(Common::IsAligned(addr, PageSize)); @@ -1123,7 +1123,7 @@ ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission* MemoryPermission perm_mask, MemoryPermission perm, MemoryAttribute attr_mask, MemoryAttribute attr, MemoryAttribute ignore_attr) { - KScopedLightLock lk{general_lock}; + std::lock_guard lock{page_table_lock}; // Get information about the first block const VAddr last_addr{addr + size - 1}; diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/memory/page_table.h index 2e91837ac..ce0d38849 100755 --- a/src/core/hle/kernel/memory/page_table.h +++ b/src/core/hle/kernel/memory/page_table.h @@ -111,7 +111,7 @@ private: perm, attr_mask, attr, ignore_attr); } - KLightLock general_lock; + std::recursive_mutex page_table_lock; std::unique_ptr block_manager; public: diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index be7fcb5fb..27124ef67 100755 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -61,8 +61,6 @@ public: */ bool IsWaitable() const; - virtual void Finalize() = 0; - protected: /// The kernel instance this object was created under. KernelCore& kernel; diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 9f4583b49..37b77fa6e 100755 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -16,13 +16,13 @@ #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/errors.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/memory/memory_block_manager.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/memory/slab_heap.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" +#include "core/hle/kernel/thread.h" #include "core/hle/lock.h" #include "core/memory.h" #include "core/settings.h" @@ -38,10 +38,11 @@ namespace { */ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); - auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, - owner_process.GetIdealCoreId(), stack_top, &owner_process); + ThreadType type = THREADTYPE_USER; + auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0, + owner_process.GetIdealCore(), stack_top, &owner_process); - std::shared_ptr thread = std::move(thread_res).Unwrap(); + std::shared_ptr thread = std::move(thread_res).Unwrap(); // Register 1 must be a handle to the main thread const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); @@ -136,23 +137,6 @@ std::shared_ptr Process::GetResourceLimit() const { 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 { const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) + page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + @@ -178,66 +162,11 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); } -bool Process::ReleaseUserException(KThread* 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(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) { +void Process::RegisterThread(const Thread* thread) { thread_list.push_back(thread); } -void Process::UnregisterThread(const KThread* thread) { +void Process::UnregisterThread(const Thread* thread) { thread_list.remove(thread); } @@ -338,7 +267,7 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { void Process::PrepareForTermination() { ChangeStatus(ProcessStatus::Exiting); - const auto stop_threads = [this](const std::vector>& thread_list) { + const auto stop_threads = [this](const std::vector>& thread_list) { for (auto& thread : thread_list) { if (thread->GetOwnerProcess() != this) continue; @@ -350,7 +279,7 @@ void Process::PrepareForTermination() { ASSERT_MSG(thread->GetState() == ThreadState::Waiting, "Exiting processes with non-waiting threads is currently unimplemented"); - thread->Exit(); + thread->Stop(); } }; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 31d0142d8..564e1f27d 100755 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -30,7 +30,7 @@ namespace Kernel { class KernelCore; class ResourceLimit; -class KThread; +class Thread; class TLSPage; struct CodeSet; @@ -173,15 +173,10 @@ public: std::shared_ptr GetResourceLimit() const; /// Gets the ideal CPU core ID for this process - u8 GetIdealCoreId() const { + u8 GetIdealCore() const { 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. u64 GetCoreMask() const { return capabilities.GetCoreMask(); @@ -217,14 +212,6 @@ public: 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. u64 GetCPUTimeTicks() const { return total_process_running_time_ticks; @@ -245,33 +232,6 @@ public: ++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(Core::Hardware::NUM_CPU_CORES)); - return pinned_threads[core_id]; - } - /// Gets 8 bytes of random data for svcGetInfo RandomEntropy u64 GetRandomEntropy(std::size_t index) const { return random_entropy.at(index); @@ -292,17 +252,17 @@ public: u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const; /// Gets the list of all threads created with this process as their owner. - const std::list& GetThreadList() const { + const std::list& GetThreadList() const { return thread_list; } /// Registers a thread as being created under this process, /// 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 /// 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. /// @@ -343,11 +303,6 @@ public: bool IsSignaled() const override; - void Finalize() override{}; - - void PinCurrentThread(); - void UnpinCurrentThread(); - /////////////////////////////////////////////////////////////////////////////////////////////// // Thread-local storage management @@ -358,20 +313,6 @@ public: void FreeTLSRegion(VAddr tls_address); private: - void PinThread(s32 core_id, KThread* thread) { - ASSERT(0 <= core_id && core_id < static_cast(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(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 /// from the current process status, then this will trigger /// a process signal. @@ -439,7 +380,7 @@ private: std::array random_entropy{}; /// List of threads that are running with this process as their owner. - std::list thread_list; + std::list thread_list; /// Address of the top of the main thread's stack VAddr main_thread_stack_top{}; @@ -460,17 +401,6 @@ private: s64 schedule_count{}; bool is_signaled{}; - bool is_suspended{}; - - std::atomic num_created_threads{}; - std::atomic num_threads{}; - u16 peak_num_threads{}; - - std::array running_threads{}; - std::array running_thread_idle_counts{}; - std::array pinned_threads{}; - - KThread* exception_thread{}; /// System context Core::System& system; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 596d01479..99ed0857e 100755 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -7,10 +7,10 @@ #include "common/logging/log.h" #include "core/hle/kernel/errors.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/object.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" namespace Kernel { diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index 56a7a5766..34e477274 100755 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h @@ -47,8 +47,6 @@ public: bool IsSignaled() const override; - void Finalize() override{}; - private: explicit ReadableEvent(KernelCore& kernel); diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 464d4f2a6..936cc4d0f 100755 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -85,8 +85,6 @@ public: */ ResultCode SetLimitValue(ResourceType resource, s64 value); - void Finalize() override {} - private: // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create // functions diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index fe7a483c4..82857f93b 100755 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -6,10 +6,10 @@ #include "common/assert.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/errors.h" -#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/thread.h" namespace Kernel { diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index b42c6a458..6470df993 100755 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -81,8 +81,6 @@ public: bool IsSignaled() const override; - void Finalize() override{}; - private: /// ServerSessions waiting to be accepted by the port std::vector> pending_sessions; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 790dbb998..4f2bb7822 100755 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -15,11 +15,11 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.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/process.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" +#include "core/hle/kernel/thread.h" #include "core/memory.h" namespace Kernel { @@ -116,7 +116,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con return RESULT_SUCCESS; } -ResultCode ServerSession::QueueSyncRequest(std::shared_ptr thread, +ResultCode ServerSession::QueueSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory) { u32* cmd_buf{reinterpret_cast(memory.GetPointer(thread->GetTLSAddress()))}; auto context = @@ -154,14 +154,14 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { KScopedSchedulerLock lock(kernel); if (!context.IsThreadWaiting()) { context.GetThread().Wakeup(); - context.GetThread().SetSyncedObject(nullptr, result); + context.GetThread().SetSynchronizationResults(nullptr, result); } } return result; } -ResultCode ServerSession::HandleSyncRequest(std::shared_ptr thread, +ResultCode ServerSession::HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing) { return QueueSyncRequest(std::move(thread), memory); diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 47ef9e290..9155cf7f5 100755 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -29,7 +29,7 @@ class HLERequestContext; class KernelCore; class Session; class SessionRequestHandler; -class KThread; +class Thread; /** * 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. */ - ResultCode HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, + ResultCode HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing); /// Called when a client disconnection occurs. @@ -126,11 +126,9 @@ public: bool IsSignaled() const override; - void Finalize() override{}; - private: /// Queues a sync request from the emulated application. - ResultCode QueueSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory); + ResultCode QueueSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory); /// Completes a sync request from the emulated application. 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 /// 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. - std::vector> pending_requesting_threads; + std::vector> pending_requesting_threads; /// Thread whose request is currently being handled. A request is considered "handled" when a /// response is sent via svcReplyAndReceive. /// TODO(Subv): Find a better name for this. - std::shared_ptr currently_handling; + std::shared_ptr currently_handling; /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 75104d73e..f6dd2c1d2 100755 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -39,8 +39,6 @@ public: bool IsSignaled() const override; - void Finalize() override{}; - std::shared_ptr Client() { if (auto result{client.lock()}) { return result; diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 623bd8b11..0ef87235c 100755 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -71,8 +71,6 @@ public: return device_memory.GetPointer(physical_address + offset); } - void Finalize() override {} - private: Core::DeviceMemory& device_memory; Process* owner_process{}; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4d96f0a3b..cc8b661af 100755 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -29,7 +29,6 @@ #include "core/hle/kernel/k_scheduler.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_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/memory_block.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_types.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/transfer_memory.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()); } - KSynchronizationObject* dummy{}; - return thread->GetWaitResult(std::addressof(dummy)); + return thread->GetSignalingResult(); } 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. -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); - // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + const std::shared_ptr thread = handle_table.Get(thread_handle); + 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. - *out_thread_id = thread->GetThreadID(); + *thread_id = thread->GetThreadID(); return RESULT_SUCCESS; } -static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low, - u32* out_thread_id_high, Handle thread_handle) { - u64 out_thread_id{}; - const ResultCode result{GetThreadId(system, &out_thread_id, thread_handle)}; +static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high, + Handle thread_handle) { + u64 thread_id{}; + const ResultCode result{GetThreadId(system, &thread_id, thread_handle)}; - *out_thread_id_low = static_cast(out_thread_id >> 32); - *out_thread_id_high = static_cast(out_thread_id & std::numeric_limits::max()); + *thread_id_low = static_cast(thread_id >> 32); + *thread_id_high = static_cast(thread_id & std::numeric_limits::max()); return result; } @@ -395,7 +395,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han return RESULT_SUCCESS; } - const std::shared_ptr thread = handle_table.Get(handle); + const std::shared_ptr thread = handle_table.Get(handle); if (thread) { const Process* const owner_process = thread->GetOwnerProcess(); 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) { LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); - // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - std::shared_ptr thread = handle_table.Get(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + std::shared_ptr thread = handle_table.Get(thread_handle); + 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->WaitCancel(); + thread->CancelWait(); return RESULT_SUCCESS; } @@ -628,7 +630,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { handle_debug_buffer(info1, info2); 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(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; } - const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get( + const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get( static_cast(handle)); if (!thread) { 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(); u64 out_ticks = 0; 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); } 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); } -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 -static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, - Svc::ThreadActivity thread_activity) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, - thread_activity); +static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); + if (activity > static_cast(ThreadActivity::Paused)) { + return ERR_INVALID_ENUM_VALUE; + } - // Validate the activity. - R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); + const auto* current_process = system.Kernel().CurrentProcess(); + const std::shared_ptr thread = current_process->GetHandleTable().Get(handle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); + return ERR_INVALID_HANDLE; + } - // Get the thread from its handle. - auto& kernel = system.Kernel(); - const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + 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; + } - // 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); + if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { + LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); + return ERR_BUSY; + } - // Set the activity. - R_TRY(thread->SetActivity(thread_activity)); - - return RESULT_SUCCESS; + return thread->SetActivity(static_cast(activity)); } -static ResultCode SetThreadActivity32(Core::System& system, Handle thread_handle, - Svc::ThreadActivity thread_activity) { - return SetThreadActivity(system, thread_handle, thread_activity); +static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { + return SetThreadActivity(system, handle, activity); } /// Gets the thread context -static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) { - LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, - thread_handle); +static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { + LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); - // Get the thread from its handle. const auto* current_process = system.Kernel().CurrentProcess(); - const std::shared_ptr thread = - current_process->GetHandleTable().Get(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + const std::shared_ptr thread = current_process->GetHandleTable().Get(handle); + if (!thread) { + 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. - R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); - R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), - Svc::ResultBusy); + 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; + } - // Get the thread context. - std::vector context; - R_TRY(thread->GetThreadContext3(context)); + if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) { + LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); + return ERR_BUSY; + } - // Copy the thread context to user space. - system.Memory().WriteBlock(out_context, context.data(), context.size()); + Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64(); + // 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; } -static ResultCode GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) { - return GetThreadContext(system, out_context, thread_handle); +static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { + return GetThreadContext(system, thread_context, handle); } /// 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"); - // Get the thread from its handle. const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + const std::shared_ptr thread = handle_table.Get(handle); + 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. - *out_priority = thread->GetPriority(); + *priority = thread->GetPriority(); return RESULT_SUCCESS; } -static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) { - return GetThreadPriority(system, out_priority, handle); +static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) { + return GetThreadPriority(system, priority, handle); } /// Sets the priority for the specified thread static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { LOG_TRACE(Kernel_SVC, "called"); - // Validate the priority. - R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, - Svc::ResultInvalidPriority); + if (priority > THREADPRIO_LOWEST) { + LOG_ERROR( + 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& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + const auto* const current_process = system.Kernel().CurrentProcess(); + + std::shared_ptr thread = current_process->GetHandleTable().Get(handle); + 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); + return RESULT_SUCCESS; } @@ -1416,47 +1438,62 @@ static void ExitProcess(Core::System& system) { current_process->PrepareForTermination(); // Kill the current thread - system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit(); + system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop(); } static void ExitProcess32(Core::System& system) { ExitProcess(system); } -static constexpr bool IsValidCoreId(int32_t core_id) { - return (0 <= core_id && core_id < static_cast(Core::Hardware::NUM_CPU_CORES)); -} - /// Creates a new thread 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, - "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, " - "priority=0x{:08X}, core_id=0x{:08X}", - entry_point, arg, stack_bottom, priority, core_id); + "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, " + "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", + entry_point, arg, stack_top, priority, processor_id, *out_handle); - // Adjust core id, if it's the default magic. - auto& kernel = system.Kernel(); - auto& process = *kernel.CurrentProcess(); - if (core_id == Svc::IdealCoreUseProcessValue) { - core_id = process.GetIdealCoreId(); + auto* const current_process = system.Kernel().CurrentProcess(); + + if (processor_id == THREADPROCESSORID_IDEAL) { + // Set the target CPU to the one specified by the process. + processor_id = current_process->GetIdealCore(); + ASSERT(processor_id != THREADPROCESSORID_IDEAL); } - // Validate arguments. - R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); - R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); + if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) { + LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id); + return ERR_INVALID_PROCESSOR_ID; + } - R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, - Svc::ResultInvalidPriority); - R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); + const u64 core_mask = current_process->GetCoreMask(); + if ((core_mask | (1ULL << processor_id)) != core_mask) { + LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id); + return ERR_INVALID_PROCESSOR_ID; + } + + if (priority > 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)); - CASCADE_RESULT(std::shared_ptr thread, - KThread::Create(system, ThreadType::User, "", entry_point, priority, arg, - core_id, stack_bottom, &process)); + ThreadType type = THREADTYPE_USER; + CASCADE_RESULT(std::shared_ptr thread, + 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()) { LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", 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) { 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 std::shared_ptr thread = handle_table.Get(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + const std::shared_ptr thread = handle_table.Get(thread_handle); + 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. - R_TRY(thread->Run()); + ASSERT(thread->GetState() == ThreadState::Initialized); - return RESULT_SUCCESS; + return thread->Start(); } 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(); system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); - current_thread->Exit(); + current_thread->Stop(); } static void ExitThread32(Core::System& system) { @@ -1510,30 +1549,34 @@ static void ExitThread32(Core::System& system) { /// Sleep the current thread static void SleepThread(Core::System& system, s64 nanoseconds) { - auto& kernel = system.Kernel(); - const auto yield_type = static_cast(nanoseconds); - LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); - // When the input tick is positive, sleep. - if (nanoseconds > 0) { - // Convert the timeout from nanoseconds to ticks. - // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... - s64 timeout{}; + enum class SleepType : s64 { + YieldWithoutCoreMigration = 0, + YieldWithCoreMigration = -1, + YieldAndWaitForLoadBalancing = -2, + }; - // Sleep. - // NOTE: Nintendo does not check the result of this sleep. - auto& scheduler = *system.Kernel().CurrentScheduler(); - static_cast(GetCurrentThread(kernel).Sleep(nanoseconds)); - } else if (yield_type == Svc::YieldType::WithoutCoreMigration) { - KScheduler::YieldWithoutCoreMigration(kernel); - } else if (yield_type == Svc::YieldType::WithCoreMigration) { - KScheduler::YieldWithCoreMigration(kernel); - } else if (yield_type == Svc::YieldType::ToAnyThread) { - KScheduler::YieldToAnyThread(kernel); + auto& scheduler = *system.Kernel().CurrentScheduler(); + if (nanoseconds <= 0) { + switch (static_cast(nanoseconds)) { + case SleepType::YieldWithoutCoreMigration: { + scheduler.YieldWithoutCoreMigration(); + break; + } + case SleepType::YieldWithCoreMigration: { + scheduler.YieldWithCoreMigration(); + break; + } + case SleepType::YieldAndWaitForLoadBalancing: { + scheduler.YieldToAnyThread(); + break; + } + default: + UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); + } } else { - // Nintendo does nothing at all if an otherwise invalid value is passed. - UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); + scheduler.GetCurrentThread()->Sleep(nanoseconds); } } @@ -1796,72 +1839,95 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u return CreateTransferMemory(system, handle, addr, size, permissions); } -static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, - u64* out_affinity_mask) { +static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, + u64* mask) { 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 std::shared_ptr thread = handle_table.Get(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + const std::shared_ptr thread = handle_table.Get(thread_handle); + 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. - R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); + *core = thread->GetIdealCore(); + *mask = thread->GetAffinityMask().GetAffinityMask(); return RESULT_SUCCESS; } -static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id, - u32* out_affinity_mask_low, u32* out_affinity_mask_high) { - u64 out_affinity_mask{}; - const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask); - *out_affinity_mask_high = static_cast(out_affinity_mask >> 32); - *out_affinity_mask_low = static_cast(out_affinity_mask); +static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, + u32* mask_low, u32* mask_high) { + u64 mask{}; + const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); + *mask_high = static_cast(mask >> 32); + *mask_low = static_cast(mask); 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) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}", - thread_handle, core_id, affinity_mask); + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", + 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_id == Svc::IdealCoreUseProcessValue) { - core_id = current_process.GetIdealCoreId(); - affinity_mask = (1ULL << core_id); + if (core == static_cast(THREADPROCESSORID_IDEAL)) { + const u8 ideal_cpu_core = current_process->GetIdealCore(); + + ASSERT(ideal_cpu_core != static_cast(THREADPROCESSORID_IDEAL)); + + // Set the target CPU to the ideal core specified by the process. + core = ideal_cpu_core; + affinity_mask = 1ULL << core; } else { - // Validate the affinity mask. - 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); + const u64 core_mask = current_process->GetCoreMask(); - // Validate the core id. - if (IsValidCoreId(core_id)) { - R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); - } else { - R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, - Svc::ResultInvalidCoreId); + if ((core_mask | affinity_mask) != core_mask) { + LOG_ERROR( + Kernel_SVC, + "Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})", + core_mask, affinity_mask); + return ERR_INVALID_PROCESSOR_ID; + } + + if (affinity_mask == 0) { + LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero."); + return ERR_INVALID_COMBINATION; + } + + if (core < Core::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(THREADPROCESSORID_DONT_CARE) && + core != static_cast(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 = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); - R_UNLESS(thread, Svc::ResultInvalidHandle); + const auto& handle_table = current_process->GetHandleTable(); + const std::shared_ptr thread = handle_table.Get(thread_handle); + if (!thread) { + LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", + thread_handle); + return ERR_INVALID_HANDLE; + } - // Set the core mask. - R_TRY(thread->SetCoreMask(core_id, affinity_mask)); - - return RESULT_SUCCESS; + return thread->SetCoreAndAffinityMask(core, affinity_mask); } -static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id, +static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, u32 affinity_mask_low, u32 affinity_mask_high) { 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) { @@ -2425,7 +2491,7 @@ void Call(Core::System& system, u32 immediate) { kernel.EnterSVCProfile(); auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); - thread->SetIsCallingSvc(); + thread->SetContinuousOnSVC(true); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); @@ -2441,7 +2507,7 @@ void Call(Core::System& system, u32 immediate) { kernel.ExitSVCProfile(); - if (!thread->IsCallingSvc()) { + if (!thread->IsContinuousOnSVC()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index 7b897fbce..78282f021 100755 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h @@ -8,18 +8,13 @@ namespace Kernel::Svc { -constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57}; constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; 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 ResultInvalidCombination{ErrorModule::Kernel, 116}; constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117}; constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118}; constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120}; -constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122}; constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index ec463b97c..d623f7a50 100755 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h @@ -77,22 +77,4 @@ enum class ArbitrationType : u32 { 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 diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 96afd544b..a32750ed7 100755 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -58,14 +58,6 @@ void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))).raw); } -// Used by SetThreadActivity -template -void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast(Param(system, 0)), - static_cast(Param(system, 1))) - .raw); -} - template void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0)), Param(system, 1), @@ -166,18 +158,9 @@ void SvcWrap64(Core::System& system) { .raw); } -// Used by SetThreadCoreMask -template +template void SvcWrap64(Core::System& system) { - FuncReturn(system, func(system, static_cast(Param(system, 0)), - static_cast(Param(system, 1)), Param(system, 2)) - .raw); -} - -// Used by GetThreadCoreMask -template -void SvcWrap64(Core::System& system) { - s32 param_1 = 0; + u32 param_1 = 0; u64 param_2 = 0; const ResultCode retval = func(system, static_cast(Param(system, 2)), ¶m_1, ¶m_2); @@ -490,35 +473,12 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } -// Used by GetThreadCoreMask32 -template -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 template void SvcWrap32(Core::System& system) { func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))); } -// Used by SetThreadActivity32 -template -void SvcWrap32(Core::System& system) { - const u32 retval = func(system, static_cast(Param(system, 0)), - static_cast(Param(system, 1))) - .raw; - FuncReturn(system, retval); -} - // Used by SetThreadPriority32 template void SvcWrap32(Core::System& system) { @@ -527,7 +487,7 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } -// Used by SetMemoryAttribute32 +// Used by SetThreadCoreMask32 template void SvcWrap32(Core::System& system) { const u32 retval = @@ -537,16 +497,6 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } -// Used by SetThreadCoreMask32 -template -void SvcWrap32(Core::System& system) { - const u32 retval = - func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), - static_cast(Param(system, 2)), static_cast(Param(system, 3))) - .raw; - FuncReturn(system, retval); -} - // Used by WaitProcessWideKeyAtomic32 template void SvcWrap32(Core::System& system) { diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index fd0630019..832edd629 100755 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -8,8 +8,8 @@ #include "core/core_timing_util.h" #include "core/hle/kernel/handle_table.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/thread.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -18,30 +18,50 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { time_manager_event_type = Core::Timing::CreateEvent( "Kernel::TimeManagerCallback", [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { - std::shared_ptr thread; + std::shared_ptr thread; { std::lock_guard lock{mutex}; - thread = SharedFrom(reinterpret_cast(thread_handle)); + const auto proper_handle = static_cast(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}; + event_handle = timetask->GetGlobalHandle(); if (nanoseconds > 0) { - ASSERT(thread); - ASSERT(thread->GetState() != ThreadState::Runnable); + ASSERT(timetask); + ASSERT(timetask->GetState() != ThreadState::Runnable); system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, - time_manager_event_type, - reinterpret_cast(thread)); + time_manager_event_type, event_handle); + } 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}; - system.CoreTiming().UnscheduleEvent(time_manager_event_type, - reinterpret_cast(thread)); + if (event_handle == InvalidHandle) { + 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 diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index 0d7f05f30..f39df39a0 100755 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -20,7 +20,7 @@ struct EventType; namespace Kernel { -class KThread; +class Thread; /** * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp @@ -31,14 +31,18 @@ public: explicit TimeManager(Core::System& system); /// 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 - void UnscheduleTimeEvent(KThread* thread); + void UnscheduleTimeEvent(Handle event_handle); + + void CancelTimeEvent(Thread* time_task); private: Core::System& system; std::shared_ptr time_manager_event_type; + std::unordered_map cancelled_events; std::mutex mutex; }; diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 777799d12..05e9f7464 100755 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h @@ -72,8 +72,6 @@ public: /// is closed. ResultCode Reset(); - void Finalize() override {} - private: /// The base address for the memory managed by this instance. VAddr base_address{}; diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp index 142212ee4..fc2f7c424 100755 --- a/src/core/hle/kernel/writable_event.cpp +++ b/src/core/hle/kernel/writable_event.cpp @@ -4,10 +4,10 @@ #include #include "common/assert.h" -#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" namespace Kernel { @@ -38,4 +38,8 @@ void WritableEvent::Clear() { readable->Clear(); } +bool WritableEvent::IsSignaled() const { + return readable->IsSignaled(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h index 467eb2c21..6189cf65c 100755 --- a/src/core/hle/kernel/writable_event.h +++ b/src/core/hle/kernel/writable_event.h @@ -46,8 +46,7 @@ public: void Signal(); void Clear(); - - void Finalize() override {} + bool IsSignaled() const; private: explicit WritableEvent(KernelCore& kernel); diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index a515fdc60..641bcadea 100755 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -8,9 +8,9 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" #include "core/hle/service/nfp/nfp.h" diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 1328b64d0..cc23b001c 100755 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -6,9 +6,9 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/interface.h" #include "core/hle/service/nvdrv/nvdata.h" diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 1da56bc27..ff2a5b1db 100755 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -11,10 +11,10 @@ #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.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/process.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/am/am.h" #include "core/hle/service/aoc/aoc_u.h" diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 7bdfea6a9..2b824059d 100755 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -13,7 +13,7 @@ #include "common/microprofile.h" #include "common/thread.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/sockets_translate.h" #include "core/network/network.h" diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 18629dd7e..abc753d5d 100755 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -121,7 +121,7 @@ private: }; 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) { auto& time_manager{system.GetTimeManager()}; diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 4154c7ee9..975a8ae5b 100755 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -39,7 +39,7 @@ public: private: ResultCode GetClockSnapshotFromSystemClockContextInternal( - Kernel::KThread* thread, Clock::SystemClockContext user_context, + Kernel::Thread* thread, Clock::SystemClockContext user_context, Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& cloc_snapshot); diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h index e0c3e63da..5976b2046 100755 --- a/src/core/hle/service/time/time_sharedmemory.h +++ b/src/core/hle/service/time/time_sharedmemory.h @@ -6,8 +6,8 @@ #include "common/common_types.h" #include "common/uuid.h" -#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" #include "core/hle/service/time/clock_types.h" namespace Service::Time { diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index f3de2c428..968cd16b6 100755 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -18,8 +18,8 @@ #include "common/swap.h" #include "core/core_timing.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/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/nvdrv.h" diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index f976d0a9c..ccf8cc153 100755 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -15,9 +15,9 @@ #include "core/file_sys/romfs_factory.h" #include "core/file_sys/vfs_offset.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/process.h" +#include "core/hle/kernel/thread.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/nro.h" #include "core/loader/nso.h" @@ -219,8 +219,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::Sy } is_loaded = true; - return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, - Core::Memory::DEFAULT_STACK_SIZE}}; + return {ResultStatus::Success, + LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}}; } ResultStatus AppLoader_NRO::ReadIcon(std::vector& buffer) { diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index ea347ea83..95b6f339a 100755 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -15,9 +15,9 @@ #include "core/core.h" #include "core/file_sys/patch_manager.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/process.h" +#include "core/hle/kernel/thread.h" #include "core/loader/nso.h" #include "core/memory.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); is_loaded = true; - return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, - Core::Memory::DEFAULT_STACK_SIZE}}; + return {ResultStatus::Success, + LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}}; } ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) { diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index c96255871..e165a6987 100755 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1334,7 +1334,10 @@ private: } if (const auto comment = std::get_if(&*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 {}; } diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index cbec692f9..a93b5d3c2 100755 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -15,11 +15,10 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_scheduler.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/readable_event.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" namespace { @@ -91,10 +90,12 @@ std::size_t WaitTreeItem::Row() const { std::vector> WaitTreeItem::MakeThreadItemList() { std::vector> item_list; std::size_t row = 0; - auto add_threads = [&](const std::vector>& threads) { + auto add_threads = [&](const std::vector>& threads) { for (std::size_t i = 0; i < threads.size(); ++i) { - item_list.push_back(std::make_unique(*threads[i])); - item_list.back()->row = row; + if (!threads[i]->IsHLEThread()) { + item_list.push_back(std::make_unique(*threads[i])); + item_list.back()->row = row; + } ++row; } }; @@ -116,7 +117,7 @@ WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTa : mutex_address(mutex_address) { mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address); owner_handle = static_cast(mutex_value & Kernel::Svc::HandleWaitMask); - owner = handle_table.Get(owner_handle); + owner = handle_table.Get(owner_handle); } WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; @@ -138,7 +139,7 @@ std::vector> WaitTreeMutexInfo::GetChildren() cons return list; } -WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread) : thread(thread) {} +WaitTreeCallstack::WaitTreeCallstack(const Kernel::Thread& thread) : thread(thread) {} WaitTreeCallstack::~WaitTreeCallstack() = default; QString WaitTreeCallstack::GetText() const { @@ -148,6 +149,10 @@ QString WaitTreeCallstack::GetText() const { std::vector> WaitTreeCallstack::GetChildren() const { std::vector> list; + if (thread.IsHLEThread()) { + return list; + } + if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) { return list; } @@ -189,7 +194,7 @@ std::unique_ptr WaitTreeSynchronizationObject::ma case Kernel::HandleType::ReadableEvent: return std::make_unique(static_cast(object)); case Kernel::HandleType::Thread: - return std::make_unique(static_cast(object)); + return std::make_unique(static_cast(object)); default: return std::make_unique(object); } @@ -226,17 +231,21 @@ std::vector> WaitTreeObjectList::GetChildren() con return list; } -WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread) +WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) : WaitTreeSynchronizationObject(thread) {} WaitTreeThread::~WaitTreeThread() = default; QString WaitTreeThread::GetText() const { - const auto& thread = static_cast(object); + const auto& thread = static_cast(object); QString status; switch (thread.GetState()) { case Kernel::ThreadState::Runnable: - if (!thread.IsSuspended()) { - status = tr("runnable"); + if (!thread.IsPaused()) { + if (thread.WasRunning()) { + status = tr("running"); + } else { + status = tr("ready"); + } } else { status = tr("paused"); } @@ -288,11 +297,15 @@ QString WaitTreeThread::GetText() const { QColor WaitTreeThread::GetColor() const { const std::size_t color_index = IsDarkTheme() ? 1 : 0; - const auto& thread = static_cast(object); + const auto& thread = static_cast(object); switch (thread.GetState()) { case Kernel::ThreadState::Runnable: - if (!thread.IsSuspended()) { - return QColor(WaitTreeColors[0][color_index]); + if (!thread.IsPaused()) { + if (thread.WasRunning()) { + return QColor(WaitTreeColors[0][color_index]); + } else { + return QColor(WaitTreeColors[1][color_index]); + } } else { return QColor(WaitTreeColors[2][color_index]); } @@ -323,21 +336,27 @@ QColor WaitTreeThread::GetColor() const { std::vector> WaitTreeThread::GetChildren() const { std::vector> list(WaitTreeSynchronizationObject::GetChildren()); - const auto& thread = static_cast(object); + const auto& thread = static_cast(object); QString processor; - switch (thread.GetActiveCore()) { - case Kernel::Svc::IdealCoreUseProcessValue: + switch (thread.GetProcessorID()) { + case Kernel::ThreadProcessorId::THREADPROCESSORID_IDEAL: processor = tr("ideal"); 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: - processor = tr("core %1").arg(thread.GetActiveCore()); + processor = tr("Unknown processor %1").arg(thread.GetProcessorID()); break; } list.push_back(std::make_unique(tr("processor = %1").arg(processor))); - list.push_back(std::make_unique( - tr("ideal core = %1").arg(thread.GetIdealCoreForDebugging()))); + list.push_back( + std::make_unique(tr("ideal core = %1").arg(thread.GetIdealCore()))); list.push_back(std::make_unique( tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask()))); list.push_back(std::make_unique(tr("thread id = %1").arg(thread.GetThreadID()))); @@ -371,7 +390,7 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeSynchronizationObject(object) {} WaitTreeEvent::~WaitTreeEvent() = default; -WaitTreeThreadList::WaitTreeThreadList(const std::vector& list) +WaitTreeThreadList::WaitTreeThreadList(const std::vector& list) : thread_list(list) {} WaitTreeThreadList::~WaitTreeThreadList() = default; diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index b202c5567..cf96911ea 100755 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h @@ -19,8 +19,8 @@ class EmuThread; namespace Kernel { class HandleTable; class KSynchronizationObject; -class KThread; class ReadableEvent; +class Thread; } // namespace Kernel class WaitTreeThread; @@ -83,20 +83,20 @@ private: VAddr mutex_address; u32 mutex_value; Kernel::Handle owner_handle; - std::shared_ptr owner; + std::shared_ptr owner; }; class WaitTreeCallstack : public WaitTreeExpandableItem { Q_OBJECT public: - explicit WaitTreeCallstack(const Kernel::KThread& thread); + explicit WaitTreeCallstack(const Kernel::Thread& thread); ~WaitTreeCallstack() override; QString GetText() const override; std::vector> GetChildren() const override; private: - const Kernel::KThread& thread; + const Kernel::Thread& thread; }; class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { @@ -131,7 +131,7 @@ private: class WaitTreeThread : public WaitTreeSynchronizationObject { Q_OBJECT public: - explicit WaitTreeThread(const Kernel::KThread& thread); + explicit WaitTreeThread(const Kernel::Thread& thread); ~WaitTreeThread() override; QString GetText() const override; @@ -149,14 +149,14 @@ public: class WaitTreeThreadList : public WaitTreeExpandableItem { Q_OBJECT public: - explicit WaitTreeThreadList(const std::vector& list); + explicit WaitTreeThreadList(const std::vector& list); ~WaitTreeThreadList() override; QString GetText() const override; std::vector> GetChildren() const override; private: - const std::vector& thread_list; + const std::vector& thread_list; }; class WaitTreeModel : public QAbstractItemModel {