diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/core.cpp | 8 | ||||
| -rw-r--r-- | src/core/core.h | 6 | ||||
| -rw-r--r-- | src/core/hardware_properties.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 121 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 37 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.cpp | 56 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.h | 46 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.cpp | 44 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.h | 43 |
12 files changed, 349 insertions, 34 deletions
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 | |||
| 187 | hle/kernel/synchronization.h | 187 | hle/kernel/synchronization.h |
| 188 | hle/kernel/thread.cpp | 188 | hle/kernel/thread.cpp |
| 189 | hle/kernel/thread.h | 189 | hle/kernel/thread.h |
| 190 | hle/kernel/time_manager.cpp | ||
| 191 | hle/kernel/time_manager.h | ||
| 190 | hle/kernel/transfer_memory.cpp | 192 | hle/kernel/transfer_memory.cpp |
| 191 | hle/kernel/transfer_memory.h | 193 | hle/kernel/transfer_memory.h |
| 192 | hle/kernel/vm_manager.cpp | 194 | hle/kernel/vm_manager.cpp |
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 { | |||
| 707 | return *impl->service_manager; | 707 | return *impl->service_manager; |
| 708 | } | 708 | } |
| 709 | 709 | ||
| 710 | void System::RegisterCoreThread(std::size_t id) { | ||
| 711 | impl->kernel.RegisterCoreThread(id); | ||
| 712 | } | ||
| 713 | |||
| 714 | void System::RegisterHostThread() { | ||
| 715 | impl->kernel.RegisterHostThread(); | ||
| 716 | } | ||
| 717 | |||
| 710 | } // namespace Core | 718 | } // 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: | |||
| 360 | 360 | ||
| 361 | const CurrentBuildProcessID& GetCurrentProcessBuildID() const; | 361 | const CurrentBuildProcessID& GetCurrentProcessBuildID() const; |
| 362 | 362 | ||
| 363 | /// Register a host thread as an emulated CPU Core. | ||
| 364 | void RegisterCoreThread(std::size_t id); | ||
| 365 | |||
| 366 | /// Register a host thread as an auxiliary thread. | ||
| 367 | void RegisterHostThread(); | ||
| 368 | |||
| 363 | private: | 369 | private: |
| 364 | System(); | 370 | System(); |
| 365 | 371 | ||
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 | |||
| 20 | 20 | ||
| 21 | } // namespace Hardware | 21 | } // namespace Hardware |
| 22 | 22 | ||
| 23 | constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF; | ||
| 24 | |||
| 23 | struct EmuThreadHandle { | 25 | struct EmuThreadHandle { |
| 24 | u32 host_handle; | 26 | u32 host_handle; |
| 25 | u32 guest_handle; | 27 | u32 guest_handle; |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4eb1d8703..9232f4d7e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -3,9 +3,12 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <atomic> | 5 | #include <atomic> |
| 6 | #include <bitset> | ||
| 6 | #include <functional> | 7 | #include <functional> |
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include <mutex> | 9 | #include <mutex> |
| 10 | #include <thread> | ||
| 11 | #include <unordered_map> | ||
| 9 | #include <utility> | 12 | #include <utility> |
| 10 | 13 | ||
| 11 | #include "common/assert.h" | 14 | #include "common/assert.h" |
| @@ -15,6 +18,7 @@ | |||
| 15 | #include "core/core.h" | 18 | #include "core/core.h" |
| 16 | #include "core/core_timing.h" | 19 | #include "core/core_timing.h" |
| 17 | #include "core/core_timing_util.h" | 20 | #include "core/core_timing_util.h" |
| 21 | #include "core/hardware_properties.h" | ||
| 18 | #include "core/hle/kernel/client_port.h" | 22 | #include "core/hle/kernel/client_port.h" |
| 19 | #include "core/hle/kernel/errors.h" | 23 | #include "core/hle/kernel/errors.h" |
| 20 | #include "core/hle/kernel/handle_table.h" | 24 | #include "core/hle/kernel/handle_table.h" |
| @@ -25,6 +29,7 @@ | |||
| 25 | #include "core/hle/kernel/scheduler.h" | 29 | #include "core/hle/kernel/scheduler.h" |
| 26 | #include "core/hle/kernel/synchronization.h" | 30 | #include "core/hle/kernel/synchronization.h" |
| 27 | #include "core/hle/kernel/thread.h" | 31 | #include "core/hle/kernel/thread.h" |
| 32 | #include "core/hle/kernel/time_manager.h" | ||
| 28 | #include "core/hle/lock.h" | 33 | #include "core/hle/lock.h" |
| 29 | #include "core/hle/result.h" | 34 | #include "core/hle/result.h" |
| 30 | #include "core/memory.h" | 35 | #include "core/memory.h" |
| @@ -44,7 +49,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ | |||
| 44 | std::lock_guard lock{HLE::g_hle_lock}; | 49 | std::lock_guard lock{HLE::g_hle_lock}; |
| 45 | 50 | ||
| 46 | std::shared_ptr<Thread> thread = | 51 | std::shared_ptr<Thread> thread = |
| 47 | system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle); | 52 | system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); |
| 48 | if (thread == nullptr) { | 53 | if (thread == nullptr) { |
| 49 | LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); | 54 | LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); |
| 50 | return; | 55 | return; |
| @@ -97,8 +102,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ | |||
| 97 | } | 102 | } |
| 98 | 103 | ||
| 99 | struct KernelCore::Impl { | 104 | struct KernelCore::Impl { |
| 100 | explicit Impl(Core::System& system) | 105 | explicit Impl(Core::System& system, KernelCore& kernel) |
| 101 | : system{system}, global_scheduler{system}, synchronization{system} {} | 106 | : system{system}, global_scheduler{kernel}, synchronization{system}, time_manager{system} {} |
| 102 | 107 | ||
| 103 | void Initialize(KernelCore& kernel) { | 108 | void Initialize(KernelCore& kernel) { |
| 104 | Shutdown(); | 109 | Shutdown(); |
| @@ -120,7 +125,7 @@ struct KernelCore::Impl { | |||
| 120 | 125 | ||
| 121 | system_resource_limit = nullptr; | 126 | system_resource_limit = nullptr; |
| 122 | 127 | ||
| 123 | thread_wakeup_callback_handle_table.Clear(); | 128 | global_handle_table.Clear(); |
| 124 | thread_wakeup_event_type = nullptr; | 129 | thread_wakeup_event_type = nullptr; |
| 125 | preemption_event = nullptr; | 130 | preemption_event = nullptr; |
| 126 | 131 | ||
| @@ -138,8 +143,8 @@ struct KernelCore::Impl { | |||
| 138 | 143 | ||
| 139 | void InitializePhysicalCores() { | 144 | void InitializePhysicalCores() { |
| 140 | exclusive_monitor = | 145 | exclusive_monitor = |
| 141 | Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount()); | 146 | Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); |
| 142 | for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) { | 147 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 143 | cores.emplace_back(system, i, *exclusive_monitor); | 148 | cores.emplace_back(system, i, *exclusive_monitor); |
| 144 | } | 149 | } |
| 145 | } | 150 | } |
| @@ -184,6 +189,50 @@ struct KernelCore::Impl { | |||
| 184 | system.Memory().SetCurrentPageTable(*process); | 189 | system.Memory().SetCurrentPageTable(*process); |
| 185 | } | 190 | } |
| 186 | 191 | ||
| 192 | void RegisterCoreThread(std::size_t core_id) { | ||
| 193 | std::unique_lock lock{register_thread_mutex}; | ||
| 194 | const std::thread::id this_id = std::this_thread::get_id(); | ||
| 195 | const auto it = host_thread_ids.find(this_id); | ||
| 196 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | ||
| 197 | ASSERT(it == host_thread_ids.end()); | ||
| 198 | ASSERT(!registered_core_threads[core_id]); | ||
| 199 | host_thread_ids[this_id] = static_cast<u32>(core_id); | ||
| 200 | registered_core_threads.set(core_id); | ||
| 201 | } | ||
| 202 | |||
| 203 | void RegisterHostThread() { | ||
| 204 | std::unique_lock lock{register_thread_mutex}; | ||
| 205 | const std::thread::id this_id = std::this_thread::get_id(); | ||
| 206 | const auto it = host_thread_ids.find(this_id); | ||
| 207 | ASSERT(it == host_thread_ids.end()); | ||
| 208 | host_thread_ids[this_id] = registered_thread_ids++; | ||
| 209 | } | ||
| 210 | |||
| 211 | u32 GetCurrentHostThreadID() const { | ||
| 212 | const std::thread::id this_id = std::this_thread::get_id(); | ||
| 213 | const auto it = host_thread_ids.find(this_id); | ||
| 214 | if (it == host_thread_ids.end()) { | ||
| 215 | return Core::INVALID_HOST_THREAD_ID; | ||
| 216 | } | ||
| 217 | return it->second; | ||
| 218 | } | ||
| 219 | |||
| 220 | Core::EmuThreadHandle GetCurrentEmuThreadID() const { | ||
| 221 | Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); | ||
| 222 | result.host_handle = GetCurrentHostThreadID(); | ||
| 223 | if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { | ||
| 224 | return result; | ||
| 225 | } | ||
| 226 | const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); | ||
| 227 | const Kernel::Thread* current = sched.GetCurrentThread(); | ||
| 228 | if (current != nullptr) { | ||
| 229 | result.guest_handle = current->GetGlobalHandle(); | ||
| 230 | } else { | ||
| 231 | result.guest_handle = InvalidHandle; | ||
| 232 | } | ||
| 233 | return result; | ||
| 234 | } | ||
| 235 | |||
| 187 | std::atomic<u32> next_object_id{0}; | 236 | std::atomic<u32> next_object_id{0}; |
| 188 | std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; | 237 | std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; |
| 189 | std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; | 238 | std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; |
| @@ -194,15 +243,16 @@ struct KernelCore::Impl { | |||
| 194 | Process* current_process = nullptr; | 243 | Process* current_process = nullptr; |
| 195 | Kernel::GlobalScheduler global_scheduler; | 244 | Kernel::GlobalScheduler global_scheduler; |
| 196 | Kernel::Synchronization synchronization; | 245 | Kernel::Synchronization synchronization; |
| 246 | Kernel::TimeManager time_manager; | ||
| 197 | 247 | ||
| 198 | std::shared_ptr<ResourceLimit> system_resource_limit; | 248 | std::shared_ptr<ResourceLimit> system_resource_limit; |
| 199 | 249 | ||
| 200 | std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type; | 250 | std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type; |
| 201 | std::shared_ptr<Core::Timing::EventType> preemption_event; | 251 | std::shared_ptr<Core::Timing::EventType> preemption_event; |
| 202 | 252 | ||
| 203 | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, | 253 | // This is the kernel's handle table or supervisor handle table which |
| 204 | // allowing us to simply use a pool index or similar. | 254 | // stores all the objects in place. |
| 205 | Kernel::HandleTable thread_wakeup_callback_handle_table; | 255 | Kernel::HandleTable global_handle_table; |
| 206 | 256 | ||
| 207 | /// Map of named ports managed by the kernel, which can be retrieved using | 257 | /// Map of named ports managed by the kernel, which can be retrieved using |
| 208 | /// the ConnectToPort SVC. | 258 | /// the ConnectToPort SVC. |
| @@ -211,11 +261,17 @@ struct KernelCore::Impl { | |||
| 211 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | 261 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; |
| 212 | std::vector<Kernel::PhysicalCore> cores; | 262 | std::vector<Kernel::PhysicalCore> cores; |
| 213 | 263 | ||
| 264 | // 0-3 IDs represent core threads, >3 represent others | ||
| 265 | std::unordered_map<std::thread::id, u32> host_thread_ids; | ||
| 266 | u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; | ||
| 267 | std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; | ||
| 268 | std::mutex register_thread_mutex; | ||
| 269 | |||
| 214 | // System context | 270 | // System context |
| 215 | Core::System& system; | 271 | Core::System& system; |
| 216 | }; | 272 | }; |
| 217 | 273 | ||
| 218 | KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system)} {} | 274 | KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {} |
| 219 | KernelCore::~KernelCore() { | 275 | KernelCore::~KernelCore() { |
| 220 | Shutdown(); | 276 | Shutdown(); |
| 221 | } | 277 | } |
| @@ -232,9 +288,8 @@ std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { | |||
| 232 | return impl->system_resource_limit; | 288 | return impl->system_resource_limit; |
| 233 | } | 289 | } |
| 234 | 290 | ||
| 235 | std::shared_ptr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable( | 291 | std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { |
| 236 | Handle handle) const { | 292 | return impl->global_handle_table.Get<Thread>(handle); |
| 237 | return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle); | ||
| 238 | } | 293 | } |
| 239 | 294 | ||
| 240 | void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { | 295 | void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { |
| @@ -265,6 +320,14 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { | |||
| 265 | return impl->global_scheduler; | 320 | return impl->global_scheduler; |
| 266 | } | 321 | } |
| 267 | 322 | ||
| 323 | Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { | ||
| 324 | return impl->cores[id].Scheduler(); | ||
| 325 | } | ||
| 326 | |||
| 327 | const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { | ||
| 328 | return impl->cores[id].Scheduler(); | ||
| 329 | } | ||
| 330 | |||
| 268 | Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { | 331 | Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { |
| 269 | return impl->cores[id]; | 332 | return impl->cores[id]; |
| 270 | } | 333 | } |
| @@ -281,6 +344,14 @@ const Kernel::Synchronization& KernelCore::Synchronization() const { | |||
| 281 | return impl->synchronization; | 344 | return impl->synchronization; |
| 282 | } | 345 | } |
| 283 | 346 | ||
| 347 | Kernel::TimeManager& KernelCore::TimeManager() { | ||
| 348 | return impl->time_manager; | ||
| 349 | } | ||
| 350 | |||
| 351 | const Kernel::TimeManager& KernelCore::TimeManager() const { | ||
| 352 | return impl->time_manager; | ||
| 353 | } | ||
| 354 | |||
| 284 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { | 355 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { |
| 285 | return *impl->exclusive_monitor; | 356 | return *impl->exclusive_monitor; |
| 286 | } | 357 | } |
| @@ -338,12 +409,28 @@ const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallback | |||
| 338 | return impl->thread_wakeup_event_type; | 409 | return impl->thread_wakeup_event_type; |
| 339 | } | 410 | } |
| 340 | 411 | ||
| 341 | Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() { | 412 | Kernel::HandleTable& KernelCore::GlobalHandleTable() { |
| 342 | return impl->thread_wakeup_callback_handle_table; | 413 | return impl->global_handle_table; |
| 414 | } | ||
| 415 | |||
| 416 | const Kernel::HandleTable& KernelCore::GlobalHandleTable() const { | ||
| 417 | return impl->global_handle_table; | ||
| 418 | } | ||
| 419 | |||
| 420 | void KernelCore::RegisterCoreThread(std::size_t core_id) { | ||
| 421 | impl->RegisterCoreThread(core_id); | ||
| 422 | } | ||
| 423 | |||
| 424 | void KernelCore::RegisterHostThread() { | ||
| 425 | impl->RegisterHostThread(); | ||
| 426 | } | ||
| 427 | |||
| 428 | u32 KernelCore::GetCurrentHostThreadID() const { | ||
| 429 | return impl->GetCurrentHostThreadID(); | ||
| 343 | } | 430 | } |
| 344 | 431 | ||
| 345 | const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const { | 432 | Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { |
| 346 | return impl->thread_wakeup_callback_handle_table; | 433 | return impl->GetCurrentEmuThreadID(); |
| 347 | } | 434 | } |
| 348 | 435 | ||
| 349 | } // namespace Kernel | 436 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1eede3063..c4f78ab71 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "core/hle/kernel/object.h" | 11 | #include "core/hle/kernel/object.h" |
| 12 | 12 | ||
| 13 | namespace Core { | 13 | namespace Core { |
| 14 | struct EmuThreadHandle; | ||
| 14 | class ExclusiveMonitor; | 15 | class ExclusiveMonitor; |
| 15 | class System; | 16 | class System; |
| 16 | } // namespace Core | 17 | } // namespace Core |
| @@ -29,8 +30,10 @@ class HandleTable; | |||
| 29 | class PhysicalCore; | 30 | class PhysicalCore; |
| 30 | class Process; | 31 | class Process; |
| 31 | class ResourceLimit; | 32 | class ResourceLimit; |
| 33 | class Scheduler; | ||
| 32 | class Synchronization; | 34 | class Synchronization; |
| 33 | class Thread; | 35 | class Thread; |
| 36 | class TimeManager; | ||
| 34 | 37 | ||
| 35 | /// Represents a single instance of the kernel. | 38 | /// Represents a single instance of the kernel. |
| 36 | class KernelCore { | 39 | class KernelCore { |
| @@ -64,7 +67,7 @@ public: | |||
| 64 | std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; | 67 | std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; |
| 65 | 68 | ||
| 66 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. | 69 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. |
| 67 | std::shared_ptr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; | 70 | std::shared_ptr<Thread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; |
| 68 | 71 | ||
| 69 | /// Adds the given shared pointer to an internal list of active processes. | 72 | /// Adds the given shared pointer to an internal list of active processes. |
| 70 | void AppendNewProcess(std::shared_ptr<Process> process); | 73 | void AppendNewProcess(std::shared_ptr<Process> process); |
| @@ -87,6 +90,12 @@ public: | |||
| 87 | /// Gets the sole instance of the global scheduler | 90 | /// Gets the sole instance of the global scheduler |
| 88 | const Kernel::GlobalScheduler& GlobalScheduler() const; | 91 | const Kernel::GlobalScheduler& GlobalScheduler() const; |
| 89 | 92 | ||
| 93 | /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' | ||
| 94 | Kernel::Scheduler& Scheduler(std::size_t id); | ||
| 95 | |||
| 96 | /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' | ||
| 97 | const Kernel::Scheduler& Scheduler(std::size_t id) const; | ||
| 98 | |||
| 90 | /// Gets the an instance of the respective physical CPU core. | 99 | /// Gets the an instance of the respective physical CPU core. |
| 91 | Kernel::PhysicalCore& PhysicalCore(std::size_t id); | 100 | Kernel::PhysicalCore& PhysicalCore(std::size_t id); |
| 92 | 101 | ||
| @@ -99,6 +108,12 @@ public: | |||
| 99 | /// Gets the an instance of the Synchronization Interface. | 108 | /// Gets the an instance of the Synchronization Interface. |
| 100 | const Kernel::Synchronization& Synchronization() const; | 109 | const Kernel::Synchronization& Synchronization() const; |
| 101 | 110 | ||
| 111 | /// Gets the an instance of the TimeManager Interface. | ||
| 112 | Kernel::TimeManager& TimeManager(); | ||
| 113 | |||
| 114 | /// Gets the an instance of the TimeManager Interface. | ||
| 115 | const Kernel::TimeManager& TimeManager() const; | ||
| 116 | |||
| 102 | /// Stops execution of 'id' core, in order to reschedule a new thread. | 117 | /// Stops execution of 'id' core, in order to reschedule a new thread. |
| 103 | void PrepareReschedule(std::size_t id); | 118 | void PrepareReschedule(std::size_t id); |
| 104 | 119 | ||
| @@ -120,6 +135,18 @@ public: | |||
| 120 | /// Determines whether or not the given port is a valid named port. | 135 | /// Determines whether or not the given port is a valid named port. |
| 121 | bool IsValidNamedPort(NamedPortTable::const_iterator port) const; | 136 | bool IsValidNamedPort(NamedPortTable::const_iterator port) const; |
| 122 | 137 | ||
| 138 | /// Gets the current host_thread/guest_thread handle. | ||
| 139 | Core::EmuThreadHandle GetCurrentEmuThreadID() const; | ||
| 140 | |||
| 141 | /// Gets the current host_thread handle. | ||
| 142 | u32 GetCurrentHostThreadID() const; | ||
| 143 | |||
| 144 | /// Register the current thread as a CPU Core Thread. | ||
| 145 | void RegisterCoreThread(std::size_t core_id); | ||
| 146 | |||
| 147 | /// Register the current thread as a non CPU core thread. | ||
| 148 | void RegisterHostThread(); | ||
| 149 | |||
| 123 | private: | 150 | private: |
| 124 | friend class Object; | 151 | friend class Object; |
| 125 | friend class Process; | 152 | friend class Process; |
| @@ -140,11 +167,11 @@ private: | |||
| 140 | /// Retrieves the event type used for thread wakeup callbacks. | 167 | /// Retrieves the event type used for thread wakeup callbacks. |
| 141 | const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const; | 168 | const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const; |
| 142 | 169 | ||
| 143 | /// Provides a reference to the thread wakeup callback handle table. | 170 | /// Provides a reference to the global handle table. |
| 144 | Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); | 171 | Kernel::HandleTable& GlobalHandleTable(); |
| 145 | 172 | ||
| 146 | /// Provides a const reference to the thread wakeup callback handle table. | 173 | /// Provides a const reference to the global handle table. |
| 147 | const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const; | 174 | const Kernel::HandleTable& GlobalHandleTable() const; |
| 148 | 175 | ||
| 149 | struct Impl; | 176 | struct Impl; |
| 150 | std::unique_ptr<Impl> impl; | 177 | std::unique_ptr<Impl> impl; |
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 86f1421bf..c65f82fb7 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -18,10 +18,11 @@ | |||
| 18 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| 19 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/scheduler.h" | 20 | #include "core/hle/kernel/scheduler.h" |
| 21 | #include "core/hle/kernel/time_manager.h" | ||
| 21 | 22 | ||
| 22 | namespace Kernel { | 23 | namespace Kernel { |
| 23 | 24 | ||
| 24 | GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {} | 25 | GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {} |
| 25 | 26 | ||
| 26 | GlobalScheduler::~GlobalScheduler() = default; | 27 | GlobalScheduler::~GlobalScheduler() = default; |
| 27 | 28 | ||
| @@ -35,7 +36,7 @@ void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) { | |||
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | void GlobalScheduler::UnloadThread(std::size_t core) { | 38 | void GlobalScheduler::UnloadThread(std::size_t core) { |
| 38 | Scheduler& sched = system.Scheduler(core); | 39 | Scheduler& sched = kernel.Scheduler(core); |
| 39 | sched.UnloadThread(); | 40 | sched.UnloadThread(); |
| 40 | } | 41 | } |
| 41 | 42 | ||
| @@ -50,7 +51,7 @@ void GlobalScheduler::SelectThread(std::size_t core) { | |||
| 50 | sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; | 51 | sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; |
| 51 | std::atomic_thread_fence(std::memory_order_seq_cst); | 52 | std::atomic_thread_fence(std::memory_order_seq_cst); |
| 52 | }; | 53 | }; |
| 53 | Scheduler& sched = system.Scheduler(core); | 54 | Scheduler& sched = kernel.Scheduler(core); |
| 54 | Thread* current_thread = nullptr; | 55 | Thread* current_thread = nullptr; |
| 55 | // Step 1: Get top thread in schedule queue. | 56 | // Step 1: Get top thread in schedule queue. |
| 56 | current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); | 57 | current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); |
| @@ -356,6 +357,32 @@ void GlobalScheduler::Shutdown() { | |||
| 356 | thread_list.clear(); | 357 | thread_list.clear(); |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 360 | void GlobalScheduler::Lock() { | ||
| 361 | Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID(); | ||
| 362 | if (current_thread == current_owner) { | ||
| 363 | ++scope_lock; | ||
| 364 | } else { | ||
| 365 | inner_lock.lock(); | ||
| 366 | current_owner = current_thread; | ||
| 367 | ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle()); | ||
| 368 | scope_lock = 1; | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | void GlobalScheduler::Unlock() { | ||
| 373 | if (--scope_lock != 0) { | ||
| 374 | ASSERT(scope_lock > 0); | ||
| 375 | return; | ||
| 376 | } | ||
| 377 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | ||
| 378 | SelectThread(i); | ||
| 379 | } | ||
| 380 | current_owner = Core::EmuThreadHandle::InvalidHandle(); | ||
| 381 | scope_lock = 1; | ||
| 382 | inner_lock.unlock(); | ||
| 383 | // TODO(Blinkhawk): Setup the interrupts and change context on current core. | ||
| 384 | } | ||
| 385 | |||
| 359 | Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) | 386 | Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) |
| 360 | : system(system), cpu_core(cpu_core), core_id(core_id) {} | 387 | : system(system), cpu_core(cpu_core), core_id(core_id) {} |
| 361 | 388 | ||
| @@ -485,4 +512,27 @@ void Scheduler::Shutdown() { | |||
| 485 | selected_thread = nullptr; | 512 | selected_thread = nullptr; |
| 486 | } | 513 | } |
| 487 | 514 | ||
| 515 | SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} { | ||
| 516 | kernel.GlobalScheduler().Lock(); | ||
| 517 | } | ||
| 518 | |||
| 519 | SchedulerLock::~SchedulerLock() { | ||
| 520 | kernel.GlobalScheduler().Unlock(); | ||
| 521 | } | ||
| 522 | |||
| 523 | SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, | ||
| 524 | Thread* time_task, s64 nanoseconds) | ||
| 525 | : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{ | ||
| 526 | nanoseconds} { | ||
| 527 | event_handle = InvalidHandle; | ||
| 528 | } | ||
| 529 | |||
| 530 | SchedulerLockAndSleep::~SchedulerLockAndSleep() { | ||
| 531 | if (sleep_cancelled) { | ||
| 532 | return; | ||
| 533 | } | ||
| 534 | auto& time_manager = kernel.TimeManager(); | ||
| 535 | time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); | ||
| 536 | } | ||
| 537 | |||
| 488 | } // namespace Kernel | 538 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 96db049cb..1c93a838c 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <mutex> | ||
| 9 | #include <vector> | 10 | #include <vector> |
| 10 | 11 | ||
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| @@ -20,11 +21,13 @@ class System; | |||
| 20 | 21 | ||
| 21 | namespace Kernel { | 22 | namespace Kernel { |
| 22 | 23 | ||
| 24 | class KernelCore; | ||
| 23 | class Process; | 25 | class Process; |
| 26 | class SchedulerLock; | ||
| 24 | 27 | ||
| 25 | class GlobalScheduler final { | 28 | class GlobalScheduler final { |
| 26 | public: | 29 | public: |
| 27 | explicit GlobalScheduler(Core::System& system); | 30 | explicit GlobalScheduler(KernelCore& kernel); |
| 28 | ~GlobalScheduler(); | 31 | ~GlobalScheduler(); |
| 29 | 32 | ||
| 30 | /// Adds a new thread to the scheduler | 33 | /// Adds a new thread to the scheduler |
| @@ -138,6 +141,14 @@ public: | |||
| 138 | void Shutdown(); | 141 | void Shutdown(); |
| 139 | 142 | ||
| 140 | private: | 143 | private: |
| 144 | friend class SchedulerLock; | ||
| 145 | |||
| 146 | /// Lock the scheduler to the current thread. | ||
| 147 | void Lock(); | ||
| 148 | |||
| 149 | /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling | ||
| 150 | /// and reschedules current core if needed. | ||
| 151 | void Unlock(); | ||
| 141 | /** | 152 | /** |
| 142 | * Transfers a thread into an specific core. If the destination_core is -1 | 153 | * Transfers a thread into an specific core. If the destination_core is -1 |
| 143 | * it will be unscheduled from its source code and added into its suggested | 154 | * it will be unscheduled from its source code and added into its suggested |
| @@ -158,9 +169,14 @@ private: | |||
| 158 | // ordered from Core 0 to Core 3. | 169 | // ordered from Core 0 to Core 3. |
| 159 | std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; | 170 | std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; |
| 160 | 171 | ||
| 172 | /// Scheduler lock mechanisms. | ||
| 173 | std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock | ||
| 174 | std::atomic<s64> scope_lock{}; | ||
| 175 | Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; | ||
| 176 | |||
| 161 | /// Lists all thread ids that aren't deleted/etc. | 177 | /// Lists all thread ids that aren't deleted/etc. |
| 162 | std::vector<std::shared_ptr<Thread>> thread_list; | 178 | std::vector<std::shared_ptr<Thread>> thread_list; |
| 163 | Core::System& system; | 179 | KernelCore& kernel; |
| 164 | }; | 180 | }; |
| 165 | 181 | ||
| 166 | class Scheduler final { | 182 | class Scheduler final { |
| @@ -227,4 +243,30 @@ private: | |||
| 227 | bool is_context_switch_pending = false; | 243 | bool is_context_switch_pending = false; |
| 228 | }; | 244 | }; |
| 229 | 245 | ||
| 246 | class SchedulerLock { | ||
| 247 | public: | ||
| 248 | explicit SchedulerLock(KernelCore& kernel); | ||
| 249 | ~SchedulerLock(); | ||
| 250 | |||
| 251 | protected: | ||
| 252 | KernelCore& kernel; | ||
| 253 | }; | ||
| 254 | |||
| 255 | class SchedulerLockAndSleep : public SchedulerLock { | ||
| 256 | public: | ||
| 257 | explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task, | ||
| 258 | s64 nanoseconds); | ||
| 259 | ~SchedulerLockAndSleep(); | ||
| 260 | |||
| 261 | void CancelSleep() { | ||
| 262 | sleep_cancelled = true; | ||
| 263 | } | ||
| 264 | |||
| 265 | private: | ||
| 266 | Handle& event_handle; | ||
| 267 | Thread* time_task; | ||
| 268 | s64 nanoseconds; | ||
| 269 | bool sleep_cancelled{}; | ||
| 270 | }; | ||
| 271 | |||
| 230 | } // namespace Kernel | 272 | } // namespace Kernel |
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; | |||
| 46 | void Thread::Stop() { | 46 | void Thread::Stop() { |
| 47 | // Cancel any outstanding wakeup events for this thread | 47 | // Cancel any outstanding wakeup events for this thread |
| 48 | Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), | 48 | Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), |
| 49 | callback_handle); | 49 | global_handle); |
| 50 | kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); | 50 | kernel.GlobalHandleTable().Close(global_handle); |
| 51 | callback_handle = 0; | 51 | global_handle = 0; |
| 52 | SetStatus(ThreadStatus::Dead); | 52 | SetStatus(ThreadStatus::Dead); |
| 53 | Signal(); | 53 | Signal(); |
| 54 | 54 | ||
| @@ -73,12 +73,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { | |||
| 73 | // thread-safe version of ScheduleEvent. | 73 | // thread-safe version of ScheduleEvent. |
| 74 | const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); | 74 | const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); |
| 75 | Core::System::GetInstance().CoreTiming().ScheduleEvent( | 75 | Core::System::GetInstance().CoreTiming().ScheduleEvent( |
| 76 | cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); | 76 | cycles, kernel.ThreadWakeupCallbackEventType(), global_handle); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | void Thread::CancelWakeupTimer() { | 79 | void Thread::CancelWakeupTimer() { |
| 80 | Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), | 80 | Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), |
| 81 | callback_handle); | 81 | global_handle); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | void Thread::ResumeFromWait() { | 84 | void Thread::ResumeFromWait() { |
| @@ -190,7 +190,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin | |||
| 190 | thread->condvar_wait_address = 0; | 190 | thread->condvar_wait_address = 0; |
| 191 | thread->wait_handle = 0; | 191 | thread->wait_handle = 0; |
| 192 | thread->name = std::move(name); | 192 | thread->name = std::move(name); |
| 193 | thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); | 193 | thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); |
| 194 | thread->owner_process = &owner_process; | 194 | thread->owner_process = &owner_process; |
| 195 | auto& scheduler = kernel.GlobalScheduler(); | 195 | auto& scheduler = kernel.GlobalScheduler(); |
| 196 | scheduler.AddThread(thread); | 196 | 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: | |||
| 453 | is_sync_cancelled = value; | 453 | is_sync_cancelled = value; |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | Handle GetGlobalHandle() const { | ||
| 457 | return global_handle; | ||
| 458 | } | ||
| 459 | |||
| 456 | private: | 460 | private: |
| 457 | void SetSchedulingStatus(ThreadSchedStatus new_status); | 461 | void SetSchedulingStatus(ThreadSchedStatus new_status); |
| 458 | void SetCurrentPriority(u32 new_priority); | 462 | void SetCurrentPriority(u32 new_priority); |
| @@ -514,7 +518,7 @@ private: | |||
| 514 | VAddr arb_wait_address{0}; | 518 | VAddr arb_wait_address{0}; |
| 515 | 519 | ||
| 516 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | 520 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. |
| 517 | Handle callback_handle = 0; | 521 | Handle global_handle = 0; |
| 518 | 522 | ||
| 519 | /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread | 523 | /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread |
| 520 | /// was waiting via WaitSynchronization then the object will be the last object that became | 524 | /// was waiting via WaitSynchronization then the object will be the last object that became |
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp new file mode 100644 index 000000000..21b290468 --- /dev/null +++ b/src/core/hle/kernel/time_manager.cpp | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/core_timing.h" | ||
| 8 | #include "core/core_timing_util.h" | ||
| 9 | #include "core/hle/kernel/handle_table.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | ||
| 12 | #include "core/hle/kernel/time_manager.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | TimeManager::TimeManager(Core::System& system) : system{system} { | ||
| 17 | time_manager_event_type = Core::Timing::CreateEvent( | ||
| 18 | "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { | ||
| 19 | Handle proper_handle = static_cast<Handle>(thread_handle); | ||
| 20 | std::shared_ptr<Thread> thread = | ||
| 21 | this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); | ||
| 22 | thread->ResumeFromWait(); | ||
| 23 | }); | ||
| 24 | } | ||
| 25 | |||
| 26 | void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { | ||
| 27 | if (nanoseconds > 0) { | ||
| 28 | ASSERT(timetask); | ||
| 29 | event_handle = timetask->GetGlobalHandle(); | ||
| 30 | const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); | ||
| 31 | system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle); | ||
| 32 | } else { | ||
| 33 | event_handle = InvalidHandle; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | void TimeManager::UnscheduleTimeEvent(Handle event_handle) { | ||
| 38 | if (event_handle == InvalidHandle) { | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); | ||
| 42 | } | ||
| 43 | |||
| 44 | } // 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..eaec486d1 --- /dev/null +++ b/src/core/hle/kernel/time_manager.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | #include "core/hle/kernel/object.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } // namespace Core | ||
| 14 | |||
| 15 | namespace Core::Timing { | ||
| 16 | struct EventType; | ||
| 17 | } // namespace Core::Timing | ||
| 18 | |||
| 19 | namespace Kernel { | ||
| 20 | |||
| 21 | class Thread; | ||
| 22 | |||
| 23 | /** | ||
| 24 | * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp | ||
| 25 | * method when the event is triggered. | ||
| 26 | */ | ||
| 27 | class TimeManager { | ||
| 28 | public: | ||
| 29 | explicit TimeManager(Core::System& system); | ||
| 30 | |||
| 31 | /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' | ||
| 32 | /// returns a non-invalid handle in `event_handle` if correctly scheduled | ||
| 33 | void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds); | ||
| 34 | |||
| 35 | /// Unschedule an existing time event | ||
| 36 | void UnscheduleTimeEvent(Handle event_handle); | ||
| 37 | |||
| 38 | private: | ||
| 39 | Core::System& system; | ||
| 40 | std::shared_ptr<Core::Timing::EventType> time_manager_event_type; | ||
| 41 | }; | ||
| 42 | |||
| 43 | } // namespace Kernel | ||