join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
timer.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_TIMER_HPP
26#define JOIN_CORE_TIMER_HPP
27
28// libjoin.
29#include <join/reactor.hpp>
30#include <join/clock.hpp>
31
32// C++.
33#include <functional>
34#include <stdexcept>
35#include <chrono>
36
37// C.
38#include <sys/timerfd.h>
39#include <unistd.h>
40
41namespace join
42{
46 template <class ClockPolicy>
47 class BasicTimer : protected EventHandler
48 {
49 public:
54 explicit BasicTimer (Reactor& reactor = ReactorThread::reactor ())
55 : _handle (timerfd_create (ClockPolicy::type (), TFD_NONBLOCK | TFD_CLOEXEC))
56 , _reactor (reactor)
57 {
58 if (_handle == -1)
59 {
60 throw std::system_error (errno, std::system_category (), "timerfd_create failed");
61 }
62
63 _reactor.addHandler (_handle, this);
64 }
65
70 BasicTimer (const BasicTimer& other) = delete;
71
77 BasicTimer& operator= (const BasicTimer& other) = delete;
78
83 BasicTimer (BasicTimer&& other) = delete;
84
90 BasicTimer& operator= (BasicTimer&& other) = delete;
91
95 ~BasicTimer () noexcept
96 {
97 _reactor.delHandler (_handle);
98 if (_handle != -1)
99 {
100 close (_handle);
101 }
102 }
103
109 template <class Rep, class Period, typename Func>
110 void setOneShot (std::chrono::duration<Rep, Period> duration, Func&& callback)
111 {
112 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (duration);
113 _callback = std::forward<Func> (callback);
114 _oneShot = true;
115 _ns = std::chrono::nanoseconds::zero ();
116
117 auto ts = toTimerSpec (ns);
118 timerfd_settime (handle (), 0, &ts, nullptr);
119 }
120
126 template <class Clock, class Duration, typename Func>
127 void setOneShot (std::chrono::time_point<Clock, Duration> timePoint, Func&& callback)
128 {
129 static_assert (
130 (std::is_same<ClockPolicy, RealTime>::value && std::is_same<Clock, std::chrono::system_clock>::value) ||
131 (std::is_same<ClockPolicy, Monotonic>::value &&
132 std::is_same<Clock, std::chrono::steady_clock>::value),
133 "Clock type mismatch timer policy");
134
135 auto elapsed = timePoint.time_since_epoch ();
136 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (elapsed);
137 _callback = std::forward<Func> (callback);
138 _oneShot = true;
139 _ns = std::chrono::nanoseconds::zero ();
140
141 auto ts = toTimerSpec (ns);
142 timerfd_settime (handle (), TFD_TIMER_ABSTIME, &ts, nullptr);
143 }
144
150 template <class Rep, class Period, typename Func>
151 void setInterval (std::chrono::duration<Rep, Period> duration, Func&& callback)
152 {
153 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (duration);
154 _callback = std::forward<Func> (callback);
155 _oneShot = false;
156 _ns = ns;
157
158 auto ts = toTimerSpec (ns, true);
159 timerfd_settime (handle (), 0, &ts, nullptr);
160 }
161
165 void cancel () noexcept
166 {
167 _callback = nullptr;
168 _oneShot = true;
169 _ns = std::chrono::nanoseconds::zero ();
170
171 struct itimerspec ts = {};
172 timerfd_settime (handle (), 0, &ts, nullptr);
173 }
174
179 bool active () const noexcept
180 {
181 struct itimerspec ts = {};
182 timerfd_gettime (handle (), &ts);
183 const bool hasValue = (ts.it_value.tv_sec != 0 || ts.it_value.tv_nsec != 0);
184 const bool hasInterval = (ts.it_interval.tv_sec != 0 || ts.it_interval.tv_nsec != 0);
185 return hasValue || hasInterval;
186 }
187
192 std::chrono::nanoseconds remaining () const noexcept
193 {
194 struct itimerspec ts = {};
195 timerfd_gettime (handle (), &ts);
196 return std::chrono::seconds (ts.it_value.tv_sec) + std::chrono::nanoseconds (ts.it_value.tv_nsec);
197 }
198
203 std::chrono::nanoseconds interval () const noexcept
204 {
205 return _ns;
206 }
207
212 bool oneShot () const noexcept
213 {
214 return _oneShot;
215 }
216
221 static constexpr int type () noexcept
222 {
223 return ClockPolicy::type ();
224 }
225
226 private:
231 virtual void onReadable ([[maybe_unused]] int fd) override
232 {
233 uint64_t expirations;
234 ssize_t result = read (handle (), &expirations, sizeof (expirations));
235 if (result == sizeof (expirations) && _callback)
236 {
237 for (uint64_t i = 0; i < expirations; ++i)
238 {
239 _callback ();
240 }
241 }
242 }
243
250 static constexpr itimerspec toTimerSpec (std::chrono::nanoseconds ns, bool periodic = false) noexcept
251 {
252 itimerspec ts{};
253 ts.it_value.tv_sec = ns.count () / _nsPerSec;
254 ts.it_value.tv_nsec = ns.count () % _nsPerSec;
255 if (periodic)
256 {
257 ts.it_interval.tv_sec = ts.it_value.tv_sec;
258 ts.it_interval.tv_nsec = ts.it_value.tv_nsec;
259 }
260 return ts;
261 }
262
267 int handle () const noexcept
268 {
269 return _handle;
270 }
271
273 static constexpr uint64_t _nsPerSec = 1000000000ULL;
274
276 std::function<void ()> _callback;
277
279 std::chrono::nanoseconds _ns{};
280
282 bool _oneShot = true;
283
285 int _handle = -1;
286
288 Reactor& _reactor;
289 };
290}
291
292#endif
base timer class.
Definition timer.hpp:48
std::chrono::nanoseconds interval() const noexcept
get the interval of the running periodic timer.
Definition timer.hpp:203
std::chrono::nanoseconds remaining() const noexcept
get the remaining time until expiration.
Definition timer.hpp:192
void setOneShot(std::chrono::duration< Rep, Period > duration, Func &&callback)
arm the timer as a one-shot timer.
Definition timer.hpp:110
void cancel() noexcept
cancel the timer.
Definition timer.hpp:165
~BasicTimer() noexcept
destroy instance.
Definition timer.hpp:95
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:151
bool active() const noexcept
check if timer is running.
Definition timer.hpp:179
static constexpr int type() noexcept
get the timer type.
Definition timer.hpp:221
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:127
BasicTimer(BasicTimer &&other)=delete
move constructor.
bool oneShot() const noexcept
check if timer is a one-shot timer.
Definition timer.hpp:212
BasicTimer(Reactor &reactor=ReactorThread::reactor())
create instance.
Definition timer.hpp:54
BasicTimer & operator=(const BasicTimer &other)=delete
copy assignment operator.
Event handler interface class.
Definition reactor.hpp:46
friend class Reactor
friendship with reactor.
Definition reactor.hpp:122
static Reactor & reactor()
get the global Reactor instance.
Definition reactor.cpp:514
Reactor class.
Definition reactor.hpp:129
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:155
int addHandler(int fd, EventHandler *handler, bool wantRead=true, bool wantWrite=false, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:100
Definition acceptor.hpp:32