summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2021-01-21 13:00:16 -0800
committerGravatar bunnei2021-01-28 21:42:26 -0800
commit6e953f7f0294d945ba9d6f08350d5dccb0d76075 (patch)
tree92a498827c4de7dd372731eff83c66aa3f57f060 /src
parenthle: kernel: k_scheduler: Use atomics for current_thread, etc. (diff)
downloadyuzu-6e953f7f0294d945ba9d6f08350d5dccb0d76075.tar.gz
yuzu-6e953f7f0294d945ba9d6f08350d5dccb0d76075.tar.xz
yuzu-6e953f7f0294d945ba9d6f08350d5dccb0d76075.zip
hle: kernel: Allocate a dummy KThread for each host thread, and use it for scheduling.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/k_light_lock.cpp12
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp6
-rw-r--r--src/core/hle/kernel/k_scheduler.h4
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h27
-rw-r--r--src/core/hle/kernel/k_thread.cpp6
-rw-r--r--src/core/hle/kernel/kernel.cpp27
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/yuzu/main.cpp2
8 files changed, 45 insertions, 43 deletions
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index 1d54ba5df..08fa65fd5 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -9,12 +9,6 @@
9 9
10namespace Kernel { 10namespace Kernel {
11 11
12static KThread* ToThread(uintptr_t thread_) {
13 ASSERT((thread_ & EmuThreadHandleReserved) == 0);
14 ASSERT((thread_ & 1) == 0);
15 return reinterpret_cast<KThread*>(thread_);
16}
17
18void KLightLock::Lock() { 12void KLightLock::Lock() {
19 const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); 13 const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
20 const uintptr_t cur_thread_tag = (cur_thread | 1); 14 const uintptr_t cur_thread_tag = (cur_thread | 1);
@@ -48,7 +42,7 @@ void KLightLock::Unlock() {
48} 42}
49 43
50void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { 44void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
51 KThread* cur_thread = ToThread(_cur_thread); 45 KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
52 46
53 // Pend the current thread waiting on the owner thread. 47 // Pend the current thread waiting on the owner thread.
54 { 48 {
@@ -60,7 +54,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
60 } 54 }
61 55
62 // Add the current thread as a waiter on the owner. 56 // Add the current thread as a waiter on the owner.
63 KThread* owner_thread = ToThread(_owner & ~1ul); 57 KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ul);
64 cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); 58 cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
65 owner_thread->AddWaiter(cur_thread); 59 owner_thread->AddWaiter(cur_thread);
66 60
@@ -88,7 +82,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
88} 82}
89 83
90void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { 84void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
91 KThread* owner_thread = ToThread(_cur_thread); 85 KThread* owner_thread = reinterpret_cast<KThread*>(_cur_thread);
92 86
93 // Unlock. 87 // Unlock.
94 { 88 {
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index fbdc061df..bb5f43b53 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -623,7 +623,7 @@ KThread* KScheduler::GetCurrentThread() const {
623 if (auto result = current_thread.load(); result) { 623 if (auto result = current_thread.load(); result) {
624 return result; 624 return result;
625 } 625 }
626 return idle_thread.get(); 626 return idle_thread;
627} 627}
628 628
629u64 KScheduler::GetLastContextSwitchTicks() const { 629u64 KScheduler::GetLastContextSwitchTicks() const {
@@ -708,7 +708,7 @@ void KScheduler::ScheduleImpl() {
708 708
709 // We never want to schedule a null thread, so use the idle thread if we don't have a next. 709 // We never want to schedule a null thread, so use the idle thread if we don't have a next.
710 if (next_thread == nullptr) { 710 if (next_thread == nullptr) {
711 next_thread = idle_thread.get(); 711 next_thread = idle_thread;
712 } 712 }
713 713
714 // If we're not actually switching thread, there's nothing to do. 714 // If we're not actually switching thread, there's nothing to do.
@@ -803,7 +803,7 @@ void KScheduler::Initialize() {
803 auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, 803 auto thread_res = KThread::Create(system, ThreadType::Main, name, 0,
804 KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0, 804 KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
805 nullptr, std::move(init_func), init_func_parameter); 805 nullptr, std::move(init_func), init_func_parameter);
806 idle_thread = thread_res.Unwrap(); 806 idle_thread = thread_res.Unwrap().get();
807} 807}
808 808
809KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) 809KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index e0d052593..f595b9a5c 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -54,7 +54,7 @@ public:
54 54
55 /// Returns true if the scheduler is idle 55 /// Returns true if the scheduler is idle
56 [[nodiscard]] bool IsIdle() const { 56 [[nodiscard]] bool IsIdle() const {
57 return GetCurrentThread() == idle_thread.get(); 57 return GetCurrentThread() == idle_thread;
58 } 58 }
59 59
60 /// Gets the timestamp for the last context switch in ticks. 60 /// Gets the timestamp for the last context switch in ticks.
@@ -176,7 +176,7 @@ private:
176 KThread* prev_thread{}; 176 KThread* prev_thread{};
177 std::atomic<KThread*> current_thread{}; 177 std::atomic<KThread*> current_thread{};
178 178
179 std::shared_ptr<KThread> idle_thread; 179 KThread* idle_thread;
180 180
181 std::shared_ptr<Common::Fiber> switch_fiber{}; 181 std::shared_ptr<Common::Fiber> switch_fiber{};
182 182
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 5d48dcf38..3b38f8f3e 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -10,6 +10,7 @@
10#include "common/assert.h" 10#include "common/assert.h"
11#include "common/spin_lock.h" 11#include "common/spin_lock.h"
12#include "core/hardware_properties.h" 12#include "core/hardware_properties.h"
13#include "core/hle/kernel/k_thread.h"
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
14 15
15namespace Kernel { 16namespace Kernel {
@@ -22,42 +23,42 @@ public:
22 explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {} 23 explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {}
23 24
24 bool IsLockedByCurrentThread() const { 25 bool IsLockedByCurrentThread() const {
25 return this->owner_thread == kernel.GetCurrentEmuThreadID(); 26 return this->owner_thread == GetCurrentThreadPointer(kernel);
26 } 27 }
27 28
28 void Lock() { 29 void Lock() {
29 if (this->IsLockedByCurrentThread()) { 30 if (this->IsLockedByCurrentThread()) {
30 // If we already own the lock, we can just increment the count. 31 // If we already own the lock, we can just increment the count.
31 ASSERT(this->lock_count > 0); 32 ASSERT(lock_count > 0);
32 this->lock_count++; 33 lock_count++;
33 } else { 34 } else {
34 // Otherwise, we want to disable scheduling and acquire the spinlock. 35 // Otherwise, we want to disable scheduling and acquire the spinlock.
35 SchedulerType::DisableScheduling(kernel); 36 SchedulerType::DisableScheduling(kernel);
36 this->spin_lock.lock(); 37 spin_lock.lock();
37 38
38 // For debug, ensure that our state is valid. 39 // For debug, ensure that our state is valid.
39 ASSERT(this->lock_count == 0); 40 ASSERT(lock_count == 0);
40 ASSERT(this->owner_thread == EmuThreadHandleInvalid); 41 ASSERT(owner_thread == nullptr);
41 42
42 // Increment count, take ownership. 43 // Increment count, take ownership.
43 this->lock_count = 1; 44 lock_count = 1;
44 this->owner_thread = kernel.GetCurrentEmuThreadID(); 45 owner_thread = GetCurrentThreadPointer(kernel);
45 } 46 }
46 } 47 }
47 48
48 void Unlock() { 49 void Unlock() {
49 ASSERT(this->IsLockedByCurrentThread()); 50 ASSERT(this->IsLockedByCurrentThread());
50 ASSERT(this->lock_count > 0); 51 ASSERT(lock_count > 0);
51 52
52 // Release an instance of the lock. 53 // Release an instance of the lock.
53 if ((--this->lock_count) == 0) { 54 if ((--lock_count) == 0) {
54 // We're no longer going to hold the lock. Take note of what cores need scheduling. 55 // We're no longer going to hold the lock. Take note of what cores need scheduling.
55 const u64 cores_needing_scheduling = 56 const u64 cores_needing_scheduling =
56 SchedulerType::UpdateHighestPriorityThreads(kernel); 57 SchedulerType::UpdateHighestPriorityThreads(kernel);
57 58
58 // Note that we no longer hold the lock, and unlock the spinlock. 59 // Note that we no longer hold the lock, and unlock the spinlock.
59 this->owner_thread = EmuThreadHandleInvalid; 60 owner_thread = nullptr;
60 this->spin_lock.unlock(); 61 spin_lock.unlock();
61 62
62 // Enable scheduling, and perform a rescheduling operation. 63 // Enable scheduling, and perform a rescheduling operation.
63 SchedulerType::EnableScheduling(kernel, cores_needing_scheduling); 64 SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
@@ -68,7 +69,7 @@ private:
68 KernelCore& kernel; 69 KernelCore& kernel;
69 Common::SpinLock spin_lock{}; 70 Common::SpinLock spin_lock{};
70 s32 lock_count{}; 71 s32 lock_count{};
71 EmuThreadHandle owner_thread{EmuThreadHandleInvalid}; 72 KThread* owner_thread{};
72}; 73};
73 74
74} // namespace Kernel 75} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 62ce2fbd5..f57e98047 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -1034,11 +1034,7 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
1034} 1034}
1035 1035
1036KThread* GetCurrentThreadPointer(KernelCore& kernel) { 1036KThread* GetCurrentThreadPointer(KernelCore& kernel) {
1037 if (!kernel.CurrentScheduler()) { 1037 return kernel.GetCurrentEmuThread();
1038 // We are not called from a core thread
1039 return {};
1040 }
1041 return kernel.CurrentScheduler()->GetCurrentThread();
1042} 1038}
1043 1039
1044KThread& GetCurrentThread(KernelCore& kernel) { 1040KThread& GetCurrentThread(KernelCore& kernel) {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 6142496b6..093886b7c 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -57,9 +57,10 @@ struct KernelCore::Impl {
57 } 57 }
58 58
59 void Initialize(KernelCore& kernel) { 59 void Initialize(KernelCore& kernel) {
60 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
61
60 RegisterHostThread(); 62 RegisterHostThread();
61 63
62 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
63 service_thread_manager = 64 service_thread_manager =
64 std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager"); 65 std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
65 is_phantom_mode_for_singlecore = false; 66 is_phantom_mode_for_singlecore = false;
@@ -206,6 +207,18 @@ struct KernelCore::Impl {
206 return host_thread_id; 207 return host_thread_id;
207 } 208 }
208 209
210 // Gets the dummy KThread for the caller, allocating a new one if this is the first time
211 KThread* GetHostDummyThread() {
212 const thread_local auto thread =
213 KThread::Create(
214 system, ThreadType::Main,
215 std::string{"DummyThread:" + GetHostThreadId()}, 0, KThread::DefaultThreadPriority,
216 0, static_cast<u32>(3), 0, nullptr,
217 []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr)
218 .Unwrap();
219 return thread.get();
220 }
221
209 /// Registers a CPU core thread by allocating a host thread ID for it 222 /// Registers a CPU core thread by allocating a host thread ID for it
210 void RegisterCoreThread(std::size_t core_id) { 223 void RegisterCoreThread(std::size_t core_id) {
211 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); 224 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
@@ -218,6 +231,7 @@ struct KernelCore::Impl {
218 /// Registers a new host thread by allocating a host thread ID for it 231 /// Registers a new host thread by allocating a host thread ID for it
219 void RegisterHostThread() { 232 void RegisterHostThread() {
220 [[maybe_unused]] const auto this_id = GetHostThreadId(); 233 [[maybe_unused]] const auto this_id = GetHostThreadId();
234 [[maybe_unused]] const auto dummy_thread = GetHostDummyThread();
221 } 235 }
222 236
223 [[nodiscard]] u32 GetCurrentHostThreadID() { 237 [[nodiscard]] u32 GetCurrentHostThreadID() {
@@ -237,13 +251,12 @@ struct KernelCore::Impl {
237 is_phantom_mode_for_singlecore = value; 251 is_phantom_mode_for_singlecore = value;
238 } 252 }
239 253
240 [[nodiscard]] EmuThreadHandle GetCurrentEmuThreadID() { 254 KThread* GetCurrentEmuThread() {
241 const auto thread_id = GetCurrentHostThreadID(); 255 const auto thread_id = GetCurrentHostThreadID();
242 if (thread_id >= Core::Hardware::NUM_CPU_CORES) { 256 if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
243 // Reserved value for HLE threads 257 return GetHostDummyThread();
244 return EmuThreadHandleReserved + (static_cast<u64>(thread_id) << 1);
245 } 258 }
246 return reinterpret_cast<uintptr_t>(schedulers[thread_id].get()); 259 return schedulers[thread_id]->GetCurrentThread();
247 } 260 }
248 261
249 void InitializeMemoryLayout() { 262 void InitializeMemoryLayout() {
@@ -548,8 +561,8 @@ u32 KernelCore::GetCurrentHostThreadID() const {
548 return impl->GetCurrentHostThreadID(); 561 return impl->GetCurrentHostThreadID();
549} 562}
550 563
551EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { 564KThread* KernelCore::GetCurrentEmuThread() const {
552 return impl->GetCurrentEmuThreadID(); 565 return impl->GetCurrentEmuThread();
553} 566}
554 567
555Memory::MemoryManager& KernelCore::MemoryManager() { 568Memory::MemoryManager& KernelCore::MemoryManager() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index b92c017f6..e7c77727b 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -165,8 +165,8 @@ public:
165 /// Determines whether or not the given port is a valid named port. 165 /// Determines whether or not the given port is a valid named port.
166 bool IsValidNamedPort(NamedPortTable::const_iterator port) const; 166 bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
167 167
168 /// Gets the current host_thread/guest_thread handle. 168 /// Gets the current host_thread/guest_thread pointer.
169 EmuThreadHandle GetCurrentEmuThreadID() const; 169 KThread* GetCurrentEmuThread() const;
170 170
171 /// Gets the current host_thread handle. 171 /// Gets the current host_thread handle.
172 u32 GetCurrentHostThreadID() const; 172 u32 GetCurrentHostThreadID() const;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index e76141125..886e6e9d2 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1039,8 +1039,6 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
1039 std::make_unique<QtWebBrowser>(*this), // Web Browser 1039 std::make_unique<QtWebBrowser>(*this), // Web Browser
1040 }); 1040 });
1041 1041
1042 system.RegisterHostThread();
1043
1044 const Core::System::ResultStatus result{ 1042 const Core::System::ResultStatus result{
1045 system.Load(*render_window, filename.toStdString(), program_index)}; 1043 system.Load(*render_window, filename.toStdString(), program_index)};
1046 1044