summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2022-01-17 18:08:24 -0800
committerGravatar GitHub2022-01-17 18:08:24 -0800
commit101d86897b729ca66caf7cfee246e6f238ecf723 (patch)
tree92b516dd4958ca01bb5544a475011a2634412132 /src
parentMerge pull request #7724 from ameerj/astc_new_nv (diff)
parentcore: hle: kernel: KThread: Integrate with KWorkerTask and implement DoWorker... (diff)
downloadyuzu-101d86897b729ca66caf7cfee246e6f238ecf723.tar.gz
yuzu-101d86897b729ca66caf7cfee246e6f238ecf723.tar.xz
yuzu-101d86897b729ca66caf7cfee246e6f238ecf723.zip
Merge pull request #7712 from bunnei/fix-thread-exit
Accurately implement thread exit
Diffstat (limited to 'src')
-rw-r--r--src/common/fiber.cpp5
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/hle/kernel/k_process.cpp6
-rw-r--r--src/core/hle/kernel/k_process.h6
-rw-r--r--src/core/hle/kernel/k_thread.cpp78
-rw-r--r--src/core/hle/kernel/k_thread.h11
-rw-r--r--src/core/hle/kernel/k_worker_task.h18
-rw-r--r--src/core/hle/kernel/k_worker_task_manager.cpp42
-rw-r--r--src/core/hle/kernel/k_worker_task_manager.h33
-rw-r--r--src/core/hle/kernel/kernel.cpp11
-rw-r--r--src/core/hle/kernel/kernel.h7
11 files changed, 181 insertions, 39 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp
index 62010d762..81b212e4b 100644
--- a/src/common/fiber.cpp
+++ b/src/common/fiber.cpp
@@ -124,7 +124,10 @@ void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
124 124
125 // "from" might no longer be valid if the thread was killed 125 // "from" might no longer be valid if the thread was killed
126 if (auto from = weak_from.lock()) { 126 if (auto from = weak_from.lock()) {
127 ASSERT(from->impl->previous_fiber != nullptr); 127 if (from->impl->previous_fiber == nullptr) {
128 ASSERT_MSG(false, "previous_fiber is nullptr!");
129 return;
130 }
128 from->impl->previous_fiber->impl->context = transfer.fctx; 131 from->impl->previous_fiber->impl->context = transfer.fctx;
129 from->impl->previous_fiber->impl->guard.unlock(); 132 from->impl->previous_fiber->impl->guard.unlock();
130 from->impl->previous_fiber.reset(); 133 from->impl->previous_fiber.reset();
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index b1a746727..6e8d11919 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -247,6 +247,9 @@ add_library(core STATIC
247 hle/kernel/k_trace.h 247 hle/kernel/k_trace.h
248 hle/kernel/k_transfer_memory.cpp 248 hle/kernel/k_transfer_memory.cpp
249 hle/kernel/k_transfer_memory.h 249 hle/kernel/k_transfer_memory.h
250 hle/kernel/k_worker_task.h
251 hle/kernel/k_worker_task_manager.cpp
252 hle/kernel/k_worker_task_manager.h
250 hle/kernel/k_writable_event.cpp 253 hle/kernel/k_writable_event.cpp
251 hle/kernel/k_writable_event.h 254 hle/kernel/k_writable_event.h
252 hle/kernel/kernel.cpp 255 hle/kernel/kernel.cpp
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index cca405fed..265ac6fa1 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -149,6 +149,10 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st
149 return ResultSuccess; 149 return ResultSuccess;
150} 150}
151 151
152void KProcess::DoWorkerTaskImpl() {
153 UNIMPLEMENTED();
154}
155
152KResourceLimit* KProcess::GetResourceLimit() const { 156KResourceLimit* KProcess::GetResourceLimit() const {
153 return resource_limit; 157 return resource_limit;
154} 158}
@@ -477,7 +481,7 @@ void KProcess::Finalize() {
477 } 481 }
478 482
479 // Perform inherited finalization. 483 // Perform inherited finalization.
480 KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); 484 KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize();
481} 485}
482 486
483/** 487/**
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index e7c8b5838..c2a672021 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -15,6 +15,7 @@
15#include "core/hle/kernel/k_condition_variable.h" 15#include "core/hle/kernel/k_condition_variable.h"
16#include "core/hle/kernel/k_handle_table.h" 16#include "core/hle/kernel/k_handle_table.h"
17#include "core/hle/kernel/k_synchronization_object.h" 17#include "core/hle/kernel/k_synchronization_object.h"
18#include "core/hle/kernel/k_worker_task.h"
18#include "core/hle/kernel/process_capability.h" 19#include "core/hle/kernel/process_capability.h"
19#include "core/hle/kernel/slab_helpers.h" 20#include "core/hle/kernel/slab_helpers.h"
20#include "core/hle/result.h" 21#include "core/hle/result.h"
@@ -62,8 +63,7 @@ enum class ProcessStatus {
62 DebugBreak, 63 DebugBreak,
63}; 64};
64 65
65class KProcess final 66class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> {
66 : public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject> {
67 KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); 67 KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
68 68
69public: 69public:
@@ -345,6 +345,8 @@ public:
345 345
346 bool IsSignaled() const override; 346 bool IsSignaled() const override;
347 347
348 void DoWorkerTaskImpl();
349
348 void PinCurrentThread(s32 core_id); 350 void PinCurrentThread(s32 core_id);
349 void UnpinCurrentThread(s32 core_id); 351 void UnpinCurrentThread(s32 core_id);
350 void UnpinThread(KThread* thread); 352 void UnpinThread(KThread* thread);
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 71e029a3f..7a5e6fc08 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -30,6 +30,7 @@
30#include "core/hle/kernel/k_system_control.h" 30#include "core/hle/kernel/k_system_control.h"
31#include "core/hle/kernel/k_thread.h" 31#include "core/hle/kernel/k_thread.h"
32#include "core/hle/kernel/k_thread_queue.h" 32#include "core/hle/kernel/k_thread_queue.h"
33#include "core/hle/kernel/k_worker_task_manager.h"
33#include "core/hle/kernel/kernel.h" 34#include "core/hle/kernel/kernel.h"
34#include "core/hle/kernel/svc_results.h" 35#include "core/hle/kernel/svc_results.h"
35#include "core/hle/kernel/time_manager.h" 36#include "core/hle/kernel/time_manager.h"
@@ -332,7 +333,7 @@ void KThread::Finalize() {
332 } 333 }
333 334
334 // Perform inherited finalization. 335 // Perform inherited finalization.
335 KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize(); 336 KSynchronizationObject::Finalize();
336} 337}
337 338
338bool KThread::IsSignaled() const { 339bool KThread::IsSignaled() const {
@@ -376,11 +377,28 @@ void KThread::StartTermination() {
376 377
377 // Register terminated dpc flag. 378 // Register terminated dpc flag.
378 RegisterDpc(DpcFlag::Terminated); 379 RegisterDpc(DpcFlag::Terminated);
380}
381
382void KThread::FinishTermination() {
383 // Ensure that the thread is not executing on any core.
384 if (parent != nullptr) {
385 for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) {
386 KThread* core_thread{};
387 do {
388 core_thread = kernel.Scheduler(i).GetCurrentThread();
389 } while (core_thread == this);
390 }
391 }
379 392
380 // Close the thread. 393 // Close the thread.
381 this->Close(); 394 this->Close();
382} 395}
383 396
397void KThread::DoWorkerTaskImpl() {
398 // Finish the termination that was begun by Exit().
399 this->FinishTermination();
400}
401
384void KThread::Pin(s32 current_core) { 402void KThread::Pin(s32 current_core) {
385 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 403 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
386 404
@@ -417,12 +435,7 @@ void KThread::Pin(s32 current_core) {
417 static_cast<u32>(ThreadState::SuspendShift))); 435 static_cast<u32>(ThreadState::SuspendShift)));
418 436
419 // Update our state. 437 // Update our state.
420 const ThreadState old_state = thread_state; 438 UpdateState();
421 thread_state = static_cast<ThreadState>(GetSuspendFlags() |
422 static_cast<u32>(old_state & ThreadState::Mask));
423 if (thread_state != old_state) {
424 KScheduler::OnThreadStateChanged(kernel, this, old_state);
425 }
426 } 439 }
427 440
428 // TODO(bunnei): Update our SVC access permissions. 441 // TODO(bunnei): Update our SVC access permissions.
@@ -463,20 +476,13 @@ void KThread::Unpin() {
463 } 476 }
464 477
465 // Allow performing thread suspension (if termination hasn't been requested). 478 // Allow performing thread suspension (if termination hasn't been requested).
466 { 479 if (!IsTerminationRequested()) {
467 // Update our allow flags. 480 // Update our allow flags.
468 if (!IsTerminationRequested()) { 481 suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) +
469 suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) + 482 static_cast<u32>(ThreadState::SuspendShift)));
470 static_cast<u32>(ThreadState::SuspendShift)));
471 }
472 483
473 // Update our state. 484 // Update our state.
474 const ThreadState old_state = thread_state; 485 UpdateState();
475 thread_state = static_cast<ThreadState>(GetSuspendFlags() |
476 static_cast<u32>(old_state & ThreadState::Mask));
477 if (thread_state != old_state) {
478 KScheduler::OnThreadStateChanged(kernel, this, old_state);
479 }
480 } 486 }
481 487
482 // TODO(bunnei): Update our SVC access permissions. 488 // TODO(bunnei): Update our SVC access permissions.
@@ -689,12 +695,7 @@ void KThread::Resume(SuspendType type) {
689 ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type))); 695 ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
690 696
691 // Update our state. 697 // Update our state.
692 const ThreadState old_state = thread_state; 698 this->UpdateState();
693 thread_state = static_cast<ThreadState>(GetSuspendFlags() |
694 static_cast<u32>(old_state & ThreadState::Mask));
695 if (thread_state != old_state) {
696 KScheduler::OnThreadStateChanged(kernel, this, old_state);
697 }
698} 699}
699 700
700void KThread::WaitCancel() { 701void KThread::WaitCancel() {
@@ -721,19 +722,22 @@ void KThread::TrySuspend() {
721 ASSERT(GetNumKernelWaiters() == 0); 722 ASSERT(GetNumKernelWaiters() == 0);
722 723
723 // Perform the suspend. 724 // Perform the suspend.
724 Suspend(); 725 this->UpdateState();
725} 726}
726 727
727void KThread::Suspend() { 728void KThread::UpdateState() {
728 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 729 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
729 ASSERT(IsSuspendRequested());
730 730
731 // Set our suspend flags in state. 731 // Set our suspend flags in state.
732 const auto old_state = thread_state; 732 const auto old_state = thread_state;
733 thread_state = static_cast<ThreadState>(GetSuspendFlags()) | (old_state & ThreadState::Mask); 733 const auto new_state =
734 static_cast<ThreadState>(this->GetSuspendFlags()) | (old_state & ThreadState::Mask);
735 thread_state = new_state;
734 736
735 // Note the state change in scheduler. 737 // Note the state change in scheduler.
736 KScheduler::OnThreadStateChanged(kernel, this, old_state); 738 if (new_state != old_state) {
739 KScheduler::OnThreadStateChanged(kernel, this, old_state);
740 }
737} 741}
738 742
739void KThread::Continue() { 743void KThread::Continue() {
@@ -998,13 +1002,16 @@ ResultCode KThread::Run() {
998 1002
999 // If the current thread has been asked to suspend, suspend it and retry. 1003 // If the current thread has been asked to suspend, suspend it and retry.
1000 if (GetCurrentThread(kernel).IsSuspended()) { 1004 if (GetCurrentThread(kernel).IsSuspended()) {
1001 GetCurrentThread(kernel).Suspend(); 1005 GetCurrentThread(kernel).UpdateState();
1002 continue; 1006 continue;
1003 } 1007 }
1004 1008
1005 // If we're not a kernel thread and we've been asked to suspend, suspend ourselves. 1009 // If we're not a kernel thread and we've been asked to suspend, suspend ourselves.
1006 if (IsUserThread() && IsSuspended()) { 1010 if (KProcess* owner = this->GetOwnerProcess(); owner != nullptr) {
1007 Suspend(); 1011 if (IsUserThread() && IsSuspended()) {
1012 this->UpdateState();
1013 }
1014 owner->IncrementThreadCount();
1008 } 1015 }
1009 1016
1010 // Set our state and finish. 1017 // Set our state and finish.
@@ -1031,9 +1038,16 @@ void KThread::Exit() {
1031 1038
1032 // Disallow all suspension. 1039 // Disallow all suspension.
1033 suspend_allowed_flags = 0; 1040 suspend_allowed_flags = 0;
1041 this->UpdateState();
1042
1043 // Disallow all suspension.
1044 suspend_allowed_flags = 0;
1034 1045
1035 // Start termination. 1046 // Start termination.
1036 StartTermination(); 1047 StartTermination();
1048
1049 // Register the thread as a work task.
1050 KWorkerTaskManager::AddTask(kernel, KWorkerTaskManager::WorkerType::Exit, this);
1037 } 1051 }
1038} 1052}
1039 1053
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 83dfde69b..cc427f6cf 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -19,6 +19,7 @@
19#include "core/hle/kernel/k_light_lock.h" 19#include "core/hle/kernel/k_light_lock.h"
20#include "core/hle/kernel/k_spin_lock.h" 20#include "core/hle/kernel/k_spin_lock.h"
21#include "core/hle/kernel/k_synchronization_object.h" 21#include "core/hle/kernel/k_synchronization_object.h"
22#include "core/hle/kernel/k_worker_task.h"
22#include "core/hle/kernel/slab_helpers.h" 23#include "core/hle/kernel/slab_helpers.h"
23#include "core/hle/kernel/svc_common.h" 24#include "core/hle/kernel/svc_common.h"
24#include "core/hle/kernel/svc_types.h" 25#include "core/hle/kernel/svc_types.h"
@@ -100,7 +101,7 @@ enum class ThreadWaitReasonForDebugging : u32 {
100[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); 101[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
101[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); 102[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
102 103
103class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>, 104class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
104 public boost::intrusive::list_base_hook<> { 105 public boost::intrusive::list_base_hook<> {
105 KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); 106 KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
106 107
@@ -192,9 +193,9 @@ public:
192 193
193 void TrySuspend(); 194 void TrySuspend();
194 195
195 void Continue(); 196 void UpdateState();
196 197
197 void Suspend(); 198 void Continue();
198 199
199 constexpr void SetSyncedIndex(s32 index) { 200 constexpr void SetSyncedIndex(s32 index) {
200 synced_index = index; 201 synced_index = index;
@@ -385,6 +386,8 @@ public:
385 386
386 void OnTimer(); 387 void OnTimer();
387 388
389 void DoWorkerTaskImpl();
390
388 static void PostDestroy(uintptr_t arg); 391 static void PostDestroy(uintptr_t arg);
389 392
390 [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); 393 [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
@@ -679,6 +682,8 @@ private:
679 682
680 void StartTermination(); 683 void StartTermination();
681 684
685 void FinishTermination();
686
682 [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, 687 [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
683 s32 prio, s32 virt_core, KProcess* owner, ThreadType type); 688 s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
684 689
diff --git a/src/core/hle/kernel/k_worker_task.h b/src/core/hle/kernel/k_worker_task.h
new file mode 100644
index 000000000..b7794c6a8
--- /dev/null
+++ b/src/core/hle/kernel/k_worker_task.h
@@ -0,0 +1,18 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/kernel/k_synchronization_object.h"
8
9namespace Kernel {
10
11class KWorkerTask : public KSynchronizationObject {
12public:
13 explicit KWorkerTask(KernelCore& kernel_);
14
15 void DoWorkerTask();
16};
17
18} // namespace Kernel
diff --git a/src/core/hle/kernel/k_worker_task_manager.cpp b/src/core/hle/kernel/k_worker_task_manager.cpp
new file mode 100644
index 000000000..785e08111
--- /dev/null
+++ b/src/core/hle/kernel/k_worker_task_manager.cpp
@@ -0,0 +1,42 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_thread.h"
8#include "core/hle/kernel/k_worker_task.h"
9#include "core/hle/kernel/k_worker_task_manager.h"
10#include "core/hle/kernel/kernel.h"
11
12namespace Kernel {
13
14KWorkerTask::KWorkerTask(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
15
16void KWorkerTask::DoWorkerTask() {
17 if (auto* const thread = this->DynamicCast<KThread*>(); thread != nullptr) {
18 return thread->DoWorkerTaskImpl();
19 } else {
20 auto* const process = this->DynamicCast<KProcess*>();
21 ASSERT(process != nullptr);
22
23 return process->DoWorkerTaskImpl();
24 }
25}
26
27KWorkerTaskManager::KWorkerTaskManager() : m_waiting_thread(1, "yuzu:KWorkerTaskManager") {}
28
29void KWorkerTaskManager::AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task) {
30 ASSERT(type <= WorkerType::Count);
31 kernel.WorkerTaskManager().AddTask(kernel, task);
32}
33
34void KWorkerTaskManager::AddTask(KernelCore& kernel, KWorkerTask* task) {
35 KScopedSchedulerLock sl(kernel);
36 m_waiting_thread.QueueWork([task]() {
37 // Do the task.
38 task->DoWorkerTask();
39 });
40}
41
42} // namespace Kernel
diff --git a/src/core/hle/kernel/k_worker_task_manager.h b/src/core/hle/kernel/k_worker_task_manager.h
new file mode 100644
index 000000000..43d1bfcec
--- /dev/null
+++ b/src/core/hle/kernel/k_worker_task_manager.h
@@ -0,0 +1,33 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/thread_worker.h"
9
10namespace Kernel {
11
12class KernelCore;
13class KWorkerTask;
14
15class KWorkerTaskManager final {
16public:
17 enum class WorkerType : u32 {
18 Exit,
19 Count,
20 };
21
22 KWorkerTaskManager();
23
24 static void AddTask(KernelCore& kernel_, WorkerType type, KWorkerTask* task);
25
26private:
27 void AddTask(KernelCore& kernel, KWorkerTask* task);
28
29private:
30 Common::ThreadWorker m_waiting_thread;
31};
32
33} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0b618fb46..e5cf9abb3 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -37,6 +37,7 @@
37#include "core/hle/kernel/k_shared_memory.h" 37#include "core/hle/kernel/k_shared_memory.h"
38#include "core/hle/kernel/k_slab_heap.h" 38#include "core/hle/kernel/k_slab_heap.h"
39#include "core/hle/kernel/k_thread.h" 39#include "core/hle/kernel/k_thread.h"
40#include "core/hle/kernel/k_worker_task_manager.h"
40#include "core/hle/kernel/kernel.h" 41#include "core/hle/kernel/kernel.h"
41#include "core/hle/kernel/physical_core.h" 42#include "core/hle/kernel/physical_core.h"
42#include "core/hle/kernel/service_thread.h" 43#include "core/hle/kernel/service_thread.h"
@@ -797,6 +798,8 @@ struct KernelCore::Impl {
797 798
798 std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; 799 std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
799 800
801 KWorkerTaskManager worker_task_manager;
802
800 // System context 803 // System context
801 Core::System& system; 804 Core::System& system;
802}; 805};
@@ -1137,6 +1140,14 @@ const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const {
1137 return impl->slab_resource_counts; 1140 return impl->slab_resource_counts;
1138} 1141}
1139 1142
1143KWorkerTaskManager& KernelCore::WorkerTaskManager() {
1144 return impl->worker_task_manager;
1145}
1146
1147const KWorkerTaskManager& KernelCore::WorkerTaskManager() const {
1148 return impl->worker_task_manager;
1149}
1150
1140bool KernelCore::IsPhantomModeForSingleCore() const { 1151bool KernelCore::IsPhantomModeForSingleCore() const {
1141 return impl->IsPhantomModeForSingleCore(); 1152 return impl->IsPhantomModeForSingleCore();
1142} 1153}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index b9b423908..0e04fc3bb 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -52,6 +52,7 @@ class KSharedMemory;
52class KSharedMemoryInfo; 52class KSharedMemoryInfo;
53class KThread; 53class KThread;
54class KTransferMemory; 54class KTransferMemory;
55class KWorkerTaskManager;
55class KWritableEvent; 56class KWritableEvent;
56class KCodeMemory; 57class KCodeMemory;
57class PhysicalCore; 58class PhysicalCore;
@@ -343,6 +344,12 @@ public:
343 /// Gets the current slab resource counts. 344 /// Gets the current slab resource counts.
344 const Init::KSlabResourceCounts& SlabResourceCounts() const; 345 const Init::KSlabResourceCounts& SlabResourceCounts() const;
345 346
347 /// Gets the current worker task manager, used for dispatching KThread/KProcess tasks.
348 KWorkerTaskManager& WorkerTaskManager();
349
350 /// Gets the current worker task manager, used for dispatching KThread/KProcess tasks.
351 const KWorkerTaskManager& WorkerTaskManager() const;
352
346private: 353private:
347 friend class KProcess; 354 friend class KProcess;
348 friend class KThread; 355 friend class KThread;