Lely core libraries  2.2.5
timer.hpp
Go to the documentation of this file.
1 
24 #ifndef LELY_IO2_TIMER_HPP_
25 #define LELY_IO2_TIMER_HPP_
26 
27 #include <lely/ev/future.hpp>
28 #include <lely/io2/dev.hpp>
29 #include <lely/io2/clock.hpp>
30 #include <lely/io2/timer.h>
31 
32 #include <utility>
33 
34 namespace lely {
35 namespace io {
36 
37 namespace detail {
38 
39 template <class F>
41  public:
42  TimerWaitWrapper(ev_exec_t* exec, F&& f)
44  exec,
45  [](ev_task * task) noexcept {
46  auto wait = io_timer_wait_from_task(task);
47  auto overrun = wait->r.result;
48  ::std::error_code ec;
49  if (overrun == -1) ec = util::make_error_code(wait->r.errc);
50  auto self = static_cast<TimerWaitWrapper*>(wait);
51  compat::invoke(::std::move(self->func_), overrun, ec);
52  delete self;
53  }),
54  func_(::std::forward<F>(f)) {}
55 
56  TimerWaitWrapper(const TimerWaitWrapper&) = delete;
57 
58  TimerWaitWrapper& operator=(const TimerWaitWrapper&) = delete;
59 
60  private:
61  typename ::std::decay<F>::type func_;
62 };
63 
64 } // namespace detail
65 
71 template <class F>
72 inline typename ::std::enable_if<
76  return new detail::TimerWaitWrapper<F>(exec, ::std::forward<F>(f));
77 }
78 
84 class TimerWait : public io_timer_wait {
85  public:
86  using Signature = void(int, ::std::error_code);
87 
89  template <class F>
90  TimerWait(ev_exec_t* exec, F&& f)
92  IO_TIMER_WAIT_INIT(exec,
93  [](ev_task * task) noexcept {
94  auto wait = io_timer_wait_from_task(task);
95  auto self = static_cast<TimerWait*>(wait);
96  if (self->func_) {
97  auto overrun = wait->r.result;
98  ::std::error_code ec;
99  if (overrun == -1)
100  ec = util::make_error_code(wait->r.errc);
101  self->func_(overrun, ec);
102  }
103  }),
104  func_(::std::forward<F>(f)) {}
105 
107  template <class F>
108  explicit TimerWait(F&& f) : TimerWait(nullptr, ::std::forward<F>(f)) {}
109 
110  TimerWait(const TimerWait&) = delete;
111 
112  TimerWait& operator=(const TimerWait&) = delete;
113 
114  operator ev_task&() & noexcept { return task; }
115 
118  get_executor() const noexcept {
119  return ev::Executor(task.exec);
120  }
121 
122  private:
123  ::std::function<Signature> func_;
124 };
125 
130 class TimerBase : public Device {
131  public:
132  using Device::operator io_dev_t*;
133 
134  using duration = Clock::duration;
135  using time_point = Clock::time_point;
136 
137  explicit TimerBase(io_timer_t* timer_) noexcept
138  : Device(timer_ ? io_timer_get_dev(timer_) : nullptr), timer(timer_) {}
139 
140  operator io_timer_t*() const noexcept { return timer; }
141 
143  Clock
144  get_clock() const noexcept {
145  return Clock(io_timer_get_clock(*this));
146  }
147 
149  int
150  getoverrun(::std::error_code& ec) const noexcept {
151  int errsv = get_errc();
152  set_errc(0);
153  int overrun = io_timer_getoverrun(*this);
154  if (overrun >= 0)
155  ec.clear();
156  else
157  ec = util::make_error_code();
158  set_errc(errsv);
159  return overrun;
160  }
161 
163  int
164  getoverrun() const {
165  ::std::error_code ec;
166  int overrun = getoverrun(ec);
167  if (overrun < 0) throw ::std::system_error(ec, "getoverrun");
168  return overrun;
169  }
170 
178  ::std::pair<duration, duration>
179  gettime(::std::error_code& ec) const noexcept {
180  int errsv = get_errc();
181  set_errc(0);
182  itimerspec value = {{0, 0}, {0, 0}};
183  if (!io_timer_gettime(*this, &value))
184  ec.clear();
185  else
186  ec = util::make_error_code();
187  set_errc(errsv);
188  return {util::from_timespec(value.it_value),
189  util::from_timespec(value.it_interval)};
190  }
191 
199  ::std::pair<duration, duration>
200  gettime() const {
201  ::std::error_code ec;
202  auto value = gettime(ec);
203  if (ec) throw ::std::system_error(ec, "gettime");
204  return value;
205  }
206 
208  ::std::pair<duration, duration>
209  settime(const duration& expiry, const duration& period,
210  ::std::error_code& ec) noexcept {
211  int errsv = get_errc();
212  set_errc(0);
213  itimerspec value = {util::to_timespec(period), util::to_timespec(expiry)};
214  itimerspec ovalue = {{0, 0}, {0, 0}};
215  if (!io_timer_settime(*this, 0, &value, &ovalue))
216  ec.clear();
217  else
218  ec = util::make_error_code();
219  set_errc(errsv);
220  return {util::from_timespec(ovalue.it_value),
221  util::from_timespec(ovalue.it_interval)};
222  }
223 
225  ::std::pair<duration, duration>
226  settime(const duration& expiry, const duration& period = {}) {
227  ::std::error_code ec;
228  auto ovalue = settime(expiry, period, ec);
229  if (ec) throw ::std::system_error(ec, "settime");
230  return ovalue;
231  }
232 
234  ::std::pair<duration, duration>
235  settime(const time_point& expiry, const duration& period,
236  ::std::error_code& ec) noexcept {
237  int errsv = get_errc();
238  set_errc(0);
239  itimerspec value = {util::to_timespec(period), util::to_timespec(expiry)};
240  itimerspec ovalue = {{0, 0}, {0, 0}};
241  if (!io_timer_settime(*this, TIMER_ABSTIME, &value, &ovalue))
242  ec.clear();
243  else
244  ec = util::make_error_code();
245  set_errc(errsv);
246  return {util::from_timespec(ovalue.it_value),
247  util::from_timespec(ovalue.it_interval)};
248  }
249 
251  ::std::pair<duration, duration>
252  settime(const time_point& expiry, const duration& period = {}) {
253  ::std::error_code ec;
254  auto ovalue = settime(expiry, period, ec);
255  if (ec) throw ::std::system_error(ec, "settime");
256  return ovalue;
257  }
258 
260  void
261  submit_wait(io_timer_wait& wait) noexcept {
262  io_timer_submit_wait(*this, &wait);
263  }
264 
266  template <class F>
267  void
268  submit_wait(ev_exec_t* exec, F&& f) {
269  submit_wait(*make_timer_wait_wrapper(exec, ::std::forward<F>(f)));
270  }
271 
273  template <class F>
274  typename ::std::enable_if<!::std::is_base_of<
275  io_timer_wait, typename ::std::decay<F>::type>::value>::type
276  submit_wait(F&& f) {
277  submit_wait(nullptr, ::std::forward<F>(f));
278  }
279 
281  bool
282  cancel_wait(struct io_timer_wait& wait) noexcept {
283  return io_timer_cancel_wait(*this, &wait) != 0;
284  }
285 
287  bool
288  abort_wait(struct io_timer_wait& wait) noexcept {
289  return io_timer_abort_wait(*this, &wait) != 0;
290  }
291 
294  async_wait(ev_exec_t* exec, struct io_timer_wait** pwait = nullptr) {
295  auto future = io_timer_async_wait(*this, exec, pwait);
296  if (!future) util::throw_errc("async_wait");
297  return ev::Future<int, int>(future);
298  }
299 
302  async_wait(struct io_timer_wait** pwait = nullptr) {
303  return async_wait(nullptr, pwait);
304  }
305 
306  protected:
307  io_timer_t* timer{nullptr};
308 };
309 
310 } // namespace io
311 } // namespace lely
312 
313 #endif // !LELY_IO2_TIMER_HPP_
An abstract task executor. This class is a wrapper around #ev_exec_t*.
Definition: exec.hpp:38
A future.
Definition: future.hpp:384
An abstract clock. This class is a wrapper around #io_clock_t*.
Definition: clock.hpp:35
An abstract I/O device. This class is a wrapper around #io_dev_t*.
Definition: dev.hpp:35
A reference to an abstract timer.
Definition: timer.hpp:130
void submit_wait(io_timer_wait &wait) noexcept
Definition: timer.hpp:261
ev::Future< int, int > async_wait(struct io_timer_wait **pwait=nullptr)
Definition: timer.hpp:302
bool abort_wait(struct io_timer_wait &wait) noexcept
Definition: timer.hpp:288
ev::Future< int, int > async_wait(ev_exec_t *exec, struct io_timer_wait **pwait=nullptr)
Definition: timer.hpp:294
bool cancel_wait(struct io_timer_wait &wait) noexcept
Definition: timer.hpp:282
void submit_wait(ev_exec_t *exec, F &&f)
Definition: timer.hpp:268
typename ::std::enable_if<!::std::is_base_of< io_timer_wait, typename ::std::decay< F >::type >::value >::type submit_wait(F &&f)
Definition: timer.hpp:276
int getoverrun(::std::error_code &ec) const noexcept
Definition: timer.hpp:150
::std::pair< duration, duration > settime(const time_point &expiry, const duration &period={})
Definition: timer.hpp:252
::std::pair< duration, duration > gettime() const
Definition: timer.hpp:200
int getoverrun() const
Definition: timer.hpp:164
Clock get_clock() const noexcept
Definition: timer.hpp:144
::std::pair< duration, duration > settime(const duration &expiry, const duration &period, ::std::error_code &ec) noexcept
Definition: timer.hpp:209
::std::pair< duration, duration > settime(const duration &expiry, const duration &period={})
Definition: timer.hpp:226
::std::pair< duration, duration > gettime(::std::error_code &ec) const noexcept
Definition: timer.hpp:179
::std::pair< duration, duration > settime(const time_point &expiry, const duration &period, ::std::error_code &ec) noexcept
Definition: timer.hpp:235
A wait operation suitable for use with an I/O timer.
Definition: timer.hpp:84
ev::Executor get_executor() const noexcept
Returns the executor to which the completion task is (to be) submitted.
Definition: timer.hpp:118
TimerWait(ev_exec_t *exec, F &&f)
Constructs a wait operation with a completion task.
Definition: timer.hpp:90
TimerWait(F &&f)
Constructs a wait operation with a completion task.
Definition: timer.hpp:108
This header file is part of the I/O library; it contains the C++ interface for the abstract clock.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
This header file is part of the event library; it contains the C++ interface for the futures and prom...
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
This header file is part of the I/O library; it contains the abstract timer interface.
int io_timer_settime(io_timer_t *timer, int flags, const struct itimerspec *value, struct itimerspec *ovalue)
Arms or disarms an I/O timer.
Definition: timer.h:256
const struct io_timer_vtbl *const io_timer_t
An abstract timer.
Definition: timer.h:38
ev_future_t * io_timer_async_wait(io_timer_t *timer, ev_exec_t *exec, struct io_timer_wait **pwait)
Submits an asynchronous wait operation to an I/O timer and creates a future which becomes ready once ...
Definition: timer.c:39
struct io_timer_wait * io_timer_wait_from_task(struct ev_task *task)
Obtains a pointer to an I/O timer wait operation from a pointer to its completion task.
Definition: timer.c:61
static size_t io_timer_abort_wait(io_timer_t *timer, struct io_timer_wait *wait)
Aborts the specified I/O timer wait operation if it is pending.
Definition: timer.h:275
static size_t io_timer_cancel_wait(io_timer_t *timer, struct io_timer_wait *wait)
Cancels the specified I/O timer wait operation if it is pending.
Definition: timer.h:269
io_clock_t * io_timer_get_clock(const io_timer_t *timer)
Returns a pointer to the clock used by the timer.
Definition: timer.h:238
io_dev_t * io_timer_get_dev(const io_timer_t *timer)
Returns a pointer to the abstract I/O device representing the timer.
Definition: timer.h:232
void io_timer_submit_wait(io_timer_t *timer, struct io_timer_wait *wait)
Submits a wait operation to an I/O timer.
Definition: timer.h:263
int io_timer_getoverrun(const io_timer_t *timer)
Obtains the I/O timer expiration overrun count of the last successfully processed expiration.
Definition: timer.h:244
int io_timer_gettime(const io_timer_t *timer, struct itimerspec *value)
Obtains the amount of time until the specified I/O timer expires and the reload value of the timer.
Definition: timer.h:250
#define IO_TIMER_WAIT_INIT(exec, func)
The static initializer for io_timer_wait.
Definition: timer.h:65
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
Definition: dev.h:35
This header file is part of the I/O library; it contains the C++ interface for the abstract I/O devic...
::std::error_code make_error_code(SdoErrc e) noexcept
Creates an error code corresponding to an SDO abort code.
Definition: sdo_error.cpp:170
An executable task.
Definition: task.h:41
int result
The result of the wait operation: the expiration overrun count (see io_timer_getoverrun()) on success...
Definition: timer.h:48
A wait operation suitable for use with an I/O timer.
Definition: timer.h:54
struct io_timer_wait_result r
The result of the wait operation.
Definition: timer.h:61
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the wait operation.
Definition: timer.h:59
Determines whether F can be invoked with the arguments Args....
typename ::std::enable_if< compat::is_invocable< F, int, ::std::error_code >::value, detail::TimerWaitWrapper< F > * >::type make_timer_wait_wrapper(ev_exec_t *exec, F &&f)
Creates a wait operation with a completion task.
Definition: timer.hpp:75