From 2147240e47d2ea98d43369f30ffc066900c80991 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 11 Jan 2022 20:49:11 -0800 Subject: hle: kernel: Fix service_threads access to be thread safe. - CreateServiceThread and ReleaseServiceThread can be accessed by different threads, uses a lock to make this thread safe. - Fixes a rare crash in Pokemon Sword/Shield that can occur when a new service thread is being created while an old one is being destroyed. --- src/core/hle/kernel/kernel.cpp | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1225e1fba..e1e17db13 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -121,7 +121,7 @@ struct KernelCore::Impl { object_list_container.Finalize(); // Ensures all service threads gracefully shutdown. - service_threads.clear(); + ClearServiceThreads(); next_object_id = 0; next_kernel_process_id = KProcess::InitialKIPIDMin; @@ -704,11 +704,35 @@ struct KernelCore::Impl { return port; } + std::weak_ptr CreateServiceThread(KernelCore& kernel, + const std::string& name) { + auto service_thread = std::make_shared(kernel, 1, name); + { + std::lock_guard lk(service_threads_lock); + service_threads.emplace(service_thread); + } + return service_thread; + } + + void ReleaseServiceThread(std::weak_ptr service_thread) { + auto strong_ptr = service_thread.lock(); + { + std::lock_guard lk(service_threads_lock); + service_threads.erase(strong_ptr); + } + } + + void ClearServiceThreads() { + std::lock_guard lk(service_threads_lock); + service_threads.clear(); + } + std::mutex server_ports_lock; std::mutex server_sessions_lock; std::mutex registered_objects_lock; std::mutex registered_in_use_objects_lock; std::mutex dummy_thread_lock; + std::mutex service_threads_lock; std::atomic next_object_id{0}; std::atomic next_kernel_process_id{KProcess::InitialKIPIDMin}; @@ -1099,15 +1123,11 @@ 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); - return service_thread; + return impl->CreateServiceThread(*this, name); } void KernelCore::ReleaseServiceThread(std::weak_ptr service_thread) { - if (auto strong_ptr = service_thread.lock()) { - impl->service_threads.erase(strong_ptr); - } + impl->ReleaseServiceThread(service_thread); } Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() { -- cgit v1.2.3