From c0d3aef28c0a0c68c18de30228f29e30f0e52533 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 30 Dec 2020 23:01:08 -0800 Subject: core: hle: kernel: Rename Thread to KThread. --- src/core/hle/kernel/client_session.cpp | 4 +- src/core/hle/kernel/client_session.h | 4 +- src/core/hle/kernel/global_scheduler_context.cpp | 4 +- src/core/hle/kernel/global_scheduler_context.h | 12 +- src/core/hle/kernel/handle_table.cpp | 2 +- src/core/hle/kernel/hle_ipc.cpp | 6 +- src/core/hle/kernel/hle_ipc.h | 14 +- src/core/hle/kernel/k_address_arbiter.cpp | 12 +- src/core/hle/kernel/k_condition_variable.cpp | 34 +- 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 | 70 +- src/core/hle/kernel/k_scheduler.h | 24 +- .../hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 6 +- src/core/hle/kernel/k_synchronization_object.cpp | 10 +- src/core/hle/kernel/k_synchronization_object.h | 6 +- src/core/hle/kernel/k_thread.cpp | 460 ++++++++++++ src/core/hle/kernel/k_thread.h | 781 ++++++++++++++++++++ src/core/hle/kernel/kernel.cpp | 14 +- src/core/hle/kernel/kernel.h | 6 +- src/core/hle/kernel/process.cpp | 14 +- src/core/hle/kernel/process.h | 10 +- src/core/hle/kernel/readable_event.cpp | 2 +- src/core/hle/kernel/server_port.cpp | 2 +- src/core/hle/kernel/server_session.cpp | 6 +- src/core/hle/kernel/server_session.h | 10 +- src/core/hle/kernel/svc.cpp | 30 +- src/core/hle/kernel/thread.cpp | 460 ------------ src/core/hle/kernel/thread.h | 782 --------------------- src/core/hle/kernel/time_manager.cpp | 8 +- src/core/hle/kernel/time_manager.h | 6 +- src/core/hle/kernel/writable_event.cpp | 2 +- 32 files changed, 1407 insertions(+), 1408 deletions(-) create mode 100644 src/core/hle/kernel/k_thread.cpp create mode 100644 src/core/hle/kernel/k_thread.h delete mode 100644 src/core/hle/kernel/thread.cpp delete mode 100644 src/core/hle/kernel/thread.h (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index e8e52900d..a2be1a8f6 100644 --- 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 d5c9ebee8..a914c0990 100644 --- 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 Thread; +class KThread; class ClientSession final : public KSynchronizationObject { public: @@ -46,7 +46,7 @@ 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; diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index a133e8ed0..c6838649f 100644 --- 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 5c7b89290..a365ffdaf 100644 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -12,7 +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/thread.h" +#include "core/hle/kernel/k_thread.h" namespace Kernel { @@ -20,7 +20,7 @@ class KernelCore; class SchedulerLock; using KSchedulerPriorityQueue = - KPriorityQueue; + KPriorityQueue; constexpr s32 HighestCoreMigrationAllowedPriority = 2; class GlobalSchedulerContext final { @@ -33,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; } @@ -74,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 40988b0fd..10a4e0510 100644 --- 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 { diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index a419f9602..c7b10ca7a 100644 --- 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(Thread& thread) { +ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& 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 698f607e6..b8a746882 100644 --- 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 Thread; +class KThread; 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. @@ -127,14 +127,14 @@ public: } using WakeupCallback = std::function thread, HLERequestContext& context, ThreadWakeupReason reason)>; + std::shared_ptr 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(Thread& thread); + ResultCode WriteToOutgoingCommandBuffer(KThread& thread); u32_le GetCommand() const { return command; @@ -267,11 +267,11 @@ public: std::string Description() const; - Thread& GetThread() { + KThread& GetThread() { return *thread; } - const Thread& GetThread() const { + const KThread& GetThread() const { return *thread; } @@ -286,7 +286,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 d9e702f13..282f02257 100644 --- 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)) { - Thread* target_thread = std::addressof(*it); + KThread* 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)) { - Thread* target_thread = std::addressof(*it); + KThread* 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)) { - Thread* target_thread = std::addressof(*it); + KThread* target_thread = std::addressof(*it); target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); ASSERT(target_thread->IsWaitingForAddressArbiter()); @@ -231,7 +231,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { // Prepare to wait. - Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); Handle timer = InvalidHandle; { @@ -302,7 +302,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { // Prepare to wait. - Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); Handle timer = InvalidHandle; { diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 49a068310..2fa2d5289 100644 --- 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) { - Thread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread(); // Signal the address. { @@ -74,7 +74,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { // Remove waiter thread. s32 num_waiters{}; - Thread* next_owner_thread = + KThread* 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) { - Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* 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); - Thread* owner_thread = cur_thread->GetLockOwner(); + KThread* 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)); } -Thread* KConditionVariable::SignalImpl(Thread* thread) { +KThread* KConditionVariable::SignalImpl(KThread* thread) { // Check pre-conditions. ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -174,7 +174,7 @@ Thread* KConditionVariable::SignalImpl(Thread* thread) { } } - Thread* thread_to_close = nullptr; + KThread* 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 @@ Thread* KConditionVariable::SignalImpl(Thread* 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)) { - Thread* target_thread = std::addressof(*it); + KThread* target_thread = std::addressof(*it); - if (Thread* thread = SignalImpl(target_thread); thread != nullptr) { + if (KThread* thread = SignalImpl(target_thread); thread != nullptr) { if (num_to_close < MaxThreads) { thread_array[num_to_close++] = thread; } else { @@ -257,7 +257,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { // Prepare to wait. - Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); Handle timer = InvalidHandle; { @@ -276,7 +276,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { // Remove waiter thread. s32 num_waiters{}; - Thread* next_owner_thread = + KThread* next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr); // Update for the next owner thread. @@ -331,7 +331,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { KScopedSchedulerLock sl(kernel); - if (Thread* owner = cur_thread->GetLockOwner(); owner != nullptr) { + if (KThread* 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 98ed5b323..861dbd420 100644 --- 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 Thread::ConditionVariableThreadTreeType; + using ThreadTree = typename KThread::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]] Thread* SignalImpl(Thread* thread); + [[nodiscard]] KThread* SignalImpl(KThread* thread); ThreadTree thread_tree; @@ -43,14 +43,14 @@ private: }; inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, - Thread* thread) { + KThread* thread) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); tree->erase(tree->iterator_to(*thread)); } inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, - Thread* thread) { + KThread* 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 0dc929040..13d628b85 100644 --- 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 Thread; +class KThread; 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 Thread* MoveToScheduledBack(Member* member) { + constexpr KThread* 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 12b5619fb..0f7a541c8 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -17,15 +17,15 @@ #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::Thread* thread) { +static void IncrementScheduledCount(Kernel::KThread* thread) { if (auto process = thread->GetOwnerProcess(); process) { process->IncrementScheduledCount(); } @@ -56,9 +56,9 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul } } -u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) { +u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { std::scoped_lock lock{guard}; - if (Thread* prev_highest_thread = this->state.highest_priority_thread; + if (KThread* prev_highest_thread = this->state.highest_priority_thread; prev_highest_thread != highest_thread) { if (prev_highest_thread != nullptr) { IncrementScheduledCount(prev_highest_thread); @@ -90,13 +90,13 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { ClearSchedulerUpdateNeeded(kernel); u64 cores_needing_scheduling = 0, idle_cores = 0; - Thread* top_threads[Core::Hardware::NUM_CPU_CORES]; + KThread* 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++) { - Thread* top_thread = priority_queue.GetScheduledFront(static_cast(core_id)); + KThread* 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. // TODO(bunnei): Implement thread pinning @@ -112,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 (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { + if (KThread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; size_t num_candidates = 0; @@ -120,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 (Thread* top_thread = + if (KThread* 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. @@ -152,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 (Thread* next_on_candidate_core = + if (KThread* 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 @@ -182,7 +182,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { return cores_needing_scheduling; } -void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state) { +void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Check if the state has changed, because if it hasn't there's nothing to do. @@ -205,7 +205,7 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, Thread } } -void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority) { +void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // If the thread is runnable, we want to change its priority in the queue. @@ -217,7 +217,7 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 } } -void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, +void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread, const KAffinityMask& old_affinity, s32 old_core) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -237,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. - Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority); - Thread* next_thread = nullptr; + KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority); + KThread* next_thread = nullptr; if (top_thread != nullptr) { next_thread = priority_queue.MoveToScheduledBack(top_thread); if (next_thread != top_thread) { @@ -249,11 +249,11 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { // While we have a suggested thread, try to migrate it! { - Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority); + KThread* 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 (Thread* top_on_suggested_core = + if (KThread* top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { @@ -285,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. { - Thread* best_thread = priority_queue.GetScheduledFront(core_id); + KThread* best_thread = priority_queue.GetScheduledFront(core_id); if (best_thread == GetCurrentThread()) { best_thread = priority_queue.GetScheduledNext(core_id, best_thread); } @@ -293,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) { - Thread* suggested = priority_queue.GetSuggestedFront(core_id); + KThread* 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()) { @@ -302,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 (Thread* top_on_suggested_core = + if (KThread* top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { @@ -380,7 +380,7 @@ void KScheduler::YieldWithoutCoreMigration() { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - Thread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -398,7 +398,7 @@ void KScheduler::YieldWithoutCoreMigration() { const auto cur_state = cur_thread.GetRawState(); if (cur_state == ThreadState::Runnable) { // Put the current thread at the back of the queue. - Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); + KThread* 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. @@ -421,7 +421,7 @@ void KScheduler::YieldWithCoreMigration() { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - Thread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -442,17 +442,17 @@ void KScheduler::YieldWithCoreMigration() { const s32 core_id = cur_thread.GetActiveCore(); // Put the current thread at the back of the queue. - Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); + KThread* 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; - Thread* suggested = priority_queue.GetSuggestedFront(core_id); + KThread* 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 (Thread* running_on_suggested_core = + if (KThread* running_on_suggested_core = (suggested_core >= 0) ? kernel.Scheduler(suggested_core).state.highest_priority_thread : nullptr; @@ -511,7 +511,7 @@ void KScheduler::YieldToAnyThread() { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - Thread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -539,11 +539,11 @@ void KScheduler::YieldToAnyThread() { // 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! - Thread* suggested = priority_queue.GetSuggestedFront(core_id); + KThread* 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 (Thread* top_on_suggested_core = + if (KThread* top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { @@ -594,7 +594,7 @@ KScheduler::KScheduler(Core::System& system, std::size_t core_id) KScheduler::~KScheduler() = default; -Thread* KScheduler::GetCurrentThread() const { +KThread* KScheduler::GetCurrentThread() const { if (current_thread) { return current_thread; } @@ -624,7 +624,7 @@ void KScheduler::OnThreadStart() { SwitchContextStep2(); } -void KScheduler::Unload(Thread* thread) { +void KScheduler::Unload(KThread* thread) { if (thread) { thread->SetIsRunning(false); if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) { @@ -643,7 +643,7 @@ void KScheduler::Unload(Thread* thread) { } } -void KScheduler::Reload(Thread* thread) { +void KScheduler::Reload(KThread* thread) { if (thread) { ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); @@ -674,7 +674,7 @@ void KScheduler::SwitchContextStep2() { } void KScheduler::ScheduleImpl() { - Thread* previous_thread = current_thread; + KThread* previous_thread = current_thread; current_thread = state.highest_priority_thread; this->state.needs_scheduling = false; @@ -744,7 +744,7 @@ void KScheduler::SwitchToCurrent() { } } -void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { +void KScheduler::UpdateLastContextSwitchTime(KThread* 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; @@ -765,8 +765,8 @@ void KScheduler::Initialize() { std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); 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); + auto thread_res = KThread::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(); { diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 783665123..157373934 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -29,7 +29,7 @@ namespace Kernel { class KernelCore; class Process; class SchedulerLock; -class Thread; +class KThread; class KScheduler final { public: @@ -45,13 +45,13 @@ public: /// The next two are for SingleCore Only. /// Unload current thread before preempting core. - void Unload(Thread* thread); + void Unload(KThread* thread); /// Reload current thread after core preemption. - void Reload(Thread* thread); + void Reload(KThread* thread); /// Gets the current running thread - [[nodiscard]] Thread* GetCurrentThread() const; + [[nodiscard]] KThread* GetCurrentThread() const; /// Gets the timestamp for the last context switch in ticks. [[nodiscard]] u64 GetLastContextSwitchTicks() const; @@ -72,7 +72,7 @@ public: return switch_fiber; } - [[nodiscard]] u64 UpdateHighestPriorityThread(Thread* highest_thread); + [[nodiscard]] u64 UpdateHighestPriorityThread(KThread* highest_thread); /** * Takes a thread and moves it to the back of the it's priority list. @@ -100,13 +100,13 @@ public: void YieldToAnyThread(); /// Notify the scheduler a thread's status has changed. - static void OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state); + static void OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state); /// Notify the scheduler a thread's priority has changed. - static void OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority); + static void OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority); /// Notify the scheduler a thread's core and/or affinity mask has changed. - static void OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, + static void OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread, const KAffinityMask& old_affinity, s32 old_core); static bool CanSchedule(KernelCore& kernel); @@ -163,13 +163,13 @@ private: * most recent tick count retrieved. No special arithmetic is * applied to it. */ - void UpdateLastContextSwitchTime(Thread* thread, Process* process); + void UpdateLastContextSwitchTime(KThread* thread, Process* process); static void OnSwitch(void* this_scheduler); void SwitchToCurrent(); - Thread* current_thread{}; - Thread* idle_thread{}; + KThread* current_thread{}; + KThread* idle_thread{}; std::shared_ptr switch_fiber{}; @@ -178,7 +178,7 @@ private: bool interrupt_task_thread_runnable{}; bool should_count_idle{}; u64 idle_count{}; - Thread* highest_priority_thread{}; + KThread* highest_priority_thread{}; void* idle_thread_stack{}; }; 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 2bb3817fa..fac39aeb7 100644 --- 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,15 +9,15 @@ #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, Handle& event_handle, Thread* t, + explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, KThread* t, s64 timeout) : kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) { event_handle = InvalidHandle; @@ -43,7 +43,7 @@ public: private: KernelCore& kernel; Handle& event_handle; - Thread* thread{}; + KThread* 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 1c508cb55..61432fef8 100644 --- 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,7 +20,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, std::vector thread_nodes(num_objects); // Prepare for wait. - Thread* thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* thread = kernel.CurrentScheduler()->GetCurrentThread(); Handle timer = InvalidHandle; { @@ -148,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) { - Thread* thread = cur_node->thread; + KThread* thread = cur_node->thread; if (thread->GetState() == ThreadState::Waiting) { thread->SetSyncedObject(this, result); thread->SetState(ThreadState::Runnable); @@ -156,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 14d80ebf1..f65c71c28 100644 --- 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 Thread; +class KThread; /// Class that represents a Kernel object that a thread can be waiting on class KSynchronizationObject : public Object { public: struct ThreadListNode { ThreadListNode* next{}; - Thread* thread{}; + KThread* 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/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp new file mode 100644 index 000000000..1ec29636c --- /dev/null +++ b/src/core/hle/kernel/k_thread.cpp @@ -0,0 +1,460 @@ +// Copyright 2014 Citra Emulator Project / PPSSPP Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include + +#include "common/assert.h" +#include "common/common_types.h" +#include "common/fiber.h" +#include "common/logging/log.h" +#include "common/thread_queue_list.h" +#include "core/core.h" +#include "core/cpu_manager.h" +#include "core/hardware_properties.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_condition_variable.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/memory/memory_layout.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/time_manager.h" +#include "core/hle/result.h" +#include "core/memory.h" + +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif + +namespace Kernel { + +bool KThread::IsSignaled() const { + return signaled; +} + +KThread::KThread(KernelCore& kernel) : KSynchronizationObject{kernel} {} +KThread::~KThread() = default; + +void KThread::Stop() { + { + KScopedSchedulerLock lock(kernel); + SetState(ThreadState::Terminated); + signaled = true; + NotifyAvailable(); + kernel.GlobalHandleTable().Close(global_handle); + + if (owner_process) { + owner_process->UnregisterThread(this); + + // Mark the TLS slot in the thread's page as free. + owner_process->FreeTLSRegion(tls_address); + } + has_exited = true; + } + global_handle = 0; +} + +void KThread::Wakeup() { + KScopedSchedulerLock lock(kernel); + SetState(ThreadState::Runnable); +} + +ResultCode KThread::Start() { + KScopedSchedulerLock lock(kernel); + SetState(ThreadState::Runnable); + return RESULT_SUCCESS; +} + +void KThread::CancelWait() { + KScopedSchedulerLock lock(kernel); + if (GetState() != ThreadState::Waiting || !is_cancellable) { + is_sync_cancelled = true; + return; + } + // TODO(Blinkhawk): Implement cancel of server session + is_sync_cancelled = false; + SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); + SetState(ThreadState::Runnable); +} + +static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, + u32 entry_point, u32 arg) { + context = {}; + context.cpu_registers[0] = arg; + context.cpu_registers[15] = entry_point; + context.cpu_registers[13] = stack_top; +} + +static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, VAddr stack_top, + VAddr entry_point, u64 arg) { + context = {}; + context.cpu_registers[0] = arg; + context.pc = entry_point; + context.sp = stack_top; + // TODO(merry): Perform a hardware test to determine the below value. + context.fpcr = 0; +} + +std::shared_ptr& KThread::GetHostContext() { + return host_context; +} + +ResultVal> KThread::Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, + VAddr stack_top, Process* owner_process) { + std::function init_func = Core::CpuManager::GetGuestThreadStartFunc(); + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, + owner_process, std::move(init_func), init_func_parameter); +} + +ResultVal> KThread::Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, + VAddr stack_top, Process* owner_process, + std::function&& thread_start_func, + void* thread_start_parameter) { + auto& kernel = system.Kernel(); + // Check if priority is in ranged. Lowest priority -> highest priority id. + if (priority > THREADPRIO_LOWEST && ((type_flags & THREADTYPE_IDLE) == 0)) { + LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); + return ERR_INVALID_THREAD_PRIORITY; + } + + if (processor_id > THREADPROCESSORID_MAX) { + LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); + return ERR_INVALID_PROCESSOR_ID; + } + + if (owner_process) { + if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) { + LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); + // TODO (bunnei): Find the correct error code to use here + return RESULT_UNKNOWN; + } + } + + std::shared_ptr thread = std::make_shared(kernel); + + thread->thread_id = kernel.CreateNewThreadID(); + thread->thread_state = ThreadState::Initialized; + thread->entry_point = entry_point; + thread->stack_top = stack_top; + thread->disable_count = 1; + thread->tpidr_el0 = 0; + thread->current_priority = priority; + thread->base_priority = priority; + thread->lock_owner = nullptr; + thread->schedule_count = -1; + thread->last_scheduled_tick = 0; + thread->processor_id = processor_id; + thread->ideal_core = processor_id; + thread->affinity_mask.SetAffinity(processor_id, true); + thread->name = std::move(name); + thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); + thread->owner_process = owner_process; + thread->type = type_flags; + thread->signaled = false; + if ((type_flags & THREADTYPE_IDLE) == 0) { + auto& scheduler = kernel.GlobalSchedulerContext(); + scheduler.AddThread(thread); + } + if (owner_process) { + thread->tls_address = thread->owner_process->CreateTLSRegion(); + thread->owner_process->RegisterThread(thread.get()); + } else { + thread->tls_address = 0; + } + + // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used + // to initialize the context + if ((type_flags & THREADTYPE_HLE) == 0) { + ResetThreadContext32(thread->context_32, static_cast(stack_top), + static_cast(entry_point), static_cast(arg)); + ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); + } + thread->host_context = + std::make_shared(std::move(thread_start_func), thread_start_parameter); + + return MakeResult>(std::move(thread)); +} + +void KThread::SetBasePriority(u32 priority) { + ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, + "Invalid priority value."); + + KScopedSchedulerLock lock(kernel); + + // Change our base priority. + base_priority = priority; + + // Perform a priority restoration. + RestorePriority(kernel, this); +} + +void KThread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) { + signaling_object = object; + signaling_result = result; +} + +VAddr KThread::GetCommandBufferAddress() const { + // Offset from the start of TLS at which the IPC command buffer begins. + constexpr u64 command_header_offset = 0x80; + return GetTLSAddress() + command_header_offset; +} + +void KThread::SetState(ThreadState state) { + KScopedSchedulerLock sl(kernel); + + // Clear debugging state + SetMutexWaitAddressForDebugging({}); + SetWaitReasonForDebugging({}); + + const ThreadState old_state = thread_state; + thread_state = + static_cast((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); + if (thread_state != old_state) { + KScheduler::OnThreadStateChanged(kernel, this, old_state); + } +} + +void KThread::AddWaiterImpl(KThread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // Find the right spot to insert the waiter. + auto it = waiter_list.begin(); + while (it != waiter_list.end()) { + if (it->GetPriority() > thread->GetPriority()) { + break; + } + it++; + } + + // Keep track of how many kernel waiters we have. + if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + ASSERT((num_kernel_waiters++) >= 0); + } + + // Insert the waiter. + waiter_list.insert(it, *thread); + thread->SetLockOwner(this); +} + +void KThread::RemoveWaiterImpl(KThread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // Keep track of how many kernel waiters we have. + if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + ASSERT((num_kernel_waiters--) > 0); + } + + // Remove the waiter. + waiter_list.erase(waiter_list.iterator_to(*thread)); + thread->SetLockOwner(nullptr); +} + +void KThread::RestorePriority(KernelCore& kernel, KThread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + while (true) { + // We want to inherit priority where possible. + s32 new_priority = thread->GetBasePriority(); + if (thread->HasWaiters()) { + new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority()); + } + + // If the priority we would inherit is not different from ours, don't do anything. + if (new_priority == thread->GetPriority()) { + return; + } + + // Ensure we don't violate condition variable red black tree invariants. + if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { + BeforeUpdatePriority(kernel, cv_tree, thread); + } + + // Change the priority. + const s32 old_priority = thread->GetPriority(); + thread->SetPriority(new_priority); + + // Restore the condition variable, if relevant. + if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { + AfterUpdatePriority(kernel, cv_tree, thread); + } + + // Update the scheduler. + KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); + + // Keep the lock owner up to date. + KThread* lock_owner = thread->GetLockOwner(); + if (lock_owner == nullptr) { + return; + } + + // Update the thread in the lock owner's sorted list, and continue inheriting. + lock_owner->RemoveWaiterImpl(thread); + lock_owner->AddWaiterImpl(thread); + thread = lock_owner; + } +} + +void KThread::AddWaiter(KThread* thread) { + AddWaiterImpl(thread); + RestorePriority(kernel, this); +} + +void KThread::RemoveWaiter(KThread* thread) { + RemoveWaiterImpl(thread); + RestorePriority(kernel, this); +} + +KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + s32 num_waiters{}; + KThread* next_lock_owner{}; + auto it = waiter_list.begin(); + while (it != waiter_list.end()) { + if (it->GetAddressKey() == key) { + KThread* thread = std::addressof(*it); + + // Keep track of how many kernel waiters we have. + if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + ASSERT((num_kernel_waiters--) > 0); + } + it = waiter_list.erase(it); + + // Update the next lock owner. + if (next_lock_owner == nullptr) { + next_lock_owner = thread; + next_lock_owner->SetLockOwner(nullptr); + } else { + next_lock_owner->AddWaiterImpl(thread); + } + num_waiters++; + } else { + it++; + } + } + + // Do priority updates, if we have a next owner. + if (next_lock_owner) { + RestorePriority(kernel, this); + RestorePriority(kernel, next_lock_owner); + } + + // Return output. + *out_num_waiters = num_waiters; + return next_lock_owner; +} + +ResultCode KThread::SetActivity(ThreadActivity value) { + KScopedSchedulerLock lock(kernel); + + auto sched_status = GetState(); + + if (sched_status != ThreadState::Runnable && sched_status != ThreadState::Waiting) { + return ERR_INVALID_STATE; + } + + if (IsTerminationRequested()) { + return RESULT_SUCCESS; + } + + if (value == ThreadActivity::Paused) { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) != 0) { + return ERR_INVALID_STATE; + } + AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); + } else { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) == 0) { + return ERR_INVALID_STATE; + } + RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); + } + return RESULT_SUCCESS; +} + +ResultCode KThread::Sleep(s64 nanoseconds) { + Handle event_handle{}; + { + KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); + SetState(ThreadState::Waiting); + SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); + } + + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); + } + return RESULT_SUCCESS; +} + +void KThread::AddSchedulingFlag(ThreadSchedFlags flag) { + const auto old_state = GetRawState(); + pausing_state |= static_cast(flag); + const auto base_scheduling = GetState(); + thread_state = base_scheduling | static_cast(pausing_state); + KScheduler::OnThreadStateChanged(kernel, this, old_state); +} + +void KThread::RemoveSchedulingFlag(ThreadSchedFlags flag) { + const auto old_state = GetRawState(); + pausing_state &= ~static_cast(flag); + const auto base_scheduling = GetState(); + thread_state = base_scheduling | static_cast(pausing_state); + KScheduler::OnThreadStateChanged(kernel, this, old_state); +} + +ResultCode KThread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { + KScopedSchedulerLock lock(kernel); + const auto HighestSetCore = [](u64 mask, u32 max_cores) { + for (s32 core = static_cast(max_cores - 1); core >= 0; core--) { + if (((mask >> core) & 1) != 0) { + return core; + } + } + return -1; + }; + + const bool use_override = affinity_override_count != 0; + if (new_core == THREADPROCESSORID_DONT_UPDATE) { + new_core = use_override ? ideal_core_override : ideal_core; + if ((new_affinity_mask & (1ULL << new_core)) == 0) { + LOG_ERROR(Kernel, "New affinity mask is incorrect! new_core={}, new_affinity_mask={}", + new_core, new_affinity_mask); + return ERR_INVALID_COMBINATION; + } + } + if (use_override) { + ideal_core_override = new_core; + } else { + const auto old_affinity_mask = affinity_mask; + affinity_mask.SetAffinityMask(new_affinity_mask); + ideal_core = new_core; + if (old_affinity_mask.GetAffinityMask() != new_affinity_mask) { + const s32 old_core = processor_id; + if (processor_id >= 0 && !affinity_mask.GetAffinity(processor_id)) { + if (static_cast(ideal_core) < 0) { + processor_id = HighestSetCore(affinity_mask.GetAffinityMask(), + Core::Hardware::NUM_CPU_CORES); + } else { + processor_id = ideal_core; + } + } + KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_affinity_mask, old_core); + } + } + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h new file mode 100644 index 000000000..75257d2b4 --- /dev/null +++ b/src/core/hle/kernel/k_thread.h @@ -0,0 +1,781 @@ +// Copyright 2014 Citra Emulator Project / PPSSPP Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include "common/common_types.h" +#include "common/intrusive_red_black_tree.h" +#include "common/spin_lock.h" +#include "core/arm/arm_interface.h" +#include "core/hle/kernel/k_affinity_mask.h" +#include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/svc_common.h" +#include "core/hle/result.h" + +namespace Common { +class Fiber; +} + +namespace Core { +class ARM_Interface; +class System; +} // namespace Core + +namespace Kernel { + +class GlobalSchedulerContext; +class KernelCore; +class Process; +class KScheduler; + +enum ThreadPriority : u32 { + THREADPRIO_HIGHEST = 0, ///< Highest thread priority + THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration + THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps + THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps + THREADPRIO_LOWEST = 63, ///< Lowest thread priority + THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. +}; + +enum ThreadType : u32 { + THREADTYPE_USER = 0x1, + THREADTYPE_KERNEL = 0x2, + THREADTYPE_HLE = 0x4, + THREADTYPE_IDLE = 0x8, + THREADTYPE_SUSPEND = 0x10, +}; + +enum ThreadProcessorId : s32 { + /// Indicates that no particular processor core is preferred. + THREADPROCESSORID_DONT_CARE = -1, + + /// Run thread on the ideal core specified by the process. + THREADPROCESSORID_IDEAL = -2, + + /// Indicates that the preferred processor ID shouldn't be updated in + /// a core mask setting operation. + THREADPROCESSORID_DONT_UPDATE = -3, + + THREADPROCESSORID_0 = 0, ///< Run thread on core 0 + THREADPROCESSORID_1 = 1, ///< Run thread on core 1 + THREADPROCESSORID_2 = 2, ///< Run thread on core 2 + THREADPROCESSORID_3 = 3, ///< Run thread on core 3 + THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this + + /// Allowed CPU mask + THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) | + (1 << THREADPROCESSORID_2) | (1 << THREADPROCESSORID_3) +}; + +enum class ThreadState : u16 { + Initialized = 0, + Waiting = 1, + Runnable = 2, + Terminated = 3, + + SuspendShift = 4, + Mask = (1 << SuspendShift) - 1, + + ProcessSuspended = (1 << (0 + SuspendShift)), + ThreadSuspended = (1 << (1 + SuspendShift)), + DebugSuspended = (1 << (2 + SuspendShift)), + BacktraceSuspended = (1 << (3 + SuspendShift)), + InitSuspended = (1 << (4 + SuspendShift)), + + SuspendFlagMask = ((1 << 5) - 1) << SuspendShift, +}; +DECLARE_ENUM_FLAG_OPERATORS(ThreadState); + +enum class ThreadWakeupReason { + Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal. + Timeout // The thread was woken up due to a wait timeout. +}; + +enum class ThreadActivity : u32 { + Normal = 0, + Paused = 1, +}; + +enum class ThreadSchedFlags : u32 { + ProcessPauseFlag = 1 << 4, + ThreadPauseFlag = 1 << 5, + ProcessDebugPauseFlag = 1 << 6, + KernelInitPauseFlag = 1 << 8, +}; + +enum class ThreadWaitReasonForDebugging : u32 { + None, ///< Thread is not waiting + Sleep, ///< Thread is waiting due to a SleepThread SVC + IPC, ///< Thread is waiting for the reply from an IPC request + Synchronization, ///< Thread is waiting due to a WaitSynchronization SVC + ConditionVar, ///< Thread is waiting due to a WaitProcessWideKey SVC + Arbitration, ///< Thread is waiting due to a SignalToAddress/WaitForAddress SVC + Suspended, ///< Thread is waiting due to process suspension +}; + +class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { + friend class KScheduler; + friend class Process; + +public: + explicit KThread(KernelCore& kernel); + ~KThread() override; + + using MutexWaitingThreads = std::vector>; + + using ThreadContext32 = Core::ARM_Interface::ThreadContext32; + using ThreadContext64 = Core::ARM_Interface::ThreadContext64; + + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param system The instance of the whole system + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @return A shared pointer to the newly created thread + */ + static ResultVal> Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, + VAddr stack_top, Process* owner_process); + + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param system The instance of the whole system + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @param thread_start_func The function where the host context will start. + * @param thread_start_parameter The parameter which will passed to host context on init + * @return A shared pointer to the newly created thread + */ + static ResultVal> Create( + Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process, + std::function&& thread_start_func, void* thread_start_parameter); + + std::string GetName() const override { + return name; + } + + void SetName(std::string new_name) { + name = std::move(new_name); + } + + std::string GetTypeName() const override { + return "Thread"; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::Thread; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + /** + * Gets the thread's current priority + * @return The current thread's priority + */ + [[nodiscard]] s32 GetPriority() const { + return current_priority; + } + + /** + * Sets the thread's current priority. + * @param priority The new priority. + */ + void SetPriority(s32 priority) { + current_priority = priority; + } + + /** + * Gets the thread's nominal priority. + * @return The current thread's nominal priority. + */ + [[nodiscard]] s32 GetBasePriority() const { + return base_priority; + } + + /** + * Sets the thread's nominal priority. + * @param priority The new priority. + */ + void SetBasePriority(u32 priority); + + /// Changes the core that the thread is running or scheduled to run on. + [[nodiscard]] ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); + + /** + * Gets the thread's thread ID + * @return The thread's ID + */ + [[nodiscard]] u64 GetThreadID() const { + return thread_id; + } + + /// Resumes a thread from waiting + void Wakeup(); + + ResultCode Start(); + + virtual bool IsSignaled() const override; + + /// Cancels a waiting operation that this thread may or may not be within. + /// + /// When the thread is within a waiting state, this will set the thread's + /// waiting result to signal a canceled wait. The function will then resume + /// this thread. + /// + void CancelWait(); + + void SetSynchronizationResults(KSynchronizationObject* object, ResultCode result); + + void SetSyncedObject(KSynchronizationObject* object, ResultCode result) { + SetSynchronizationResults(object, result); + } + + ResultCode GetWaitResult(KSynchronizationObject** out) const { + *out = signaling_object; + return signaling_result; + } + + ResultCode GetSignalingResult() const { + return signaling_result; + } + + /** + * Stops a thread, invalidating it from further use + */ + void Stop(); + + /* + * Returns the Thread Local Storage address of the current thread + * @returns VAddr of the thread's TLS + */ + VAddr GetTLSAddress() const { + return tls_address; + } + + /* + * Returns the value of the TPIDR_EL0 Read/Write system register for this thread. + * @returns The value of the TPIDR_EL0 register. + */ + u64 GetTPIDR_EL0() const { + return tpidr_el0; + } + + /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread. + void SetTPIDR_EL0(u64 value) { + tpidr_el0 = value; + } + + /* + * Returns the address of the current thread's command buffer, located in the TLS. + * @returns VAddr of the thread's command buffer. + */ + VAddr GetCommandBufferAddress() const; + + ThreadContext32& GetContext32() { + return context_32; + } + + const ThreadContext32& GetContext32() const { + return context_32; + } + + ThreadContext64& GetContext64() { + return context_64; + } + + const ThreadContext64& GetContext64() const { + return context_64; + } + + bool IsHLEThread() const { + return (type & THREADTYPE_HLE) != 0; + } + + bool IsSuspendThread() const { + return (type & THREADTYPE_SUSPEND) != 0; + } + + bool IsIdleThread() const { + return (type & THREADTYPE_IDLE) != 0; + } + + bool WasRunning() const { + return was_running; + } + + void SetWasRunning(bool value) { + was_running = value; + } + + std::shared_ptr& GetHostContext(); + + ThreadState GetState() const { + return thread_state & ThreadState::Mask; + } + + ThreadState GetRawState() const { + return thread_state; + } + + void SetState(ThreadState state); + + s64 GetLastScheduledTick() const { + return last_scheduled_tick; + } + + void SetLastScheduledTick(s64 tick) { + last_scheduled_tick = tick; + } + + u64 GetTotalCPUTimeTicks() const { + return total_cpu_time_ticks; + } + + void UpdateCPUTimeTicks(u64 ticks) { + total_cpu_time_ticks += ticks; + } + + s32 GetProcessorID() const { + return processor_id; + } + + s32 GetActiveCore() const { + return GetProcessorID(); + } + + void SetProcessorID(s32 new_core) { + processor_id = new_core; + } + + void SetActiveCore(s32 new_core) { + processor_id = new_core; + } + + Process* GetOwnerProcess() { + return owner_process; + } + + const Process* GetOwnerProcess() const { + return owner_process; + } + + const MutexWaitingThreads& GetMutexWaitingThreads() const { + return wait_mutex_threads; + } + + KThread* GetLockOwner() const { + return lock_owner; + } + + void SetLockOwner(KThread* owner) { + lock_owner = owner; + } + + u32 GetIdealCore() const { + return ideal_core; + } + + const KAffinityMask& GetAffinityMask() const { + return affinity_mask; + } + + ResultCode SetActivity(ThreadActivity value); + + /// Sleeps this thread for the given amount of nanoseconds. + ResultCode Sleep(s64 nanoseconds); + + s64 GetYieldScheduleCount() const { + return schedule_count; + } + + void SetYieldScheduleCount(s64 count) { + schedule_count = count; + } + + bool IsRunning() const { + return is_running; + } + + void SetIsRunning(bool value) { + is_running = value; + } + + bool IsWaitCancelled() const { + return is_sync_cancelled; + } + + void ClearWaitCancelled() { + is_sync_cancelled = false; + } + + Handle GetGlobalHandle() const { + return global_handle; + } + + bool IsCancellable() const { + return is_cancellable; + } + + void SetCancellable() { + is_cancellable = true; + } + + void ClearCancellable() { + is_cancellable = false; + } + + bool IsTerminationRequested() const { + return will_be_terminated || GetRawState() == ThreadState::Terminated; + } + + bool IsPaused() const { + return pausing_state != 0; + } + + bool IsContinuousOnSVC() const { + return is_continuous_on_svc; + } + + void SetContinuousOnSVC(bool is_continuous) { + is_continuous_on_svc = is_continuous; + } + + bool IsPhantomMode() const { + return is_phantom_mode; + } + + void SetPhantomMode(bool phantom) { + is_phantom_mode = phantom; + } + + bool HasExited() const { + return has_exited; + } + + class QueueEntry { + public: + constexpr QueueEntry() = default; + + constexpr void Initialize() { + prev = nullptr; + next = nullptr; + } + + constexpr KThread* GetPrev() const { + return prev; + } + constexpr KThread* GetNext() const { + return next; + } + constexpr void SetPrev(KThread* thread) { + prev = thread; + } + constexpr void SetNext(KThread* thread) { + next = thread; + } + + private: + KThread* prev{}; + KThread* next{}; + }; + + QueueEntry& GetPriorityQueueEntry(s32 core) { + return per_core_priority_queue_entry[core]; + } + + const QueueEntry& GetPriorityQueueEntry(s32 core) const { + return per_core_priority_queue_entry[core]; + } + + s32 GetDisableDispatchCount() const { + return disable_count; + } + + void DisableDispatch() { + ASSERT(GetDisableDispatchCount() >= 0); + disable_count++; + } + + void EnableDispatch() { + ASSERT(GetDisableDispatchCount() > 0); + disable_count--; + } + + void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) { + wait_reason_for_debugging = reason; + } + + [[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const { + return wait_reason_for_debugging; + } + + void SetWaitObjectsForDebugging(const std::span& objects) { + wait_objects_for_debugging.clear(); + wait_objects_for_debugging.reserve(objects.size()); + for (const auto& object : objects) { + wait_objects_for_debugging.emplace_back(object); + } + } + + [[nodiscard]] const std::vector& GetWaitObjectsForDebugging() const { + return wait_objects_for_debugging; + } + + void SetMutexWaitAddressForDebugging(VAddr address) { + mutex_wait_address_for_debugging = address; + } + + [[nodiscard]] VAddr GetMutexWaitAddressForDebugging() const { + return mutex_wait_address_for_debugging; + } + + void AddWaiter(KThread* thread); + + void RemoveWaiter(KThread* thread); + + [[nodiscard]] KThread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key); + + [[nodiscard]] VAddr GetAddressKey() const { + return address_key; + } + + [[nodiscard]] u32 GetAddressKeyValue() const { + return address_key_value; + } + + void SetAddressKey(VAddr key) { + address_key = key; + } + + void SetAddressKey(VAddr key, u32 val) { + address_key = key; + address_key_value = val; + } + +private: + static constexpr size_t PriorityInheritanceCountMax = 10; + union SyncObjectBuffer { + std::array sync_objects{}; + std::array + handles; + constexpr SyncObjectBuffer() {} + }; + static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles)); + + struct ConditionVariableComparator { + struct LightCompareType { + u64 cv_key{}; + s32 priority{}; + + [[nodiscard]] constexpr u64 GetConditionVariableKey() const { + return cv_key; + } + + [[nodiscard]] constexpr s32 GetPriority() const { + return priority; + } + }; + + template + requires( + std::same_as || + std::same_as) static constexpr int Compare(const T& lhs, + const KThread& rhs) { + const uintptr_t l_key = lhs.GetConditionVariableKey(); + const uintptr_t r_key = rhs.GetConditionVariableKey(); + + if (l_key < r_key) { + // Sort first by key + return -1; + } else if (l_key == r_key && lhs.GetPriority() < rhs.GetPriority()) { + // And then by priority. + return -1; + } else { + return 1; + } + } + }; + + Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{}; + + using ConditionVariableThreadTreeTraits = + Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert< + &KThread::condvar_arbiter_tree_node>; + using ConditionVariableThreadTree = + ConditionVariableThreadTreeTraits::TreeType; + +public: + using ConditionVariableThreadTreeType = ConditionVariableThreadTree; + + [[nodiscard]] uintptr_t GetConditionVariableKey() const { + return condvar_key; + } + + [[nodiscard]] uintptr_t GetAddressArbiterKey() const { + return condvar_key; + } + + void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, uintptr_t cv_key, + u32 value) { + condvar_tree = tree; + condvar_key = cv_key; + address_key = address; + address_key_value = value; + } + + void ClearConditionVariable() { + condvar_tree = nullptr; + } + + [[nodiscard]] bool IsWaitingForConditionVariable() const { + return condvar_tree != nullptr; + } + + void SetAddressArbiter(ConditionVariableThreadTree* tree, uintptr_t address) { + condvar_tree = tree; + condvar_key = address; + } + + void ClearAddressArbiter() { + condvar_tree = nullptr; + } + + [[nodiscard]] bool IsWaitingForAddressArbiter() const { + return condvar_tree != nullptr; + } + + [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const { + return condvar_tree; + } + + [[nodiscard]] bool HasWaiters() const { + return !waiter_list.empty(); + } + +private: + void AddSchedulingFlag(ThreadSchedFlags flag); + void RemoveSchedulingFlag(ThreadSchedFlags flag); + void AddWaiterImpl(KThread* thread); + void RemoveWaiterImpl(KThread* thread); + static void RestorePriority(KernelCore& kernel, KThread* thread); + + Common::SpinLock context_guard{}; + ThreadContext32 context_32{}; + ThreadContext64 context_64{}; + std::shared_ptr host_context{}; + + ThreadState thread_state = ThreadState::Initialized; + + u64 thread_id = 0; + + VAddr entry_point = 0; + VAddr stack_top = 0; + std::atomic_int disable_count = 0; + + ThreadType type; + + /// Nominal thread priority, as set by the emulated application. + /// The nominal priority is the thread priority without priority + /// inheritance taken into account. + s32 base_priority{}; + + /// Current thread priority. This may change over the course of the + /// thread's lifetime in order to facilitate priority inheritance. + s32 current_priority{}; + + u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. + s64 schedule_count{}; + s64 last_scheduled_tick{}; + + s32 processor_id = 0; + + VAddr tls_address = 0; ///< Virtual address of the Thread Local Storage of the thread + u64 tpidr_el0 = 0; ///< TPIDR_EL0 read/write system register. + + /// Process that owns this thread + Process* owner_process; + + /// Objects that the thread is waiting on, in the same order as they were + /// passed to WaitSynchronization. This is used for debugging only. + std::vector wait_objects_for_debugging; + + /// The current mutex wait address. This is used for debugging only. + VAddr mutex_wait_address_for_debugging{}; + + /// The reason the thread is waiting. This is used for debugging only. + ThreadWaitReasonForDebugging wait_reason_for_debugging{}; + + KSynchronizationObject* signaling_object; + ResultCode signaling_result{RESULT_SUCCESS}; + + /// List of threads that are waiting for a mutex that is held by this thread. + MutexWaitingThreads wait_mutex_threads; + + /// Thread that owns the lock that this thread is waiting for. + KThread* lock_owner{}; + + /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. + Handle global_handle = 0; + + KScheduler* scheduler = nullptr; + + std::array per_core_priority_queue_entry{}; + + u32 ideal_core{0xFFFFFFFF}; + KAffinityMask affinity_mask{}; + + s32 ideal_core_override = -1; + u32 affinity_override_count = 0; + + u32 pausing_state = 0; + bool is_running = false; + bool is_cancellable = false; + bool is_sync_cancelled = false; + + bool is_continuous_on_svc = false; + + bool will_be_terminated = false; + bool is_phantom_mode = false; + bool has_exited = false; + + bool was_running = false; + + bool signaled{}; + + ConditionVariableThreadTree* condvar_tree{}; + uintptr_t condvar_key{}; + VAddr address_key{}; + u32 address_key_value{}; + s32 num_kernel_waiters{}; + + using WaiterList = boost::intrusive::list; + WaiterList waiter_list{}; + WaiterList pinned_waiter_list{}; + + std::string name; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c0ff287a6..523dd63a5 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -29,6 +29,7 @@ #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" @@ -38,7 +39,6 @@ #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" @@ -171,8 +171,8 @@ struct KernelCore::Impl { 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); + KThread::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(); } @@ -236,7 +236,7 @@ struct KernelCore::Impl { return result; } const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler(); - const Kernel::Thread* current = sched.GetCurrentThread(); + const Kernel::KThread* current = sched.GetCurrentThread(); if (current != nullptr && !current->IsPhantomMode()) { result.guest_handle = current->GetGlobalHandle(); } else { @@ -342,7 +342,7 @@ 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{}; @@ -380,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) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 933d9a7d6..41c553582 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -43,7 +43,7 @@ class KScheduler; class SharedMemory; class ServiceThread; class Synchronization; -class Thread; +class KThread; class TimeManager; /// Represents a single instance of the kernel. @@ -84,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); @@ -240,7 +240,7 @@ public: private: friend class Object; friend class Process; - friend class Thread; + friend class KThread; /// Creates a new object ID, incrementing the internal object ID counter. u32 CreateNewObjectID(); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 37b77fa6e..ccd371aba 100644 --- 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" @@ -39,10 +39,10 @@ namespace { void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); ThreadType type = THREADTYPE_USER; - auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0, - owner_process.GetIdealCore(), stack_top, &owner_process); + auto thread_res = KThread::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(); @@ -162,11 +162,11 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); } -void Process::RegisterThread(const Thread* thread) { +void Process::RegisterThread(const KThread* thread) { thread_list.push_back(thread); } -void Process::UnregisterThread(const Thread* thread) { +void Process::UnregisterThread(const KThread* thread) { thread_list.remove(thread); } @@ -267,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; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 564e1f27d..db01d6c8a 100644 --- 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 Thread; +class KThread; class TLSPage; struct CodeSet; @@ -252,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 Thread* thread); + void RegisterThread(const KThread* thread); /// Unregisters a thread from this process, removing it /// from this process' thread list. - void UnregisterThread(const Thread* thread); + void UnregisterThread(const KThread* thread); /// Clears the signaled state of the process if and only if it's signaled. /// @@ -380,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{}; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 99ed0857e..596d01479 100644 --- 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/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 82857f93b..fe7a483c4 100644 --- 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_session.cpp b/src/core/hle/kernel/server_session.cpp index 4f2bb7822..280c9b5f6 100644 --- 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 = @@ -161,7 +161,7 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { 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 9155cf7f5..d45cddec3 100644 --- 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 Thread; +class KThread; /** * 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. @@ -128,7 +128,7 @@ public: 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); @@ -149,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/svc.cpp b/src/core/hle/kernel/svc.cpp index cc8b661af..3609346d6 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -29,6 +29,7 @@ #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" @@ -42,7 +43,6 @@ #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" @@ -363,7 +363,7 @@ static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle threa LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); + 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; @@ -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) { @@ -474,7 +474,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - std::shared_ptr thread = handle_table.Get(thread_handle); + 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); @@ -872,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}", @@ -1033,7 +1033,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act } const auto* current_process = system.Kernel().CurrentProcess(); - const std::shared_ptr thread = current_process->GetHandleTable().Get(handle); + 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; @@ -1066,7 +1066,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); const auto* current_process = system.Kernel().CurrentProcess(); - const std::shared_ptr thread = current_process->GetHandleTable().Get(handle); + 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; @@ -1111,7 +1111,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle LOG_TRACE(Kernel_SVC, "called"); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(handle); + 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); @@ -1140,7 +1140,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri const auto* const current_process = system.Kernel().CurrentProcess(); - std::shared_ptr thread = current_process->GetHandleTable().Get(handle); + 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; @@ -1489,9 +1489,9 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1)); ThreadType type = THREADTYPE_USER; - CASCADE_RESULT(std::shared_ptr thread, - Thread::Create(system, type, "", entry_point, priority, arg, processor_id, - stack_top, current_process)); + CASCADE_RESULT(std::shared_ptr thread, + KThread::Create(system, type, "", entry_point, priority, arg, processor_id, + stack_top, current_process)); const auto new_thread_handle = current_process->GetHandleTable().Create(thread); if (new_thread_handle.Failed()) { @@ -1518,7 +1518,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); + 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); @@ -1844,7 +1844,7 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); + 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); @@ -1914,7 +1914,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, } const auto& handle_table = current_process->GetHandleTable(); - const std::shared_ptr thread = handle_table.Get(thread_handle); + 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); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp deleted file mode 100644 index d97323255..000000000 --- a/src/core/hle/kernel/thread.cpp +++ /dev/null @@ -1,460 +0,0 @@ -// Copyright 2014 Citra Emulator Project / PPSSPP Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include - -#include "common/assert.h" -#include "common/common_types.h" -#include "common/fiber.h" -#include "common/logging/log.h" -#include "common/thread_queue_list.h" -#include "core/core.h" -#include "core/cpu_manager.h" -#include "core/hardware_properties.h" -#include "core/hle/kernel/errors.h" -#include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/k_condition_variable.h" -#include "core/hle/kernel/k_scheduler.h" -#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/memory_layout.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/kernel/time_manager.h" -#include "core/hle/result.h" -#include "core/memory.h" - -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#endif - -namespace Kernel { - -bool Thread::IsSignaled() const { - return signaled; -} - -Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {} -Thread::~Thread() = default; - -void Thread::Stop() { - { - KScopedSchedulerLock lock(kernel); - SetState(ThreadState::Terminated); - signaled = true; - NotifyAvailable(); - kernel.GlobalHandleTable().Close(global_handle); - - if (owner_process) { - owner_process->UnregisterThread(this); - - // Mark the TLS slot in the thread's page as free. - owner_process->FreeTLSRegion(tls_address); - } - has_exited = true; - } - global_handle = 0; -} - -void Thread::Wakeup() { - KScopedSchedulerLock lock(kernel); - SetState(ThreadState::Runnable); -} - -ResultCode Thread::Start() { - KScopedSchedulerLock lock(kernel); - SetState(ThreadState::Runnable); - return RESULT_SUCCESS; -} - -void Thread::CancelWait() { - KScopedSchedulerLock lock(kernel); - if (GetState() != ThreadState::Waiting || !is_cancellable) { - is_sync_cancelled = true; - return; - } - // TODO(Blinkhawk): Implement cancel of server session - is_sync_cancelled = false; - SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); - SetState(ThreadState::Runnable); -} - -static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, - u32 entry_point, u32 arg) { - context = {}; - context.cpu_registers[0] = arg; - context.cpu_registers[15] = entry_point; - context.cpu_registers[13] = stack_top; -} - -static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, VAddr stack_top, - VAddr entry_point, u64 arg) { - context = {}; - context.cpu_registers[0] = arg; - context.pc = entry_point; - context.sp = stack_top; - // TODO(merry): Perform a hardware test to determine the below value. - context.fpcr = 0; -} - -std::shared_ptr& Thread::GetHostContext() { - return host_context; -} - -ResultVal> Thread::Create(Core::System& system, ThreadType type_flags, - std::string name, VAddr entry_point, u32 priority, - u64 arg, s32 processor_id, VAddr stack_top, - Process* owner_process) { - std::function init_func = Core::CpuManager::GetGuestThreadStartFunc(); - void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, - owner_process, std::move(init_func), init_func_parameter); -} - -ResultVal> Thread::Create(Core::System& system, ThreadType type_flags, - std::string name, VAddr entry_point, u32 priority, - u64 arg, s32 processor_id, VAddr stack_top, - Process* owner_process, - std::function&& thread_start_func, - void* thread_start_parameter) { - auto& kernel = system.Kernel(); - // Check if priority is in ranged. Lowest priority -> highest priority id. - if (priority > THREADPRIO_LOWEST && ((type_flags & THREADTYPE_IDLE) == 0)) { - LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); - return ERR_INVALID_THREAD_PRIORITY; - } - - if (processor_id > THREADPROCESSORID_MAX) { - LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id); - return ERR_INVALID_PROCESSOR_ID; - } - - if (owner_process) { - if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) { - LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); - // TODO (bunnei): Find the correct error code to use here - return RESULT_UNKNOWN; - } - } - - std::shared_ptr thread = std::make_shared(kernel); - - thread->thread_id = kernel.CreateNewThreadID(); - thread->thread_state = ThreadState::Initialized; - thread->entry_point = entry_point; - thread->stack_top = stack_top; - thread->disable_count = 1; - thread->tpidr_el0 = 0; - thread->current_priority = priority; - thread->base_priority = priority; - thread->lock_owner = nullptr; - thread->schedule_count = -1; - thread->last_scheduled_tick = 0; - thread->processor_id = processor_id; - thread->ideal_core = processor_id; - thread->affinity_mask.SetAffinity(processor_id, true); - thread->name = std::move(name); - thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); - thread->owner_process = owner_process; - thread->type = type_flags; - thread->signaled = false; - if ((type_flags & THREADTYPE_IDLE) == 0) { - auto& scheduler = kernel.GlobalSchedulerContext(); - scheduler.AddThread(thread); - } - if (owner_process) { - thread->tls_address = thread->owner_process->CreateTLSRegion(); - thread->owner_process->RegisterThread(thread.get()); - } else { - thread->tls_address = 0; - } - - // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used - // to initialize the context - if ((type_flags & THREADTYPE_HLE) == 0) { - ResetThreadContext32(thread->context_32, static_cast(stack_top), - static_cast(entry_point), static_cast(arg)); - ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); - } - thread->host_context = - std::make_shared(std::move(thread_start_func), thread_start_parameter); - - return MakeResult>(std::move(thread)); -} - -void Thread::SetBasePriority(u32 priority) { - ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, - "Invalid priority value."); - - KScopedSchedulerLock lock(kernel); - - // Change our base priority. - base_priority = priority; - - // Perform a priority restoration. - RestorePriority(kernel, this); -} - -void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) { - signaling_object = object; - signaling_result = result; -} - -VAddr Thread::GetCommandBufferAddress() const { - // Offset from the start of TLS at which the IPC command buffer begins. - constexpr u64 command_header_offset = 0x80; - return GetTLSAddress() + command_header_offset; -} - -void Thread::SetState(ThreadState state) { - KScopedSchedulerLock sl(kernel); - - // Clear debugging state - SetMutexWaitAddressForDebugging({}); - SetWaitReasonForDebugging({}); - - const ThreadState old_state = thread_state; - thread_state = - static_cast((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); - if (thread_state != old_state) { - KScheduler::OnThreadStateChanged(kernel, this, old_state); - } -} - -void Thread::AddWaiterImpl(Thread* thread) { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - - // Find the right spot to insert the waiter. - auto it = waiter_list.begin(); - while (it != waiter_list.end()) { - if (it->GetPriority() > thread->GetPriority()) { - break; - } - it++; - } - - // Keep track of how many kernel waiters we have. - if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { - ASSERT((num_kernel_waiters++) >= 0); - } - - // Insert the waiter. - waiter_list.insert(it, *thread); - thread->SetLockOwner(this); -} - -void Thread::RemoveWaiterImpl(Thread* thread) { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - - // Keep track of how many kernel waiters we have. - if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { - ASSERT((num_kernel_waiters--) > 0); - } - - // Remove the waiter. - waiter_list.erase(waiter_list.iterator_to(*thread)); - thread->SetLockOwner(nullptr); -} - -void Thread::RestorePriority(KernelCore& kernel, Thread* thread) { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - - while (true) { - // We want to inherit priority where possible. - s32 new_priority = thread->GetBasePriority(); - if (thread->HasWaiters()) { - new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority()); - } - - // If the priority we would inherit is not different from ours, don't do anything. - if (new_priority == thread->GetPriority()) { - return; - } - - // Ensure we don't violate condition variable red black tree invariants. - if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { - BeforeUpdatePriority(kernel, cv_tree, thread); - } - - // Change the priority. - const s32 old_priority = thread->GetPriority(); - thread->SetPriority(new_priority); - - // Restore the condition variable, if relevant. - if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { - AfterUpdatePriority(kernel, cv_tree, thread); - } - - // Update the scheduler. - KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); - - // Keep the lock owner up to date. - Thread* lock_owner = thread->GetLockOwner(); - if (lock_owner == nullptr) { - return; - } - - // Update the thread in the lock owner's sorted list, and continue inheriting. - lock_owner->RemoveWaiterImpl(thread); - lock_owner->AddWaiterImpl(thread); - thread = lock_owner; - } -} - -void Thread::AddWaiter(Thread* thread) { - AddWaiterImpl(thread); - RestorePriority(kernel, this); -} - -void Thread::RemoveWaiter(Thread* thread) { - RemoveWaiterImpl(thread); - RestorePriority(kernel, this); -} - -Thread* Thread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); - - s32 num_waiters{}; - Thread* next_lock_owner{}; - auto it = waiter_list.begin(); - while (it != waiter_list.end()) { - if (it->GetAddressKey() == key) { - Thread* thread = std::addressof(*it); - - // Keep track of how many kernel waiters we have. - if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { - ASSERT((num_kernel_waiters--) > 0); - } - it = waiter_list.erase(it); - - // Update the next lock owner. - if (next_lock_owner == nullptr) { - next_lock_owner = thread; - next_lock_owner->SetLockOwner(nullptr); - } else { - next_lock_owner->AddWaiterImpl(thread); - } - num_waiters++; - } else { - it++; - } - } - - // Do priority updates, if we have a next owner. - if (next_lock_owner) { - RestorePriority(kernel, this); - RestorePriority(kernel, next_lock_owner); - } - - // Return output. - *out_num_waiters = num_waiters; - return next_lock_owner; -} - -ResultCode Thread::SetActivity(ThreadActivity value) { - KScopedSchedulerLock lock(kernel); - - auto sched_status = GetState(); - - if (sched_status != ThreadState::Runnable && sched_status != ThreadState::Waiting) { - return ERR_INVALID_STATE; - } - - if (IsTerminationRequested()) { - return RESULT_SUCCESS; - } - - if (value == ThreadActivity::Paused) { - if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) != 0) { - return ERR_INVALID_STATE; - } - AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); - } else { - if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) == 0) { - return ERR_INVALID_STATE; - } - RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); - } - return RESULT_SUCCESS; -} - -ResultCode Thread::Sleep(s64 nanoseconds) { - Handle event_handle{}; - { - KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); - SetState(ThreadState::Waiting); - SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); - } - - if (event_handle != InvalidHandle) { - auto& time_manager = kernel.TimeManager(); - time_manager.UnscheduleTimeEvent(event_handle); - } - return RESULT_SUCCESS; -} - -void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { - const auto old_state = GetRawState(); - pausing_state |= static_cast(flag); - const auto base_scheduling = GetState(); - thread_state = base_scheduling | static_cast(pausing_state); - KScheduler::OnThreadStateChanged(kernel, this, old_state); -} - -void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { - const auto old_state = GetRawState(); - pausing_state &= ~static_cast(flag); - const auto base_scheduling = GetState(); - thread_state = base_scheduling | static_cast(pausing_state); - KScheduler::OnThreadStateChanged(kernel, this, old_state); -} - -ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { - KScopedSchedulerLock lock(kernel); - const auto HighestSetCore = [](u64 mask, u32 max_cores) { - for (s32 core = static_cast(max_cores - 1); core >= 0; core--) { - if (((mask >> core) & 1) != 0) { - return core; - } - } - return -1; - }; - - const bool use_override = affinity_override_count != 0; - if (new_core == THREADPROCESSORID_DONT_UPDATE) { - new_core = use_override ? ideal_core_override : ideal_core; - if ((new_affinity_mask & (1ULL << new_core)) == 0) { - LOG_ERROR(Kernel, "New affinity mask is incorrect! new_core={}, new_affinity_mask={}", - new_core, new_affinity_mask); - return ERR_INVALID_COMBINATION; - } - } - if (use_override) { - ideal_core_override = new_core; - } else { - const auto old_affinity_mask = affinity_mask; - affinity_mask.SetAffinityMask(new_affinity_mask); - ideal_core = new_core; - if (old_affinity_mask.GetAffinityMask() != new_affinity_mask) { - const s32 old_core = processor_id; - if (processor_id >= 0 && !affinity_mask.GetAffinity(processor_id)) { - if (static_cast(ideal_core) < 0) { - processor_id = HighestSetCore(affinity_mask.GetAffinityMask(), - Core::Hardware::NUM_CPU_CORES); - } else { - processor_id = ideal_core; - } - } - KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_affinity_mask, old_core); - } - } - return RESULT_SUCCESS; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h deleted file mode 100644 index 6b66c9a0e..000000000 --- a/src/core/hle/kernel/thread.h +++ /dev/null @@ -1,782 +0,0 @@ -// Copyright 2014 Citra Emulator Project / PPSSPP Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -#include "common/common_types.h" -#include "common/intrusive_red_black_tree.h" -#include "common/spin_lock.h" -#include "core/arm/arm_interface.h" -#include "core/hle/kernel/k_affinity_mask.h" -#include "core/hle/kernel/k_synchronization_object.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/svc_common.h" -#include "core/hle/result.h" - -namespace Common { -class Fiber; -} - -namespace Core { -class ARM_Interface; -class System; -} // namespace Core - -namespace Kernel { - -class GlobalSchedulerContext; -class KernelCore; -class Process; -class KScheduler; - -enum ThreadPriority : u32 { - THREADPRIO_HIGHEST = 0, ///< Highest thread priority - THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration - THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps - THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps - THREADPRIO_LOWEST = 63, ///< Lowest thread priority - THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. -}; - -enum ThreadType : u32 { - THREADTYPE_USER = 0x1, - THREADTYPE_KERNEL = 0x2, - THREADTYPE_HLE = 0x4, - THREADTYPE_IDLE = 0x8, - THREADTYPE_SUSPEND = 0x10, -}; - -enum ThreadProcessorId : s32 { - /// Indicates that no particular processor core is preferred. - THREADPROCESSORID_DONT_CARE = -1, - - /// Run thread on the ideal core specified by the process. - THREADPROCESSORID_IDEAL = -2, - - /// Indicates that the preferred processor ID shouldn't be updated in - /// a core mask setting operation. - THREADPROCESSORID_DONT_UPDATE = -3, - - THREADPROCESSORID_0 = 0, ///< Run thread on core 0 - THREADPROCESSORID_1 = 1, ///< Run thread on core 1 - THREADPROCESSORID_2 = 2, ///< Run thread on core 2 - THREADPROCESSORID_3 = 3, ///< Run thread on core 3 - THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this - - /// Allowed CPU mask - THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) | - (1 << THREADPROCESSORID_2) | (1 << THREADPROCESSORID_3) -}; - -enum class ThreadState : u16 { - Initialized = 0, - Waiting = 1, - Runnable = 2, - Terminated = 3, - - SuspendShift = 4, - Mask = (1 << SuspendShift) - 1, - - ProcessSuspended = (1 << (0 + SuspendShift)), - ThreadSuspended = (1 << (1 + SuspendShift)), - DebugSuspended = (1 << (2 + SuspendShift)), - BacktraceSuspended = (1 << (3 + SuspendShift)), - InitSuspended = (1 << (4 + SuspendShift)), - - SuspendFlagMask = ((1 << 5) - 1) << SuspendShift, -}; -DECLARE_ENUM_FLAG_OPERATORS(ThreadState); - -enum class ThreadWakeupReason { - Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal. - Timeout // The thread was woken up due to a wait timeout. -}; - -enum class ThreadActivity : u32 { - Normal = 0, - Paused = 1, -}; - -enum class ThreadSchedFlags : u32 { - ProcessPauseFlag = 1 << 4, - ThreadPauseFlag = 1 << 5, - ProcessDebugPauseFlag = 1 << 6, - KernelInitPauseFlag = 1 << 8, -}; - -enum class ThreadWaitReasonForDebugging : u32 { - None, ///< Thread is not waiting - Sleep, ///< Thread is waiting due to a SleepThread SVC - IPC, ///< Thread is waiting for the reply from an IPC request - Synchronization, ///< Thread is waiting due to a WaitSynchronization SVC - ConditionVar, ///< Thread is waiting due to a WaitProcessWideKey SVC - Arbitration, ///< Thread is waiting due to a SignalToAddress/WaitForAddress SVC - Suspended, ///< Thread is waiting due to process suspension -}; - -class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { - friend class KScheduler; - friend class Process; - -public: - explicit Thread(KernelCore& kernel); - ~Thread() override; - - using MutexWaitingThreads = std::vector>; - - using ThreadContext32 = Core::ARM_Interface::ThreadContext32; - using ThreadContext64 = Core::ARM_Interface::ThreadContext64; - - /** - * Creates and returns a new thread. The new thread is immediately scheduled - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @return A shared pointer to the newly created thread - */ - static ResultVal> Create(Core::System& system, ThreadType type_flags, - std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, - VAddr stack_top, Process* owner_process); - - /** - * Creates and returns a new thread. The new thread is immediately scheduled - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @param thread_start_func The function where the host context will start. - * @param thread_start_parameter The parameter which will passed to host context on init - * @return A shared pointer to the newly created thread - */ - static ResultVal> Create(Core::System& system, ThreadType type_flags, - std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, - VAddr stack_top, Process* owner_process, - std::function&& thread_start_func, - void* thread_start_parameter); - - std::string GetName() const override { - return name; - } - - void SetName(std::string new_name) { - name = std::move(new_name); - } - - std::string GetTypeName() const override { - return "Thread"; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Thread; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - /** - * Gets the thread's current priority - * @return The current thread's priority - */ - [[nodiscard]] s32 GetPriority() const { - return current_priority; - } - - /** - * Sets the thread's current priority. - * @param priority The new priority. - */ - void SetPriority(s32 priority) { - current_priority = priority; - } - - /** - * Gets the thread's nominal priority. - * @return The current thread's nominal priority. - */ - [[nodiscard]] s32 GetBasePriority() const { - return base_priority; - } - - /** - * Sets the thread's nominal priority. - * @param priority The new priority. - */ - void SetBasePriority(u32 priority); - - /// Changes the core that the thread is running or scheduled to run on. - [[nodiscard]] ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); - - /** - * Gets the thread's thread ID - * @return The thread's ID - */ - [[nodiscard]] u64 GetThreadID() const { - return thread_id; - } - - /// Resumes a thread from waiting - void Wakeup(); - - ResultCode Start(); - - virtual bool IsSignaled() const override; - - /// Cancels a waiting operation that this thread may or may not be within. - /// - /// When the thread is within a waiting state, this will set the thread's - /// waiting result to signal a canceled wait. The function will then resume - /// this thread. - /// - void CancelWait(); - - void SetSynchronizationResults(KSynchronizationObject* object, ResultCode result); - - void SetSyncedObject(KSynchronizationObject* object, ResultCode result) { - SetSynchronizationResults(object, result); - } - - ResultCode GetWaitResult(KSynchronizationObject** out) const { - *out = signaling_object; - return signaling_result; - } - - ResultCode GetSignalingResult() const { - return signaling_result; - } - - /** - * Stops a thread, invalidating it from further use - */ - void Stop(); - - /* - * Returns the Thread Local Storage address of the current thread - * @returns VAddr of the thread's TLS - */ - VAddr GetTLSAddress() const { - return tls_address; - } - - /* - * Returns the value of the TPIDR_EL0 Read/Write system register for this thread. - * @returns The value of the TPIDR_EL0 register. - */ - u64 GetTPIDR_EL0() const { - return tpidr_el0; - } - - /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread. - void SetTPIDR_EL0(u64 value) { - tpidr_el0 = value; - } - - /* - * Returns the address of the current thread's command buffer, located in the TLS. - * @returns VAddr of the thread's command buffer. - */ - VAddr GetCommandBufferAddress() const; - - ThreadContext32& GetContext32() { - return context_32; - } - - const ThreadContext32& GetContext32() const { - return context_32; - } - - ThreadContext64& GetContext64() { - return context_64; - } - - const ThreadContext64& GetContext64() const { - return context_64; - } - - bool IsHLEThread() const { - return (type & THREADTYPE_HLE) != 0; - } - - bool IsSuspendThread() const { - return (type & THREADTYPE_SUSPEND) != 0; - } - - bool IsIdleThread() const { - return (type & THREADTYPE_IDLE) != 0; - } - - bool WasRunning() const { - return was_running; - } - - void SetWasRunning(bool value) { - was_running = value; - } - - std::shared_ptr& GetHostContext(); - - ThreadState GetState() const { - return thread_state & ThreadState::Mask; - } - - ThreadState GetRawState() const { - return thread_state; - } - - void SetState(ThreadState state); - - s64 GetLastScheduledTick() const { - return last_scheduled_tick; - } - - void SetLastScheduledTick(s64 tick) { - last_scheduled_tick = tick; - } - - u64 GetTotalCPUTimeTicks() const { - return total_cpu_time_ticks; - } - - void UpdateCPUTimeTicks(u64 ticks) { - total_cpu_time_ticks += ticks; - } - - s32 GetProcessorID() const { - return processor_id; - } - - s32 GetActiveCore() const { - return GetProcessorID(); - } - - void SetProcessorID(s32 new_core) { - processor_id = new_core; - } - - void SetActiveCore(s32 new_core) { - processor_id = new_core; - } - - Process* GetOwnerProcess() { - return owner_process; - } - - const Process* GetOwnerProcess() const { - return owner_process; - } - - const MutexWaitingThreads& GetMutexWaitingThreads() const { - return wait_mutex_threads; - } - - Thread* GetLockOwner() const { - return lock_owner; - } - - void SetLockOwner(Thread* owner) { - lock_owner = owner; - } - - u32 GetIdealCore() const { - return ideal_core; - } - - const KAffinityMask& GetAffinityMask() const { - return affinity_mask; - } - - ResultCode SetActivity(ThreadActivity value); - - /// Sleeps this thread for the given amount of nanoseconds. - ResultCode Sleep(s64 nanoseconds); - - s64 GetYieldScheduleCount() const { - return schedule_count; - } - - void SetYieldScheduleCount(s64 count) { - schedule_count = count; - } - - bool IsRunning() const { - return is_running; - } - - void SetIsRunning(bool value) { - is_running = value; - } - - bool IsWaitCancelled() const { - return is_sync_cancelled; - } - - void ClearWaitCancelled() { - is_sync_cancelled = false; - } - - Handle GetGlobalHandle() const { - return global_handle; - } - - bool IsCancellable() const { - return is_cancellable; - } - - void SetCancellable() { - is_cancellable = true; - } - - void ClearCancellable() { - is_cancellable = false; - } - - bool IsTerminationRequested() const { - return will_be_terminated || GetRawState() == ThreadState::Terminated; - } - - bool IsPaused() const { - return pausing_state != 0; - } - - bool IsContinuousOnSVC() const { - return is_continuous_on_svc; - } - - void SetContinuousOnSVC(bool is_continuous) { - is_continuous_on_svc = is_continuous; - } - - bool IsPhantomMode() const { - return is_phantom_mode; - } - - void SetPhantomMode(bool phantom) { - is_phantom_mode = phantom; - } - - bool HasExited() const { - return has_exited; - } - - class QueueEntry { - public: - constexpr QueueEntry() = default; - - constexpr void Initialize() { - prev = nullptr; - next = nullptr; - } - - constexpr Thread* GetPrev() const { - return prev; - } - constexpr Thread* GetNext() const { - return next; - } - constexpr void SetPrev(Thread* thread) { - prev = thread; - } - constexpr void SetNext(Thread* thread) { - next = thread; - } - - private: - Thread* prev{}; - Thread* next{}; - }; - - QueueEntry& GetPriorityQueueEntry(s32 core) { - return per_core_priority_queue_entry[core]; - } - - const QueueEntry& GetPriorityQueueEntry(s32 core) const { - return per_core_priority_queue_entry[core]; - } - - s32 GetDisableDispatchCount() const { - return disable_count; - } - - void DisableDispatch() { - ASSERT(GetDisableDispatchCount() >= 0); - disable_count++; - } - - void EnableDispatch() { - ASSERT(GetDisableDispatchCount() > 0); - disable_count--; - } - - void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) { - wait_reason_for_debugging = reason; - } - - [[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const { - return wait_reason_for_debugging; - } - - void SetWaitObjectsForDebugging(const std::span& objects) { - wait_objects_for_debugging.clear(); - wait_objects_for_debugging.reserve(objects.size()); - for (const auto& object : objects) { - wait_objects_for_debugging.emplace_back(object); - } - } - - [[nodiscard]] const std::vector& GetWaitObjectsForDebugging() const { - return wait_objects_for_debugging; - } - - void SetMutexWaitAddressForDebugging(VAddr address) { - mutex_wait_address_for_debugging = address; - } - - [[nodiscard]] VAddr GetMutexWaitAddressForDebugging() const { - return mutex_wait_address_for_debugging; - } - - void AddWaiter(Thread* thread); - - void RemoveWaiter(Thread* thread); - - [[nodiscard]] Thread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key); - - [[nodiscard]] VAddr GetAddressKey() const { - return address_key; - } - - [[nodiscard]] u32 GetAddressKeyValue() const { - return address_key_value; - } - - void SetAddressKey(VAddr key) { - address_key = key; - } - - void SetAddressKey(VAddr key, u32 val) { - address_key = key; - address_key_value = val; - } - -private: - static constexpr size_t PriorityInheritanceCountMax = 10; - union SyncObjectBuffer { - std::array sync_objects{}; - std::array - handles; - constexpr SyncObjectBuffer() {} - }; - static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles)); - - struct ConditionVariableComparator { - struct LightCompareType { - u64 cv_key{}; - s32 priority{}; - - [[nodiscard]] constexpr u64 GetConditionVariableKey() const { - return cv_key; - } - - [[nodiscard]] constexpr s32 GetPriority() const { - return priority; - } - }; - - template - requires( - std::same_as || - std::same_as) static constexpr int Compare(const T& lhs, - const Thread& rhs) { - const uintptr_t l_key = lhs.GetConditionVariableKey(); - const uintptr_t r_key = rhs.GetConditionVariableKey(); - - if (l_key < r_key) { - // Sort first by key - return -1; - } else if (l_key == r_key && lhs.GetPriority() < rhs.GetPriority()) { - // And then by priority. - return -1; - } else { - return 1; - } - } - }; - - Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{}; - - using ConditionVariableThreadTreeTraits = - Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&Thread::condvar_arbiter_tree_node>; - using ConditionVariableThreadTree = - ConditionVariableThreadTreeTraits::TreeType; - -public: - using ConditionVariableThreadTreeType = ConditionVariableThreadTree; - - [[nodiscard]] uintptr_t GetConditionVariableKey() const { - return condvar_key; - } - - [[nodiscard]] uintptr_t GetAddressArbiterKey() const { - return condvar_key; - } - - void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, uintptr_t cv_key, - u32 value) { - condvar_tree = tree; - condvar_key = cv_key; - address_key = address; - address_key_value = value; - } - - void ClearConditionVariable() { - condvar_tree = nullptr; - } - - [[nodiscard]] bool IsWaitingForConditionVariable() const { - return condvar_tree != nullptr; - } - - void SetAddressArbiter(ConditionVariableThreadTree* tree, uintptr_t address) { - condvar_tree = tree; - condvar_key = address; - } - - void ClearAddressArbiter() { - condvar_tree = nullptr; - } - - [[nodiscard]] bool IsWaitingForAddressArbiter() const { - return condvar_tree != nullptr; - } - - [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const { - return condvar_tree; - } - - [[nodiscard]] bool HasWaiters() const { - return !waiter_list.empty(); - } - -private: - void AddSchedulingFlag(ThreadSchedFlags flag); - void RemoveSchedulingFlag(ThreadSchedFlags flag); - void AddWaiterImpl(Thread* thread); - void RemoveWaiterImpl(Thread* thread); - static void RestorePriority(KernelCore& kernel, Thread* thread); - - Common::SpinLock context_guard{}; - ThreadContext32 context_32{}; - ThreadContext64 context_64{}; - std::shared_ptr host_context{}; - - ThreadState thread_state = ThreadState::Initialized; - - u64 thread_id = 0; - - VAddr entry_point = 0; - VAddr stack_top = 0; - std::atomic_int disable_count = 0; - - ThreadType type; - - /// Nominal thread priority, as set by the emulated application. - /// The nominal priority is the thread priority without priority - /// inheritance taken into account. - s32 base_priority{}; - - /// Current thread priority. This may change over the course of the - /// thread's lifetime in order to facilitate priority inheritance. - s32 current_priority{}; - - u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. - s64 schedule_count{}; - s64 last_scheduled_tick{}; - - s32 processor_id = 0; - - VAddr tls_address = 0; ///< Virtual address of the Thread Local Storage of the thread - u64 tpidr_el0 = 0; ///< TPIDR_EL0 read/write system register. - - /// Process that owns this thread - Process* owner_process; - - /// Objects that the thread is waiting on, in the same order as they were - /// passed to WaitSynchronization. This is used for debugging only. - std::vector wait_objects_for_debugging; - - /// The current mutex wait address. This is used for debugging only. - VAddr mutex_wait_address_for_debugging{}; - - /// The reason the thread is waiting. This is used for debugging only. - ThreadWaitReasonForDebugging wait_reason_for_debugging{}; - - KSynchronizationObject* signaling_object; - ResultCode signaling_result{RESULT_SUCCESS}; - - /// List of threads that are waiting for a mutex that is held by this thread. - MutexWaitingThreads wait_mutex_threads; - - /// Thread that owns the lock that this thread is waiting for. - Thread* lock_owner{}; - - /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. - Handle global_handle = 0; - - KScheduler* scheduler = nullptr; - - std::array per_core_priority_queue_entry{}; - - u32 ideal_core{0xFFFFFFFF}; - KAffinityMask affinity_mask{}; - - s32 ideal_core_override = -1; - u32 affinity_override_count = 0; - - u32 pausing_state = 0; - bool is_running = false; - bool is_cancellable = false; - bool is_sync_cancelled = false; - - bool is_continuous_on_svc = false; - - bool will_be_terminated = false; - bool is_phantom_mode = false; - bool has_exited = false; - - bool was_running = false; - - bool signaled{}; - - ConditionVariableThreadTree* condvar_tree{}; - uintptr_t condvar_key{}; - VAddr address_key{}; - u32 address_key_value{}; - s32 num_kernel_waiters{}; - - using WaiterList = boost::intrusive::list; - WaiterList waiter_list{}; - WaiterList pinned_waiter_list{}; - - std::string name; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 832edd629..aaeef3033 100644 --- 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,7 +18,7 @@ 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}; const auto proper_handle = static_cast(thread_handle); @@ -35,7 +35,7 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { }); } -void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { +void TimeManager::ScheduleTimeEvent(Handle& event_handle, KThread* timetask, s64 nanoseconds) { std::lock_guard lock{mutex}; event_handle = timetask->GetGlobalHandle(); if (nanoseconds > 0) { @@ -58,7 +58,7 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) { cancelled_events[event_handle] = true; } -void TimeManager::CancelTimeEvent(Thread* time_task) { +void TimeManager::CancelTimeEvent(KThread* time_task) { std::lock_guard lock{mutex}; const Handle event_handle = time_task->GetGlobalHandle(); UnscheduleTimeEvent(event_handle); diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index f39df39a0..7cc702bec 100644 --- 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 Thread; +class KThread; /** * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp @@ -32,12 +32,12 @@ public: /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' /// returns a non-invalid handle in `event_handle` if correctly scheduled - void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds); + void ScheduleTimeEvent(Handle& event_handle, KThread* timetask, s64 nanoseconds); /// Unschedule an existing time event void UnscheduleTimeEvent(Handle event_handle); - void CancelTimeEvent(Thread* time_task); + void CancelTimeEvent(KThread* time_task); private: Core::System& system; diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp index fc2f7c424..dbe34472b 100644 --- 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 { -- cgit v1.2.3