diff options
| author | 2020-12-30 22:06:05 -0800 | |
|---|---|---|
| committer | 2020-12-30 22:06:05 -0800 | |
| commit | 25d607f5f63929369fb74f386a920b69bb24f442 (patch) | |
| tree | 9ee5a023f033d99561a0358c5c71aeecc92c9d64 /src/core/hle/kernel/kernel.cpp | |
| parent | Merge pull request #5263 from lioncash/uninit (diff) | |
| parent | hle: kernel: service_thread: Make thread naming more consistent. (diff) | |
| download | yuzu-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.cpp | 113 |
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 | ||
| 642 | std::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 | |||
| 649 | void 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 |