join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
timer.hpp
Go to the documentation of this file.
1
25#ifndef __JOIN_TIMER_HPP__
26#define __JOIN_TIMER_HPP__
27
28// libjoin.
29#include <join/reactor.hpp>
30
31// C++.
32#include <functional>
33#include <stdexcept>
34#include <chrono>
35
36// C.
37#include <sys/timerfd.h>
38#include <unistd.h>
39
40namespace join
41{
42 class RealTime;
43 class Monotonic;
44
48 template <class ClockPolicy>
49 class BasicTimer : protected EventHandler
50 {
51 public:
56 : _handle (timerfd_create (_policy.type (), TFD_NONBLOCK))
57 {
59 }
60
65 BasicTimer (const BasicTimer& other) = delete;
66
72 BasicTimer& operator= (const BasicTimer& other) = delete;
73
78 BasicTimer (BasicTimer&& other) noexcept
79 : _callback (std::move (other._callback))
80 , _ns (other._ns)
81 , _oneShot (other._oneShot)
82 , _handle (other._handle)
83 {
84 Reactor::instance ()->delHandler (&other);
85
86 other._callback = nullptr;
87 other._ns = std::chrono::nanoseconds::zero ();
88 other._oneShot = true;
89 other._handle = -1;
90
92 }
93
99 BasicTimer& operator= (BasicTimer&& other) noexcept
100 {
101 Reactor::instance ()->delHandler (this);
102 cancel ();
103 if (_handle != -1)
104 {
105 close (_handle);
106 }
107
108 _callback = std::move (other._callback);
109 _ns = other._ns;
110 _oneShot = other._oneShot;
111 _handle = other._handle;
112
113 Reactor::instance ()->delHandler (&other);
114
115 other._callback = nullptr;
116 other._ns = std::chrono::nanoseconds::zero ();
117 other._oneShot = true;
118 other._handle = -1;
119
120 Reactor::instance ()->addHandler (this);
121
122 return *this;
123 }
124
128 virtual ~BasicTimer ()
129 {
130 Reactor::instance ()->delHandler (this);
131 cancel ();
132 if (_handle != -1)
133 {
134 close (_handle);
135 }
136 }
137
143 template <class Rep, class Period, typename Func>
144 void setOneShot (std::chrono::duration <Rep, Period> duration, Func&& callback)
145 {
146 auto ns = std::chrono::duration_cast <std::chrono::nanoseconds> (duration);
147 _callback = std::forward <Func> (callback);
148 _oneShot = true;
149 _ns = std::chrono::nanoseconds::zero ();
150
151 auto ts = toTimerSpec (ns);
152 timerfd_settime (_handle, 0, &ts, nullptr);
153 }
154
160 template <class Clock, class Duration, typename Func>
161 void setOneShot (std::chrono::time_point <Clock, Duration> timePoint, Func&& callback)
162 {
163 static_assert(
164 (std::is_same <ClockPolicy, RealTime>::value && std::is_same <Clock, std::chrono::system_clock>::value) ||
165 (std::is_same <ClockPolicy, Monotonic>::value && std::is_same <Clock, std::chrono::steady_clock>::value),
166 "Clock type mismatch timer policy"
167 );
168
169 auto elapsed = timePoint.time_since_epoch ();
170 auto ns = std::chrono::duration_cast <std::chrono::nanoseconds> (elapsed);
171 _callback = std::forward <Func> (callback);
172 _oneShot = true;
173 _ns = std::chrono::nanoseconds::zero ();
174
175 auto ts = toTimerSpec (ns);
176 timerfd_settime (_handle, TFD_TIMER_ABSTIME, &ts, nullptr);
177 }
178
184 template <class Rep, class Period, typename Func>
185 void setInterval (std::chrono::duration <Rep, Period> duration, Func&& callback)
186 {
187 auto ns = std::chrono::duration_cast <std::chrono::nanoseconds> (duration);
188 _callback = std::forward <Func> (callback);
189 _oneShot = false;
190 _ns = ns;
191
192 auto ts = toTimerSpec (ns, true);
193 timerfd_settime (_handle, 0, &ts, nullptr);
194 }
195
199 void cancel ()
200 {
201 _callback = nullptr;
202 _oneShot = true;
203 _ns = std::chrono::nanoseconds::zero ();
204
205 struct itimerspec ts {};
206 timerfd_settime (_handle, 0, &ts, nullptr);
207 }
208
213 bool active () const
214 {
215 struct itimerspec ts {};
216 timerfd_gettime (_handle, &ts);
217 const bool hasValue = (ts.it_value.tv_sec != 0 || ts.it_value.tv_nsec != 0);
218 const bool hasInterval = (ts.it_interval.tv_sec != 0 || ts.it_interval.tv_nsec != 0);
219 return hasValue || hasInterval;
220 }
221
226 std::chrono::nanoseconds remaining () const
227 {
228 struct itimerspec ts {};
229 timerfd_gettime (_handle, &ts);
230 return std::chrono::seconds (ts.it_value.tv_sec) + std::chrono::nanoseconds (ts.it_value.tv_nsec);
231 }
232
237 std::chrono::nanoseconds interval () const noexcept
238 {
239 return _ns;
240 }
241
246 bool oneShot () const noexcept
247 {
248 return _oneShot;
249 }
250
255 int type () const noexcept
256 {
257 return _policy.type ();
258 }
259
260 protected:
264 virtual void onReceive () override
265 {
266 uint64_t expirations;
267 ssize_t result = read (_handle, &expirations, sizeof (expirations));
268 if (result == sizeof (expirations) && _callback)
269 {
270 for (uint64_t i = 0; i < expirations; ++i)
271 {
272 _callback ();
273 }
274 }
275 }
276
283 static itimerspec toTimerSpec (std::chrono::nanoseconds ns, bool periodic = false) noexcept
284 {
285 itimerspec ts {};
286 ts.it_value.tv_sec = ns.count () / NS_PER_SEC;
287 ts.it_value.tv_nsec = ns.count () % NS_PER_SEC;
288 if (periodic)
289 {
290 ts.it_interval.tv_sec = ts.it_value.tv_sec;
291 ts.it_interval.tv_nsec = ts.it_value.tv_nsec;
292 }
293 return ts;
294 }
295
300 virtual int handle () const noexcept override
301 {
302 return _handle;
303 }
304
305 private:
307 static constexpr uint64_t NS_PER_SEC = 1000000000ULL;
308
310 ClockPolicy _policy;
311
313 std::function <void ()> _callback;
314
316 std::chrono::nanoseconds _ns {};
317
319 bool _oneShot = true;
320
322 int _handle = -1;
323 };
324
329 {
330 public:
331 using Timer = BasicTimer <RealTime>;
332
336 constexpr RealTime () noexcept = default;
337
342 constexpr int type () const noexcept
343 {
344 return CLOCK_REALTIME;
345 }
346 };
347
352 {
353 public:
354 using Timer = BasicTimer <Monotonic>;
355
359 constexpr Monotonic () noexcept = default;
360
365 constexpr int type () const noexcept
366 {
367 return CLOCK_MONOTONIC;
368 }
369 };
370}
371
372#endif
base timer class.
Definition timer.hpp:50
virtual int handle() const noexcept override
get native handle.
Definition timer.hpp:300
std::chrono::nanoseconds interval() const noexcept
get the interval of the running periodic timer.
Definition timer.hpp:237
void setOneShot(std::chrono::duration< Rep, Period > duration, Func &&callback)
arm the timer as a one-shot timer.
Definition timer.hpp:144
virtual ~BasicTimer()
destroy instance.
Definition timer.hpp:128
std::chrono::nanoseconds remaining() const
get the remaining time until expiration.
Definition timer.hpp:226
bool active() const
check if timer is running.
Definition timer.hpp:213
static itimerspec toTimerSpec(std::chrono::nanoseconds ns, bool periodic=false) noexcept
convert nsec to itimerspec.
Definition timer.hpp:283
BasicTimer(const BasicTimer &other)=delete
copy constructor.
BasicTimer()
create instance.
Definition timer.hpp:55
void cancel()
cancel the timer.
Definition timer.hpp:199
void setInterval(std::chrono::duration< Rep, Period > duration, Func &&callback)
arm the timer as a periodic timer.
Definition timer.hpp:185
BasicTimer(BasicTimer &&other) noexcept
move constructor.
Definition timer.hpp:78
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:161
bool oneShot() const noexcept
check if timer is a one-shot timer.
Definition timer.hpp:246
virtual void onReceive() override
method called when data are ready to be read on handle.
Definition timer.hpp:264
int type() const noexcept
get the timer type.
Definition timer.hpp:255
BasicTimer & operator=(const BasicTimer &other)=delete
copy assignment operator.
Event handler interface class.
Definition reactor.hpp:44
monotonic clock policy class.
Definition timer.hpp:352
constexpr Monotonic() noexcept=default
construct the timer policy instance by default.
constexpr int type() const noexcept
get timer type.
Definition timer.hpp:365
int delHandler(EventHandler *handler)
delete handler from reactor.
Definition reactor.cpp:120
int addHandler(EventHandler *handler)
add handler to reactor.
Definition reactor.cpp:77
static Reactor * instance()
create the Reactor instance.
Definition reactor.cpp:158
real time clock policy class.
Definition timer.hpp:329
constexpr int type() const noexcept
get timer type.
Definition timer.hpp:342
constexpr RealTime() noexcept=default
construct the timer policy instance by default.
Definition acceptor.hpp:32