diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 213461b6a0..b04e046ed3 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -20,6 +20,8 @@ constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores } // namespace Hardware +constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF; + struct EmuThreadHandle { u32 host_handle; u32 guest_handle; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d312ae31ee..b3a5d75052 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include "common/assert.h" @@ -44,7 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ std::lock_guard lock{HLE::g_hle_lock}; std::shared_ptr thread = - system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle); + system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); if (thread == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); return; @@ -120,7 +122,7 @@ struct KernelCore::Impl { system_resource_limit = nullptr; - thread_wakeup_callback_handle_table.Clear(); + global_handle_table.Clear(); thread_wakeup_event_type = nullptr; preemption_event = nullptr; @@ -138,8 +140,8 @@ struct KernelCore::Impl { void InitializePhysicalCores() { exclusive_monitor = - Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount()); - for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) { + Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { cores.emplace_back(system, i, *exclusive_monitor); } } @@ -184,6 +186,48 @@ struct KernelCore::Impl { system.Memory().SetCurrentPageTable(*process); } + void RegisterCoreThread(std::size_t core_id) { + const std::thread::id this_id = std::this_thread::get_id(); + const auto it = host_thread_ids.find(this_id); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + ASSERT(it == host_thread_ids.end()); + ASSERT(!registered_core_threads[core_id]); + host_thread_ids[this_id] = static_cast(core_id); + registered_core_threads.set(core_id); + } + + void RegisterHostThread() { + const std::thread::id this_id = std::this_thread::get_id(); + const auto it = host_thread_ids.find(this_id); + ASSERT(it == host_thread_ids.end()); + host_thread_ids[this_id] = registered_thread_ids++; + } + + u32 GetCurrentHostThreadId() const { + const std::thread::id this_id = std::this_thread::get_id(); + const auto it = host_thread_ids.find(this_id); + if (it == host_thread_ids.end()) { + return Core::INVALID_HOST_THREAD_ID; + } + return it->second; + } + + Core::EmuThreadHandle GetCurrentEmuThreadId() const { + Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); + result.host_handle = GetCurrentHostThreadId(); + if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { + return result; + } + const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); + const Kernel::Thread* current = sched.GetCurrentThread(); + if (current != nullptr) { + result.guest_handle = current->GetGlobalHandle(); + } else { + result.guest_handle = InvalidHandle; + } + return result; + } + std::atomic next_object_id{0}; std::atomic next_kernel_process_id{Process::InitialKIPIDMin}; std::atomic next_user_process_id{Process::ProcessIDMin}; @@ -202,7 +246,7 @@ struct KernelCore::Impl { // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, // allowing us to simply use a pool index or similar. - Kernel::HandleTable thread_wakeup_callback_handle_table; + Kernel::HandleTable global_handle_table; /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. @@ -211,6 +255,11 @@ struct KernelCore::Impl { std::unique_ptr exclusive_monitor; std::vector cores; + // 0-3 Ids represent core threads, >3 represent others + std::unordered_map host_thread_ids; + u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; + std::bitset registered_core_threads{}; + // System context Core::System& system; }; @@ -232,9 +281,8 @@ std::shared_ptr KernelCore::GetSystemResourceLimit() const { return impl->system_resource_limit; } -std::shared_ptr KernelCore::RetrieveThreadFromWakeupCallbackHandleTable( - Handle handle) const { - return impl->thread_wakeup_callback_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) { @@ -346,12 +394,28 @@ const std::shared_ptr& KernelCore::ThreadWakeupCallback return impl->thread_wakeup_event_type; } -Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() { - return impl->thread_wakeup_callback_handle_table; +Kernel::HandleTable& KernelCore::GlobalHandleTable() { + return impl->global_handle_table; } -const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const { - return impl->thread_wakeup_callback_handle_table; +const Kernel::HandleTable& KernelCore::GlobalHandleTable() const { + return impl->global_handle_table; +} + +void KernelCore::RegisterCoreThread(std::size_t core_id) { + impl->RegisterCoreThread(core_id); +} + +void KernelCore::RegisterHostThread() { + impl->RegisterHostThread(); +} + +u32 KernelCore::GetCurrentHostThreadId() const { + return impl->GetCurrentHostThreadId(); +} + +Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadId() const { + return impl->GetCurrentEmuThreadId(); } } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 0dfc559e94..c5e05f7b6a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,6 +8,7 @@ #include #include #include +#include "core/hardware_properties.h" #include "core/hle/kernel/object.h" namespace Core { @@ -65,7 +66,7 @@ public: std::shared_ptr GetSystemResourceLimit() const; /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. - std::shared_ptr RetrieveThreadFromWakeupCallbackHandleTable(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); @@ -127,6 +128,18 @@ public: /// Determines whether or not the given port is a valid named port. bool IsValidNamedPort(NamedPortTable::const_iterator port) const; + /// Gets the current host_thread/guest_thread handle. + Core::EmuThreadHandle GetCurrentEmuThreadId() const; + + /// Gets the current host_thread handle. + u32 GetCurrentHostThreadId() const; + + /// Register the current thread as a CPU Core Thread. + void RegisterCoreThread(std::size_t core_id); + + /// Register the current thread as a non CPU core thread. + void RegisterHostThread(); + private: friend class Object; friend class Process; @@ -147,11 +160,11 @@ private: /// Retrieves the event type used for thread wakeup callbacks. const std::shared_ptr& ThreadWakeupCallbackEventType() const; - /// Provides a reference to the thread wakeup callback handle table. - Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); + /// Provides a reference to the global handle table. + Kernel::HandleTable& GlobalHandleTable(); - /// Provides a const reference to the thread wakeup callback handle table. - const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const; + /// Provides a const reference to the global handle table. + const Kernel::HandleTable& GlobalHandleTable() const; struct Impl; std::unique_ptr impl; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ae5f2c8bd8..bf850e0b23 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -46,9 +46,9 @@ Thread::~Thread() = default; void Thread::Stop() { // Cancel any outstanding wakeup events for this thread Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); - kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); - callback_handle = 0; + global_handle); + kernel.GlobalHandleTable().Close(global_handle); + global_handle = 0; SetStatus(ThreadStatus::Dead); Signal(); @@ -73,12 +73,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // thread-safe version of ScheduleEvent. const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); Core::System::GetInstance().CoreTiming().ScheduleEvent( - cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); + cycles, kernel.ThreadWakeupCallbackEventType(), global_handle); } void Thread::CancelWakeupTimer() { Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); + global_handle); } void Thread::ResumeFromWait() { @@ -190,7 +190,7 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin thread->condvar_wait_address = 0; thread->wait_handle = 0; thread->name = std::move(name); - thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); + thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); thread->owner_process = &owner_process; auto& scheduler = kernel.GlobalScheduler(); scheduler.AddThread(thread); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 7a49163187..129e7858af 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -453,6 +453,10 @@ public: is_sync_cancelled = value; } + Handle GetGlobalHandle() const { + return global_handle; + } + private: void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); @@ -514,7 +518,7 @@ private: VAddr arb_wait_address{0}; /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. - Handle callback_handle = 0; + Handle global_handle = 0; /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread /// was waiting via WaitSynchronization then the object will be the last object that became