From f5da5046633c92b7f82ac2ab8e16fe23b3ac8983 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 13 Feb 2020 22:04:10 -0400 Subject: Kernel: Make global scheduler depend on KernelCore --- src/core/hle/kernel/scheduler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 86f1421bfd..118c1aa950 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -21,7 +21,7 @@ namespace Kernel { -GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {} +GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {} GlobalScheduler::~GlobalScheduler() = default; @@ -35,7 +35,7 @@ void GlobalScheduler::RemoveThread(std::shared_ptr thread) { } void GlobalScheduler::UnloadThread(std::size_t core) { - Scheduler& sched = system.Scheduler(core); + Scheduler& sched = kernel.Scheduler(core); sched.UnloadThread(); } @@ -50,7 +50,7 @@ void GlobalScheduler::SelectThread(std::size_t core) { sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; std::atomic_thread_fence(std::memory_order_seq_cst); }; - Scheduler& sched = system.Scheduler(core); + Scheduler& sched = kernel.Scheduler(core); Thread* current_thread = nullptr; // Step 1: Get top thread in schedule queue. current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); -- cgit v1.2.3 From 7c2b72bcef636e3e1bbf8f05842638b1dec2913b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 14 Feb 2020 11:44:31 -0400 Subject: Kernel: Implement Scheduler locks --- src/core/hle/kernel/scheduler.cpp | 48 +++++++++++++++++++++++++++++++++++++++ src/core/hle/kernel/scheduler.h | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 118c1aa950..9556df9513 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -18,6 +18,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/time_manager.h" namespace Kernel { @@ -356,6 +357,29 @@ void GlobalScheduler::Shutdown() { thread_list.clear(); } +void GlobalScheduler::Lock() { + Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadId(); + if (current_thread == current_owner) { + ++scope_lock; + } else { + inner_lock.lock(); + current_owner = current_thread; + scope_lock = 1; + } +} + +void GlobalScheduler::Unlock() { + if (--scope_lock == 0) { + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + SelectThread(i); + } + current_owner = Core::EmuThreadHandle::InvalidHandle(); + scope_lock = 1; + inner_lock.unlock(); + // TODO(Blinkhawk): Setup the interrupts and change context on current core. + } +} + Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) : system(system), cpu_core(cpu_core), core_id(core_id) {} @@ -485,4 +509,28 @@ void Scheduler::Shutdown() { selected_thread = nullptr; } +SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} { + auto& global_scheduler = kernel.GlobalScheduler(); + global_scheduler.Lock(); +} + +SchedulerLock::~SchedulerLock() { + auto& global_scheduler = kernel.GlobalScheduler(); + global_scheduler.Unlock(); +} + +SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, + Thread* time_task, s64 nanoseconds) + : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{ + nanoseconds} { + event_handle = InvalidHandle; +} + +SchedulerLockAndSleep::~SchedulerLockAndSleep() { + if (!sleep_cancelled) { + auto& time_manager = kernel.TimeManager(); + time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); + } +} + } // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 283236d4c5..a779bb70fa 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "common/common_types.h" @@ -22,6 +23,7 @@ namespace Kernel { class KernelCore; class Process; +class SchedulerLock; class GlobalScheduler final { public: @@ -139,6 +141,14 @@ public: void Shutdown(); private: + friend class SchedulerLock; + + /// Lock the scheduler to the current thread. + void Lock(); + + /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling + /// and reschedules current core if needed. + void Unlock(); /** * Transfers a thread into an specific core. If the destination_core is -1 * it will be unscheduled from its source code and added into its suggested @@ -159,6 +169,11 @@ private: // ordered from Core 0 to Core 3. std::array preemption_priorities = {59, 59, 59, 62}; + /// Scheduler lock mechanisms. + std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock + std::atomic scope_lock{}; + Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; + /// Lists all thread ids that aren't deleted/etc. std::vector> thread_list; KernelCore& kernel; @@ -228,4 +243,30 @@ private: bool is_context_switch_pending = false; }; +class SchedulerLock { +public: + SchedulerLock(KernelCore& kernel); + ~SchedulerLock(); + +protected: + KernelCore& kernel; +}; + +class SchedulerLockAndSleep : public SchedulerLock { +public: + SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task, + s64 nanoseconds); + ~SchedulerLockAndSleep(); + + void CancelSleep() { + sleep_cancelled = true; + } + +private: + Handle& event_handle; + Thread* time_task; + s64 nanoseconds; + bool sleep_cancelled{}; +}; + } // namespace Kernel -- cgit v1.2.3 From 78f01601d068db4828c2499463c5efa9c9181261 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 22 Feb 2020 10:27:40 -0400 Subject: Kernel: Address Feedback. --- src/core/hle/kernel/kernel.cpp | 27 ++++++++++++++++----------- src/core/hle/kernel/kernel.h | 6 +++--- src/core/hle/kernel/scheduler.cpp | 21 ++++++++++++--------- src/core/hle/kernel/scheduler.h | 8 ++++---- src/core/hle/kernel/time_manager.cpp | 6 ++++-- src/core/hle/kernel/time_manager.h | 9 ++++++++- 6 files changed, 47 insertions(+), 30 deletions(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index de14e19360..9232f4d7e3 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -17,6 +18,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/hardware_properties.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" @@ -188,6 +190,7 @@ struct KernelCore::Impl { } void RegisterCoreThread(std::size_t core_id) { + std::unique_lock lock{register_thread_mutex}; const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); @@ -198,13 +201,14 @@ struct KernelCore::Impl { } void RegisterHostThread() { + std::unique_lock lock{register_thread_mutex}; const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); ASSERT(it == host_thread_ids.end()); host_thread_ids[this_id] = registered_thread_ids++; } - u32 GetCurrentHostThreadId() const { + u32 GetCurrentHostThreadID() const { const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); if (it == host_thread_ids.end()) { @@ -213,9 +217,9 @@ struct KernelCore::Impl { return it->second; } - Core::EmuThreadHandle GetCurrentEmuThreadId() const { + Core::EmuThreadHandle GetCurrentEmuThreadID() const { Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); - result.host_handle = GetCurrentHostThreadId(); + result.host_handle = GetCurrentHostThreadID(); if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { return result; } @@ -246,8 +250,8 @@ struct KernelCore::Impl { std::shared_ptr thread_wakeup_event_type; std::shared_ptr preemption_event; - // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, - // allowing us to simply use a pool index or similar. + // This is the kernel's handle table or supervisor handle table which + // stores all the objects in place. Kernel::HandleTable global_handle_table; /// Map of named ports managed by the kernel, which can be retrieved using @@ -257,10 +261,11 @@ struct KernelCore::Impl { std::unique_ptr exclusive_monitor; std::vector cores; - // 0-3 Ids represent core threads, >3 represent others + // 0-3 IDs represent core threads, >3 represent others std::unordered_map host_thread_ids; u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; - std::bitset registered_core_threads{}; + std::bitset registered_core_threads; + std::mutex register_thread_mutex; // System context Core::System& system; @@ -420,12 +425,12 @@ void KernelCore::RegisterHostThread() { impl->RegisterHostThread(); } -u32 KernelCore::GetCurrentHostThreadId() const { - return impl->GetCurrentHostThreadId(); +u32 KernelCore::GetCurrentHostThreadID() const { + return impl->GetCurrentHostThreadID(); } -Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadId() const { - return impl->GetCurrentEmuThreadId(); +Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { + return impl->GetCurrentEmuThreadID(); } } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 76fd12ace2..c4f78ab71e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,10 +8,10 @@ #include #include #include -#include "core/hardware_properties.h" #include "core/hle/kernel/object.h" namespace Core { +struct EmuThreadHandle; class ExclusiveMonitor; class System; } // namespace Core @@ -136,10 +136,10 @@ public: bool IsValidNamedPort(NamedPortTable::const_iterator port) const; /// Gets the current host_thread/guest_thread handle. - Core::EmuThreadHandle GetCurrentEmuThreadId() const; + Core::EmuThreadHandle GetCurrentEmuThreadID() const; /// Gets the current host_thread handle. - u32 GetCurrentHostThreadId() const; + u32 GetCurrentHostThreadID() const; /// Register the current thread as a CPU Core Thread. void RegisterCoreThread(std::size_t core_id); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 9556df9513..e5892727e9 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -358,26 +358,29 @@ void GlobalScheduler::Shutdown() { } void GlobalScheduler::Lock() { - Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadId(); + Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID(); if (current_thread == current_owner) { ++scope_lock; } else { inner_lock.lock(); current_owner = current_thread; + ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle()); scope_lock = 1; } } void GlobalScheduler::Unlock() { - if (--scope_lock == 0) { - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - SelectThread(i); - } - current_owner = Core::EmuThreadHandle::InvalidHandle(); - scope_lock = 1; - inner_lock.unlock(); - // TODO(Blinkhawk): Setup the interrupts and change context on current core. + if (--scope_lock != 0) { + ASSERT(scope_lock > 0); + return; + } + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + SelectThread(i); } + current_owner = Core::EmuThreadHandle::InvalidHandle(); + scope_lock = 1; + inner_lock.unlock(); + // TODO(Blinkhawk): Setup the interrupts and change context on current core. } Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index a779bb70fa..1c93a838c5 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -171,7 +171,7 @@ private: /// Scheduler lock mechanisms. std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock - std::atomic scope_lock{}; + std::atomic scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; /// Lists all thread ids that aren't deleted/etc. @@ -245,7 +245,7 @@ private: class SchedulerLock { public: - SchedulerLock(KernelCore& kernel); + explicit SchedulerLock(KernelCore& kernel); ~SchedulerLock(); protected: @@ -254,8 +254,8 @@ protected: class SchedulerLockAndSleep : public SchedulerLock { public: - SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task, - s64 nanoseconds); + explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task, + s64 nanoseconds); ~SchedulerLockAndSleep(); void CancelSleep() { diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 0b3e464d0e..21b2904689 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/assert.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -34,9 +35,10 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 } void TimeManager::UnscheduleTimeEvent(Handle event_handle) { - if (event_handle != InvalidHandle) { - system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); + if (event_handle == InvalidHandle) { + return; } + system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); } } // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index b760311f1f..eaec486d1a 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -20,12 +20,19 @@ namespace Kernel { class Thread; +/** + * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp + * method when the event is triggered. + */ class TimeManager { public: - TimeManager(Core::System& system); + explicit TimeManager(Core::System& system); + /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' + /// returns a non-invalid handle in `event_handle` if correctly scheduled void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds); + /// Unschedule an existing time event void UnscheduleTimeEvent(Handle event_handle); private: -- cgit v1.2.3 From d6584d988fbe6d979a1a549bfeeed48ebb599bf7 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 22 Feb 2020 11:51:03 -0400 Subject: Kernel: Correct pending feedback. --- src/core/hle/kernel/scheduler.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index e5892727e9..f2664ce65f 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -530,10 +530,11 @@ SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_h } SchedulerLockAndSleep::~SchedulerLockAndSleep() { - if (!sleep_cancelled) { - auto& time_manager = kernel.TimeManager(); - time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); + if (sleep_cancelled) { + return; } + auto& time_manager = kernel.TimeManager(); + time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); } } // namespace Kernel -- cgit v1.2.3 From d0b12c793d1d867aeed8e1385222887a70581ca1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 22 Feb 2020 12:39:17 -0400 Subject: Scheduler: Inline global scheduler in Scheduler Lock. --- src/core/hle/kernel/scheduler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index f2664ce65f..c65f82fb7c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -513,13 +513,11 @@ void Scheduler::Shutdown() { } SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} { - auto& global_scheduler = kernel.GlobalScheduler(); - global_scheduler.Lock(); + kernel.GlobalScheduler().Lock(); } SchedulerLock::~SchedulerLock() { - auto& global_scheduler = kernel.GlobalScheduler(); - global_scheduler.Unlock(); + kernel.GlobalScheduler().Unlock(); } SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, -- cgit v1.2.3