From 61801c36029a7009e0366676d4b7fb2e57a774ea Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Mon, 11 Apr 2022 04:58:40 +0200 Subject: [PATCH] early-access version 2668 --- README.md | 2 +- src/common/fiber.cpp | 5 +-- src/core/core_timing.h | 6 +-- .../hle/kernel/global_scheduler_context.h | 3 +- src/core/hle/kernel/k_scheduler.cpp | 11 ++++-- src/core/hle/kernel/k_spin_lock.cpp | 39 +++++++++++++++++-- src/core/hle/kernel/k_spin_lock.h | 4 +- src/core/hle/kernel/k_thread.cpp | 37 ++++++++++++++++++ src/core/hle/kernel/k_thread.h | 11 +++++- src/core/hle/kernel/physical_core.cpp | 3 +- src/core/hle/kernel/physical_core.h | 7 +++- src/core/hle/service/service.h | 5 ++- 12 files changed, 109 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2da745128..82e303fd8 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2667. +This is the source code for early-access 2668. ## Legal Notice diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 177a74deb..81b212e4b 100755 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -2,10 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include - #include "common/assert.h" #include "common/fiber.h" +#include "common/spin_lock.h" #include "common/virtual_buffer.h" #include @@ -20,7 +19,7 @@ struct Fiber::FiberImpl { VirtualBuffer stack; VirtualBuffer rewind_stack; - std::mutex guard; + SpinLock guard{}; std::function entry_point; std::function rewind_point; void* rewind_parameter{}; diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 28b63be43..888828fd0 100755 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -8,13 +8,13 @@ #include #include #include -#include #include #include #include #include #include "common/common_types.h" +#include "common/spin_lock.h" #include "common/thread.h" #include "common/wall_clock.h" @@ -149,8 +149,8 @@ private: std::shared_ptr ev_lost; Common::Event event{}; Common::Event pause_event{}; - std::mutex basic_lock; - std::mutex advance_lock; + Common::SpinLock basic_lock{}; + Common::SpinLock advance_lock{}; std::unique_ptr timer_thread; std::atomic paused{}; std::atomic paused_set{}; diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 47425a3a1..6f44b534f 100755 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -8,6 +8,7 @@ #include #include "common/common_types.h" +#include "common/spin_lock.h" #include "core/hardware_properties.h" #include "core/hle/kernel/k_priority_queue.h" #include "core/hle/kernel/k_scheduler_lock.h" @@ -79,7 +80,7 @@ private: /// Lists all thread ids that aren't deleted/etc. std::vector thread_list; - std::mutex global_list_guard; + Common::SpinLock global_list_guard{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 392f1e40c..6c0bb1672 100755 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -405,6 +405,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli } else { RescheduleCores(kernel, cores_needing_scheduling); } + + // Special case to ensure dummy threads that are waiting block. + current_thread->IfDummyThreadTryWait(); } u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { @@ -702,7 +705,7 @@ void KScheduler::Unload(KThread* thread) { prev_thread = nullptr; } - thread->context_guard.unlock(); + thread->context_guard.Unlock(); } void KScheduler::Reload(KThread* thread) { @@ -791,13 +794,13 @@ void KScheduler::SwitchToCurrent() { do { auto next_thread = current_thread.load(); if (next_thread != nullptr) { - const auto locked = next_thread->context_guard.try_lock(); + const auto locked = next_thread->context_guard.TryLock(); if (state.needs_scheduling.load()) { - next_thread->context_guard.unlock(); + next_thread->context_guard.Unlock(); break; } if (next_thread->GetActiveCore() != core_id) { - next_thread->context_guard.unlock(); + next_thread->context_guard.Unlock(); break; } if (!locked) { diff --git a/src/core/hle/kernel/k_spin_lock.cpp b/src/core/hle/kernel/k_spin_lock.cpp index 527ff0f9f..4412aa4bb 100755 --- a/src/core/hle/kernel/k_spin_lock.cpp +++ b/src/core/hle/kernel/k_spin_lock.cpp @@ -4,18 +4,51 @@ #include "core/hle/kernel/k_spin_lock.h" +#if _MSC_VER +#include +#if _M_AMD64 +#define __x86_64__ 1 +#endif +#if _M_ARM64 +#define __aarch64__ 1 +#endif +#else +#if __x86_64__ +#include +#endif +#endif + +namespace { + +void ThreadPause() { +#if __x86_64__ + _mm_pause(); +#elif __aarch64__ && _MSC_VER + __yield(); +#elif __aarch64__ + asm("yield"); +#endif +} + +} // namespace + namespace Kernel { void KSpinLock::Lock() { - lck.lock(); + while (lck.test_and_set(std::memory_order_acquire)) { + ThreadPause(); + } } void KSpinLock::Unlock() { - lck.unlock(); + lck.clear(std::memory_order_release); } bool KSpinLock::TryLock() { - return lck.try_lock(); + if (lck.test_and_set(std::memory_order_acquire)) { + return false; + } + return true; } } // namespace Kernel diff --git a/src/core/hle/kernel/k_spin_lock.h b/src/core/hle/kernel/k_spin_lock.h index 7868b25a5..4d87d006a 100755 --- a/src/core/hle/kernel/k_spin_lock.h +++ b/src/core/hle/kernel/k_spin_lock.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include "core/hle/kernel/k_scoped_lock.h" @@ -25,7 +25,7 @@ public: [[nodiscard]] bool TryLock(); private: - std::mutex lck; + std::atomic_flag lck = ATOMIC_FLAG_INIT; }; // TODO(bunnei): Alias for now, in case we want to implement these accurately in the future. diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index f58f8f827..d3bb1c871 100755 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -1070,12 +1070,46 @@ ResultCode KThread::Sleep(s64 timeout) { return ResultSuccess; } +void KThread::IfDummyThreadTryWait() { + if (!IsDummyThread()) { + return; + } + + if (GetState() != ThreadState::Waiting) { + return; + } + + // Block until we can grab the lock. + KScopedSpinLock lk{dummy_wait_lock}; +} + +void KThread::IfDummyThreadBeginWait() { + if (!IsDummyThread()) { + return; + } + + // Ensure the thread will block when IfDummyThreadTryWait is called. + dummy_wait_lock.Lock(); +} + +void KThread::IfDummyThreadEndWait() { + if (!IsDummyThread()) { + return; + } + + // Ensure the thread will no longer block. + dummy_wait_lock.Unlock(); +} + void KThread::BeginWait(KThreadQueue* queue) { // Set our state as waiting. SetState(ThreadState::Waiting); // Set our wait queue. wait_queue = queue; + + // Special case for dummy threads to ensure they block. + IfDummyThreadBeginWait(); } void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { @@ -1101,6 +1135,9 @@ void KThread::EndWait(ResultCode wait_result_) { } wait_queue->EndWait(this, wait_result_); + + // Special case for dummy threads to wakeup if necessary. + IfDummyThreadEndWait(); } } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index b97a21215..d0fd85130 100755 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -15,7 +15,6 @@ #include "common/common_types.h" #include "common/intrusive_red_black_tree.h" -#include "common/spin_lock.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/k_affinity_mask.h" #include "core/hle/kernel/k_light_lock.h" @@ -638,6 +637,14 @@ public: return condvar_key; } + // Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and + // therefore will not block on guest kernel synchronization primitives. These methods handle + // blocking as needed. + + void IfDummyThreadTryWait(); + void IfDummyThreadBeginWait(); + void IfDummyThreadEndWait(); + private: static constexpr size_t PriorityInheritanceCountMax = 10; union SyncObjectBuffer { @@ -755,7 +762,7 @@ private: s8 priority_inheritance_count{}; bool resource_limit_release_hint{}; StackParameters stack_parameters{}; - Common::SpinLock context_guard{}; + KSpinLock context_guard{}; KSpinLock dummy_wait_lock{}; // For emulation diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index cc49e8c7e..18a5f40f8 100755 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/spin_lock.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" @@ -15,7 +16,7 @@ namespace Kernel { PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, Core::CPUInterrupts& interrupts_) : core_index{core_index_}, system{system_}, scheduler{scheduler_}, - interrupts{interrupts_}, guard{std::make_unique()} { + interrupts{interrupts_}, guard{std::make_unique()} { #ifdef ARCHITECTURE_x86_64 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index f2112fc1d..16a032e89 100755 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -6,10 +6,13 @@ #include #include -#include #include "core/arm/arm_interface.h" +namespace Common { +class SpinLock; +} + namespace Kernel { class KScheduler; } // namespace Kernel @@ -88,7 +91,7 @@ private: Core::System& system; Kernel::KScheduler& scheduler; Core::CPUInterrupts& interrupts; - std::unique_ptr guard; + std::unique_ptr guard; std::unique_ptr arm_interface; }; diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 148265218..c78b2baeb 100755 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -9,6 +9,7 @@ #include #include #include "common/common_types.h" +#include "common/spin_lock.h" #include "core/hle/kernel/hle_ipc.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -89,7 +90,7 @@ protected: using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. - [[nodiscard]] std::scoped_lock LockService() { + [[nodiscard]] std::scoped_lock LockService() { return std::scoped_lock{lock_service}; } @@ -134,7 +135,7 @@ private: boost::container::flat_map handlers_tipc; /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. - std::mutex lock_service; + Common::SpinLock lock_service; }; /**