25#ifndef JOIN_CORE_TIMER_HPP
26#define JOIN_CORE_TIMER_HPP
42#include <sys/timerfd.h>
51 template <
class ClockPolicy,
class ProactorType>
71 : _handle (timerfd_create (ClockPolicy::
type (), TFD_NONBLOCK | TFD_CLOEXEC))
72 , _proactor (proactor)
76 throw std::system_error (errno, std::system_category (),
"timerfd_create failed");
80 static_cast<uint32_t
> (sizeof (_ops->expirations)),
this);
82 if (_proactor.submit (_ops->op,
true,
true) == -1)
86 throw std::system_error (lastError,
"timerfd submit failed");
125 while (_state.load (std::memory_order_acquire) !=
State::Closed)
127 _proactor.cancel (_ops->op,
true,
true);
140 template <
class Rep,
class Period,
typename Func,
typename... Args>
141 void setOneShot (std::chrono::duration<Rep, Period> duration, Func&& callback, Args&&... args)
145 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (duration);
146 _callback = std::bind (std::forward<Func> (callback), std::forward<Args> (args)...);
147 _oneShot.store (
true, std::memory_order_relaxed);
148 _ns.store (std::chrono::nanoseconds::zero (), std::memory_order_relaxed);
151 auto ts = toTimerSpec (ns);
152 timerfd_settime (_handle, 0, &ts,
nullptr);
161 template <
class Clock,
class Duration,
typename Func,
typename... Args>
162 void setOneShot (std::chrono::time_point<Clock, Duration> timePoint, Func&& callback, Args&&... args)
165 (std::is_same_v<ClockPolicy, RealTime> && std::is_same_v<Clock, std::chrono::system_clock>) ||
166 (std::is_same_v<ClockPolicy, Monotonic> && std::is_same_v<Clock, std::chrono::steady_clock>),
167 "Clock type mismatch timer policy");
171 auto elapsed = timePoint.time_since_epoch ();
172 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (elapsed);
173 _callback = std::bind (std::forward<Func> (callback), std::forward<Args> (args)...);
174 _oneShot.store (
true, std::memory_order_relaxed);
175 _ns.store (std::chrono::nanoseconds::zero (), std::memory_order_relaxed);
178 auto ts = toTimerSpec (ns);
179 timerfd_settime (_handle, TFD_TIMER_ABSTIME, &ts,
nullptr);
188 template <
class Rep,
class Period,
typename Func,
typename... Args>
189 void setInterval (std::chrono::duration<Rep, Period> duration, Func&& callback, Args&&... args)
193 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (duration);
194 _callback = std::bind (std::forward<Func> (callback), std::forward<Args> (args)...);
195 _oneShot.store (
false, std::memory_order_relaxed);
196 _ns.store (ns, std::memory_order_relaxed);
199 auto ts = toTimerSpec (ns,
true);
200 timerfd_settime (_handle, 0, &ts,
nullptr);
208 _oneShot.store (
true, std::memory_order_relaxed);
209 _ns.store (std::chrono::nanoseconds::zero (), std::memory_order_relaxed);
211 struct itimerspec ts = {};
212 timerfd_settime (_handle, 0, &ts,
nullptr);
216 _state.store (
State::Idle, std::memory_order_release);
223 while (!_state.compare_exchange_strong (expected,
State::Idle, std::memory_order_acq_rel,
224 std::memory_order_acquire))
244 struct itimerspec ts = {};
245 timerfd_gettime (_handle, &ts);
246 const bool hasValue = (ts.it_value.tv_sec != 0 || ts.it_value.tv_nsec != 0);
247 const bool hasInterval = (ts.it_interval.tv_sec != 0 || ts.it_interval.tv_nsec != 0);
248 return hasValue || hasInterval;
257 struct itimerspec ts = {};
258 timerfd_gettime (_handle, &ts);
259 return std::chrono::seconds (ts.it_value.tv_sec) + std::chrono::nanoseconds (ts.it_value.tv_nsec);
266 std::chrono::nanoseconds
interval () const noexcept
268 return _ns.load (std::memory_order_relaxed);
277 return _oneShot.load (std::memory_order_relaxed);
284 static constexpr int type () noexcept
286 return ClockPolicy::type ();
295 void onComplete ([[maybe_unused]]
IoOperation& op,
int result)
override
297 uint64_t expirations = _ops->expirations;
299 if (
JOIN_UNLIKELY (result !=
static_cast<int> (
sizeof (_ops->expirations)) && result != -EAGAIN &&
316 if (
JOIN_UNLIKELY (result !=
static_cast<int> (
sizeof (_ops->expirations))))
324 std::memory_order_acquire)))
326 for (uint64_t i = 0; i < expirations; ++i)
332 _state.compare_exchange_strong (expected,
State::Armed, std::memory_order_acq_rel,
333 std::memory_order_acquire);
342 void onCancel ([[maybe_unused]] IoOperation& op, [[maybe_unused]]
int result)
override
353 static constexpr itimerspec toTimerSpec (std::chrono::nanoseconds ns,
bool periodic =
false) noexcept
358 ts.it_interval.tv_sec = ns.count () / _nsPerSec;
359 ts.it_interval.tv_nsec = ns.count () % _nsPerSec;
363 ns = std::chrono::nanoseconds (1);
365 ts.it_value.tv_sec = ns.count () / _nsPerSec;
366 ts.it_value.tv_nsec = ns.count () % _nsPerSec;
380 static void*
operator new (
size_t size)
382 void* mem = ::aligned_alloc (
alignof (Ops), size);
386 throw std::bad_alloc ();
396 static void operator delete (
void* mem)
noexcept
405 uint64_t expirations = 0;
409 static constexpr uint64_t _nsPerSec = 1000000000ULL;
412 const std::unique_ptr<Ops> _ops{
new Ops ()};
418 Function<void ()> _callback;
421 std::atomic<std::chrono::nanoseconds> _ns{std::chrono::nanoseconds::zero ()};
424 std::atomic_bool _oneShot{
true};
430 ProactorType& _proactor;
adaptive backoff for busy-wait loops, requires Rdtsc::calibrate ().
Definition backoff.hpp:47
static BasicProactor & proactor()
get the Proactor instance owned by the singleton ProactorThread.
Definition proactor.hpp:1053
base timer class.
Definition timer.hpp:53
std::chrono::nanoseconds remaining() const noexcept
get the remaining time until expiration.
Definition timer.hpp:255
void setInterval(std::chrono::duration< Rep, Period > duration, Func &&callback, Args &&... args)
arm the timer as a periodic timer.
Definition timer.hpp:189
void setOneShot(std::chrono::duration< Rep, Period > duration, Func &&callback, Args &&... args)
arm the timer as a one-shot timer.
Definition timer.hpp:141
State
timer state.
Definition timer.hpp:59
void cancel() noexcept
cancel the timer.
Definition timer.hpp:206
bool oneShot() const noexcept
check if timer is a one-shot timer.
Definition timer.hpp:275
BasicTimer(BasicTimer &&other)=delete
move constructor.
bool active() const noexcept
check if timer is running.
Definition timer.hpp:242
BasicTimer(const BasicTimer &other)=delete
copy constructor.
static constexpr int type() noexcept
get the timer type.
Definition timer.hpp:284
BasicTimer(ProactorType &proactor=ProactorThread::proactor())
create instance.
Definition timer.hpp:70
std::chrono::nanoseconds interval() const noexcept
get the interval of the running periodic timer.
Definition timer.hpp:266
void setOneShot(std::chrono::time_point< Clock, Duration > timePoint, Func &&callback, Args &&... args)
arm the timer as a one-shot timer with absolute time.
Definition timer.hpp:162
~BasicTimer() noexcept
destroy instance.
Definition timer.hpp:120
BasicTimer & operator=(const BasicTimer &other)=delete
copy assignment operator.
completion handler interface class.
Definition proactor.hpp:81
Definition acceptor.hpp:32
Describes a single asynchronous operation submitted to the Proactor.
Definition io_operation.hpp:48
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:160
#define JOIN_LIKELY(x)
Definition utils.hpp:50
#define JOIN_UNLIKELY(x)
Definition utils.hpp:51