summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/timer.cpp39
-rw-r--r--src/core/hle/kernel/timer.h8
-rw-r--r--src/core/hle/svc.cpp5
3 files changed, 36 insertions, 16 deletions
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 60537f355..c42003e9d 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -52,9 +52,14 @@ void Timer::Set(s64 initial, s64 interval) {
52 initial_delay = initial; 52 initial_delay = initial;
53 interval_delay = interval; 53 interval_delay = interval;
54 54
55 u64 initial_microseconds = initial / 1000; 55 if (initial == 0) {
56 CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, 56 // Immediately invoke the callback
57 callback_handle); 57 Signal(0);
58 } else {
59 u64 initial_microseconds = initial / 1000;
60 CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
61 callback_handle);
62 }
58} 63}
59 64
60void Timer::Cancel() { 65void Timer::Cancel() {
@@ -72,6 +77,20 @@ void Timer::WakeupAllWaitingThreads() {
72 signaled = false; 77 signaled = false;
73} 78}
74 79
80void Timer::Signal(int cycles_late) {
81 LOG_TRACE(Kernel, "Timer %08" PRIx64 " fired", timer_handle);
82
83 // Resume all waiting threads
84 WakeupAllWaitingThreads();
85
86 if (interval_delay != 0) {
87 // Reschedule the timer with the interval delay
88 u64 interval_microseconds = interval_delay / 1000;
89 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
90 timer_callback_event_type, callback_handle);
91 }
92}
93
75/// The timer callback event, called when a timer is fired 94/// The timer callback event, called when a timer is fired
76static void TimerCallback(u64 timer_handle, int cycles_late) { 95static void TimerCallback(u64 timer_handle, int cycles_late) {
77 SharedPtr<Timer> timer = 96 SharedPtr<Timer> timer =
@@ -82,19 +101,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
82 return; 101 return;
83 } 102 }
84 103
85 LOG_TRACE(Kernel, "Timer %08" PRIx64 " fired", timer_handle); 104 timer->Signal(cycles_late);
86
87 timer->signaled = true;
88
89 // Resume all waiting threads
90 timer->WakeupAllWaitingThreads();
91
92 if (timer->interval_delay != 0) {
93 // Reschedule the timer with the interval delay
94 u64 interval_microseconds = timer->interval_delay / 1000;
95 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
96 timer_callback_event_type, timer_handle);
97 }
98} 105}
99 106
100void TimersInit() { 107void TimersInit() {
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index c174f5664..b0f818933 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -54,6 +54,14 @@ public:
54 void Cancel(); 54 void Cancel();
55 void Clear(); 55 void Clear();
56 56
57 /**
58 * Signals the timer, waking up any waiting threads and rescheduling it
59 * for the next interval.
60 * This method should not be called from outside the timer callback handler,
61 * lest multiple callback events get scheduled.
62 */
63 void Signal(int cycles_late);
64
57private: 65private:
58 Timer(); 66 Timer();
59 ~Timer() override; 67 ~Timer() override;
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 96db39ad9..1baa80671 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -837,6 +837,11 @@ static ResultCode SetTimer(Kernel::Handle handle, s64 initial, s64 interval) {
837 837
838 LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); 838 LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
839 839
840 if (initial < 0 || interval < 0) {
841 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
842 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
843 }
844
840 SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); 845 SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
841 if (timer == nullptr) 846 if (timer == nullptr)
842 return ERR_INVALID_HANDLE; 847 return ERR_INVALID_HANDLE;