Since the timer was created as a repeating timer, it is already restarted after the function.
116 lines
3.1 KiB
C++
116 lines
3.1 KiB
C++
/**
|
|
* @file Timer.cpp
|
|
* @author apio (cloudapio.eu)
|
|
* @brief Millisecond-precision timer.
|
|
*
|
|
* @copyright Copyright (c) 2024, the Luna authors.
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <os/EventLoop.h>
|
|
#include <os/Timer.h>
|
|
|
|
namespace os
|
|
{
|
|
Result<OwnedPtr<Timer>> Timer::create_singleshot(unsigned int milliseconds, Action&& action)
|
|
{
|
|
auto timer = TRY(adopt_owned_if_nonnull(new (std::nothrow) Timer()));
|
|
|
|
int status = timer_create(CLOCK_REALTIME, nullptr, &timer->m_timerid);
|
|
if (status < 0) return err(errno);
|
|
|
|
struct timespec time = { .tv_sec = milliseconds / 1000, .tv_nsec = (milliseconds % 1000) * 1'000'000 };
|
|
struct itimerspec itimer = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, .it_value = time };
|
|
|
|
timer_settime(timer->m_timerid, 0, &itimer, nullptr);
|
|
|
|
timer->m_repeating = false;
|
|
timer->m_action = move(action);
|
|
|
|
EventLoop::the().m_timer_list.append(timer.ptr());
|
|
|
|
return timer;
|
|
}
|
|
|
|
Result<OwnedPtr<Timer>> Timer::create_repeating(unsigned int milliseconds, Action&& action)
|
|
{
|
|
auto timer = TRY(adopt_owned_if_nonnull(new (std::nothrow) Timer()));
|
|
|
|
int status = timer_create(CLOCK_REALTIME, nullptr, &timer->m_timerid);
|
|
if (status < 0) return err(errno);
|
|
|
|
struct timespec time = { .tv_sec = milliseconds / 1000, .tv_nsec = (milliseconds % 1000) * 1'000'000 };
|
|
struct itimerspec itimer = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, .it_value = time };
|
|
|
|
timer_settime(timer->m_timerid, 0, &itimer, nullptr);
|
|
|
|
timer->m_repeating = true;
|
|
timer->m_interval = time;
|
|
timer->m_action = move(action);
|
|
|
|
EventLoop::the().m_timer_list.append(timer.ptr());
|
|
|
|
return timer;
|
|
}
|
|
|
|
void Timer::restart()
|
|
{
|
|
struct itimerspec itimer = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, .it_value = m_interval };
|
|
|
|
timer_settime(m_timerid, 0, &itimer, nullptr);
|
|
|
|
readd_if_necessary();
|
|
}
|
|
|
|
void Timer::reset(unsigned int milliseconds)
|
|
{
|
|
m_interval = { .tv_sec = milliseconds / 1000, .tv_nsec = (milliseconds % 1000) * 1'000'000 };
|
|
restart();
|
|
}
|
|
|
|
void Timer::stop()
|
|
{
|
|
EventLoop::the().m_timer_list.remove(this);
|
|
m_stopped = true;
|
|
|
|
struct itimerspec itimer;
|
|
memset(&itimer, 0, sizeof(itimer));
|
|
timer_settime(m_timerid, 0, &itimer, nullptr);
|
|
}
|
|
|
|
void Timer::check_if_should_invoke_action()
|
|
{
|
|
struct itimerspec remaining;
|
|
if (timer_gettime(m_timerid, &remaining) < 0) return;
|
|
|
|
if (!remaining.it_value.tv_sec && !remaining.it_value.tv_nsec && !m_stopped)
|
|
{
|
|
// Timer expired!
|
|
m_action();
|
|
|
|
if (!m_repeating)
|
|
{
|
|
EventLoop::the().m_timer_list.remove(this);
|
|
m_stopped = true;
|
|
}
|
|
else
|
|
restart();
|
|
}
|
|
}
|
|
|
|
void Timer::readd_if_necessary()
|
|
{
|
|
if (m_stopped)
|
|
{
|
|
m_stopped = false;
|
|
EventLoop::the().m_timer_list.append(this);
|
|
}
|
|
}
|
|
|
|
Timer::~Timer()
|
|
{
|
|
if (m_timerid >= 0) timer_delete(m_timerid);
|
|
}
|
|
}
|