diff options
| author | 2021-01-21 13:00:16 -0800 | |
|---|---|---|
| committer | 2021-01-28 21:42:26 -0800 | |
| commit | 6e953f7f0294d945ba9d6f08350d5dccb0d76075 (patch) | |
| tree | 92a498827c4de7dd372731eff83c66aa3f57f060 /src | |
| parent | hle: kernel: k_scheduler: Use atomics for current_thread, etc. (diff) | |
| download | yuzu-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.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler_lock.h | 27 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 27 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 2 |
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 | ||
| 10 | namespace Kernel { | 10 | namespace Kernel { |
| 11 | 11 | ||
| 12 | static KThread* ToThread(uintptr_t thread_) { | ||
| 13 | ASSERT((thread_ & EmuThreadHandleReserved) == 0); | ||
| 14 | ASSERT((thread_ & 1) == 0); | ||
| 15 | return reinterpret_cast<KThread*>(thread_); | ||
| 16 | } | ||
| 17 | |||
| 18 | void KLightLock::Lock() { | 12 | void 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 | ||
| 50 | void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { | 44 | void 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 | ||
| 90 | void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { | 84 | void 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 | ||
| 629 | u64 KScheduler::GetLastContextSwitchTicks() const { | 629 | u64 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 | ||
| 809 | KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) | 809 | KScopedSchedulerLock::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 | ||
| 15 | namespace Kernel { | 16 | namespace 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 | ||
| 1036 | KThread* GetCurrentThreadPointer(KernelCore& kernel) { | 1036 | KThread* 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 | ||
| 1044 | KThread& GetCurrentThread(KernelCore& kernel) { | 1040 | KThread& 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 | ||
| 551 | EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { | 564 | KThread* KernelCore::GetCurrentEmuThread() const { |
| 552 | return impl->GetCurrentEmuThreadID(); | 565 | return impl->GetCurrentEmuThread(); |
| 553 | } | 566 | } |
| 554 | 567 | ||
| 555 | Memory::MemoryManager& KernelCore::MemoryManager() { | 568 | Memory::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 | ||