diff options
| author | 2022-12-19 18:37:34 -0300 | |
|---|---|---|
| committer | 2022-12-19 18:37:34 -0300 | |
| commit | e44d1fe73cc5fac4cfab0d3d8660dbb46d60cafc (patch) | |
| tree | abfcbf2c097e1bb0b1297f0af90b94c055bc242c /src | |
| parent | Merge pull request #9471 from german77/input (diff) | |
| parent | kernel: remove TimeManager (diff) | |
| download | yuzu-e44d1fe73cc5fac4cfab0d3d8660dbb46d60cafc.tar.gz yuzu-e44d1fe73cc5fac4cfab0d3d8660dbb46d60cafc.tar.xz yuzu-e44d1fe73cc5fac4cfab0d3d8660dbb46d60cafc.zip | |
Merge pull request #9474 from liamwhite/timer
kernel: add KHardwareTimer
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_address_arbiter.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_hardware_timer.cpp | 74 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_hardware_timer.h | 54 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_hardware_timer_base.h | 92 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread_queue.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_timer_task.h | 40 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 9 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.cpp | 44 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.h | 41 |
13 files changed, 290 insertions, 109 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c6b5ac196..0252c8c31 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -201,6 +201,9 @@ add_library(core STATIC | |||
| 201 | hle/kernel/k_event_info.h | 201 | hle/kernel/k_event_info.h |
| 202 | hle/kernel/k_handle_table.cpp | 202 | hle/kernel/k_handle_table.cpp |
| 203 | hle/kernel/k_handle_table.h | 203 | hle/kernel/k_handle_table.h |
| 204 | hle/kernel/k_hardware_timer_base.h | ||
| 205 | hle/kernel/k_hardware_timer.cpp | ||
| 206 | hle/kernel/k_hardware_timer.h | ||
| 204 | hle/kernel/k_interrupt_manager.cpp | 207 | hle/kernel/k_interrupt_manager.cpp |
| 205 | hle/kernel/k_interrupt_manager.h | 208 | hle/kernel/k_interrupt_manager.h |
| 206 | hle/kernel/k_light_condition_variable.cpp | 209 | hle/kernel/k_light_condition_variable.cpp |
| @@ -268,6 +271,7 @@ add_library(core STATIC | |||
| 268 | hle/kernel/k_thread_local_page.h | 271 | hle/kernel/k_thread_local_page.h |
| 269 | hle/kernel/k_thread_queue.cpp | 272 | hle/kernel/k_thread_queue.cpp |
| 270 | hle/kernel/k_thread_queue.h | 273 | hle/kernel/k_thread_queue.h |
| 274 | hle/kernel/k_timer_task.h | ||
| 271 | hle/kernel/k_trace.h | 275 | hle/kernel/k_trace.h |
| 272 | hle/kernel/k_transfer_memory.cpp | 276 | hle/kernel/k_transfer_memory.cpp |
| 273 | hle/kernel/k_transfer_memory.h | 277 | hle/kernel/k_transfer_memory.h |
| @@ -290,8 +294,6 @@ add_library(core STATIC | |||
| 290 | hle/kernel/svc_common.h | 294 | hle/kernel/svc_common.h |
| 291 | hle/kernel/svc_types.h | 295 | hle/kernel/svc_types.h |
| 292 | hle/kernel/svc_wrap.h | 296 | hle/kernel/svc_wrap.h |
| 293 | hle/kernel/time_manager.cpp | ||
| 294 | hle/kernel/time_manager.h | ||
| 295 | hle/result.h | 297 | hle/result.h |
| 296 | hle/service/acc/acc.cpp | 298 | hle/service/acc/acc.cpp |
| 297 | hle/service/acc/acc.h | 299 | hle/service/acc/acc.h |
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index f85b11557..a442a3b98 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "core/hle/kernel/k_thread_queue.h" | 10 | #include "core/hle/kernel/k_thread_queue.h" |
| 11 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/svc_results.h" | 12 | #include "core/hle/kernel/svc_results.h" |
| 13 | #include "core/hle/kernel/time_manager.h" | ||
| 14 | #include "core/memory.h" | 13 | #include "core/memory.h" |
| 15 | 14 | ||
| 16 | namespace Kernel { | 15 | namespace Kernel { |
diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp new file mode 100644 index 000000000..6bba79ea0 --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.cpp | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/core_timing.h" | ||
| 6 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | void KHardwareTimer::Initialize() { | ||
| 12 | // Create the timing callback to register with CoreTiming. | ||
| 13 | m_event_type = Core::Timing::CreateEvent( | ||
| 14 | "KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) { | ||
| 15 | reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask(); | ||
| 16 | return std::nullopt; | ||
| 17 | }); | ||
| 18 | } | ||
| 19 | |||
| 20 | void KHardwareTimer::Finalize() { | ||
| 21 | this->DisableInterrupt(); | ||
| 22 | m_event_type.reset(); | ||
| 23 | } | ||
| 24 | |||
| 25 | void KHardwareTimer::DoTask() { | ||
| 26 | // Handle the interrupt. | ||
| 27 | { | ||
| 28 | KScopedSchedulerLock slk{m_kernel}; | ||
| 29 | KScopedSpinLock lk(this->GetLock()); | ||
| 30 | |||
| 31 | //! Ignore this event if needed. | ||
| 32 | if (!this->GetInterruptEnabled()) { | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | |||
| 36 | // Disable the timer interrupt while we handle this. | ||
| 37 | this->DisableInterrupt(); | ||
| 38 | |||
| 39 | if (const s64 next_time = this->DoInterruptTaskImpl(GetTick()); | ||
| 40 | 0 < next_time && next_time <= m_wakeup_time) { | ||
| 41 | // We have a next time, so we should set the time to interrupt and turn the interrupt | ||
| 42 | // on. | ||
| 43 | this->EnableInterrupt(next_time); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | // Clear the timer interrupt. | ||
| 48 | // Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer, | ||
| 49 | // GetCurrentCoreId()); | ||
| 50 | } | ||
| 51 | |||
| 52 | void KHardwareTimer::EnableInterrupt(s64 wakeup_time) { | ||
| 53 | this->DisableInterrupt(); | ||
| 54 | |||
| 55 | m_wakeup_time = wakeup_time; | ||
| 56 | m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time}, | ||
| 57 | m_event_type, reinterpret_cast<uintptr_t>(this), | ||
| 58 | true); | ||
| 59 | } | ||
| 60 | |||
| 61 | void KHardwareTimer::DisableInterrupt() { | ||
| 62 | m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); | ||
| 63 | m_wakeup_time = std::numeric_limits<s64>::max(); | ||
| 64 | } | ||
| 65 | |||
| 66 | s64 KHardwareTimer::GetTick() const { | ||
| 67 | return m_kernel.System().CoreTiming().GetGlobalTimeNs().count(); | ||
| 68 | } | ||
| 69 | |||
| 70 | bool KHardwareTimer::GetInterruptEnabled() { | ||
| 71 | return m_wakeup_time != std::numeric_limits<s64>::max(); | ||
| 72 | } | ||
| 73 | |||
| 74 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_hardware_timer.h b/src/core/hle/kernel/k_hardware_timer.h new file mode 100644 index 000000000..00bef6ea1 --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_hardware_timer_base.h" | ||
| 7 | |||
| 8 | namespace Core::Timing { | ||
| 9 | struct EventType; | ||
| 10 | } // namespace Core::Timing | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | class KHardwareTimer : /* public KInterruptTask, */ public KHardwareTimerBase { | ||
| 15 | public: | ||
| 16 | explicit KHardwareTimer(KernelCore& kernel) : KHardwareTimerBase{kernel} {} | ||
| 17 | |||
| 18 | // Public API. | ||
| 19 | void Initialize(); | ||
| 20 | void Finalize(); | ||
| 21 | |||
| 22 | s64 GetCount() const { | ||
| 23 | return GetTick(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void RegisterTask(KTimerTask* task, s64 time_from_now) { | ||
| 27 | this->RegisterAbsoluteTask(task, GetTick() + time_from_now); | ||
| 28 | } | ||
| 29 | |||
| 30 | void RegisterAbsoluteTask(KTimerTask* task, s64 task_time) { | ||
| 31 | KScopedDisableDispatch dd{m_kernel}; | ||
| 32 | KScopedSpinLock lk{this->GetLock()}; | ||
| 33 | |||
| 34 | if (this->RegisterAbsoluteTaskImpl(task, task_time)) { | ||
| 35 | if (task_time <= m_wakeup_time) { | ||
| 36 | this->EnableInterrupt(task_time); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | void EnableInterrupt(s64 wakeup_time); | ||
| 43 | void DisableInterrupt(); | ||
| 44 | bool GetInterruptEnabled(); | ||
| 45 | s64 GetTick() const; | ||
| 46 | void DoTask(); | ||
| 47 | |||
| 48 | private: | ||
| 49 | // Absolute time in nanoseconds | ||
| 50 | s64 m_wakeup_time{std::numeric_limits<s64>::max()}; | ||
| 51 | std::shared_ptr<Core::Timing::EventType> m_event_type{}; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_hardware_timer_base.h b/src/core/hle/kernel/k_hardware_timer_base.h new file mode 100644 index 000000000..6318b35bd --- /dev/null +++ b/src/core/hle/kernel/k_hardware_timer_base.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_spin_lock.h" | ||
| 7 | #include "core/hle/kernel/k_thread.h" | ||
| 8 | #include "core/hle/kernel/k_timer_task.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | class KHardwareTimerBase { | ||
| 13 | public: | ||
| 14 | explicit KHardwareTimerBase(KernelCore& kernel) : m_kernel{kernel} {} | ||
| 15 | |||
| 16 | void CancelTask(KTimerTask* task) { | ||
| 17 | KScopedDisableDispatch dd{m_kernel}; | ||
| 18 | KScopedSpinLock lk{m_lock}; | ||
| 19 | |||
| 20 | if (const s64 task_time = task->GetTime(); task_time > 0) { | ||
| 21 | this->RemoveTaskFromTree(task); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | protected: | ||
| 26 | KSpinLock& GetLock() { | ||
| 27 | return m_lock; | ||
| 28 | } | ||
| 29 | |||
| 30 | s64 DoInterruptTaskImpl(s64 cur_time) { | ||
| 31 | // We want to handle all tasks, returning the next time that a task is scheduled. | ||
| 32 | while (true) { | ||
| 33 | // Get the next task. If there isn't one, return 0. | ||
| 34 | KTimerTask* task = m_next_task; | ||
| 35 | if (task == nullptr) { | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | // If the task needs to be done in the future, do it in the future and not now. | ||
| 40 | if (const s64 task_time = task->GetTime(); task_time > cur_time) { | ||
| 41 | return task_time; | ||
| 42 | } | ||
| 43 | |||
| 44 | // Remove the task from the tree of tasks, and update our next task. | ||
| 45 | this->RemoveTaskFromTree(task); | ||
| 46 | |||
| 47 | // Handle the task. | ||
| 48 | task->OnTimer(); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | bool RegisterAbsoluteTaskImpl(KTimerTask* task, s64 task_time) { | ||
| 53 | ASSERT(task_time > 0); | ||
| 54 | |||
| 55 | // Set the task's time, and insert it into our tree. | ||
| 56 | task->SetTime(task_time); | ||
| 57 | m_task_tree.insert(*task); | ||
| 58 | |||
| 59 | // Update our next task if relevant. | ||
| 60 | if (m_next_task != nullptr && m_next_task->GetTime() <= task_time) { | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | m_next_task = task; | ||
| 64 | return true; | ||
| 65 | } | ||
| 66 | |||
| 67 | private: | ||
| 68 | void RemoveTaskFromTree(KTimerTask* task) { | ||
| 69 | // Erase from the tree. | ||
| 70 | auto it = m_task_tree.erase(m_task_tree.iterator_to(*task)); | ||
| 71 | |||
| 72 | // Clear the task's scheduled time. | ||
| 73 | task->SetTime(0); | ||
| 74 | |||
| 75 | // Update our next task if relevant. | ||
| 76 | if (m_next_task == task) { | ||
| 77 | m_next_task = (it != m_task_tree.end()) ? std::addressof(*it) : nullptr; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | protected: | ||
| 82 | KernelCore& m_kernel; | ||
| 83 | |||
| 84 | private: | ||
| 85 | using TimerTaskTree = Common::IntrusiveRedBlackTreeBaseTraits<KTimerTask>::TreeType<KTimerTask>; | ||
| 86 | |||
| 87 | KSpinLock m_lock{}; | ||
| 88 | TimerTaskTree m_task_tree{}; | ||
| 89 | KTimerTask* m_next_task{}; | ||
| 90 | }; | ||
| 91 | |||
| 92 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 76c095e69..76db65a4d 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | |||
| @@ -5,9 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/hle/kernel/global_scheduler_context.h" | 7 | #include "core/hle/kernel/global_scheduler_context.h" |
| 8 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | 9 | #include "core/hle/kernel/k_thread.h" |
| 9 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/time_manager.h" | ||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| @@ -22,7 +22,7 @@ public: | |||
| 22 | ~KScopedSchedulerLockAndSleep() { | 22 | ~KScopedSchedulerLockAndSleep() { |
| 23 | // Register the sleep. | 23 | // Register the sleep. |
| 24 | if (timeout_tick > 0) { | 24 | if (timeout_tick > 0) { |
| 25 | kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick); | 25 | kernel.HardwareTimer().RegisterTask(thread, timeout_tick); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | // Unlock the scheduler. | 28 | // Unlock the scheduler. |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index dc52b4ed3..7cd94a340 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "core/hle/kernel/k_light_lock.h" | 22 | #include "core/hle/kernel/k_light_lock.h" |
| 23 | #include "core/hle/kernel/k_spin_lock.h" | 23 | #include "core/hle/kernel/k_spin_lock.h" |
| 24 | #include "core/hle/kernel/k_synchronization_object.h" | 24 | #include "core/hle/kernel/k_synchronization_object.h" |
| 25 | #include "core/hle/kernel/k_timer_task.h" | ||
| 25 | #include "core/hle/kernel/k_worker_task.h" | 26 | #include "core/hle/kernel/k_worker_task.h" |
| 26 | #include "core/hle/kernel/slab_helpers.h" | 27 | #include "core/hle/kernel/slab_helpers.h" |
| 27 | #include "core/hle/kernel/svc_common.h" | 28 | #include "core/hle/kernel/svc_common.h" |
| @@ -112,7 +113,8 @@ void SetCurrentThread(KernelCore& kernel, KThread* thread); | |||
| 112 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); | 113 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); |
| 113 | 114 | ||
| 114 | class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, | 115 | class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, |
| 115 | public boost::intrusive::list_base_hook<> { | 116 | public boost::intrusive::list_base_hook<>, |
| 117 | public KTimerTask { | ||
| 116 | KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); | 118 | KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); |
| 117 | 119 | ||
| 118 | private: | 120 | private: |
| @@ -840,4 +842,8 @@ private: | |||
| 840 | KernelCore& kernel; | 842 | KernelCore& kernel; |
| 841 | }; | 843 | }; |
| 842 | 844 | ||
| 845 | inline void KTimerTask::OnTimer() { | ||
| 846 | static_cast<KThread*>(this)->OnTimer(); | ||
| 847 | } | ||
| 848 | |||
| 843 | } // namespace Kernel | 849 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp index 9f4e081ba..5f1dc97eb 100644 --- a/src/core/hle/kernel/k_thread_queue.cpp +++ b/src/core/hle/kernel/k_thread_queue.cpp | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 4 | #include "core/hle/kernel/k_thread_queue.h" | 5 | #include "core/hle/kernel/k_thread_queue.h" |
| 5 | #include "core/hle/kernel/kernel.h" | 6 | #include "core/hle/kernel/kernel.h" |
| 6 | #include "core/hle/kernel/time_manager.h" | ||
| 7 | 7 | ||
| 8 | namespace Kernel { | 8 | namespace Kernel { |
| 9 | 9 | ||
| @@ -22,7 +22,7 @@ void KThreadQueue::EndWait(KThread* waiting_thread, Result wait_result) { | |||
| 22 | waiting_thread->ClearWaitQueue(); | 22 | waiting_thread->ClearWaitQueue(); |
| 23 | 23 | ||
| 24 | // Cancel the thread task. | 24 | // Cancel the thread task. |
| 25 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | 25 | kernel.HardwareTimer().CancelTask(waiting_thread); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) { | 28 | void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) { |
| @@ -37,7 +37,7 @@ void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool | |||
| 37 | 37 | ||
| 38 | // Cancel the thread task. | 38 | // Cancel the thread task. |
| 39 | if (cancel_timer_task) { | 39 | if (cancel_timer_task) { |
| 40 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | 40 | kernel.HardwareTimer().CancelTask(waiting_thread); |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
| 43 | 43 | ||
diff --git a/src/core/hle/kernel/k_timer_task.h b/src/core/hle/kernel/k_timer_task.h new file mode 100644 index 000000000..66f0a5a90 --- /dev/null +++ b/src/core/hle/kernel/k_timer_task.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/intrusive_red_black_tree.h" | ||
| 7 | |||
| 8 | namespace Kernel { | ||
| 9 | |||
| 10 | class KTimerTask : public Common::IntrusiveRedBlackTreeBaseNode<KTimerTask> { | ||
| 11 | public: | ||
| 12 | static constexpr int Compare(const KTimerTask& lhs, const KTimerTask& rhs) { | ||
| 13 | if (lhs.GetTime() < rhs.GetTime()) { | ||
| 14 | return -1; | ||
| 15 | } else { | ||
| 16 | return 1; | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | constexpr explicit KTimerTask() = default; | ||
| 21 | |||
| 22 | constexpr void SetTime(s64 t) { | ||
| 23 | m_time = t; | ||
| 24 | } | ||
| 25 | |||
| 26 | constexpr s64 GetTime() const { | ||
| 27 | return m_time; | ||
| 28 | } | ||
| 29 | |||
| 30 | // NOTE: This is virtual in Nintendo's kernel. Prior to 13.0.0, KWaitObject was also a | ||
| 31 | // TimerTask; this is no longer the case. Since this is now KThread exclusive, we have | ||
| 32 | // devirtualized (see inline declaration for this inside k_thread.h). | ||
| 33 | void OnTimer(); | ||
| 34 | |||
| 35 | private: | ||
| 36 | // Absolute time in nanoseconds | ||
| 37 | s64 m_time{}; | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0eb74a422..b75bac5df 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include "core/hle/kernel/k_client_port.h" | 26 | #include "core/hle/kernel/k_client_port.h" |
| 27 | #include "core/hle/kernel/k_dynamic_resource_manager.h" | 27 | #include "core/hle/kernel/k_dynamic_resource_manager.h" |
| 28 | #include "core/hle/kernel/k_handle_table.h" | 28 | #include "core/hle/kernel/k_handle_table.h" |
| 29 | #include "core/hle/kernel/k_hardware_timer.h" | ||
| 29 | #include "core/hle/kernel/k_memory_layout.h" | 30 | #include "core/hle/kernel/k_memory_layout.h" |
| 30 | #include "core/hle/kernel/k_memory_manager.h" | 31 | #include "core/hle/kernel/k_memory_manager.h" |
| 31 | #include "core/hle/kernel/k_page_buffer.h" | 32 | #include "core/hle/kernel/k_page_buffer.h" |
| @@ -39,7 +40,6 @@ | |||
| 39 | #include "core/hle/kernel/kernel.h" | 40 | #include "core/hle/kernel/kernel.h" |
| 40 | #include "core/hle/kernel/physical_core.h" | 41 | #include "core/hle/kernel/physical_core.h" |
| 41 | #include "core/hle/kernel/service_thread.h" | 42 | #include "core/hle/kernel/service_thread.h" |
| 42 | #include "core/hle/kernel/time_manager.h" | ||
| 43 | #include "core/hle/result.h" | 43 | #include "core/hle/result.h" |
| 44 | #include "core/hle/service/sm/sm.h" | 44 | #include "core/hle/service/sm/sm.h" |
| 45 | #include "core/memory.h" | 45 | #include "core/memory.h" |
| @@ -55,7 +55,7 @@ struct KernelCore::Impl { | |||
| 55 | static constexpr size_t ReservedDynamicPageCount = 64; | 55 | static constexpr size_t ReservedDynamicPageCount = 64; |
| 56 | 56 | ||
| 57 | explicit Impl(Core::System& system_, KernelCore& kernel_) | 57 | explicit Impl(Core::System& system_, KernelCore& kernel_) |
| 58 | : time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"}, | 58 | : service_threads_manager{1, "ServiceThreadsManager"}, |
| 59 | service_thread_barrier{2}, system{system_} {} | 59 | service_thread_barrier{2}, system{system_} {} |
| 60 | 60 | ||
| 61 | void SetMulticore(bool is_multi) { | 61 | void SetMulticore(bool is_multi) { |
| @@ -63,6 +63,9 @@ struct KernelCore::Impl { | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | void Initialize(KernelCore& kernel) { | 65 | void Initialize(KernelCore& kernel) { |
| 66 | hardware_timer = std::make_unique<Kernel::KHardwareTimer>(kernel); | ||
| 67 | hardware_timer->Initialize(); | ||
| 68 | |||
| 66 | global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); | 69 | global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); |
| 67 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | 70 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); |
| 68 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); | 71 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); |
| @@ -193,6 +196,9 @@ struct KernelCore::Impl { | |||
| 193 | // Ensure that the object list container is finalized and properly shutdown. | 196 | // Ensure that the object list container is finalized and properly shutdown. |
| 194 | global_object_list_container->Finalize(); | 197 | global_object_list_container->Finalize(); |
| 195 | global_object_list_container.reset(); | 198 | global_object_list_container.reset(); |
| 199 | |||
| 200 | hardware_timer->Finalize(); | ||
| 201 | hardware_timer.reset(); | ||
| 196 | } | 202 | } |
| 197 | 203 | ||
| 198 | void CloseServices() { | 204 | void CloseServices() { |
| @@ -832,7 +838,7 @@ struct KernelCore::Impl { | |||
| 832 | std::vector<KProcess*> process_list; | 838 | std::vector<KProcess*> process_list; |
| 833 | std::atomic<KProcess*> current_process{}; | 839 | std::atomic<KProcess*> current_process{}; |
| 834 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | 840 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| 835 | Kernel::TimeManager time_manager; | 841 | std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; |
| 836 | 842 | ||
| 837 | Init::KSlabResourceCounts slab_resource_counts{}; | 843 | Init::KSlabResourceCounts slab_resource_counts{}; |
| 838 | KResourceLimit* system_resource_limit{}; | 844 | KResourceLimit* system_resource_limit{}; |
| @@ -1019,12 +1025,8 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() { | |||
| 1019 | return impl->schedulers[core_id].get(); | 1025 | return impl->schedulers[core_id].get(); |
| 1020 | } | 1026 | } |
| 1021 | 1027 | ||
| 1022 | Kernel::TimeManager& KernelCore::TimeManager() { | 1028 | Kernel::KHardwareTimer& KernelCore::HardwareTimer() { |
| 1023 | return impl->time_manager; | 1029 | return *impl->hardware_timer; |
| 1024 | } | ||
| 1025 | |||
| 1026 | const Kernel::TimeManager& KernelCore::TimeManager() const { | ||
| 1027 | return impl->time_manager; | ||
| 1028 | } | 1030 | } |
| 1029 | 1031 | ||
| 1030 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { | 1032 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2e22fe0f6..8d22f8d2c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -39,6 +39,7 @@ class KDynamicPageManager; | |||
| 39 | class KEvent; | 39 | class KEvent; |
| 40 | class KEventInfo; | 40 | class KEventInfo; |
| 41 | class KHandleTable; | 41 | class KHandleTable; |
| 42 | class KHardwareTimer; | ||
| 42 | class KLinkedListNode; | 43 | class KLinkedListNode; |
| 43 | class KMemoryLayout; | 44 | class KMemoryLayout; |
| 44 | class KMemoryManager; | 45 | class KMemoryManager; |
| @@ -63,7 +64,6 @@ class KCodeMemory; | |||
| 63 | class PhysicalCore; | 64 | class PhysicalCore; |
| 64 | class ServiceThread; | 65 | class ServiceThread; |
| 65 | class Synchronization; | 66 | class Synchronization; |
| 66 | class TimeManager; | ||
| 67 | 67 | ||
| 68 | using ServiceInterfaceFactory = | 68 | using ServiceInterfaceFactory = |
| 69 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; | 69 | std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; |
| @@ -175,11 +175,8 @@ public: | |||
| 175 | /// Gets the an instance of the current physical CPU core. | 175 | /// Gets the an instance of the current physical CPU core. |
| 176 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; | 176 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; |
| 177 | 177 | ||
| 178 | /// Gets the an instance of the TimeManager Interface. | 178 | /// Gets the an instance of the hardware timer. |
| 179 | Kernel::TimeManager& TimeManager(); | 179 | Kernel::KHardwareTimer& HardwareTimer(); |
| 180 | |||
| 181 | /// Gets the an instance of the TimeManager Interface. | ||
| 182 | const Kernel::TimeManager& TimeManager() const; | ||
| 183 | 180 | ||
| 184 | /// Stops execution of 'id' core, in order to reschedule a new thread. | 181 | /// Stops execution of 'id' core, in order to reschedule a new thread. |
| 185 | void PrepareReschedule(std::size_t id); | 182 | void PrepareReschedule(std::size_t id); |
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp deleted file mode 100644 index 5ee72c432..000000000 --- a/src/core/hle/kernel/time_manager.cpp +++ /dev/null | |||
| @@ -1,44 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/assert.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | ||
| 9 | #include "core/hle/kernel/time_manager.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | TimeManager::TimeManager(Core::System& system_) : system{system_} { | ||
| 14 | time_manager_event_type = Core::Timing::CreateEvent( | ||
| 15 | "Kernel::TimeManagerCallback", | ||
| 16 | [this](std::uintptr_t thread_handle, s64 time, | ||
| 17 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { | ||
| 18 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); | ||
| 19 | { | ||
| 20 | KScopedSchedulerLock sl(system.Kernel()); | ||
| 21 | thread->OnTimer(); | ||
| 22 | } | ||
| 23 | return std::nullopt; | ||
| 24 | }); | ||
| 25 | } | ||
| 26 | |||
| 27 | void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { | ||
| 28 | std::scoped_lock lock{mutex}; | ||
| 29 | if (nanoseconds > 0) { | ||
| 30 | ASSERT(thread); | ||
| 31 | ASSERT(thread->GetState() != ThreadState::Runnable); | ||
| 32 | system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, | ||
| 33 | time_manager_event_type, | ||
| 34 | reinterpret_cast<uintptr_t>(thread)); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | void TimeManager::UnscheduleTimeEvent(KThread* thread) { | ||
| 39 | std::scoped_lock lock{mutex}; | ||
| 40 | system.CoreTiming().UnscheduleEvent(time_manager_event_type, | ||
| 41 | reinterpret_cast<uintptr_t>(thread)); | ||
| 42 | } | ||
| 43 | |||
| 44 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h deleted file mode 100644 index 94d16b3b4..000000000 --- a/src/core/hle/kernel/time_manager.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } // namespace Core | ||
| 12 | |||
| 13 | namespace Core::Timing { | ||
| 14 | struct EventType; | ||
| 15 | } // namespace Core::Timing | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | class KThread; | ||
| 20 | |||
| 21 | /** | ||
| 22 | * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp | ||
| 23 | * method when the event is triggered. | ||
| 24 | */ | ||
| 25 | class TimeManager { | ||
| 26 | public: | ||
| 27 | explicit TimeManager(Core::System& system); | ||
| 28 | |||
| 29 | /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds' | ||
| 30 | void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds); | ||
| 31 | |||
| 32 | /// Unschedule an existing time event | ||
| 33 | void UnscheduleTimeEvent(KThread* thread); | ||
| 34 | |||
| 35 | private: | ||
| 36 | Core::System& system; | ||
| 37 | std::shared_ptr<Core::Timing::EventType> time_manager_event_type; | ||
| 38 | std::mutex mutex; | ||
| 39 | }; | ||
| 40 | |||
| 41 | } // namespace Kernel | ||