summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/timer.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2015-01-08 22:38:33 -0500
committerGravatar bunnei2015-01-08 22:38:33 -0500
commitd46f6500363024ac58cc23ba706e26d531a6076a (patch)
treeb5818b8b26092f425dccff628517f51fde47aaed /src/core/hle/kernel/timer.cpp
parentMerge pull request #451 from Subv/wut (diff)
parentSVC: Implemented the Timer service calls. (diff)
downloadyuzu-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.cpp142
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
14namespace Kernel {
15
16class Timer : public Object {
17public:
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 */
50Timer* 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
63ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) {
64 CreateTimer(*handle, reset_type, name);
65 return RESULT_SUCCESS;
66}
67
68ResultCode 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
79static int TimerCallbackEventType = -1;
80
81/// The timer callback event, called when a timer is fired
82static 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
111ResultCode 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
125ResultCode 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
135void TimersInit() {
136 TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
137}
138
139void TimersShutdown() {
140}
141
142} // namespace