blob: 5398cec8e2d31ea0277c2125e19fd97e13889420 [file] [log] [blame]
#include <sdeventplus/clock.hpp>
#include <sdeventplus/types.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <memory>
#include <stdexcept>
#include <utility>
namespace sdeventplus
{
namespace utility
{
template <ClockId Id>
Timer<Id>::Timer(const Event& event, Callback&& callback,
std::optional<Duration> interval,
typename source::Time<Id>::Accuracy accuracy) :
userdata(nullptr),
timeSource(event,
Clock<Id>(event).now() + interval.value_or(Duration::zero()),
accuracy, nullptr)
{
auto timerData = std::make_unique<detail::TimerData<Id>>(
*this, std::move(callback), interval);
userdata = timerData.get();
timerData->userdata = timerData.get();
auto cb = [timerData = std::move(timerData)](
source::Time<Id>&, typename source::Time<Id>::TimePoint) {
timerData->internalCallback();
};
timeSource.set_callback(std::move(cb));
setEnabled(interval.has_value());
}
template <ClockId Id>
Timer<Id>::Timer(const Timer<Id>& other, sdeventplus::internal::NoOwn) :
userdata(other.userdata),
timeSource(other.timeSource, sdeventplus::internal::NoOwn())
{}
template <ClockId Id>
void Timer<Id>::set_callback(Callback&& callback)
{
userdata->callback = std::move(callback);
}
template <ClockId Id>
const Event& Timer<Id>::get_event() const
{
return timeSource.get_event();
}
template <ClockId Id>
bool Timer<Id>::get_floating() const
{
return timeSource.get_floating();
}
template <ClockId Id>
void Timer<Id>::set_floating(bool b)
{
return timeSource.set_floating(b);
}
template <ClockId Id>
bool Timer<Id>::hasExpired() const
{
return userdata->expired;
}
template <ClockId Id>
bool Timer<Id>::isEnabled() const
{
return timeSource.get_enabled() != source::Enabled::Off;
}
template <ClockId Id>
std::optional<typename Timer<Id>::Duration> Timer<Id>::getInterval() const
{
return userdata->interval;
}
template <ClockId Id>
typename Timer<Id>::Duration Timer<Id>::getRemaining() const
{
if (!isEnabled())
{
throw std::runtime_error("Timer not running");
}
auto end = timeSource.get_time();
auto now = userdata->clock.now();
if (end < now)
{
return Duration{0};
}
return end - now;
}
template <ClockId Id>
void Timer<Id>::setEnabled(bool enabled)
{
if (enabled && !userdata->initialized)
{
throw std::runtime_error("Timer was never initialized");
}
timeSource.set_enabled(enabled ? source::Enabled::On
: source::Enabled::Off);
}
template <ClockId Id>
void Timer<Id>::setRemaining(Duration remaining)
{
timeSource.set_time(userdata->clock.now() + remaining);
userdata->initialized = true;
}
template <ClockId Id>
void Timer<Id>::resetRemaining()
{
setRemaining(userdata->interval.value());
}
template <ClockId Id>
void Timer<Id>::setInterval(std::optional<Duration> interval)
{
userdata->interval = interval;
}
template <ClockId Id>
void Timer<Id>::clearExpired()
{
userdata->expired = false;
}
template <ClockId Id>
void Timer<Id>::restart(std::optional<Duration> interval)
{
clearExpired();
userdata->initialized = false;
setInterval(interval);
if (userdata->interval)
{
resetRemaining();
}
setEnabled(userdata->interval.has_value());
}
template <ClockId Id>
void Timer<Id>::restartOnce(Duration remaining)
{
clearExpired();
userdata->initialized = false;
setInterval(std::nullopt);
setRemaining(remaining);
setEnabled(true);
}
template <ClockId Id>
void Timer<Id>::internalCallback()
{
userdata->expired = true;
userdata->initialized = false;
if (userdata->interval)
{
resetRemaining();
}
else
{
setEnabled(false);
}
if (userdata->callback)
{
userdata->callback(*userdata);
}
}
template class Timer<ClockId::RealTime>;
template class Timer<ClockId::Monotonic>;
template class Timer<ClockId::BootTime>;
template class Timer<ClockId::RealTimeAlarm>;
template class Timer<ClockId::BootTimeAlarm>;
namespace detail
{
template <ClockId Id>
TimerData<Id>::TimerData(const Timer<Id>& base,
typename Timer<Id>::Callback&& callback,
std::optional<typename Timer<Id>::Duration> interval) :
Timer<Id>(base, sdeventplus::internal::NoOwn()),
expired(false), initialized(interval.has_value()),
callback(std::move(callback)),
clock(Event(base.timeSource.get_event(), sdeventplus::internal::NoOwn())),
interval(interval)
{}
} // namespace detail
} // namespace utility
} // namespace sdeventplus