From 0728dfef84ded5e68bdb3b0781ea00ca7cc85659 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/kernel.cpp | 14 +++++++++++--- src/core/hle/kernel/kernel.h | 7 +++++++ src/core/hle/kernel/scheduler.cpp | 6 +++--- src/core/hle/kernel/scheduler.h | 5 +++-- 4 files changed, 24 insertions(+), 8 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4eb1d8703..d312ae31e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -97,8 +97,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ } struct KernelCore::Impl { - explicit Impl(Core::System& system) - : system{system}, global_scheduler{system}, synchronization{system} {} + explicit Impl(Core::System& system, KernelCore& kernel) + : system{system}, global_scheduler{kernel}, synchronization{system} {} void Initialize(KernelCore& kernel) { Shutdown(); @@ -215,7 +215,7 @@ struct KernelCore::Impl { Core::System& system; }; -KernelCore::KernelCore(Core::System& system) : impl{std::make_unique(system)} {} +KernelCore::KernelCore(Core::System& system) : impl{std::make_unique(system, *this)} {} KernelCore::~KernelCore() { Shutdown(); } @@ -265,6 +265,14 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { return impl->global_scheduler; } +Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { + return impl->cores[id].Scheduler(); +} + +const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { + return impl->cores[id].Scheduler(); +} + Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { return impl->cores[id]; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1eede3063..0dfc559e9 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -29,6 +29,7 @@ class HandleTable; class PhysicalCore; class Process; class ResourceLimit; +class Scheduler; class Synchronization; class Thread; @@ -87,6 +88,12 @@ public: /// Gets the sole instance of the global scheduler const Kernel::GlobalScheduler& GlobalScheduler() const; + /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' + Kernel::Scheduler& Scheduler(std::size_t id); + + /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' + const Kernel::Scheduler& Scheduler(std::size_t id) const; + /// Gets the an instance of the respective physical CPU core. Kernel::PhysicalCore& PhysicalCore(std::size_t id); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 86f1421bf..118c1aa95 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(); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 96db049cb..283236d4c 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -20,11 +20,12 @@ class System; namespace Kernel { +class KernelCore; class Process; class GlobalScheduler final { public: - explicit GlobalScheduler(Core::System& system); + explicit GlobalScheduler(KernelCore& kernel); ~GlobalScheduler(); /// Adds a new thread to the scheduler @@ -160,7 +161,7 @@ private: /// Lists all thread ids that aren't deleted/etc. std::vector> thread_list; - Core::System& system; + KernelCore& kernel; }; class Scheduler final { -- cgit v1.2.3 From 179bafa7cb1efae5405d38ea9b98dc6b3e1ec756 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 14 Feb 2020 09:30:53 -0400 Subject: Kernel: Rename ThreadCallbackHandleTable and Setup Thread Ids on Kernel. --- src/core/hardware_properties.h | 2 + src/core/hle/kernel/kernel.cpp | 88 ++++++++++++++++++++++++++++++++++++------ src/core/hle/kernel/kernel.h | 23 ++++++++--- src/core/hle/kernel/thread.cpp | 12 +++--- src/core/hle/kernel/thread.h | 6 ++- 5 files changed, 107 insertions(+), 24 deletions(-) (limited to 'src/core') diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 213461b6a..b04e046ed 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -20,6 +20,8 @@ constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores } // namespace Hardware +constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF; + struct EmuThreadHandle { u32 host_handle; u32 guest_handle; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d312ae31e..b3a5d7505 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include "common/assert.h" @@ -44,7 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ std::lock_guard lock{HLE::g_hle_lock}; std::shared_ptr thread = - system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle); + system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); if (thread == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); return; @@ -120,7 +122,7 @@ struct KernelCore::Impl { system_resource_limit = nullptr; - thread_wakeup_callback_handle_table.Clear(); + global_handle_table.Clear(); thread_wakeup_event_type = nullptr; preemption_event = nullptr; @@ -138,8 +140,8 @@ struct KernelCore::Impl { void InitializePhysicalCores() { exclusive_monitor = - Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount()); - for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) { + Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { cores.emplace_back(system, i, *exclusive_monitor); } } @@ -184,6 +186,48 @@ struct KernelCore::Impl { system.Memory().SetCurrentPageTable(*process); } + void RegisterCoreThread(std::size_t core_id) { + 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); + ASSERT(it == host_thread_ids.end()); + ASSERT(!registered_core_threads[core_id]); + host_thread_ids[this_id] = static_cast(core_id); + registered_core_threads.set(core_id); + } + + void RegisterHostThread() { + 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 { + 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()) { + return Core::INVALID_HOST_THREAD_ID; + } + return it->second; + } + + Core::EmuThreadHandle GetCurrentEmuThreadId() const { + Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); + result.host_handle = GetCurrentHostThreadId(); + if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { + return result; + } + const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); + const Kernel::Thread* current = sched.GetCurrentThread(); + if (current != nullptr) { + result.guest_handle = current->GetGlobalHandle(); + } else { + result.guest_handle = InvalidHandle; + } + return result; + } + std::atomic next_object_id{0}; std::atomic next_kernel_process_id{Process::InitialKIPIDMin}; std::atomic next_user_process_id{Process::ProcessIDMin}; @@ -202,7 +246,7 @@ struct KernelCore::Impl { // 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. - Kernel::HandleTable thread_wakeup_callback_handle_table; + Kernel::HandleTable global_handle_table; /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. @@ -211,6 +255,11 @@ struct KernelCore::Impl { std::unique_ptr exclusive_monitor; std::vector cores; + // 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{}; + // System context Core::System& system; }; @@ -232,9 +281,8 @@ std::shared_ptr KernelCore::GetSystemResourceLimit() const { return impl->system_resource_limit; } -std::shared_ptr KernelCore::RetrieveThreadFromWakeupCallbackHandleTable( - Handle handle) const { - return impl->thread_wakeup_callback_handle_table.Get(handle); +std::shared_ptr KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { + return impl->global_handle_table.Get(handle); } void KernelCore::AppendNewProcess(std::shared_ptr process) { @@ -346,12 +394,28 @@ const std::shared_ptr& KernelCore::ThreadWakeupCallback return impl->thread_wakeup_event_type; } -Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() { - return impl->thread_wakeup_callback_handle_table; +Kernel::HandleTable& KernelCore::GlobalHandleTable() { + return impl->global_handle_table; +} + +const Kernel::HandleTable& KernelCore::GlobalHandleTable() const { + return impl->global_handle_table; +} + +void KernelCore::RegisterCoreThread(std::size_t core_id) { + impl->RegisterCoreThread(core_id); +} + +void KernelCore::RegisterHostThread() { + impl->RegisterHostThread(); +} + +u32 KernelCore::GetCurrentHostThreadId() const { + return impl->GetCurrentHostThreadId(); } -const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const { - return impl->thread_wakeup_callback_handle_table; +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 0dfc559e9..c5e05f7b6 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,6 +8,7 @@ #include #include #include +#include "core/hardware_properties.h" #include "core/hle/kernel/object.h" namespace Core { @@ -65,7 +66,7 @@ public: std::shared_ptr GetSystemResourceLimit() const; /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. - std::shared_ptr RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; + std::shared_ptr RetrieveThreadFromGlobalHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. void AppendNewProcess(std::shared_ptr process); @@ -127,6 +128,18 @@ 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. + Core::EmuThreadHandle GetCurrentEmuThreadId() const; + + /// Gets the current host_thread handle. + u32 GetCurrentHostThreadId() const; + + /// Register the current thread as a CPU Core Thread. + void RegisterCoreThread(std::size_t core_id); + + /// Register the current thread as a non CPU core thread. + void RegisterHostThread(); + private: friend class Object; friend class Process; @@ -147,11 +160,11 @@ private: /// Retrieves the event type used for thread wakeup callbacks. const std::shared_ptr& ThreadWakeupCallbackEventType() const; - /// Provides a reference to the thread wakeup callback handle table. - Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); + /// Provides a reference to the global handle table. + Kernel::HandleTable& GlobalHandleTable(); - /// Provides a const reference to the thread wakeup callback handle table. - const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const; + /// Provides a const reference to the global handle table. + const Kernel::HandleTable& GlobalHandleTable() const; struct Impl; std::unique_ptr impl; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ae5f2c8bd..bf850e0b2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -46,9 +46,9 @@ Thread::~Thread() = default; void Thread::Stop() { // Cancel any outstanding wakeup events for this thread Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); - kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); - callback_handle = 0; + global_handle); + kernel.GlobalHandleTable().Close(global_handle); + global_handle = 0; SetStatus(ThreadStatus::Dead); Signal(); @@ -73,12 +73,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // thread-safe version of ScheduleEvent. const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); Core::System::GetInstance().CoreTiming().ScheduleEvent( - cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); + cycles, kernel.ThreadWakeupCallbackEventType(), global_handle); } void Thread::CancelWakeupTimer() { Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); + global_handle); } void Thread::ResumeFromWait() { @@ -190,7 +190,7 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin thread->condvar_wait_address = 0; thread->wait_handle = 0; thread->name = std::move(name); - thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); + thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); thread->owner_process = &owner_process; auto& scheduler = kernel.GlobalScheduler(); scheduler.AddThread(thread); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 7a4916318..129e7858a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -453,6 +453,10 @@ public: is_sync_cancelled = value; } + Handle GetGlobalHandle() const { + return global_handle; + } + private: void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); @@ -514,7 +518,7 @@ private: VAddr arb_wait_address{0}; /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. - Handle callback_handle = 0; + Handle global_handle = 0; /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread /// was waiting via WaitSynchronization then the object will be the last object that became -- cgit v1.2.3 From 5c90d22f3d92b9be818b19e03dd57eb217eb6567 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 14 Feb 2020 10:56:27 -0400 Subject: Kernel: Implement Time Manager. --- src/core/CMakeLists.txt | 2 ++ src/core/hle/kernel/kernel.cpp | 12 ++++++++++- src/core/hle/kernel/kernel.h | 7 ++++++ src/core/hle/kernel/time_manager.cpp | 42 ++++++++++++++++++++++++++++++++++++ src/core/hle/kernel/time_manager.h | 36 +++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/core/hle/kernel/time_manager.cpp create mode 100644 src/core/hle/kernel/time_manager.h (limited to 'src/core') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 26612e692..88c06b2ce 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -187,6 +187,8 @@ add_library(core STATIC hle/kernel/synchronization.h hle/kernel/thread.cpp hle/kernel/thread.h + hle/kernel/time_manager.cpp + hle/kernel/time_manager.h hle/kernel/transfer_memory.cpp hle/kernel/transfer_memory.h hle/kernel/vm_manager.cpp diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b3a5d7505..de14e1936 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -27,6 +27,7 @@ #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/memory.h" @@ -100,7 +101,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) - : system{system}, global_scheduler{kernel}, synchronization{system} {} + : system{system}, global_scheduler{kernel}, synchronization{system}, time_manager{system} {} void Initialize(KernelCore& kernel) { Shutdown(); @@ -238,6 +239,7 @@ struct KernelCore::Impl { Process* current_process = nullptr; Kernel::GlobalScheduler global_scheduler; Kernel::Synchronization synchronization; + Kernel::TimeManager time_manager; std::shared_ptr system_resource_limit; @@ -337,6 +339,14 @@ const Kernel::Synchronization& KernelCore::Synchronization() const { return impl->synchronization; } +Kernel::TimeManager& KernelCore::TimeManager() { + return impl->time_manager; +} + +const Kernel::TimeManager& KernelCore::TimeManager() const { + return impl->time_manager; +} + Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { return *impl->exclusive_monitor; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c5e05f7b6..76fd12ace 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -33,6 +33,7 @@ class ResourceLimit; class Scheduler; class Synchronization; class Thread; +class TimeManager; /// Represents a single instance of the kernel. class KernelCore { @@ -107,6 +108,12 @@ public: /// Gets the an instance of the Synchronization Interface. const Kernel::Synchronization& Synchronization() const; + /// Gets the an instance of the TimeManager Interface. + Kernel::TimeManager& TimeManager(); + + /// Gets the an instance of the TimeManager Interface. + const Kernel::TimeManager& TimeManager() const; + /// Stops execution of 'id' core, in order to reschedule a new thread. void PrepareReschedule(std::size_t id); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp new file mode 100644 index 000000000..0b3e464d0 --- /dev/null +++ b/src/core/hle/kernel/time_manager.cpp @@ -0,0 +1,42 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/core_timing_util.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" + +namespace Kernel { + +TimeManager::TimeManager(Core::System& system) : system{system} { + time_manager_event_type = Core::Timing::CreateEvent( + "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { + Handle proper_handle = static_cast(thread_handle); + std::shared_ptr thread = + this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); + thread->ResumeFromWait(); + }); +} + +void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { + if (nanoseconds > 0) { + ASSERT(timetask); + event_handle = timetask->GetGlobalHandle(); + const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); + system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle); + } else { + event_handle = InvalidHandle; + } +} + +void TimeManager::UnscheduleTimeEvent(Handle event_handle) { + if (event_handle != InvalidHandle) { + 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 new file mode 100644 index 000000000..b760311f1 --- /dev/null +++ b/src/core/hle/kernel/time_manager.h @@ -0,0 +1,36 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "core/hle/kernel/object.h" + +namespace Core { +class System; +} // namespace Core + +namespace Core::Timing { +struct EventType; +} // namespace Core::Timing + +namespace Kernel { + +class Thread; + +class TimeManager { +public: + TimeManager(Core::System& system); + + void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds); + + void UnscheduleTimeEvent(Handle event_handle); + +private: + Core::System& system; + std::shared_ptr time_manager_event_type; +}; + +} // namespace Kernel -- cgit v1.2.3 From ea956c823e5e6b7f6fd16780b613263d6fadd5da 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') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 118c1aa95..9556df951 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 283236d4c..a779bb70f 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 d219a96cc828d17932beebead209ba696b92a911 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') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index de14e1936..9232f4d7e 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 76fd12ace..c4f78ab71 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 9556df951..e5892727e 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 a779bb70f..1c93a838c 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 0b3e464d0..21b290468 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 b760311f1..eaec486d1 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 b9472eae440145042e504352472ba3a781b52f01 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 22 Feb 2020 11:13:07 -0400 Subject: System: Expose Host thread registering routines from kernel. --- src/core/core.cpp | 8 ++++++++ src/core/core.h | 6 ++++++ 2 files changed, 14 insertions(+) (limited to 'src/core') diff --git a/src/core/core.cpp b/src/core/core.cpp index 0eb0c0dca..86e314c94 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -707,4 +707,12 @@ const Service::SM::ServiceManager& System::ServiceManager() const { return *impl->service_manager; } +void System::RegisterCoreThread(std::size_t id) { + impl->kernel.RegisterCoreThread(id); +} + +void System::RegisterHostThread() { + impl->kernel.RegisterHostThread(); +} + } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index e69d68fcf..8d862a8e6 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -360,6 +360,12 @@ public: const CurrentBuildProcessID& GetCurrentProcessBuildID() const; + /// Register a host thread as an emulated CPU Core. + void RegisterCoreThread(std::size_t id); + + /// Register a host thread as an auxiliary thread. + void RegisterHostThread(); + private: System(); -- cgit v1.2.3 From a1bf353780254b8cb03ea0f820917d104ce9ca66 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') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index e5892727e..f2664ce65 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 3d0a2375ca73ae73d2ed4ee382aa0bb0378242d0 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') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index f2664ce65..c65f82fb7 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