25#ifndef JOIN_CORE_TIMER_HPP
26#define JOIN_CORE_TIMER_HPP
41#include <sys/timerfd.h>
50 template <
class ClockPolicy>
70 : _handle (timerfd_create (ClockPolicy::
type (), TFD_NONBLOCK | TFD_CLOEXEC))
71 , _proactor (proactor)
75 throw std::system_error (errno, std::system_category (),
"timerfd_create failed");
79 static_cast<uint32_t
> (sizeof (_ops->expirations)),
this);
81 if (_proactor.
submit (_ops->op,
true,
true) == -1)
85 throw std::system_error (lastError,
"timerfd submit failed");
124 while (_state.load (std::memory_order_acquire) !=
State::Closed)
126 _proactor.
cancel (_ops->op,
true,
true);
138 template <
class Rep,
class Period,
typename Func>
139 void setOneShot (std::chrono::duration<Rep, Period> duration, Func&& callback)
143 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (duration);
144 _callback = std::forward<Func> (callback);
146 _ns = std::chrono::nanoseconds::zero ();
149 auto ts = toTimerSpec (ns);
150 timerfd_settime (_handle, 0, &ts,
nullptr);
158 template <
class Clock,
class Duration,
typename Func>
159 void setOneShot (std::chrono::time_point<Clock, Duration> timePoint, Func&& callback)
162 (std::is_same<ClockPolicy, RealTime>::value && std::is_same<Clock, std::chrono::system_clock>::value) ||
163 (std::is_same<ClockPolicy, Monotonic>::value &&
164 std::is_same<Clock, std::chrono::steady_clock>::value),
165 "Clock type mismatch timer policy");
169 auto elapsed = timePoint.time_since_epoch ();
170 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (elapsed);
171 _callback = std::forward<Func> (callback);
173 _ns = std::chrono::nanoseconds::zero ();
176 auto ts = toTimerSpec (ns);
177 timerfd_settime (_handle, TFD_TIMER_ABSTIME, &ts,
nullptr);
185 template <
class Rep,
class Period,
typename Func>
186 void setInterval (std::chrono::duration<Rep, Period> duration, Func&& callback)
190 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (duration);
191 _callback = std::forward<Func> (callback);
196 auto ts = toTimerSpec (ns,
true);
197 timerfd_settime (_handle, 0, &ts,
nullptr);
206 _ns = std::chrono::nanoseconds::zero ();
208 struct itimerspec ts = {};
209 timerfd_settime (_handle, 0, &ts,
nullptr);
213 _state.store (
State::Idle, std::memory_order_release);
220 while (!_state.compare_exchange_strong (expected,
State::Idle, std::memory_order_acq_rel,
221 std::memory_order_acquire))
241 struct itimerspec ts = {};
242 timerfd_gettime (_handle, &ts);
243 const bool hasValue = (ts.it_value.tv_sec != 0 || ts.it_value.tv_nsec != 0);
244 const bool hasInterval = (ts.it_interval.tv_sec != 0 || ts.it_interval.tv_nsec != 0);
245 return hasValue || hasInterval;
254 struct itimerspec ts = {};
255 timerfd_gettime (_handle, &ts);
256 return std::chrono::seconds (ts.it_value.tv_sec) + std::chrono::nanoseconds (ts.it_value.tv_nsec);
263 std::chrono::nanoseconds
interval () const noexcept
281 static constexpr int type () noexcept
283 return ClockPolicy::type ();
292 void onComplete ([[maybe_unused]]
IoOperation& op,
int result)
override
294 uint64_t expirations = _ops->expirations;
296 if (
JOIN_UNLIKELY (result !=
static_cast<int> (
sizeof (_ops->expirations)) && result != -EAGAIN &&
313 if (
JOIN_UNLIKELY (result !=
static_cast<int> (
sizeof (_ops->expirations))))
321 std::memory_order_acquire)))
323 for (uint64_t i = 0; i < expirations; ++i)
329 _state.compare_exchange_strong (expected,
State::Armed, std::memory_order_acq_rel,
330 std::memory_order_acquire);
339 void onCancel ([[maybe_unused]] IoOperation& op, [[maybe_unused]]
int result)
override
350 static constexpr itimerspec toTimerSpec (std::chrono::nanoseconds ns,
bool periodic =
false) noexcept
355 ts.it_interval.tv_sec = ns.count () / _nsPerSec;
356 ts.it_interval.tv_nsec = ns.count () % _nsPerSec;
360 ns = std::chrono::nanoseconds (1);
362 ts.it_value.tv_sec = ns.count () / _nsPerSec;
363 ts.it_value.tv_nsec = ns.count () % _nsPerSec;
377 static void*
operator new (
size_t size)
379 void* mem = ::aligned_alloc (
alignof (Ops), size);
383 throw std::bad_alloc ();
393 static void operator delete (
void* mem)
noexcept
402 uint64_t expirations = 0;
406 static constexpr uint64_t _nsPerSec = 1000000000ULL;
409 const std::unique_ptr<Ops> _ops{
new Ops ()};
415 Function<void ()> _callback;
418 std::chrono::nanoseconds _ns{};
421 bool _oneShot =
true;
adaptive backoff strategy for busy-wait loops.
Definition backoff.hpp:43
static BasicProactor & proactor()
get the Proactor instance owned by the singleton ProactorThread.
Definition proactor.hpp:982
basic proactor class.
Definition proactor.hpp:156
int submit(IoOperation &op, bool flush=false, bool sync=false) noexcept
submit an asynchronous operation to the proactor.
Definition proactor.hpp:655
bool isProactorThread() const noexcept
check if the calling thread is the proactor thread.
Definition proactor_epoll_impl.hpp:252
int cancel(IoOperation &op, bool flush=false, bool sync=false) noexcept
cancel an in-flight operation.
Definition proactor.hpp:703
base timer class.
Definition timer.hpp:52
std::chrono::nanoseconds interval() const noexcept
get the interval of the running periodic timer.
Definition timer.hpp:263
State
timer state.
Definition timer.hpp:58
std::chrono::nanoseconds remaining() const noexcept
get the remaining time until expiration.
Definition timer.hpp:252
BasicTimer(Proactor &proactor=ProactorThread::proactor())
create instance.
Definition timer.hpp:69
void setOneShot(std::chrono::duration< Rep, Period > duration, Func &&callback)
arm the timer as a one-shot timer.
Definition timer.hpp:139
void cancel() noexcept
cancel the timer.
Definition timer.hpp:203
~BasicTimer() noexcept
destroy instance.
Definition timer.hpp:119
BasicTimer(const BasicTimer &other)=delete
copy constructor.
void setInterval(std::chrono::duration< Rep, Period > duration, Func &&callback)
arm the timer as a periodic timer.
Definition timer.hpp:186
bool active() const noexcept
check if timer is running.
Definition timer.hpp:239
static constexpr int type() noexcept
get the timer type.
Definition timer.hpp:281
void setOneShot(std::chrono::time_point< Clock, Duration > timePoint, Func &&callback)
arm the timer as a one-shot timer with absolute time.
Definition timer.hpp:159
BasicTimer(BasicTimer &&other)=delete
move constructor.
bool oneShot() const noexcept
check if timer is a one-shot timer.
Definition timer.hpp:272
BasicTimer & operator=(const BasicTimer &other)=delete
copy assignment operator.
completion handler interface class.
Definition proactor.hpp:79
Definition acceptor.hpp:32
BasicProactor Proactor
Definition proactor.hpp:70
Describes a single asynchronous operation submitted to the Proactor.
Definition io_operation.hpp:47
static IoOperation makeRead(int fd, void *buf, uint32_t len, CompletionHandler *handler, bool linked=false) noexcept
build a regular read operation.
Definition io_operation.cpp:152
#define JOIN_LIKELY(x)
Definition utils.hpp:45
#define JOIN_UNLIKELY(x)
Definition utils.hpp:46