mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-11-04 12:34:39 +08:00 
			
		
		
		
	hle: kernel: Allocate a dummy KThread for each host thread, and use it for scheduling.
This commit is contained in:
		
							parent
							
								
									37f74d8741
								
							
						
					
					
						commit
						6e953f7f02
					
				@ -9,12 +9,6 @@
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
 | 
			
		||||
static KThread* ToThread(uintptr_t thread_) {
 | 
			
		||||
    ASSERT((thread_ & EmuThreadHandleReserved) == 0);
 | 
			
		||||
    ASSERT((thread_ & 1) == 0);
 | 
			
		||||
    return reinterpret_cast<KThread*>(thread_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KLightLock::Lock() {
 | 
			
		||||
    const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
 | 
			
		||||
    const uintptr_t cur_thread_tag = (cur_thread | 1);
 | 
			
		||||
@ -48,7 +42,7 @@ void KLightLock::Unlock() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
 | 
			
		||||
    KThread* cur_thread = ToThread(_cur_thread);
 | 
			
		||||
    KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
 | 
			
		||||
 | 
			
		||||
    // Pend the current thread waiting on the owner thread.
 | 
			
		||||
    {
 | 
			
		||||
@ -60,7 +54,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Add the current thread as a waiter on the owner.
 | 
			
		||||
        KThread* owner_thread = ToThread(_owner & ~1ul);
 | 
			
		||||
        KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ul);
 | 
			
		||||
        cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
 | 
			
		||||
        owner_thread->AddWaiter(cur_thread);
 | 
			
		||||
 | 
			
		||||
@ -88,7 +82,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
 | 
			
		||||
    KThread* owner_thread = ToThread(_cur_thread);
 | 
			
		||||
    KThread* owner_thread = reinterpret_cast<KThread*>(_cur_thread);
 | 
			
		||||
 | 
			
		||||
    // Unlock.
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -623,7 +623,7 @@ KThread* KScheduler::GetCurrentThread() const {
 | 
			
		||||
    if (auto result = current_thread.load(); result) {
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    return idle_thread.get();
 | 
			
		||||
    return idle_thread;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u64 KScheduler::GetLastContextSwitchTicks() const {
 | 
			
		||||
@ -708,7 +708,7 @@ void KScheduler::ScheduleImpl() {
 | 
			
		||||
 | 
			
		||||
    // We never want to schedule a null thread, so use the idle thread if we don't have a next.
 | 
			
		||||
    if (next_thread == nullptr) {
 | 
			
		||||
        next_thread = idle_thread.get();
 | 
			
		||||
        next_thread = idle_thread;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If we're not actually switching thread, there's nothing to do.
 | 
			
		||||
@ -803,7 +803,7 @@ void KScheduler::Initialize() {
 | 
			
		||||
    auto thread_res = KThread::Create(system, ThreadType::Main, name, 0,
 | 
			
		||||
                                      KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
 | 
			
		||||
                                      nullptr, std::move(init_func), init_func_parameter);
 | 
			
		||||
    idle_thread = thread_res.Unwrap();
 | 
			
		||||
    idle_thread = thread_res.Unwrap().get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
 | 
			
		||||
 | 
			
		||||
@ -54,7 +54,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    /// Returns true if the scheduler is idle
 | 
			
		||||
    [[nodiscard]] bool IsIdle() const {
 | 
			
		||||
        return GetCurrentThread() == idle_thread.get();
 | 
			
		||||
        return GetCurrentThread() == idle_thread;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Gets the timestamp for the last context switch in ticks.
 | 
			
		||||
@ -176,7 +176,7 @@ private:
 | 
			
		||||
    KThread* prev_thread{};
 | 
			
		||||
    std::atomic<KThread*> current_thread{};
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<KThread> idle_thread;
 | 
			
		||||
    KThread* idle_thread;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Common::Fiber> switch_fiber{};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/spin_lock.h"
 | 
			
		||||
#include "core/hardware_properties.h"
 | 
			
		||||
#include "core/hle/kernel/k_thread.h"
 | 
			
		||||
#include "core/hle/kernel/kernel.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
@ -22,42 +23,42 @@ public:
 | 
			
		||||
    explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {}
 | 
			
		||||
 | 
			
		||||
    bool IsLockedByCurrentThread() const {
 | 
			
		||||
        return this->owner_thread == kernel.GetCurrentEmuThreadID();
 | 
			
		||||
        return this->owner_thread == GetCurrentThreadPointer(kernel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Lock() {
 | 
			
		||||
        if (this->IsLockedByCurrentThread()) {
 | 
			
		||||
            // If we already own the lock, we can just increment the count.
 | 
			
		||||
            ASSERT(this->lock_count > 0);
 | 
			
		||||
            this->lock_count++;
 | 
			
		||||
            ASSERT(lock_count > 0);
 | 
			
		||||
            lock_count++;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Otherwise, we want to disable scheduling and acquire the spinlock.
 | 
			
		||||
            SchedulerType::DisableScheduling(kernel);
 | 
			
		||||
            this->spin_lock.lock();
 | 
			
		||||
            spin_lock.lock();
 | 
			
		||||
 | 
			
		||||
            // For debug, ensure that our state is valid.
 | 
			
		||||
            ASSERT(this->lock_count == 0);
 | 
			
		||||
            ASSERT(this->owner_thread == EmuThreadHandleInvalid);
 | 
			
		||||
            ASSERT(lock_count == 0);
 | 
			
		||||
            ASSERT(owner_thread == nullptr);
 | 
			
		||||
 | 
			
		||||
            // Increment count, take ownership.
 | 
			
		||||
            this->lock_count = 1;
 | 
			
		||||
            this->owner_thread = kernel.GetCurrentEmuThreadID();
 | 
			
		||||
            lock_count = 1;
 | 
			
		||||
            owner_thread = GetCurrentThreadPointer(kernel);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Unlock() {
 | 
			
		||||
        ASSERT(this->IsLockedByCurrentThread());
 | 
			
		||||
        ASSERT(this->lock_count > 0);
 | 
			
		||||
        ASSERT(lock_count > 0);
 | 
			
		||||
 | 
			
		||||
        // Release an instance of the lock.
 | 
			
		||||
        if ((--this->lock_count) == 0) {
 | 
			
		||||
        if ((--lock_count) == 0) {
 | 
			
		||||
            // We're no longer going to hold the lock. Take note of what cores need scheduling.
 | 
			
		||||
            const u64 cores_needing_scheduling =
 | 
			
		||||
                SchedulerType::UpdateHighestPriorityThreads(kernel);
 | 
			
		||||
 | 
			
		||||
            // Note that we no longer hold the lock, and unlock the spinlock.
 | 
			
		||||
            this->owner_thread = EmuThreadHandleInvalid;
 | 
			
		||||
            this->spin_lock.unlock();
 | 
			
		||||
            owner_thread = nullptr;
 | 
			
		||||
            spin_lock.unlock();
 | 
			
		||||
 | 
			
		||||
            // Enable scheduling, and perform a rescheduling operation.
 | 
			
		||||
            SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
 | 
			
		||||
@ -68,7 +69,7 @@ private:
 | 
			
		||||
    KernelCore& kernel;
 | 
			
		||||
    Common::SpinLock spin_lock{};
 | 
			
		||||
    s32 lock_count{};
 | 
			
		||||
    EmuThreadHandle owner_thread{EmuThreadHandleInvalid};
 | 
			
		||||
    KThread* owner_thread{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 | 
			
		||||
@ -1034,11 +1034,7 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KThread* GetCurrentThreadPointer(KernelCore& kernel) {
 | 
			
		||||
    if (!kernel.CurrentScheduler()) {
 | 
			
		||||
        // We are not called from a core thread
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    return kernel.CurrentScheduler()->GetCurrentThread();
 | 
			
		||||
    return kernel.GetCurrentEmuThread();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KThread& GetCurrentThread(KernelCore& kernel) {
 | 
			
		||||
 | 
			
		||||
@ -57,9 +57,10 @@ struct KernelCore::Impl {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Initialize(KernelCore& kernel) {
 | 
			
		||||
        global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
 | 
			
		||||
 | 
			
		||||
        RegisterHostThread();
 | 
			
		||||
 | 
			
		||||
        global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
 | 
			
		||||
        service_thread_manager =
 | 
			
		||||
            std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
 | 
			
		||||
        is_phantom_mode_for_singlecore = false;
 | 
			
		||||
@ -206,6 +207,18 @@ struct KernelCore::Impl {
 | 
			
		||||
        return host_thread_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Gets the dummy KThread for the caller, allocating a new one if this is the first time
 | 
			
		||||
    KThread* GetHostDummyThread() {
 | 
			
		||||
        const thread_local auto thread =
 | 
			
		||||
            KThread::Create(
 | 
			
		||||
                system, ThreadType::Main,
 | 
			
		||||
                std::string{"DummyThread:" + GetHostThreadId()}, 0, KThread::DefaultThreadPriority,
 | 
			
		||||
                0, static_cast<u32>(3), 0, nullptr,
 | 
			
		||||
                []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr)
 | 
			
		||||
                .Unwrap();
 | 
			
		||||
        return thread.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Registers a CPU core thread by allocating a host thread ID for it
 | 
			
		||||
    void RegisterCoreThread(std::size_t core_id) {
 | 
			
		||||
        ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
 | 
			
		||||
@ -218,6 +231,7 @@ struct KernelCore::Impl {
 | 
			
		||||
    /// Registers a new host thread by allocating a host thread ID for it
 | 
			
		||||
    void RegisterHostThread() {
 | 
			
		||||
        [[maybe_unused]] const auto this_id = GetHostThreadId();
 | 
			
		||||
        [[maybe_unused]] const auto dummy_thread = GetHostDummyThread();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] u32 GetCurrentHostThreadID() {
 | 
			
		||||
@ -237,13 +251,12 @@ struct KernelCore::Impl {
 | 
			
		||||
        is_phantom_mode_for_singlecore = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] EmuThreadHandle GetCurrentEmuThreadID() {
 | 
			
		||||
    KThread* GetCurrentEmuThread() {
 | 
			
		||||
        const auto thread_id = GetCurrentHostThreadID();
 | 
			
		||||
        if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
 | 
			
		||||
            // Reserved value for HLE threads
 | 
			
		||||
            return EmuThreadHandleReserved + (static_cast<u64>(thread_id) << 1);
 | 
			
		||||
            return GetHostDummyThread();
 | 
			
		||||
        }
 | 
			
		||||
        return reinterpret_cast<uintptr_t>(schedulers[thread_id].get());
 | 
			
		||||
        return schedulers[thread_id]->GetCurrentThread();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void InitializeMemoryLayout() {
 | 
			
		||||
@ -548,8 +561,8 @@ u32 KernelCore::GetCurrentHostThreadID() const {
 | 
			
		||||
    return impl->GetCurrentHostThreadID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
 | 
			
		||||
    return impl->GetCurrentEmuThreadID();
 | 
			
		||||
KThread* KernelCore::GetCurrentEmuThread() const {
 | 
			
		||||
    return impl->GetCurrentEmuThread();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Memory::MemoryManager& KernelCore::MemoryManager() {
 | 
			
		||||
 | 
			
		||||
@ -165,8 +165,8 @@ public:
 | 
			
		||||
    /// Determines whether or not the given port is a valid named port.
 | 
			
		||||
    bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
 | 
			
		||||
 | 
			
		||||
    /// Gets the current host_thread/guest_thread handle.
 | 
			
		||||
    EmuThreadHandle GetCurrentEmuThreadID() const;
 | 
			
		||||
    /// Gets the current host_thread/guest_thread pointer.
 | 
			
		||||
    KThread* GetCurrentEmuThread() const;
 | 
			
		||||
 | 
			
		||||
    /// Gets the current host_thread handle.
 | 
			
		||||
    u32 GetCurrentHostThreadID() const;
 | 
			
		||||
 | 
			
		||||
@ -1039,8 +1039,6 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
 | 
			
		||||
        std::make_unique<QtWebBrowser>(*this),         // Web Browser
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    system.RegisterHostThread();
 | 
			
		||||
 | 
			
		||||
    const Core::System::ResultStatus result{
 | 
			
		||||
        system.Load(*render_window, filename.toStdString(), program_index)};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user