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_
lely::io::TimerBase::settime
::std::pair< duration, duration > settime(const duration &expiry, const duration &period={})
Definition: timer.hpp:226
io_timer_get_dev
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
lely::io::TimerBase::settime
::std::pair< duration, duration > settime(const time_point &expiry, const duration &period, ::std::error_code &ec) noexcept
Definition: timer.hpp:235
dev.hpp
ev_exec_t
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
lely::io::detail::TimerWaitWrapper
Definition: timer.hpp:40
timer.h
lely::io::TimerBase
A reference to an abstract timer.
Definition: timer.hpp:130
io_timer_wait_result::result
int result
The result of the wait operation: the expiration overrun count (see io_timer_getoverrun()) on success...
Definition: timer.h:48
lely::io::TimerBase::submit_wait
void submit_wait(io_timer_wait &wait) noexcept
Definition: timer.hpp:261
lely::io::TimerBase::abort_wait
bool abort_wait(struct io_timer_wait &wait) noexcept
Definition: timer.hpp:288
clock.hpp
io_timer_get_clock
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
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
lely::io::make_timer_wait_wrapper
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
io_timer_wait::r
struct io_timer_wait_result r
The result of the wait operation.
Definition: timer.h:61
lely::io::TimerWait::get_executor
ev::Executor get_executor() const noexcept
Returns the executor to which the completion task is (to be) submitted.
Definition: timer.hpp:118
io_timer_async_wait
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
lely::io::TimerBase::gettime
::std::pair< duration, duration > gettime() const
Definition: timer.hpp:200
lely::io::TimerBase::async_wait
ev::Future< int, int > async_wait(struct io_timer_wait **pwait=nullptr)
Definition: timer.hpp:302
lely::io::TimerBase::getoverrun
int getoverrun(::std::error_code &ec) const noexcept
Definition: timer.hpp:150
lely::io::TimerBase::getoverrun
int getoverrun() const
Definition: timer.hpp:164
io_timer_wait
A wait operation suitable for use with an I/O timer.
Definition: timer.h:54
io_timer_getoverrun
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
io_timer_gettime
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
lely::io::TimerWait::TimerWait
TimerWait(ev_exec_t *exec, F &&f)
Constructs a wait operation with a completion task.
Definition: timer.hpp:90
lely::io::TimerBase::settime
::std::pair< duration, duration > settime(const duration &expiry, const duration &period, ::std::error_code &ec) noexcept
Definition: timer.hpp:209
lely::io::TimerBase::cancel_wait
bool cancel_wait(struct io_timer_wait &wait) noexcept
Definition: timer.hpp:282
lely::io::Device
An abstract I/O device. This class is a wrapper around #io_dev_t*.
Definition: dev.hpp:35
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
lely::ev::Executor
An abstract task executor. This class is a wrapper around #ev_exec_t*.
Definition: exec.hpp:38
lely::compat::is_invocable
Determines whether F can be invoked with the arguments Args....
Definition: type_traits.hpp:206
io_timer_cancel_wait
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_TIMER_WAIT_INIT
#define IO_TIMER_WAIT_INIT(exec, func)
The static initializer for io_timer_wait.
Definition: timer.h:65
lely::ev::Future
A future.
Definition: future.hpp:50
lely::io::TimerBase::async_wait
ev::Future< int, int > async_wait(ev_exec_t *exec, struct io_timer_wait **pwait=nullptr)
Definition: timer.hpp:294
io_timer_submit_wait
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
lely::io::TimerWait::TimerWait
TimerWait(F &&f)
Constructs a wait operation with a completion task.
Definition: timer.hpp:108
lely::io::TimerBase::submit_wait
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
lely::io::TimerBase::settime
::std::pair< duration, duration > settime(const time_point &expiry, const duration &period={})
Definition: timer.hpp:252
io_timer_wait::task
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the wait operation.
Definition: timer.h:59
lely::io::TimerWait
A wait operation suitable for use with an I/O timer.
Definition: timer.hpp:84
lely::io::TimerBase::gettime
::std::pair< duration, duration > gettime(::std::error_code &ec) const noexcept
Definition: timer.hpp:179
lely::io::Clock
An abstract clock. This class is a wrapper around #io_clock_t*.
Definition: clock.hpp:35
io_timer_wait_from_task
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
future.hpp
ev_task
An executable task.
Definition: task.h:41
io_timer_settime
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
lely::io::TimerBase::submit_wait
void submit_wait(ev_exec_t *exec, F &&f)
Definition: timer.hpp:268
io_dev_t
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
Definition: dev.h:35
lely::io::TimerBase::get_clock
Clock get_clock() const noexcept
Definition: timer.hpp:144
io_timer_t
const struct io_timer_vtbl *const io_timer_t
An abstract timer.
Definition: timer.h:38
lely::canopen::make_error_code
::std::error_code make_error_code(SdoErrc e) noexcept
Creates an error code corresponding to an SDO abort code.
Definition: sdo_error.cpp:170
io_timer_abort_wait
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
ev_task::exec
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition: task.h:43