From 029a11030ee12470e3f3c3431639fbde8d350c77 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 9 Jan 2017 12:48:17 -0500 Subject: Timers: Immediately signal the timer if it was started with an initial value of 0. --- src/core/hle/kernel/timer.cpp | 39 +++++++++++++++++++++++---------------- src/core/hle/kernel/timer.h | 8 ++++++++ 2 files changed, 31 insertions(+), 16 deletions(-) (limited to 'src/core/hle') 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) { initial_delay = initial; interval_delay = interval; - u64 initial_microseconds = initial / 1000; - CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, - callback_handle); + if (initial == 0) { + // Immediately invoke the callback + Signal(0); + } else { + u64 initial_microseconds = initial / 1000; + CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, + callback_handle); + } } void Timer::Cancel() { @@ -72,6 +77,20 @@ void Timer::WakeupAllWaitingThreads() { signaled = false; } +void Timer::Signal(int cycles_late) { + LOG_TRACE(Kernel, "Timer %08" PRIx64 " fired", timer_handle); + + // Resume all waiting threads + WakeupAllWaitingThreads(); + + if (interval_delay != 0) { + // Reschedule the timer with the interval delay + u64 interval_microseconds = interval_delay / 1000; + CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, + timer_callback_event_type, callback_handle); + } +} + /// The timer callback event, called when a timer is fired static void TimerCallback(u64 timer_handle, int cycles_late) { SharedPtr timer = @@ -82,19 +101,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { return; } - LOG_TRACE(Kernel, "Timer %08" PRIx64 " fired", timer_handle); - - timer->signaled = true; - - // Resume all waiting threads - timer->WakeupAllWaitingThreads(); - - if (timer->interval_delay != 0) { - // Reschedule the timer with the interval delay - u64 interval_microseconds = timer->interval_delay / 1000; - CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, - timer_callback_event_type, timer_handle); - } + timer->Signal(cycles_late); } void 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: void Cancel(); void Clear(); + /** + * Signals the timer, waking up any waiting threads and rescheduling it + * for the next interval. + * This method should not be called from outside the timer callback handler, + * lest multiple callback events get scheduled. + */ + void Signal(int cycles_late); + private: Timer(); ~Timer() override; -- cgit v1.2.3