diff options
| author | 2015-01-08 22:38:33 -0500 | |
|---|---|---|
| committer | 2015-01-08 22:38:33 -0500 | |
| commit | d46f6500363024ac58cc23ba706e26d531a6076a (patch) | |
| tree | b5818b8b26092f425dccff628517f51fde47aaed /src/core/hle/kernel/timer.cpp | |
| parent | Merge pull request #451 from Subv/wut (diff) | |
| parent | SVC: Implemented the Timer service calls. (diff) | |
| download | yuzu-d46f6500363024ac58cc23ba706e26d531a6076a.tar.gz yuzu-d46f6500363024ac58cc23ba706e26d531a6076a.tar.xz yuzu-d46f6500363024ac58cc23ba706e26d531a6076a.zip | |
Merge pull request #255 from Subv/cbranch_3
Implemented timers
Diffstat (limited to 'src/core/hle/kernel/timer.cpp')
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp new file mode 100644 index 000000000..7ac669e31 --- /dev/null +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <set> | ||
| 6 | |||
| 7 | #include "common/common.h" | ||
| 8 | |||
| 9 | #include "core/core_timing.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/timer.h" | ||
| 12 | #include "core/hle/kernel/thread.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | class Timer : public Object { | ||
| 17 | public: | ||
| 18 | std::string GetTypeName() const override { return "Timer"; } | ||
| 19 | std::string GetName() const override { return name; } | ||
| 20 | |||
| 21 | static const HandleType HANDLE_TYPE = HandleType::Timer; | ||
| 22 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 23 | |||
| 24 | ResetType reset_type; ///< The ResetType of this timer | ||
| 25 | |||
| 26 | bool signaled; ///< Whether the timer has been signaled or not | ||
| 27 | std::set<Handle> waiting_threads; ///< Threads that are waiting for the timer | ||
| 28 | std::string name; ///< Name of timer (optional) | ||
| 29 | |||
| 30 | u64 initial_delay; ///< The delay until the timer fires for the first time | ||
| 31 | u64 interval_delay; ///< The delay until the timer fires after the first time | ||
| 32 | |||
| 33 | ResultVal<bool> WaitSynchronization() override { | ||
| 34 | bool wait = !signaled; | ||
| 35 | if (wait) { | ||
| 36 | waiting_threads.insert(GetCurrentThreadHandle()); | ||
| 37 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, GetHandle()); | ||
| 38 | } | ||
| 39 | return MakeResult<bool>(wait); | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Creates a timer. | ||
| 45 | * @param handle Reference to handle for the newly created timer | ||
| 46 | * @param reset_type ResetType describing how to create timer | ||
| 47 | * @param name Optional name of timer | ||
| 48 | * @return Newly created Timer object | ||
| 49 | */ | ||
| 50 | Timer* CreateTimer(Handle& handle, const ResetType reset_type, const std::string& name) { | ||
| 51 | Timer* timer = new Timer; | ||
| 52 | |||
| 53 | handle = Kernel::g_handle_table.Create(timer).ValueOr(INVALID_HANDLE); | ||
| 54 | |||
| 55 | timer->reset_type = reset_type; | ||
| 56 | timer->signaled = false; | ||
| 57 | timer->name = name; | ||
| 58 | timer->initial_delay = 0; | ||
| 59 | timer->interval_delay = 0; | ||
| 60 | return timer; | ||
| 61 | } | ||
| 62 | |||
| 63 | ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { | ||
| 64 | CreateTimer(*handle, reset_type, name); | ||
| 65 | return RESULT_SUCCESS; | ||
| 66 | } | ||
| 67 | |||
| 68 | ResultCode ClearTimer(Handle handle) { | ||
| 69 | Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 70 | |||
| 71 | if (timer == nullptr) | ||
| 72 | return InvalidHandle(ErrorModule::Kernel); | ||
| 73 | |||
| 74 | timer->signaled = false; | ||
| 75 | return RESULT_SUCCESS; | ||
| 76 | } | ||
| 77 | |||
| 78 | /// The event type of the generic timer callback event | ||
| 79 | static int TimerCallbackEventType = -1; | ||
| 80 | |||
| 81 | /// The timer callback event, called when a timer is fired | ||
| 82 | static void TimerCallback(u64 timer_handle, int cycles_late) { | ||
| 83 | Timer* timer = Kernel::g_handle_table.Get<Timer>(timer_handle); | ||
| 84 | |||
| 85 | if (timer == nullptr) { | ||
| 86 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | LOG_TRACE(Kernel, "Timer %u fired", timer_handle); | ||
| 91 | |||
| 92 | timer->signaled = true; | ||
| 93 | |||
| 94 | // Resume all waiting threads | ||
| 95 | for (Handle thread : timer->waiting_threads) | ||
| 96 | ResumeThreadFromWait(thread); | ||
| 97 | |||
| 98 | timer->waiting_threads.clear(); | ||
| 99 | |||
| 100 | if (timer->reset_type == RESETTYPE_ONESHOT) | ||
| 101 | timer->signaled = false; | ||
| 102 | |||
| 103 | if (timer->interval_delay != 0) { | ||
| 104 | // Reschedule the timer with the interval delay | ||
| 105 | u64 interval_microseconds = timer->interval_delay / 1000; | ||
| 106 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, | ||
| 107 | TimerCallbackEventType, timer_handle); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { | ||
| 112 | Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 113 | |||
| 114 | if (timer == nullptr) | ||
| 115 | return InvalidHandle(ErrorModule::Kernel); | ||
| 116 | |||
| 117 | timer->initial_delay = initial; | ||
| 118 | timer->interval_delay = interval; | ||
| 119 | |||
| 120 | u64 initial_microseconds = initial / 1000; | ||
| 121 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), TimerCallbackEventType, handle); | ||
| 122 | return RESULT_SUCCESS; | ||
| 123 | } | ||
| 124 | |||
| 125 | ResultCode CancelTimer(Handle handle) { | ||
| 126 | Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 127 | |||
| 128 | if (timer == nullptr) | ||
| 129 | return InvalidHandle(ErrorModule::Kernel); | ||
| 130 | |||
| 131 | CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); | ||
| 132 | return RESULT_SUCCESS; | ||
| 133 | } | ||
| 134 | |||
| 135 | void TimersInit() { | ||
| 136 | TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | ||
| 137 | } | ||
| 138 | |||
| 139 | void TimersShutdown() { | ||
| 140 | } | ||
| 141 | |||
| 142 | } // namespace | ||