From b9a9b83bee124a86501905d0b75def4ccb1cb966 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Tue, 13 Oct 2020 18:00:25 -0300 Subject: kernel: Implement host thread register methods without locking Locks on GetCurrentHostThreadID were causing performance issues according to Visual Studio's profiler. It was consuming twice the time as arm_interface.Run(). The cost was not in the function itself but in the lockinig it required. Reimplement these functions using atomics and static storage instead of an unordered_map. This is a side effect to avoid locking and using linked lists for reads. Replace unordered_map with a linear search. --- src/core/hle/kernel/kernel.cpp | 66 ++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 28 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f2b0fe2fd..96ca01194 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -107,7 +106,11 @@ struct KernelCore::Impl { cores.clear(); exclusive_monitor.reset(); - host_thread_ids.clear(); + + num_host_threads = 0; + std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(), + std::thread::id{}); + std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0); } void InitializePhysicalCores() { @@ -177,54 +180,56 @@ struct KernelCore::Impl { void MakeCurrentProcess(Process* process) { current_process = process; - if (process == nullptr) { return; } - - u32 core_id = GetCurrentHostThreadID(); + const u32 core_id = GetCurrentHostThreadID(); if (core_id < Core::Hardware::NUM_CPU_CORES) { system.Memory().SetCurrentPageTable(*process, core_id); } } void RegisterCoreThread(std::size_t core_id) { - std::unique_lock lock{register_thread_mutex}; + const std::thread::id this_id = std::this_thread::get_id(); if (!is_multicore) { - single_core_thread_id = std::this_thread::get_id(); + single_core_thread_id = this_id; } - const std::thread::id this_id = std::this_thread::get_id(); - const auto it = host_thread_ids.find(this_id); + const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto it = std::find(register_host_thread_keys.begin(), end, this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - ASSERT(it == host_thread_ids.end()); + ASSERT(it == end); ASSERT(!registered_core_threads[core_id]); - host_thread_ids[this_id] = static_cast(core_id); + InsertHostThread(static_cast(core_id)); registered_core_threads.set(core_id); } void RegisterHostThread() { - std::unique_lock lock{register_thread_mutex}; 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; + const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto it = std::find(register_host_thread_keys.begin(), end, this_id); + if (it == end) { + InsertHostThread(registered_thread_ids++); } - host_thread_ids[this_id] = registered_thread_ids++; } - u32 GetCurrentHostThreadID() const { + void InsertHostThread(u32 value) { + const size_t index = num_host_threads++; + ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads"); + register_host_thread_values[index] = value; + register_host_thread_keys[index] = std::this_thread::get_id(); + } + + [[nodiscard]] u32 GetCurrentHostThreadID() const { const std::thread::id this_id = std::this_thread::get_id(); - if (!is_multicore) { - if (single_core_thread_id == this_id) { - return static_cast(system.GetCpuManager().CurrentCore()); - } + if (!is_multicore && single_core_thread_id == this_id) { + return static_cast(system.GetCpuManager().CurrentCore()); } - std::unique_lock lock{register_thread_mutex}; - const auto it = host_thread_ids.find(this_id); - if (it == host_thread_ids.end()) { + const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto it = std::find(register_host_thread_keys.begin(), end, this_id); + if (it == end) { return Core::INVALID_HOST_THREAD_ID; } - return it->second; + return register_host_thread_values[std::distance(register_host_thread_keys.begin(), it)]; } Core::EmuThreadHandle GetCurrentEmuThreadID() const { @@ -322,10 +327,15 @@ struct KernelCore::Impl { 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::atomic registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; std::bitset registered_core_threads; - mutable std::mutex register_thread_mutex; + + // Number of host threads is a relatively high number to avoid overflowing + static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64; + std::atomic num_host_threads{0}; + std::array, NUM_REGISTRABLE_HOST_THREADS> + register_host_thread_keys{}; + std::array, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{}; // Kernel memory management std::unique_ptr memory_manager; -- cgit v1.2.3 From be1954e04cb5a0c3a526f78ed5490a5e65310280 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 15 Oct 2020 14:49:45 -0400 Subject: core: Fix clang build Recent changes to the build system that made more warnings be flagged as errors caused building via clang to break. Fixes #4795 --- src/core/hle/kernel/kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f2b0fe2fd..c04b23eff 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -168,7 +168,7 @@ 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, + Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast(i), 0, nullptr, std::move(init_func), init_func_parameter); suspend_threads[i] = std::move(thread_res).Unwrap(); -- cgit v1.2.3 From fdd91540695594c4b015f234325a950a5e6566e9 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 20 Oct 2020 20:22:33 -0400 Subject: kernel: Fix build with recent compiler flag changes This slipped through the cracks due to another change being merged before the compiler flag changes. --- src/core/hle/kernel/kernel.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ed30854ee..56e14da6b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -194,7 +194,8 @@ struct KernelCore::Impl { if (!is_multicore) { single_core_thread_id = this_id; } - const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto end = + register_host_thread_keys.begin() + static_cast(num_host_threads); const auto it = std::find(register_host_thread_keys.begin(), end, this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); ASSERT(it == end); @@ -205,7 +206,8 @@ struct KernelCore::Impl { void RegisterHostThread() { const std::thread::id this_id = std::this_thread::get_id(); - const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto end = + register_host_thread_keys.begin() + static_cast(num_host_threads); const auto it = std::find(register_host_thread_keys.begin(), end, this_id); if (it == end) { InsertHostThread(registered_thread_ids++); @@ -224,12 +226,14 @@ struct KernelCore::Impl { if (!is_multicore && single_core_thread_id == this_id) { return static_cast(system.GetCpuManager().CurrentCore()); } - const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto end = + register_host_thread_keys.begin() + static_cast(num_host_threads); const auto it = std::find(register_host_thread_keys.begin(), end, this_id); if (it == end) { return Core::INVALID_HOST_THREAD_ID; } - return register_host_thread_values[std::distance(register_host_thread_keys.begin(), it)]; + return register_host_thread_values[static_cast( + std::distance(register_host_thread_keys.begin(), it))]; } Core::EmuThreadHandle GetCurrentEmuThreadID() const { -- cgit v1.2.3 From 3d592972dc3fd61cc88771b889eff237e4e03e0f Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Oct 2020 19:07:39 -0700 Subject: Revert "core: Fix clang build" --- src/core/hle/kernel/kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 56e14da6b..b2b5b8adf 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -171,7 +171,7 @@ 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, + Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast(i), 0, nullptr, std::move(init_func), init_func_parameter); suspend_threads[i] = std::move(thread_res).Unwrap(); -- cgit v1.2.3 From ce69ff2890e0a3a34ba6b80af6b3d60811c5f7ea Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Tue, 27 Oct 2020 01:55:33 -0300 Subject: hle/kernel: Remove unused registered_core_threads to fix data races This member was only used on asserts and it triggered data races. Remove it to fix them. --- src/core/hle/kernel/kernel.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b2b5b8adf..bb3e312a7 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -86,8 +86,6 @@ struct KernelCore::Impl { } cores.clear(); - registered_core_threads.reset(); - process_list.clear(); current_process = nullptr; @@ -199,9 +197,7 @@ struct KernelCore::Impl { const auto it = std::find(register_host_thread_keys.begin(), end, this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); ASSERT(it == end); - ASSERT(!registered_core_threads[core_id]); InsertHostThread(static_cast(core_id)); - registered_core_threads.set(core_id); } void RegisterHostThread() { @@ -332,7 +328,6 @@ struct KernelCore::Impl { // 0-3 IDs represent core threads, >3 represent others std::atomic registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; - std::bitset registered_core_threads; // Number of host threads is a relatively high number to avoid overflowing static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64; -- cgit v1.2.3 From 7b642c77811dc3887756f5abac5a9710564b098e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 13 Nov 2020 11:11:12 -0800 Subject: hle: kernel: multicore: Replace n-JITs impl. with 4 JITs. --- src/core/hle/kernel/kernel.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index bb3e312a7..4cf9cee42 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -68,6 +68,12 @@ struct KernelCore::Impl { InitializeSuspendThreads(); } + void InitializeCores() { + for (auto& core : cores) { + core.Initialize(current_process->Is64BitProcess()); + } + } + void Shutdown() { next_object_id = 0; next_kernel_process_id = Process::InitialKIPIDMin; @@ -116,7 +122,7 @@ struct KernelCore::Impl { Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { schedulers[i] = std::make_unique(system, i); - cores.emplace_back(system, i, *schedulers[i], interrupts[i]); + cores.emplace_back(i, system, *schedulers[i], interrupts); } } @@ -181,6 +187,7 @@ struct KernelCore::Impl { if (process == nullptr) { return; } + const u32 core_id = GetCurrentHostThreadID(); if (core_id < Core::Hardware::NUM_CPU_CORES) { system.Memory().SetCurrentPageTable(*process, core_id); @@ -372,6 +379,10 @@ void KernelCore::Initialize() { impl->Initialize(*this); } +void KernelCore::InitializeCores() { + impl->InitializeCores(); +} + void KernelCore::Shutdown() { impl->Shutdown(); } @@ -486,12 +497,12 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - auto& threads = GlobalScheduler().GetThreadList(); - for (auto& thread : threads) { - if (!thread->IsHLEThread()) { - auto& arm_interface = thread->ArmInterface(); - arm_interface.ClearInstructionCache(); + if (!IsMulticore()) { + for (auto& physical_core : impl->cores) { + physical_core.ArmInterface().ClearInstructionCache(); } + } else { + ASSERT_MSG(false, "UNIMPLEMENTED!!!!!!!!!!!"); } } -- cgit v1.2.3 From c042a89113617f75e81163f103ef82d6d714cd87 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 13 Nov 2020 15:17:47 -0800 Subject: common: fiber: Use boost::context instead of native fibers on Windows. --- src/core/hle/kernel/kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4cf9cee42..c426b6378 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -502,7 +502,7 @@ void KernelCore::InvalidateAllInstructionCaches() { physical_core.ArmInterface().ClearInstructionCache(); } } else { - ASSERT_MSG(false, "UNIMPLEMENTED!!!!!!!!!!!"); + UNIMPLEMENTED(); } } -- cgit v1.2.3 From 63fd1bb50302867b233325f253b1e2abbc379875 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 13 Nov 2020 23:20:32 -0800 Subject: core: arm: Implement InvalidateCacheRange for CPU cache invalidation. --- src/core/hle/kernel/kernel.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c426b6378..929db696d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -497,12 +497,17 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - if (!IsMulticore()) { - for (auto& physical_core : impl->cores) { - physical_core.ArmInterface().ClearInstructionCache(); + for (auto& physical_core : impl->cores) { + physical_core.ArmInterface().ClearInstructionCache(); + } +} + +void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) { + for (auto& physical_core : impl->cores) { + if (!physical_core.IsInitialized()) { + continue; } - } else { - UNIMPLEMENTED(); + physical_core.ArmInterface().InvalidateCacheRange(addr, size); } } -- cgit v1.2.3 From 9e29e36a784496f7290c03b6a42e400a164a5b1e Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 2 Dec 2020 18:08:35 -0800 Subject: hle: kernel: Rewrite scheduler implementation based on Mesopshere. --- src/core/hle/kernel/kernel.cpp | 59 +++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 35 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 929db696d..b74e34c40 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -27,6 +27,7 @@ #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/memory_layout.h" #include "core/hle/kernel/memory/memory_manager.h" @@ -34,7 +35,6 @@ #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" -#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" @@ -49,17 +49,18 @@ namespace Kernel { struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) - : global_scheduler{kernel}, synchronization{system}, time_manager{system}, - global_handle_table{kernel}, system{system} {} + : synchronization{system}, time_manager{system}, global_handle_table{kernel}, system{ + system} {} void SetMulticore(bool is_multicore) { this->is_multicore = is_multicore; } void Initialize(KernelCore& kernel) { - Shutdown(); RegisterHostThread(); + global_scheduler_context = std::make_unique(kernel); + InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); InitializeMemoryLayout(); @@ -86,29 +87,20 @@ struct KernelCore::Impl { } } - for (std::size_t i = 0; i < cores.size(); i++) { - cores[i].Shutdown(); - schedulers[i].reset(); - } cores.clear(); process_list.clear(); + current_process = nullptr; system_resource_limit = nullptr; global_handle_table.Clear(); - preemption_event = nullptr; - global_scheduler.Shutdown(); + preemption_event = nullptr; named_ports.clear(); - for (auto& core : cores) { - core.Shutdown(); - } - cores.clear(); - exclusive_monitor.reset(); num_host_threads = 0; @@ -121,7 +113,7 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - schedulers[i] = std::make_unique(system, i); + schedulers[i] = std::make_unique(system, i); cores.emplace_back(i, system, *schedulers[i], interrupts); } } @@ -155,7 +147,7 @@ struct KernelCore::Impl { "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { { SchedulerLock lock(kernel); - global_scheduler.PreemptThreads(); + global_scheduler_context->PreemptThreads(); } const auto time_interval = std::chrono::nanoseconds{ Core::Timing::msToCycles(std::chrono::milliseconds(10))}; @@ -245,7 +237,7 @@ struct KernelCore::Impl { if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { return result; } - const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); + const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler(); const Kernel::Thread* current = sched.GetCurrentThread(); if (current != nullptr && !current->IsPhantomMode()) { result.guest_handle = current->GetGlobalHandle(); @@ -314,7 +306,7 @@ struct KernelCore::Impl { // Lists all processes that exist in the current session. std::vector> process_list; Process* current_process = nullptr; - Kernel::GlobalScheduler global_scheduler; + std::unique_ptr global_scheduler_context; Kernel::Synchronization synchronization; Kernel::TimeManager time_manager; @@ -355,7 +347,7 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; - std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; + std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; @@ -415,19 +407,19 @@ const std::vector>& KernelCore::GetProcessList() const return impl->process_list; } -Kernel::GlobalScheduler& KernelCore::GlobalScheduler() { - return impl->global_scheduler; +Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { + return *impl->global_scheduler_context; } -const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { - return impl->global_scheduler; +const Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() const { + return *impl->global_scheduler_context; } -Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { +Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) { return *impl->schedulers[id]; } -const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { +const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const { return *impl->schedulers[id]; } @@ -451,16 +443,13 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { return impl->cores[core_id]; } -Kernel::Scheduler& KernelCore::CurrentScheduler() { +Kernel::KScheduler* KernelCore::CurrentScheduler() { u32 core_id = impl->GetCurrentHostThreadID(); - ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - return *impl->schedulers[core_id]; -} - -const Kernel::Scheduler& KernelCore::CurrentScheduler() const { - u32 core_id = impl->GetCurrentHostThreadID(); - ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - return *impl->schedulers[core_id]; + if (core_id >= Core::Hardware::NUM_CPU_CORES) { + // This is expected when called from not a guest thread + return {}; + } + return impl->schedulers[core_id].get(); } std::array& KernelCore::Interrupts() { -- cgit v1.2.3 From ccce6cb3be062fc7ae162bed32202538ebc2e3d9 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 3 Dec 2020 22:26:42 -0800 Subject: hle: kernel: Migrate to KScopedSchedulerLock. --- src/core/hle/kernel/kernel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b74e34c40..04cae3a43 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -146,7 +146,7 @@ struct KernelCore::Impl { preemption_event = Core::Timing::CreateEvent( "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { { - SchedulerLock lock(kernel); + KScopedSchedulerLock lock(kernel); global_scheduler_context->PreemptThreads(); } const auto time_interval = std::chrono::nanoseconds{ @@ -612,7 +612,7 @@ const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const { void KernelCore::Suspend(bool in_suspention) { const bool should_suspend = exception_exited || in_suspention; { - SchedulerLock lock(*this); + KScopedSchedulerLock lock(*this); ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { impl->suspend_threads[i]->SetStatus(status); -- cgit v1.2.3 From 28281ae2500a4af9c36c26de5ba07b80d440b335 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 9 Dec 2020 21:27:05 -0800 Subject: core: hle: server_session: Use separate threads for each service connection. --- src/core/hle/kernel/kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 04cae3a43..1bf4c3355 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -329,7 +329,7 @@ struct KernelCore::Impl { std::atomic registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; // Number of host threads is a relatively high number to avoid overflowing - static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64; + static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 1024; std::atomic num_host_threads{0}; std::array, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_keys{}; -- cgit v1.2.3 From 6d2f9428c5387abaae03478c9204d164a718ffe5 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 14 Dec 2020 17:57:40 -0800 Subject: core: kernel: Clear process list earlier. --- src/core/hle/kernel/kernel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1bf4c3355..b3661e4c1 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -76,6 +76,8 @@ struct KernelCore::Impl { } void Shutdown() { + process_list.clear(); + next_object_id = 0; next_kernel_process_id = Process::InitialKIPIDMin; next_user_process_id = Process::ProcessIDMin; @@ -89,8 +91,6 @@ struct KernelCore::Impl { cores.clear(); - process_list.clear(); - current_process = nullptr; system_resource_limit = nullptr; -- cgit v1.2.3 From d0649d0971fa0e4486b7febe9f24b892c7864548 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 24 Dec 2020 23:29:14 -0800 Subject: core: hle: kernel: Clear process list on boot. --- src/core/hle/kernel/kernel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b3661e4c1..312c64c17 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -57,6 +57,8 @@ struct KernelCore::Impl { } void Initialize(KernelCore& kernel) { + process_list.clear(); + RegisterHostThread(); global_scheduler_context = std::make_unique(kernel); @@ -76,8 +78,6 @@ struct KernelCore::Impl { } void Shutdown() { - process_list.clear(); - next_object_id = 0; next_kernel_process_id = Process::InitialKIPIDMin; next_user_process_id = Process::ProcessIDMin; -- cgit v1.2.3 From dfdac7d38af170683812f3b474ef9d686dfa9ef8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 15 Dec 2020 00:41:48 -0800 Subject: hle: kernel: Move ServiceThread ownership to KernelCore. - Fixes a circular dependency which prevented threads from being released on shutdown. --- src/core/hle/kernel/kernel.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 312c64c17..5f917686f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include "common/assert.h" @@ -35,6 +35,7 @@ #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #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/synchronization.h" #include "core/hle/kernel/thread.h" @@ -107,6 +108,9 @@ struct KernelCore::Impl { std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(), std::thread::id{}); std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0); + + // Ensures all service threads gracefully shutdown + service_threads.clear(); } void InitializePhysicalCores() { @@ -345,6 +349,9 @@ struct KernelCore::Impl { std::shared_ptr irs_shared_mem; std::shared_ptr time_shared_mem; + // Threads used for services + std::unordered_set> service_threads; + std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; @@ -639,4 +646,16 @@ void KernelCore::ExitSVCProfile() { MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); } +std::weak_ptr KernelCore::CreateServiceThread(const std::string& name) { + auto service_thread = std::make_shared(*this, 1, name); + impl->service_threads.emplace(service_thread); + return service_thread; +} + +void KernelCore::ReleaseServiceThread(std::weak_ptr service_thread) { + if (auto strong_ptr = service_thread.lock()) { + impl->service_threads.erase(strong_ptr); + } +} + } // namespace Kernel -- cgit v1.2.3 From c192da3f82ea3b2563ce43a340c88ac9a6602f26 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 29 Dec 2020 15:55:30 -0800 Subject: hle: kernel: Manage host thread IDs using TLS. - Avoids the need to have a large map of host to guest thread IDs. --- src/core/hle/kernel/kernel.cpp | 77 +++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 46 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5f917686f..022cd413d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -104,10 +104,8 @@ struct KernelCore::Impl { exclusive_monitor.reset(); - num_host_threads = 0; - std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(), - std::thread::id{}); - std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0); + // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others + next_host_thread_id = Core::Hardware::NUM_CPU_CORES; // Ensures all service threads gracefully shutdown service_threads.clear(); @@ -190,52 +188,46 @@ struct KernelCore::Impl { } } + /// Creates a new host thread ID, should only be called by GetHostThreadId + u32 AllocateHostThreadId(std::optional core_id) { + if (core_id) { + // The first for slots are reserved for CPU core threads + ASSERT(*core_id < Core::Hardware::NUM_CPU_CORES); + return static_cast(*core_id); + } else { + return next_host_thread_id++; + } + } + + /// Gets the host thread ID for the caller, allocating a new one if this is the first time + u32 GetHostThreadId(std::optional core_id = std::nullopt) { + const thread_local auto host_thread_id{AllocateHostThreadId(core_id)}; + return host_thread_id; + } + + /// Registers a CPU core thread by allocating a host thread ID for it void RegisterCoreThread(std::size_t core_id) { - const std::thread::id this_id = std::this_thread::get_id(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + const auto this_id = GetHostThreadId(core_id); if (!is_multicore) { single_core_thread_id = this_id; } - const auto end = - register_host_thread_keys.begin() + static_cast(num_host_threads); - const auto it = std::find(register_host_thread_keys.begin(), end, this_id); - ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - ASSERT(it == end); - InsertHostThread(static_cast(core_id)); } + /// Registers a new host thread by allocating a host thread ID for it void RegisterHostThread() { - const std::thread::id this_id = std::this_thread::get_id(); - const auto end = - register_host_thread_keys.begin() + static_cast(num_host_threads); - const auto it = std::find(register_host_thread_keys.begin(), end, this_id); - if (it == end) { - InsertHostThread(registered_thread_ids++); - } - } - - void InsertHostThread(u32 value) { - const size_t index = num_host_threads++; - ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads"); - register_host_thread_values[index] = value; - register_host_thread_keys[index] = std::this_thread::get_id(); + [[maybe_unused]] const auto this_id = GetHostThreadId(); } - [[nodiscard]] u32 GetCurrentHostThreadID() const { - const std::thread::id this_id = std::this_thread::get_id(); + [[nodiscard]] u32 GetCurrentHostThreadID() { + const auto this_id = GetHostThreadId(); if (!is_multicore && single_core_thread_id == this_id) { return static_cast(system.GetCpuManager().CurrentCore()); } - const auto end = - register_host_thread_keys.begin() + static_cast(num_host_threads); - const auto it = std::find(register_host_thread_keys.begin(), end, this_id); - if (it == end) { - return Core::INVALID_HOST_THREAD_ID; - } - return register_host_thread_values[static_cast( - std::distance(register_host_thread_keys.begin(), it))]; + return this_id; } - Core::EmuThreadHandle GetCurrentEmuThreadID() const { + [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() { Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); result.host_handle = GetCurrentHostThreadID(); if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { @@ -329,15 +321,8 @@ struct KernelCore::Impl { std::unique_ptr exclusive_monitor; std::vector cores; - // 0-3 IDs represent core threads, >3 represent others - std::atomic registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; - - // Number of host threads is a relatively high number to avoid overflowing - static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 1024; - std::atomic num_host_threads{0}; - std::array, NUM_REGISTRABLE_HOST_THREADS> - register_host_thread_keys{}; - std::array, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{}; + // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others + std::atomic next_host_thread_id{Core::Hardware::NUM_CPU_CORES}; // Kernel memory management std::unique_ptr memory_manager; @@ -357,7 +342,7 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; - std::thread::id single_core_thread_id{}; + u32 single_core_thread_id{}; std::array svc_ticks{}; -- cgit v1.2.3 From a2a0f5318dba2c87578703a5bb69b9fbf7ec526d Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 29 Dec 2020 16:39:04 -0800 Subject: hle: kernel: Manage service threads on another thread. - This is to allow service threads to defer destruction of themselves. --- src/core/hle/kernel/kernel.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel/kernel.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 022cd413d..e8ece8164 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -15,6 +15,7 @@ #include "common/logging/log.h" #include "common/microprofile.h" #include "common/thread.h" +#include "common/thread_worker.h" #include "core/arm/arm_interface.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" @@ -58,11 +59,11 @@ struct KernelCore::Impl { } void Initialize(KernelCore& kernel) { - process_list.clear(); - RegisterHostThread(); global_scheduler_context = std::make_unique(kernel); + service_thread_manager = + std::make_unique(1, "yuzu:ServiceThreadManager"); InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); @@ -79,6 +80,12 @@ struct KernelCore::Impl { } void Shutdown() { + process_list.clear(); + + // Ensures all service threads gracefully shutdown + service_thread_manager.reset(); + service_threads.clear(); + next_object_id = 0; next_kernel_process_id = Process::InitialKIPIDMin; next_user_process_id = Process::ProcessIDMin; @@ -106,9 +113,6 @@ struct KernelCore::Impl { // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others next_host_thread_id = Core::Hardware::NUM_CPU_CORES; - - // Ensures all service threads gracefully shutdown - service_threads.clear(); } void InitializePhysicalCores() { @@ -337,6 +341,10 @@ struct KernelCore::Impl { // Threads used for services std::unordered_set> service_threads; + // Service threads are managed by a worker thread, so that a calling service thread can queue up + // the release of itself + std::unique_ptr service_thread_manager; + std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; @@ -633,14 +641,17 @@ void KernelCore::ExitSVCProfile() { std::weak_ptr KernelCore::CreateServiceThread(const std::string& name) { auto service_thread = std::make_shared(*this, 1, name); - impl->service_threads.emplace(service_thread); + impl->service_thread_manager->QueueWork( + [this, service_thread] { impl->service_threads.emplace(service_thread); }); return service_thread; } void KernelCore::ReleaseServiceThread(std::weak_ptr service_thread) { - if (auto strong_ptr = service_thread.lock()) { - impl->service_threads.erase(strong_ptr); - } + impl->service_thread_manager->QueueWork([this, service_thread] { + if (auto strong_ptr = service_thread.lock()) { + impl->service_threads.erase(strong_ptr); + } + }); } } // namespace Kernel -- cgit v1.2.3