summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/kernel.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2020-12-30 22:06:05 -0800
committerGravatar GitHub2020-12-30 22:06:05 -0800
commit25d607f5f63929369fb74f386a920b69bb24f442 (patch)
tree9ee5a023f033d99561a0358c5c71aeecc92c9d64 /src/core/hle/kernel/kernel.cpp
parentMerge pull request #5263 from lioncash/uninit (diff)
parenthle: kernel: service_thread: Make thread naming more consistent. (diff)
downloadyuzu-25d607f5f63929369fb74f386a920b69bb24f442.tar.gz
yuzu-25d607f5f63929369fb74f386a920b69bb24f442.tar.xz
yuzu-25d607f5f63929369fb74f386a920b69bb24f442.zip
Merge pull request #5208 from bunnei/service-threads
Service threads
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
-rw-r--r--src/core/hle/kernel/kernel.cpp113
1 files changed, 64 insertions, 49 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 04cae3a43..e8ece8164 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -8,13 +8,14 @@
8#include <functional> 8#include <functional>
9#include <memory> 9#include <memory>
10#include <thread> 10#include <thread>
11#include <unordered_map> 11#include <unordered_set>
12#include <utility> 12#include <utility>
13 13
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/microprofile.h" 16#include "common/microprofile.h"
17#include "common/thread.h" 17#include "common/thread.h"
18#include "common/thread_worker.h"
18#include "core/arm/arm_interface.h" 19#include "core/arm/arm_interface.h"
19#include "core/arm/cpu_interrupt_handler.h" 20#include "core/arm/cpu_interrupt_handler.h"
20#include "core/arm/exclusive_monitor.h" 21#include "core/arm/exclusive_monitor.h"
@@ -35,6 +36,7 @@
35#include "core/hle/kernel/physical_core.h" 36#include "core/hle/kernel/physical_core.h"
36#include "core/hle/kernel/process.h" 37#include "core/hle/kernel/process.h"
37#include "core/hle/kernel/resource_limit.h" 38#include "core/hle/kernel/resource_limit.h"
39#include "core/hle/kernel/service_thread.h"
38#include "core/hle/kernel/shared_memory.h" 40#include "core/hle/kernel/shared_memory.h"
39#include "core/hle/kernel/synchronization.h" 41#include "core/hle/kernel/synchronization.h"
40#include "core/hle/kernel/thread.h" 42#include "core/hle/kernel/thread.h"
@@ -60,6 +62,8 @@ struct KernelCore::Impl {
60 RegisterHostThread(); 62 RegisterHostThread();
61 63
62 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); 64 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
65 service_thread_manager =
66 std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
63 67
64 InitializePhysicalCores(); 68 InitializePhysicalCores();
65 InitializeSystemResourceLimit(kernel); 69 InitializeSystemResourceLimit(kernel);
@@ -76,6 +80,12 @@ struct KernelCore::Impl {
76 } 80 }
77 81
78 void Shutdown() { 82 void Shutdown() {
83 process_list.clear();
84
85 // Ensures all service threads gracefully shutdown
86 service_thread_manager.reset();
87 service_threads.clear();
88
79 next_object_id = 0; 89 next_object_id = 0;
80 next_kernel_process_id = Process::InitialKIPIDMin; 90 next_kernel_process_id = Process::InitialKIPIDMin;
81 next_user_process_id = Process::ProcessIDMin; 91 next_user_process_id = Process::ProcessIDMin;
@@ -89,8 +99,6 @@ struct KernelCore::Impl {
89 99
90 cores.clear(); 100 cores.clear();
91 101
92 process_list.clear();
93
94 current_process = nullptr; 102 current_process = nullptr;
95 103
96 system_resource_limit = nullptr; 104 system_resource_limit = nullptr;
@@ -103,10 +111,8 @@ struct KernelCore::Impl {
103 111
104 exclusive_monitor.reset(); 112 exclusive_monitor.reset();
105 113
106 num_host_threads = 0; 114 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
107 std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(), 115 next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
108 std::thread::id{});
109 std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
110 } 116 }
111 117
112 void InitializePhysicalCores() { 118 void InitializePhysicalCores() {
@@ -186,52 +192,46 @@ struct KernelCore::Impl {
186 } 192 }
187 } 193 }
188 194
195 /// Creates a new host thread ID, should only be called by GetHostThreadId
196 u32 AllocateHostThreadId(std::optional<std::size_t> core_id) {
197 if (core_id) {
198 // The first for slots are reserved for CPU core threads
199 ASSERT(*core_id < Core::Hardware::NUM_CPU_CORES);
200 return static_cast<u32>(*core_id);
201 } else {
202 return next_host_thread_id++;
203 }
204 }
205
206 /// Gets the host thread ID for the caller, allocating a new one if this is the first time
207 u32 GetHostThreadId(std::optional<std::size_t> core_id = std::nullopt) {
208 const thread_local auto host_thread_id{AllocateHostThreadId(core_id)};
209 return host_thread_id;
210 }
211
212 /// Registers a CPU core thread by allocating a host thread ID for it
189 void RegisterCoreThread(std::size_t core_id) { 213 void RegisterCoreThread(std::size_t core_id) {
190 const std::thread::id this_id = std::this_thread::get_id(); 214 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
215 const auto this_id = GetHostThreadId(core_id);
191 if (!is_multicore) { 216 if (!is_multicore) {
192 single_core_thread_id = this_id; 217 single_core_thread_id = this_id;
193 } 218 }
194 const auto end =
195 register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
196 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
197 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
198 ASSERT(it == end);
199 InsertHostThread(static_cast<u32>(core_id));
200 } 219 }
201 220
221 /// Registers a new host thread by allocating a host thread ID for it
202 void RegisterHostThread() { 222 void RegisterHostThread() {
203 const std::thread::id this_id = std::this_thread::get_id(); 223 [[maybe_unused]] const auto this_id = GetHostThreadId();
204 const auto end =
205 register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
206 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
207 if (it == end) {
208 InsertHostThread(registered_thread_ids++);
209 }
210 }
211
212 void InsertHostThread(u32 value) {
213 const size_t index = num_host_threads++;
214 ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads");
215 register_host_thread_values[index] = value;
216 register_host_thread_keys[index] = std::this_thread::get_id();
217 } 224 }
218 225
219 [[nodiscard]] u32 GetCurrentHostThreadID() const { 226 [[nodiscard]] u32 GetCurrentHostThreadID() {
220 const std::thread::id this_id = std::this_thread::get_id(); 227 const auto this_id = GetHostThreadId();
221 if (!is_multicore && single_core_thread_id == this_id) { 228 if (!is_multicore && single_core_thread_id == this_id) {
222 return static_cast<u32>(system.GetCpuManager().CurrentCore()); 229 return static_cast<u32>(system.GetCpuManager().CurrentCore());
223 } 230 }
224 const auto end = 231 return this_id;
225 register_host_thread_keys.begin() + static_cast<ptrdiff_t>(num_host_threads);
226 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
227 if (it == end) {
228 return Core::INVALID_HOST_THREAD_ID;
229 }
230 return register_host_thread_values[static_cast<size_t>(
231 std::distance(register_host_thread_keys.begin(), it))];
232 } 232 }
233 233
234 Core::EmuThreadHandle GetCurrentEmuThreadID() const { 234 [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() {
235 Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); 235 Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
236 result.host_handle = GetCurrentHostThreadID(); 236 result.host_handle = GetCurrentHostThreadID();
237 if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { 237 if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
@@ -325,15 +325,8 @@ struct KernelCore::Impl {
325 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 325 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
326 std::vector<Kernel::PhysicalCore> cores; 326 std::vector<Kernel::PhysicalCore> cores;
327 327
328 // 0-3 IDs represent core threads, >3 represent others 328 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
329 std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; 329 std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
330
331 // Number of host threads is a relatively high number to avoid overflowing
332 static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
333 std::atomic<size_t> num_host_threads{0};
334 std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
335 register_host_thread_keys{};
336 std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{};
337 330
338 // Kernel memory management 331 // Kernel memory management
339 std::unique_ptr<Memory::MemoryManager> memory_manager; 332 std::unique_ptr<Memory::MemoryManager> memory_manager;
@@ -345,12 +338,19 @@ struct KernelCore::Impl {
345 std::shared_ptr<Kernel::SharedMemory> irs_shared_mem; 338 std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
346 std::shared_ptr<Kernel::SharedMemory> time_shared_mem; 339 std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
347 340
341 // Threads used for services
342 std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
343
344 // Service threads are managed by a worker thread, so that a calling service thread can queue up
345 // the release of itself
346 std::unique_ptr<Common::ThreadWorker> service_thread_manager;
347
348 std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; 348 std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
349 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; 349 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
350 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; 350 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
351 351
352 bool is_multicore{}; 352 bool is_multicore{};
353 std::thread::id single_core_thread_id{}; 353 u32 single_core_thread_id{};
354 354
355 std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; 355 std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
356 356
@@ -639,4 +639,19 @@ void KernelCore::ExitSVCProfile() {
639 MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); 639 MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
640} 640}
641 641
642std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
643 auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
644 impl->service_thread_manager->QueueWork(
645 [this, service_thread] { impl->service_threads.emplace(service_thread); });
646 return service_thread;
647}
648
649void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
650 impl->service_thread_manager->QueueWork([this, service_thread] {
651 if (auto strong_ptr = service_thread.lock()) {
652 impl->service_threads.erase(strong_ptr);
653 }
654 });
655}
656
642} // namespace Kernel 657} // namespace Kernel