uvcc
libuv C++ bindings
handle-misc.hpp
1 
2 #ifndef UVCC_HANDLE_MISC__HPP
3 #define UVCC_HANDLE_MISC__HPP
4 
5 #include "uvcc/utility.hpp"
6 #include "uvcc/handle-base.hpp"
7 #include "uvcc/handle-io.hpp"
8 
9 #include <cstdint> // uint64_t
10 #include <uv.h>
11 
12 #include <functional> // function bind placeholders::
13 #include <utility> // forward() declval()
14 #include <vector> // vector
15 #include <stdexcept> // invalid_argument
16 
17 
18 namespace uv
19 {
20 
21 
22 /*! \ingroup doxy_group__handle
23  \brief Async handle.
24  \sa libuv API documentation: [`uv_async_t` — Async handle](http://docs.libuv.org/en/v1.x/async.html#uv-async-t-async-handle). */
25 class async : public handle
26 {
27  //! \cond
28  friend class handle::uv_interface;
29  friend class handle::instance< async >;
30  //! \endcond
31 
32 public: /*types*/
33  using uv_t = ::uv_async_t;
34  using on_send_t = std::function< void(async _handle) >;
35  /*!< \brief The function type of the callback called on the event raised by `async::send()` function.
36  \note The `async` event is not a facility for executing the given callback function
37  on the target loop on every `async::send()` call.
38  \sa libuv API documentation: [`uv_async_cb`](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_cb),
39  [`uv_async_send()`](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send). */
40 
41 protected: /*types*/
42  //! \cond internals
43  //! \addtogroup doxy_group__internals
44  //! \{
45 
46  struct properties : handle::properties
47  {
48  on_send_t async_cb;
49  };
50 
51  struct uv_interface : handle::uv_handle_interface {};
52 
53  //! \}
54  //! \endcond
55 
56 private: /*types*/
57  using instance = handle::instance< async >;
58 
59 private: /*functions*/
60  template < typename = void > static void async_cb(::uv_async_t*);
61 
62 protected: /*constructors*/
63  //! \cond
64  explicit async(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
65  //! \endcond
66 
67 public: /*constructors*/
68  ~async() = default;
69 
70  async(const async&) = default;
71  async& operator =(const async&) = default;
72 
73  async(async&&) noexcept = default;
74  async& operator =(async&&) noexcept = default;
75 
76  /*! \brief Create an `async` handle.
77  \sa libuv API documentation: [`uv_async_init()`](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_init). */
78  explicit async(uv::loop &_loop)
79  {
80  uv_handle = instance::create();
81 
82  auto uv_ret = ::uv_async_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle), async_cb);
83  if (uv_status(uv_ret) < 0) return;
84 
85  instance::from(uv_handle)->book_loop();
86  }
87 
88 public: /*interface*/
89  /*! \brief Set the `async` event callback. */
90  on_send_t& on_send() const noexcept { return instance::from(uv_handle)->properties().async_cb; }
91 
92  /*! \brief Wakeup the event loop and call the `async` callback.
93  \sa libuv API documentation: [`uv_async_send()`](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send). */
94  int send() const
95  {
96  auto instance_ptr = instance::from(uv_handle);
97 
98  instance_ptr->ref(); // the reference must be added before async event sending and possible executing
99  // of the callback in another thread that will release this reference
100 
101  uv_status(0);
102  auto uv_ret = ::uv_async_send(static_cast< uv_t* >(uv_handle));
103  if (uv_ret < 0)
104  {
105  uv_status(uv_ret);
106  instance_ptr->unref();
107  }
108 
109  return uv_ret;
110  }
111 
112  /*! \brief Set the given `async` callback and send wakeup event to the target loop.
113  \details This is equivalent for
114  ```
115  async.on_send() = std::bind(std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...);
116  async.send();
117  ```
118  \sa `async::send()` */
119  template< class _Cb_, typename... _Args_, typename = std::enable_if_t<
121  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
122  on_send_t
123  >::value
124  > >
125  int send(_Cb_ &&_cb, _Args_&&... _args) const
126  {
127  instance::from(uv_handle)->properties().async_cb = std::bind(
128  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...
129  );
130  return send();
131  }
132 
133 public: /*conversion operators*/
134  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
135  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
136 };
137 
138 template< typename >
139 void async::async_cb(::uv_async_t *_uv_handle)
140 {
141  auto instance_ptr = instance::from(_uv_handle);
142  auto &async_cb = instance_ptr->properties().async_cb;
143 
144  ref_guard< instance > unref_handle(*instance_ptr, adopt_ref);
145 
146  if (async_cb) async_cb(async(_uv_handle));
147 }
148 
149 
150 
151 /*! \ingroup doxy_group__handle
152  \brief Timer handle.
153  \sa libuv API documentation: [`uv_timer_t` — Timer handle](http://docs.libuv.org/en/v1.x/timer.html#uv-timer-t-timer-handle). */
154 class timer : public handle
155 {
156  //! \cond
157  friend class handle::uv_interface;
158  friend class handle::instance< timer >;
159  //! \endcond
160 
161 public: /*types*/
162  using uv_t = ::uv_timer_t;
163  using on_timer_t = std::function< void(timer _handle) >;
164  /*!< \brief The function type of the callback called by the timer event. */
165 
166 protected: /*types*/
167  //! \cond internals
168  //! \addtogroup doxy_group__internals
169  //! \{
170 
171  struct properties : handle::properties
172  {
173  bool has_extra_ref = false;
174  on_timer_t timer_cb;
175  };
176 
177  struct uv_interface : handle::uv_handle_interface {};
178 
179  //! \}
180  //! \endcond
181 
182 private: /*types*/
183  using instance = handle::instance< timer >;
184 
185 private: /*functions*/
186  template < typename = void > static void timer_cb(::uv_timer_t*);
187 
188 protected: /*constructors*/
189  //! \cond
190  explicit timer(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
191  //! \endcond
192 
193 public: /*constructors*/
194  ~timer() = default;
195 
196  timer(const timer&) = default;
197  timer& operator =(const timer&) = default;
198 
199  timer(timer&&) noexcept = default;
200  timer& operator =(timer&&) noexcept = default;
201 
202  /*! \brief Create a `timer` handle which has a given repeat interval.
203  \details `_repeat_interval` is in milliseconds. */
204  explicit timer(uv::loop &_loop, uint64_t _repeat_interval = 0)
205  {
206  uv_handle = instance::create();
207 
208  auto uv_ret = ::uv_timer_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle));
209  if (uv_status(uv_ret) < 0) return;
210 
211  ::uv_timer_set_repeat(static_cast< uv_t* >(uv_handle), _repeat_interval);
212 
213  instance::from(uv_handle)->book_loop();
214  }
215 
216 public: /*interface*/
217  /*! \brief _Get_ the timer repeat interval in milliseconds. */
218  uint64_t repeat_interval() const noexcept { return ::uv_timer_get_repeat(static_cast< uv_t* >(uv_handle)); }
219  /*! \brief _Set_ the timer repeat interval in milliseconds.
220  \note Setting the repeat value to zero turns the timer to be non-repeating.
221  \sa [`uv_timer_set_repeat()`](http://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_set_repeat). */
222  void repeat_interval(uint64_t _value) noexcept { ::uv_timer_set_repeat(static_cast< uv_t* >(uv_handle), _value); }
223 
224  /*! \brief Set the timer callback. */
225  on_timer_t& on_timer() const noexcept { return instance::from(uv_handle)->properties().timer_cb; }
226 
227  /*! \brief Start the timer by scheduling a timer event after the `_timeout` interval expires.
228  \details The timer callback function will be called after `_timeout` milliseconds or, if it is equal to **0**,
229  on the next event loop iteration and then repeatedly after each `repeat_interval()`, if the latter is non-zero.
230 
231  Repeated call to this function results in the automatic call to `stop()` first.
232  \note On successful start this function adds an extra reference to the handle instance,
233  which is automatically released when the timer stops because of being non-repeating or
234  the counterpart function `stop()` is called.
235  \sa libuv API documentation: [`uv_timer_start()`](http://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_start). */
236  int start(uint64_t _timeout) const
237  {
238  auto instance_ptr = instance::from(uv_handle);
239  auto &properties = instance_ptr->properties();
240 
241  if (!properties.has_extra_ref)
242  {
243  instance_ptr->ref();
244  properties.has_extra_ref = true;
245  }
246 
247  uv_status(0);
248  auto uv_ret = ::uv_timer_start(static_cast< uv_t* >(uv_handle), timer_cb,
249  _timeout, ::uv_timer_get_repeat(static_cast< uv_t* >(uv_handle))
250  );
251  if (uv_ret < 0)
252  {
253  uv_status(uv_ret);
254  properties.has_extra_ref = false;
255  instance_ptr->unref();
256  }
257 
258  return uv_ret;
259  }
260 
261  /*! \brief Start the timer with the given callback.
262  \details This is equivalent for
263  ```
264  timer.on_timer() = std::bind(
265  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...
266  );
267  timer.start(_timeout);
268  ```
269  \sa `timer::start()` */
270  template< class _Cb_, typename... _Args_, typename = std::enable_if_t<
272  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
273  on_timer_t
274  >::value
275  > >
276  int start(uint64_t _timeout, _Cb_ &&_cb, _Args_&&... _args) const
277  {
278  instance::from(uv_handle)->properties().timer_cb = std::bind(
279  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...
280  );
281 
282  return start(_timeout);
283  }
284 
285  /*! \brief Stop the timer, the callback will not be called anymore. */
286  int stop() const noexcept
287  {
288  auto instance_ptr = instance::from(uv_handle);
289  auto &properties = instance_ptr->properties();
290 
291  auto uv_ret = uv_status(::uv_timer_stop(static_cast< uv_t* >(uv_handle)));
292 
293  if (properties.has_extra_ref)
294  {
295  properties.has_extra_ref = false;
296  instance_ptr->unref();
297  }
298 
299  return uv_ret;
300  }
301 
302 public: /*conversion operators*/
303  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
304  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
305 };
306 
307 template< typename >
308 void timer::timer_cb(::uv_timer_t *_uv_handle)
309 {
310  auto instance_ptr = instance::from(_uv_handle);
311  auto &properties = instance_ptr->properties();
312 
313 #if 0
314  uvcc_debug_log_if(true, "timer [0x%08tX]: repeat_interval=%llu is_active=%i\n",
315  (ptrdiff_t)_uv_handle, ::uv_timer_get_repeat(_uv_handle), ::uv_is_active((::uv_handle_t*)_uv_handle)
316  );
317 #endif
318 
319  if (::uv_timer_get_repeat(_uv_handle) == 0 and properties.has_extra_ref)
320  {
321  ref_guard< instance > unref_handle(*instance_ptr, adopt_ref);
322  if (properties.timer_cb) properties.timer_cb(timer(_uv_handle));
323  }
324  else
325  if (properties.timer_cb) properties.timer_cb(timer(_uv_handle));
326 }
327 
328 
329 
330 /*! \defgroup doxy_group__idle_prepare_check idle, prepare, check
331  \ingroup doxy_group__handle
332  \brief `uv::idle`, `uv::prepare`, and `uv::check` handles. */
333 //! \{
334 #if 0
335 //{
336 
337 /*! \brief The class template for `uv::idle`, `uv::prepare`, and `uv::check` handles.
338  \sa libuv API documentation:
339  \li [`uv_idle_t` — Idle handle](http://docs.libuv.org/en/v1.x/idle.html#uv-idle-t-idle-handle),
340  \li [`uv_prepare_t` — Prepare handle](http://docs.libuv.org/en/v1.x/prepare.html#uv-prepare-t-prepare-handle),
341  \li [`uv_check_t` — Check handle](http://docs.libuv.org/en/v1.x/check.html#uv-check-t-check-handle). */
342 template<
343  typename _uvHandleTp_,
344  int (*_uvInitFn_)(::uv_loop_t*, _uvHandleTp_*),
345  int (*_uvStartFn_)(_uvHandleTp_*, void (*)(_uvHandleTp_*)),
346  int (*_uvStopFn_)(_uvHandleTp_*)
347 >
348 class loop_watcher : public handle
349 {
350  //! \cond
351  friend class handle::uv_interface;
352  friend class handle::instance< loop_watcher >;
353  //! \endcond
354 
355 public: /*types*/
356  using uv_t = _uvHandleTp_;
357  using cb_t = std::function< void(loop_watcher _handle) >;
358  /*!< \brief The function type of the handle's callback. */
359 
360 protected: /*types*/
361  //! \cond internals
362  //! \addtogroup doxy_group__internals
363  //! \{
364 
365  enum class opcmd { UNKNOWN, STOP, START };
366 
367  struct properties : handle::properties
368  {
370  cb_t cb;
371  };
372 
374 
375  //! \}
376  //! \endcond
377 
378 private: /*types*/
379  using instance = handle::instance< loop_watcher >;
380 
381 private: /*functions*/
382  static void cb(uv_t *_uv_handle)
383  {
384  auto &cb = instance::from(_uv_handle)->properties().cb;
385  if (cb) cb(idle(_uv_handle));
386  }
387 
388 protected: /*constructors*/
389  //! \cond
390  explicit loop_watcher(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
391  //! \endcond
392 
393 public: /*constructors*/
394  ~loop_watcher() = default;
395 
396  loop_watcher(const loop_watcher&) = default;
397  loop_watcher& operator =(const loop_watcher&) = default;
398 
399  loop_watcher(loop_watcher&&) noexcept = default;
400  loop_watcher& operator =(loop_watcher&&) noexcept = default;
401 
402  /*! \brief Create a watcher handle. */
403  explicit loop_watcher(uv::loop &_loop)
404  {
406 
407  auto uv_ret = (*_uvInitFn_)(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle));
408  if (uv_status(uv_ret) < 0) return;
409 
411  }
412 
413 public: /*interface*/
414  /*! \brief Set the handle's callback. */
415  cb_t& cb() const noexcept { return instance::from(uv_handle)->properties().cb; }
416 
417  /*! \brief Start the handle.
418  \note On successful start this function adds an extra reference to the handle instance,
419  which is released when the counterpart function `stop()` is called. Repeated calls don't
420  change the reference count. */
421  int start() const
422  {
425 
427 
429  instance_ptr->ref(); // REF:START -- make sure it will exist for the future idle_cb() calls until stop()
430 
431  switch (opcmd_state0)
432  {
433  case opcmd::UNKNOWN:
434  case opcmd::STOP:
435  break;
436  case opcmd::START:
437  // uv_status(::uv_idle_stop(static_cast< uv_t* >(uv_handle))); // it does not need to be explicitly stopped
438  instance_ptr->unref(); // UNREF:START -- adjust extra reference number
439  break;
440  }
441 
442  uv_status(0);
443  auto uv_ret = (*_uvStartFn_)(static_cast< uv_t* >(uv_handle), cb);
444  if (uv_ret < 0)
445  {
446  uv_status(uv_ret);
448  instance_ptr->unref(); // UNREF:START_FAILURE -- release the extra reference on failure
449  }
450 
451  return uv_ret;
452  }
453 
454  /*! \brief Start the handle with the given callback.
455  \details This is equivalent for
456  ```
457  loop_watcher.cb() = std::bind(
458  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...
459  );
460  loop_watcher.start();
461  ```
462  \sa `loop_watcher::start()` */
463  template< class _Cb_, typename... _Args_, typename = std::enable_if_t< std::is_convertible<
464  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
465  cb_t
466  >::value > >
467  int start(_Cb_ &&_cb, _Args_&&... _args) const
468  {
469  cb() = std::bind(std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...);
470  return start();
471  }
472 
473  /*! \brief Stop the handle, the callback will no longer be called. */
474  int stop() const noexcept
475  {
478 
479  auto opcmd_state0 = opcmd_state;
481 
482  auto uv_ret = uv_status((*_uvStopFn_)(static_cast< uv_t* >(uv_handle)));
483 
484  switch (opcmd_state0)
485  {
486  case opcmd::UNKNOWN:
487  case opcmd::STOP:
488  break;
489  case opcmd::START:
490  instance_ptr->unref(); // UNREF:STOP -- release the reference from start()
491  break;
492  }
493 
494  return uv_ret;
495  }
496 
497 public: /*conversion operators*/
498  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
499  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
500 };
501 
502 /*! \brief Idle handle.
503  \sa libuv API documentation: [`uv_idle_t` — Idle handle](http://docs.libuv.org/en/v1.x/idle.html#uv-idle-t-idle-handle). */
505 
506 /*! \brief Prepare handle.
507  \sa libuv API documentation: [`uv_prepare_t` — Prepare handle](http://docs.libuv.org/en/v1.x/prepare.html#uv-prepare-t-prepare-handle). */
509 
510 /*! \brief Check handle.
511  \sa libuv API documentation: [`uv_check_t` — Check handle](http://docs.libuv.org/en/v1.x/check.html#uv-check-t-check-handle). */
513 
514 //}
515 #else
516 //{
517 
518 /*! \brief Idle handle.
519  \sa libuv API documentation: [`uv_idle_t` — Idle handle](http://docs.libuv.org/en/v1.x/idle.html#uv-idle-t-idle-handle). */
520 class idle : public handle
521 {
522  //! \cond
523  friend class handle::uv_interface;
524  friend class handle::instance< idle >;
525  //! \endcond
526 
527 public: /*types*/
528  using uv_t = ::uv_idle_t;
529  using on_idle_t = std::function< void(idle _handle) >;
530  /*!< \brief The function type of the handle's callback. */
531 
532 protected: /*types*/
533  //! \cond internals
534  //! \addtogroup doxy_group__internals
535  //! \{
536 
537  enum class opcmd { UNKNOWN, STOP, START };
538 
539  struct properties : handle::properties
540  {
541  opcmd opcmd_state = opcmd::UNKNOWN;
542  on_idle_t idle_cb;
543  };
544 
545  struct uv_interface : handle::uv_handle_interface {};
546 
547  //! \}
548  //! \endcond
549 
550 private: /*types*/
551  using instance = handle::instance< idle >;
552 
553 private: /*functions*/
554  template < typename = void > static void idle_cb(::uv_idle_t*);
555 
556 protected: /*constructors*/
557  //! \cond
558  explicit idle(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
559  //! \endcond
560 
561 public: /*constructors*/
562  ~idle() = default;
563 
564  idle(const idle&) = default;
565  idle& operator =(const idle&) = default;
566 
567  idle(idle&&) noexcept = default;
568  idle& operator =(idle&&) noexcept = default;
569 
570  /*! \brief Create an `idle` handle. */
571  explicit idle(uv::loop &_loop)
572  {
573  uv_handle = instance::create();
574 
575  auto uv_ret = ::uv_idle_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle));
576  if (uv_status(uv_ret) < 0) return;
577 
578  instance::from(uv_handle)->book_loop();
579  }
580 
581 public: /*interface*/
582  /*! \brief Set the handle's callback. */
583  on_idle_t& on_idle() const noexcept { return instance::from(uv_handle)->properties().idle_cb; }
584 
585  /*! \brief Start the handle.
586  \note On successful start this function adds an extra reference to the handle instance,
587  which is released when the counterpart function `stop()` is called. Repeated calls don't
588  change the reference count.
589  \sa libuv API documentation: [`uv_idle_t` — Idle handle](http://docs.libuv.org/en/v1.x/idle.html#uv-idle-t-idle-handle). */
590  int start() const
591  {
592  auto instance_ptr = instance::from(uv_handle);
593  auto &properties = instance_ptr->properties();
594 
595  auto opcmd_state0 = properties.opcmd_state;
596 
597  properties.opcmd_state = opcmd::START;
598  instance_ptr->ref(); // REF:START -- make sure it will exist for the future idle_cb() calls until stop()
599 
600  switch (opcmd_state0)
601  {
602  case opcmd::UNKNOWN:
603  case opcmd::STOP:
604  break;
605  case opcmd::START:
606  // uv_status(::uv_idle_stop(static_cast< uv_t* >(uv_handle))); // it does not need to be explicitly stopped
607  instance_ptr->unref(); // UNREF:START -- adjust extra reference number
608  break;
609  }
610 
611  uv_status(0);
612  auto uv_ret = ::uv_idle_start(static_cast< uv_t* >(uv_handle), idle_cb);
613  if (uv_ret < 0)
614  {
615  uv_status(uv_ret);
616  properties.opcmd_state = opcmd::UNKNOWN;
617  instance_ptr->unref(); // UNREF:START_FAILURE -- release the extra reference on failure
618  }
619 
620  return uv_ret;
621  }
622 
623  /*! \brief Start the handle with the given callback.
624  \details This is equivalent for
625  ```
626  idle.on_idle() = std::bind(
627  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...
628  );
629  idle.start();
630  ```
631  \sa `idle::start()` */
632  template< class _Cb_, typename... _Args_, typename = std::enable_if_t< std::is_convertible<
633  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
634  on_idle_t
635  >::value > >
636  int start(_Cb_ &&_cb, _Args_&&... _args) const
637  {
638  on_idle() = std::bind(std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...);
639  return start();
640  }
641 
642  /*! \brief Stop the handle, the callback will no longer be called. */
643  int stop() const noexcept
644  {
645  auto instance_ptr = instance::from(uv_handle);
646  auto &opcmd_state = instance_ptr->properties().opcmd_state;
647 
648  auto opcmd_state0 = opcmd_state;
649  opcmd_state = opcmd::STOP;
650 
651  auto uv_ret = uv_status(::uv_idle_stop(static_cast< uv_t* >(uv_handle)));
652 
653  switch (opcmd_state0)
654  {
655  case opcmd::UNKNOWN:
656  case opcmd::STOP:
657  break;
658  case opcmd::START:
659  instance_ptr->unref(); // UNREF:STOP -- release the reference from start()
660  break;
661  }
662 
663  return uv_ret;
664  }
665 
666 public: /*conversion operators*/
667  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
668  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
669 };
670 
671 template< typename >
672 void idle::idle_cb(::uv_idle_t *_uv_handle)
673 {
674  auto &idle_cb = instance::from(_uv_handle)->properties().idle_cb;
675  if (idle_cb) idle_cb(idle(_uv_handle));
676 }
677 
678 
679 /*! \brief Prepare handle.
680  \sa libuv API documentation: [`uv_prepare_t` — Prepare handle](http://docs.libuv.org/en/v1.x/prepare.html#uv-prepare-t-prepare-handle). */
681 class prepare : public handle
682 {
683  //! \cond
684  friend class handle::uv_interface;
685  friend class handle::instance< prepare >;
686  //! \endcond
687 
688 public: /*types*/
689  using uv_t = ::uv_prepare_t;
690  using on_prepare_t = std::function< void(prepare _handle) >;
691  /*!< \brief The function type of the handle's callback. */
692 
693 protected: /*types*/
694  //! \cond internals
695  //! \addtogroup doxy_group__internals
696  //! \{
697 
698  enum class opcmd { UNKNOWN, STOP, START };
699 
700  struct properties : handle::properties
701  {
702  opcmd opcmd_state = opcmd::UNKNOWN;
703  on_prepare_t prepare_cb;
704  };
705 
706  struct uv_interface : handle::uv_handle_interface {};
707 
708  //! \}
709  //! \endcond
710 
711 private: /*types*/
712  using instance = handle::instance< prepare >;
713 
714 private: /*functions*/
715  template < typename = void > static void prepare_cb(::uv_prepare_t*);
716 
717 protected: /*constructors*/
718  //! \cond
719  explicit prepare(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
720  //! \endcond
721 
722 public: /*constructors*/
723  ~prepare() = default;
724 
725  prepare(const prepare&) = default;
726  prepare& operator =(const prepare&) = default;
727 
728  prepare(prepare&&) noexcept = default;
729  prepare& operator =(prepare&&) noexcept = default;
730 
731  /*! \brief Create an `prepare` handle. */
732  explicit prepare(uv::loop &_loop)
733  {
734  uv_handle = instance::create();
735 
736  auto uv_ret = ::uv_prepare_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle));
737  if (uv_status(uv_ret) < 0) return;
738 
739  instance::from(uv_handle)->book_loop();
740  }
741 
742 public: /*interface*/
743  /*! \brief Set the handle's callback. */
744  on_prepare_t& on_prepare() const noexcept { return instance::from(uv_handle)->properties().prepare_cb; }
745 
746  /*! \brief Start the handle.
747  \note On successful start this function adds an extra reference to the handle instance,
748  which is released when the counterpart function `stop()` is called. Repeated calls don't
749  change the reference count.
750  \sa libuv API documentation: [`uv_prepare_t` — Prepare handle](http://docs.libuv.org/en/v1.x/prepare.html#uv-prepare-t-prepare-handle). */
751  int start() const
752  {
753  auto instance_ptr = instance::from(uv_handle);
754  auto &properties = instance_ptr->properties();
755 
756  auto opcmd_state0 = properties.opcmd_state;
757 
758  properties.opcmd_state = opcmd::START;
759  instance_ptr->ref(); // REF:START -- make sure it will exist for the future prepare_cb() calls until stop()
760 
761  switch (opcmd_state0)
762  {
763  case opcmd::UNKNOWN:
764  case opcmd::STOP:
765  break;
766  case opcmd::START:
767  // uv_status(::uv_prepare_stop(static_cast< uv_t* >(uv_handle))); // it does not need to be explicitly stopped
768  instance_ptr->unref(); // UNREF:START -- adjust extra reference number
769  break;
770  }
771 
772  uv_status(0);
773  auto uv_ret = ::uv_prepare_start(static_cast< uv_t* >(uv_handle), prepare_cb);
774  if (uv_ret < 0)
775  {
776  uv_status(uv_ret);
777  properties.opcmd_state = opcmd::UNKNOWN;
778  instance_ptr->unref(); // UNREF:START_FAILURE -- release the extra reference on failure
779  }
780 
781  return uv_ret;
782  }
783 
784  /*! \brief Start the handle with the given callback.
785  \details This is equivalent for
786  ```
787  prepare.on_prepare() = std::bind(
788  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...
789  );
790  prepare.start();
791  ```
792  \sa `prepare::start()` */
793  template< class _Cb_, typename... _Args_, typename = std::enable_if_t< std::is_convertible<
794  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
796  >::value > >
797  int start(_Cb_ &&_cb, _Args_&&... _args) const
798  {
799  on_prepare() = std::bind(std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...);
800  return start();
801  }
802 
803  /*! \brief Stop the handle, the callback will no longer be called. */
804  int stop() const noexcept
805  {
806  auto instance_ptr = instance::from(uv_handle);
807  auto &opcmd_state = instance_ptr->properties().opcmd_state;
808 
809  auto opcmd_state0 = opcmd_state;
810  opcmd_state = opcmd::STOP;
811 
812  auto uv_ret = uv_status(::uv_prepare_stop(static_cast< uv_t* >(uv_handle)));
813 
814  switch (opcmd_state0)
815  {
816  case opcmd::UNKNOWN:
817  case opcmd::STOP:
818  break;
819  case opcmd::START:
820  instance_ptr->unref(); // UNREF:STOP -- release the reference from start()
821  break;
822  }
823 
824  return uv_ret;
825  }
826 
827 public: /*conversion operators*/
828  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
829  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
830 };
831 
832 template< typename >
833 void prepare::prepare_cb(::uv_prepare_t *_uv_handle)
834 {
835  auto &prepare_cb = instance::from(_uv_handle)->properties().prepare_cb;
836  if (prepare_cb) prepare_cb(prepare(_uv_handle));
837 }
838 
839 
840 /*! \brief Check handle.
841  \sa libuv API documentation: [`uv_check_t` — Check handle](http://docs.libuv.org/en/v1.x/check.html#uv-check-t-check-handle). */
842 class check : public handle
843 {
844  //! \cond
845  friend class handle::uv_interface;
846  friend class handle::instance< check >;
847  //! \endcond
848 
849 public: /*types*/
850  using uv_t = ::uv_check_t;
851  using on_check_t = std::function< void(check _handle) >;
852  /*!< \brief The function type of the handle's callback. */
853 
854 protected: /*types*/
855  //! \cond internals
856  //! \addtogroup doxy_group__internals
857  //! \{
858 
859  enum class opcmd { UNKNOWN, STOP, START };
860 
861  struct properties : handle::properties
862  {
863  opcmd opcmd_state = opcmd::UNKNOWN;
864  on_check_t check_cb;
865  };
866 
867  struct uv_interface : handle::uv_handle_interface {};
868 
869  //! \}
870  //! \endcond
871 
872 private: /*types*/
873  using instance = handle::instance< check >;
874 
875 private: /*functions*/
876  template < typename = void > static void check_cb(::uv_check_t*);
877 
878 protected: /*constructors*/
879  //! \cond
880  explicit check(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
881  //! \endcond
882 
883 public: /*constructors*/
884  ~check() = default;
885 
886  check(const check&) = default;
887  check& operator =(const check&) = default;
888 
889  check(check&&) noexcept = default;
890  check& operator =(check&&) noexcept = default;
891 
892  /*! \brief Create an `check` handle. */
893  explicit check(uv::loop &_loop)
894  {
895  uv_handle = instance::create();
896 
897  auto uv_ret = ::uv_check_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle));
898  if (uv_status(uv_ret) < 0) return;
899 
900  instance::from(uv_handle)->book_loop();
901  }
902 
903 public: /*interface*/
904  /*! \brief Set the handle's callback. */
905  on_check_t& on_check() const noexcept { return instance::from(uv_handle)->properties().check_cb; }
906 
907  /*! \brief Start the handle.
908  \note On successful start this function adds an extra reference to the handle instance,
909  which is released when the counterpart function `stop()` is called. Repeated calls don't
910  change the reference count.
911  \sa libuv API documentation: [`uv_check_t` — Check handle](http://docs.libuv.org/en/v1.x/check.html#uv-check-t-check-handle). */
912  int start() const
913  {
914  auto instance_ptr = instance::from(uv_handle);
915  auto &properties = instance_ptr->properties();
916 
917  auto opcmd_state0 = properties.opcmd_state;
918 
919  properties.opcmd_state = opcmd::START;
920  instance_ptr->ref(); // REF:START -- make sure it will exist for the future check_cb() calls until stop()
921 
922  switch (opcmd_state0)
923  {
924  case opcmd::UNKNOWN:
925  case opcmd::STOP:
926  break;
927  case opcmd::START:
928  // uv_status(::uv_check_stop(static_cast< uv_t* >(uv_handle))); // it does not need to be explicitly stopped
929  instance_ptr->unref(); // UNREF:START -- adjust extra reference number
930  break;
931  }
932 
933  uv_status(0);
934  auto uv_ret = ::uv_check_start(static_cast< uv_t* >(uv_handle), check_cb);
935  if (uv_ret < 0)
936  {
937  uv_status(uv_ret);
938  properties.opcmd_state = opcmd::UNKNOWN;
939  instance_ptr->unref(); // UNREF:START_FAILURE -- release the extra reference on failure
940  }
941 
942  return uv_ret;
943  }
944 
945  /*! \brief Start the handle with the given callback.
946  \details This is equivalent for
947  ```
948  check.on_check() = std::bind(
949  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...
950  );
951  check.start();
952  ```
953  \sa `check::start()` */
954  template< class _Cb_, typename... _Args_, typename = std::enable_if_t< std::is_convertible<
955  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
956  on_check_t
957  >::value > >
958  int start(_Cb_ &&_cb, _Args_&&... _args) const
959  {
960  on_check() = std::bind(std::forward< _Cb_ >(_cb), std::placeholders::_1, std::forward< _Args_ >(_args)...);
961  return start();
962  }
963 
964  /*! \brief Stop the handle, the callback will no longer be called. */
965  int stop() const noexcept
966  {
967  auto instance_ptr = instance::from(uv_handle);
968  auto &opcmd_state = instance_ptr->properties().opcmd_state;
969 
970  auto opcmd_state0 = opcmd_state;
971  opcmd_state = opcmd::STOP;
972 
973  auto uv_ret = uv_status(::uv_check_stop(static_cast< uv_t* >(uv_handle)));
974 
975  switch (opcmd_state0)
976  {
977  case opcmd::UNKNOWN:
978  case opcmd::STOP:
979  break;
980  case opcmd::START:
981  instance_ptr->unref(); // UNREF:STOP -- release the reference from start()
982  break;
983  }
984 
985  return uv_ret;
986  }
987 
988 public: /*conversion operators*/
989  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
990  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
991 };
992 
993 template< typename >
994 void check::check_cb(::uv_check_t *_uv_handle)
995 {
996  auto &check_cb = instance::from(_uv_handle)->properties().check_cb;
997  if (check_cb) check_cb(check(_uv_handle));
998 }
999 
1000 //}
1001 #endif
1002 //! \}
1003 
1004 
1005 
1006 /*! \ingroup doxy_group__handle
1007  \brief Signal handle.
1008  \sa libuv API documentation: [`uv_signal_t` — Signal handle](http://docs.libuv.org/en/v1.x/signal.html#uv-signal-t-signal-handle). */
1009 class signal : public handle
1010 {
1011  //! \cond
1012  friend class handle::uv_interface;
1013  friend class handle::instance< signal >;
1014  //! \endcond
1015 
1016 public: /*types*/
1017  using uv_t = ::uv_signal_t;
1018  using on_signal_t = std::function< void(signal _handle, bool _oneshot) >;
1019  /*!< \brief The function type of the signal callback.
1020  \details The `_oneshot` parameter indicates that the signal handling was started in mode of `start_oneshot()` function.
1021  \sa libuv API documentation: [`uv_signal_cb`](http://docs.libuv.org/en/v1.x/signal.html#c.uv_signal_cb). */
1022 
1023 protected: /*types*/
1024  //! \cond internals
1025  //! \addtogroup doxy_group__internals
1026  //! \{
1027 
1028  enum class opcmd { UNKNOWN, STOP, START, START_ONESHOT };
1029 
1030  struct properties : handle::properties
1031  {
1032  opcmd opcmd_state = opcmd::UNKNOWN;
1033  int signum = 0;
1034  on_signal_t signal_cb;
1035  };
1036 
1037  struct uv_interface : handle::uv_handle_interface {};
1038 
1039  //! \}
1040  //! \endcond
1041 
1042 private: /*types*/
1043  using instance = handle::instance< signal >;
1044 
1045 private: /*functions*/
1046  template < typename = void > static void signal_cb(::uv_signal_t*, int);
1047 
1048 protected: /*constructors*/
1049  //! \cond
1050  explicit signal(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
1051  //! \endcond
1052 
1053 public: /*constructors*/
1054  ~signal() = default;
1055 
1056  signal(const signal&) = default;
1057  signal& operator =(const signal&) = default;
1058 
1059  signal(signal&&) noexcept = default;
1060  signal& operator =(signal&&) noexcept = default;
1061 
1062  /*! \brief Create a `signal` handle watching for `_signum` signal. */
1063  signal(uv::loop &_loop, int _signum)
1064  {
1065  uv_handle = instance::create();
1066 
1067  auto uv_ret = ::uv_signal_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle));
1068  instance::from(uv_handle)->properties().signum = _signum;
1069 
1070  if (uv_status(uv_ret) < 0) return;
1071 
1072  instance::from(uv_handle)->book_loop();
1073  }
1074 
1075 protected: /*functions*/
1076  //! \cond
1077  int start(opcmd _startcmd_state) const
1078  {
1079  switch (_startcmd_state)
1080  {
1081  case opcmd::UNKNOWN:
1082  case opcmd::STOP:
1083  throw std::invalid_argument(__PRETTY_FUNCTION__);
1084  break;
1085  case opcmd::START:
1086  case opcmd::START_ONESHOT:
1087  break;
1088  }
1089 
1090  auto instance_ptr = instance::from(uv_handle);
1091  auto &properties = instance_ptr->properties();
1092 
1093  auto opcmd_state0 = properties.opcmd_state;
1094 
1095  properties.opcmd_state = _startcmd_state;
1096  instance_ptr->ref(); // REF:START/START_ONESHOT -- make sure it will exist for the future signal_cb() calls until stop()
1097 
1098  switch (opcmd_state0)
1099  {
1100  case opcmd::UNKNOWN:
1101  case opcmd::STOP:
1102  break;
1103  case opcmd::START:
1104  case opcmd::START_ONESHOT:
1105  // uv_status(::uv_signal_stop(static_cast< uv_t* >(uv_handle))); // ::uv_signal_start() does this when necessary
1106  instance_ptr->unref(); // UNREF:RESTART -- adjust extra reference number
1107  break;
1108  }
1109 
1110  uv_status(0);
1111  auto uv_ret = ::uv_signal_start(static_cast< uv_t* >(uv_handle), signal_cb, properties.signum);
1112  if (uv_ret < 0)
1113  {
1114  uv_status(uv_ret);
1115  properties.opcmd_state = opcmd::UNKNOWN;
1116  instance_ptr->unref(); // UNREF:START_FAILURE -- release the extra reference on failure
1117  }
1118 
1119  return uv_ret;
1120  }
1121  //! \endcond
1122 
1123 public: /*interface*/
1124  /*! \brief Get the signal number being watched for by this handle. */
1125  int signum() const noexcept
1126  {
1127  auto signum = static_cast< uv_t* >(uv_handle)->signum;
1128  return signum ? signum : instance::from(uv_handle)->properties().signum;
1129  }
1130 
1131  /*! \brief Set the signal callback. */
1132  on_signal_t& on_signal() const noexcept { return instance::from(uv_handle)->properties().signal_cb; }
1133 
1134  /*! \brief Start the handle for watching for the signal.
1135  \details Repeated call to this function results in the automatic call to `stop()` first
1136  (possible signal events are not missed if the signal number has not changed).
1137  \note On successful start this function adds an extra reference to the handle instance,
1138  which is released when the counterpart function `stop()` is called.
1139  \sa libuv API documentation: [`uv_signal_t` — Signal handle](http://docs.libuv.org/en/v1.x/signal.html#uv-signal-t-signal-handle). */
1140  int start() const { return start(opcmd::START); }
1141 
1142  /*! \brief Start the handle with the given signal callback.
1143  \details This is equivalent for
1144  ```
1145  signal.on_signal() = std::bind(
1146  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::placeholders::_2, std::forward< _Args_ >(_args)...
1147  );
1148  signal.start();
1149  ```
1150  \sa `signal::start()` */
1151  template< class _Cb_, typename... _Args_, typename = std::enable_if_t< std::is_convertible<
1152  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, std::placeholders::_2, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
1153  on_signal_t
1154  >::value > >
1155  int start(_Cb_ &&_cb, _Args_&&... _args) const
1156  {
1157  instance::from(uv_handle)->properties().signal_cb = std::bind(
1158  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::placeholders::_2, std::forward< _Args_ >(_args)...
1159  );
1160  return start(opcmd::START);
1161  }
1162 
1163  /*! \brief Start the handle with the given signal callback, watching for the given signal number.
1164  \details This function overload allows to change the signal number being watched for by the handle.
1165  This is equivalent for
1166  ```
1167  signal.signum() = _signum; // change the signal number being watched for
1168  signal.on_signal() = std::bind(
1169  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::placeholders::_2, std::forward< _Args_ >(_args)...
1170  );
1171  signal.start();
1172  ```
1173  \sa `signal::start()` */
1174  template< class _Cb_, typename... _Args_, typename = std::enable_if_t< std::is_convertible<
1175  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, std::placeholders::_2, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
1176  on_signal_t
1177  >::value > >
1178  int start(int _signum, _Cb_ &&_cb, _Args_&&... _args) const
1179  {
1180  instance::from(uv_handle)->properties().signum = _signum;
1181  instance::from(uv_handle)->properties().signal_cb = std::bind(
1182  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::placeholders::_2, std::forward< _Args_ >(_args)...
1183  );
1184  return start(opcmd::START);
1185  }
1186 
1187 #if (UV_VERSION_MAJOR >= 1) && (UV_VERSION_MINOR >= 12)
1188  /*! \brief Start the handle for watching for the signal for the it first occurrence.
1189  \details The signal handler is called for the first occasion of the signal received,
1190  after which the handle is immediately stopped.
1191 
1192  Repeated call to this function results in the automatic call to `stop()` first.
1193  \note On successful start this function adds an extra reference to the handle instance,
1194  which is **automatically released** when the signal is received or if none has received,
1195  when the counterpart function `stop()` is called. */
1196  int start_oneshot() const { return start(opcmd::START_ONESHOT); }
1197 #endif
1198 
1199  /*! \brief Stop the handle, the callback will no longer be called. */
1200  int stop() const noexcept
1201  {
1202  auto instance_ptr = instance::from(uv_handle);
1203  auto &opcmd_state = instance_ptr->properties().opcmd_state;
1204 
1205  auto opcmd_state0 = opcmd_state;
1206  opcmd_state = opcmd::STOP;
1207 
1208  auto uv_ret = uv_status(::uv_signal_stop(static_cast< uv_t* >(uv_handle)));
1209 
1210  switch (opcmd_state0)
1211  {
1212  case opcmd::UNKNOWN:
1213  case opcmd::STOP:
1214  break;
1215  case opcmd::START:
1216  case opcmd::START_ONESHOT:
1217  instance_ptr->unref(); // UNREF:STOP -- release the reference from start() or fruitless start_oneshot()
1218  break;
1219  }
1220 
1221  return uv_ret;
1222  }
1223 
1224 public: /*conversion operators*/
1225  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
1226  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
1227 };
1228 
1229 template< typename >
1230 void signal::signal_cb(::uv_signal_t *_uv_handle, int)
1231 {
1232  auto instance_ptr = instance::from(_uv_handle);
1233  auto &signal_cb = instance_ptr->properties().signal_cb;
1234 
1235  if (instance_ptr->properties().opcmd_state == opcmd::START_ONESHOT)
1236  {
1237  instance_ptr->properties().opcmd_state = opcmd::UNKNOWN;
1238  ref_guard< instance > unref_handle(*instance_ptr, adopt_ref); // UNREF:START_ONESHOT
1239 
1240  if (signal_cb) signal_cb(signal(_uv_handle), true);
1241  }
1242  else
1243  if (signal_cb) signal_cb(signal(_uv_handle), false);
1244 }
1245 
1246 
1247 
1248 /*! \ingroup doxy_group__handle
1249  \brief Process handle.
1250  \sa libuv API documentation: [`uv_process_t` — Process handle](http://docs.libuv.org/en/v1.x/process.html#uv-process-t-process-handle). */
1251 class process : public handle
1252 {
1253  //! \cond
1254  friend class handle::uv_interface;
1255  friend class handle::instance< process >;
1256  //! \endcond
1257 
1258 public: /*types*/
1259  using uv_t = ::uv_process_t;
1260  using on_exit_t = std::function< void(process _handle, int64_t _exit_status, int _termination_signal) >;
1261  /*!< \brief The function type of the callback called when the child process exits.
1262  \sa libuv API documentation: [`uv_exit_cb`](http://docs.libuv.org/en/v1.x/process.html#c.uv_exit_cb). */
1263 
1264 protected: /*types*/
1265  //! \cond internals
1266  //! \addtogroup doxy_group__internals
1267  //! \{
1268 
1269  struct properties : handle::properties
1270  {
1271  struct stdio_container : ::uv_stdio_container_t
1272  {
1273  stdio_container() noexcept // to provide proper initialization
1274  {
1275  flags = UV_IGNORE;
1276  data.fd = -1;
1277  }
1278  };
1279  struct stdio_endpoint : io
1280  {
1281  stdio_endpoint() noexcept = default; // to provide demandable access to protected `io` default ctor
1282  };
1283 
1284  ::uv_process_options_t spawn_options = { 0,};
1285  on_exit_t exit_cb;
1286  std::vector< stdio_container > stdio_uv_containers;
1287  std::vector< stdio_endpoint > stdio_uvcc_endpoints;
1288 
1289  properties()
1290  {
1291  spawn_options.exit_cb = process::exit_cb;
1292  }
1293 
1294  void ensure_stdio_number(unsigned _target_fd_number)
1295  {
1296  if (_target_fd_number >= stdio_uv_containers.size())
1297  {
1298  stdio_uv_containers.resize(_target_fd_number + 1);
1299  stdio_uvcc_endpoints.resize(_target_fd_number + 1);
1300 
1301  spawn_options.stdio_count = stdio_uv_containers.size();
1302  spawn_options.stdio = stdio_uv_containers.data();
1303  }
1304  }
1305  };
1306 
1307  struct uv_interface : handle::uv_handle_interface {};
1308 
1309  //! \}
1310  //! \endcond
1311 
1312 private: /*types*/
1313  using instance = handle::instance< process >;
1314 
1315 private: /*functions*/
1316  template < typename = void > static void exit_cb(::uv_process_t*, int64_t, int);
1317 
1318 protected: /*constructors*/
1319  //! \cond
1320  explicit process(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
1321  //! \endcond
1322 
1323 public: /*constructors*/
1324  ~process() = default;
1325 
1326  process(const process&) = default;
1327  process& operator =(const process&) = default;
1328 
1329  process(process&&) noexcept = default;
1330  process& operator =(process&&) noexcept = default;
1331 
1332  /*! \brief Create a `process` handle. */
1333  explicit process(uv::loop &_loop)
1334  {
1335  uv_handle = instance::create();
1336  static_cast< uv_t* >(uv_handle)->loop = static_cast< loop::uv_t* >(_loop);
1337  instance::from(uv_handle)->book_loop();
1338  }
1339 
1340 public: /*interface*/
1341  /*! \brief Force child processes spawned by this process not to inherit file descriptors/handles that this process has inherited from its parent.
1342  \sa libuv API documentation: [`uv_disable_stdio_inheritance()`](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance). */
1343  static void disable_stdio_inheritance() noexcept { ::uv_disable_stdio_inheritance(); }
1344 
1345  /*! \brief Send the specified signal to the given PID.
1346  \sa libuv API documentation: [`uv_kill()`](http://docs.libuv.org/en/v1.x/process.html#c.uv_kill). */
1347  static int kill(int _pid, int _signum) noexcept { return ::uv_kill(_pid, _signum); }
1348 
1349  /*! \brief The PID of the child process. It is set after calling `spawn()`. */
1350  int pid() const noexcept { return static_cast< uv_t* >(uv_handle)->pid; }
1351 
1352  /*! \name Functions to prepare for spawning a child process:: */
1353  //! \{
1354 
1355  /*! \brief Set the callback function called when the child process exits. */
1356  on_exit_t& on_exit() const noexcept { return instance::from(uv_handle)->properties().exit_cb; }
1357 
1358  /*! \brief Set pointer to environment for the child process. If `nullptr` the parents environment is used. */
1359  void set_environment(char *_envp[]) const noexcept
1360  {
1361  auto &spawn_options = instance::from(uv_handle)->properties().spawn_options;
1362  spawn_options.env = _envp;
1363  }
1364 
1365  /*! \brief Set current working directory when spawning the child process. */
1366  void set_working_dir(const char *_cwd) const noexcept
1367  {
1368  auto &spawn_options = instance::from(uv_handle)->properties().spawn_options;
1369  spawn_options.cwd = _cwd;
1370  }
1371 
1372  /*! \brief Set the io endpoint that should be available to the child process as the target stdio file descriptor number.
1373  \sa libuv API documentation: [`uv_process_options_t.stdio`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_options_t.stdio),
1374  [`uv_process_options_t`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_options_t),
1375  [`uv_stdio_container_t`](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_container_t),
1376  [`uv_stdio_flags`](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags). */
1377  void inherit_stdio(unsigned _target_fd_number, io _io) const
1378  {
1379  auto &properties = instance::from(uv_handle)->properties();
1380 
1381  properties.ensure_stdio_number(_target_fd_number);
1382 
1383  if (_io.id()) switch (_io.type())
1384  {
1385  case UV_NAMED_PIPE:
1386  case UV_STREAM:
1387  case UV_TCP:
1388  case UV_TTY:
1389  properties.stdio_uv_containers[_target_fd_number].flags = UV_INHERIT_STREAM;
1390  properties.stdio_uv_containers[_target_fd_number].data.stream = static_cast< stream::uv_t* >(static_cast< stream& >(_io));
1391  break;
1392  case UV_FILE:
1393  properties.stdio_uv_containers[_target_fd_number].flags = UV_INHERIT_FD;
1394  properties.stdio_uv_containers[_target_fd_number].data.fd = static_cast< file& >(_io).fd();
1395  break;
1396  default:
1397  properties.stdio_uv_containers[_target_fd_number].flags = UV_IGNORE;
1398  properties.stdio_uv_containers[_target_fd_number].data.fd = -1;
1399  }
1400 
1401  properties.stdio_uvcc_endpoints[_target_fd_number] = static_cast< properties::stdio_endpoint&& >(_io); // move assignment
1402  }
1403 
1404  /*! \brief Set the file descriptor that should be inherited by the child process as the target stdio descriptor number. */
1405  void inherit_stdio(unsigned _target_fd_number, ::uv_file _fd) const
1406  {
1407  auto &properties = instance::from(uv_handle)->properties();
1408 
1409  properties.ensure_stdio_number(_target_fd_number);
1410 
1411  properties.stdio_uv_containers[_target_fd_number].flags = UV_INHERIT_FD;
1412  properties.stdio_uv_containers[_target_fd_number].data.fd = _fd;
1413  }
1414 
1415  /*! \brief Create a pipe to the child process' stdio fd number.
1416  \details Only `UV_READABLE_PIPE` and `UV_WRITABLE_PIPE` flags from the
1417  [`uv_stdio_flags`](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags) enumeration take effect.\n
1418  Set `_ipc` parameter to `true` if the created pipe is going to be used for handle passing between processes.
1419  \sa libuv API documentation: [`uv_stdio_flags`](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags),
1420  [`uv_process_options_t.stdio`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_options_t.stdio). */
1421  int create_stdio_pipe(unsigned _target_fd_number, uv::loop &_pipe_loop, ::uv_stdio_flags _pipe_flags, bool _ipc = false) const
1422  {
1423  auto &properties = instance::from(uv_handle)->properties();
1424 
1425  properties.ensure_stdio_number(_target_fd_number);
1426 
1427  pipe p(_pipe_loop, _ipc);
1428  if (!p) return uv_status(p.uv_status());
1429 
1430  int flags = UV_CREATE_PIPE;
1431  if (_pipe_flags & UV_READABLE_PIPE) flags |= UV_READABLE_PIPE;
1432  if (_pipe_flags & UV_WRITABLE_PIPE) flags |= UV_WRITABLE_PIPE;
1433  properties.stdio_uv_containers[_target_fd_number].flags = static_cast< ::uv_stdio_flags >(flags);
1434  properties.stdio_uv_containers[_target_fd_number].data.stream = static_cast< stream::uv_t* >(p);
1435 
1436  properties.stdio_uvcc_endpoints[_target_fd_number] = static_cast< properties::stdio_endpoint&& >(static_cast< io& >(p)); // move assignment
1437  return 0;
1438  }
1439 
1440  /*! \brief The stdio endpoints to be set for the child process. */
1441  std::vector< io >& stdio() const noexcept
1442  {
1443  auto &properties = instance::from(uv_handle)->properties();
1444  return reinterpret_cast< std::vector< io >& >(properties.stdio_uvcc_endpoints);
1445  }
1446 
1447  /*! \brief Set the child process' user id.
1448  \details Specifying a value of **-1** clears the `UV_PROCESS_SETUID` flag.
1449  \note On Windows this function is no-op.
1450  \sa libuv API documentation: [`uv_process_options_t.uid`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_options_t.uid),
1451  [`uv_process_flags`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags), */
1452  void set_uid(::uv_uid_t _uid) const noexcept
1453  {
1454 #ifndef _WIN32
1455  auto &spawn_options = instance::from(uv_handle)->properties().spawn_options;
1456  if (_uid == -1)
1457  spawn_options.flags &= ~UV_PROCESS_SETUID;
1458  else
1459  spawn_options.flags |= UV_PROCESS_SETUID;
1460  spawn_options.uid = _uid;
1461 #endif
1462  }
1463  /*! \brief Set the child process' group id.
1464  \details Specifying a value of **-1** clears the `UV_PROCESS_SETGID` flag.
1465  \note On Windows this function is no-op.
1466  \sa libuv API documentation: [`uv_process_options_t.gid`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_options_t.gid),
1467  [`uv_process_flags`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags), */
1468  void set_gid(::uv_gid_t _gid) const noexcept
1469  {
1470 #ifndef _WIN32
1471  auto &spawn_options = instance::from(uv_handle)->properties().spawn_options;
1472  if (_gid == -1)
1473  spawn_options.flags &= ~UV_PROCESS_SETGID;
1474  else
1475  spawn_options.flags |= UV_PROCESS_SETGID;
1476  spawn_options.gid = _gid;
1477 #endif
1478  }
1479 
1480  //! \}
1481 
1482  /*! \brief Create and start a new child process.
1483  \sa libuv API documentation: [`uv_spawn()`](http://docs.libuv.org/en/v1.x/process.html#c.uv_spawn),
1484  [`uv_process_flags`](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags). */
1485  int spawn(const char *_file, char *_argv[], ::uv_process_flags _flags = static_cast< ::uv_process_flags >(0)) const noexcept
1486  {
1487  auto &properties = instance::from(uv_handle)->properties();
1488  {
1489  properties.spawn_options.file = _file;
1490  properties.spawn_options.args = _argv;
1491  properties.spawn_options.flags |= _flags;
1492  }
1493 
1494  return uv_status(
1495  ::uv_spawn(static_cast< uv_t* >(uv_handle)->loop, static_cast< uv_t* >(uv_handle), &properties.spawn_options)
1496  );
1497  }
1498  int spawn(const char *_file, const char *_argv[], ::uv_process_flags _flags = static_cast< ::uv_process_flags >(0)) const noexcept
1499  {
1500  return spawn(_file, const_cast< char** >(_argv), _flags);
1501  }
1502 
1503  /*! \brief Send the specified signal to the child process. */
1504  int kill(int _signum) const noexcept
1505  {
1506  return uv_status(::uv_process_kill(static_cast< uv_t* >(uv_handle), _signum));
1507  }
1508 
1509 public: /*conversion operators*/
1510  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
1511  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
1512 };
1513 
1514 template< typename >
1515 void process::exit_cb(::uv_process_t* _uv_handle, int64_t _exit_status, int _termination_signal)
1516 {
1517  auto &exit_cb = instance::from(_uv_handle)->properties().exit_cb;
1518  if (exit_cb) exit_cb(process(_uv_handle), _exit_status, _termination_signal);
1519 }
1520 
1521 
1522 
1523 /*! \ingroup doxy_group__handle
1524  \brief Poll handle.
1525  \sa libuv API documentation: [`uv_poll_t` — Poll handle](http://docs.libuv.org/en/v1.x/poll.html#uv-poll-t-poll-handle). */
1526 class poll : public handle
1527 {
1528  //! \cond
1529  friend class handle::uv_interface;
1530  friend class handle::instance< poll >;
1531  //! \endcond
1532 
1533 public: /*types*/
1534  using uv_t = ::uv_poll_t;
1535  using on_poll_t = std::function< void(poll _handle, int _events) >;
1536  /*!< \brief The function type of the handle's callback. */
1537 
1538 protected: /*types*/
1539  //! \cond internals
1540  //! \addtogroup doxy_group__internals
1541  //! \{
1542 
1543  enum class opcmd { UNKNOWN, STOP, START };
1544 
1545  struct properties : handle::properties
1546  {
1547  opcmd opcmd_state = opcmd::UNKNOWN;
1548  on_poll_t poll_cb;
1549  };
1550 
1551  struct uv_interface : handle::uv_handle_interface {};
1552 
1553  //! \}
1554  //! \endcond
1555 
1556 private: /*types*/
1557  using instance = handle::instance< poll >;
1558 
1559 private: /*functions*/
1560  template < typename = void > static void poll_cb(::uv_poll_t*, int, int);
1561 
1562 protected: /*constructors*/
1563  //! \cond
1564  explicit poll(uv_t *_uv_handle) : handle(reinterpret_cast< handle::uv_t* >(_uv_handle)) {}
1565  //! \endcond
1566 
1567 public: /*constructors*/
1568  ~poll() = default;
1569 
1570  poll(const poll&) = default;
1571  poll& operator =(const poll&) = default;
1572 
1573  poll(poll&&) noexcept = default;
1574  poll& operator =(poll&&) noexcept = default;
1575 
1576  /*! \brief Create a `poll` handle for a file descriptor (_Windows and Unix-like systems_) or for a socket descriptor (_Unix-like systems only_).
1577  \sa libuv API documentation [`uv_poll_init()`](http://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_init). */
1578  poll(uv::loop &_loop, int _fd)
1579  {
1580  uv_handle = instance::create();
1581 
1582  auto uv_ret = ::uv_poll_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle), _fd);
1583  if (uv_status(uv_ret) < 0) return;
1584 
1585  instance::from(uv_handle)->book_loop();
1586  }
1587 
1588 #ifdef _WIN32
1589  /*! \brief Create a `poll` handle for a socket descriptor. (_Windows only._)
1590  \sa libuv API documentation [`uv_poll_init_socket()`](http://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_init_socket).*/
1592  {
1593  uv_handle = instance::create();
1594 
1595  auto uv_ret = ::uv_poll_init_socket(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle), _socket);
1596  if (uv_status(uv_ret) < 0) return;
1597 
1599  }
1600 #endif
1601 
1602 public: /*interface*/
1603  /*! \brief Set the handle's callback. */
1604  on_poll_t& on_poll() const noexcept { return instance::from(uv_handle)->properties().poll_cb; }
1605 
1606  /*! \brief Start the handle.
1607  \note On successful start this function adds an extra reference to the handle instance,
1608  which is released when the counterpart function `stop()` is called. Repeated calls don't
1609  change the reference count.
1610  \sa libuv API documentation: [`uv_poll_start()`](http://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_start). */
1611  int start(int _events) const
1612  {
1613  auto instance_ptr = instance::from(uv_handle);
1614  auto &properties = instance_ptr->properties();
1615 
1616  auto opcmd_state0 = properties.opcmd_state;
1617 
1618  properties.opcmd_state = opcmd::START;
1619  instance_ptr->ref(); // REF:START -- make sure it will exist for the future poll_cb() calls until stop()
1620 
1621  switch (opcmd_state0)
1622  {
1623  case opcmd::UNKNOWN:
1624  case opcmd::STOP:
1625  break;
1626  case opcmd::START:
1627  // uv_status(::uv_poll_stop(static_cast< uv_t* >(uv_handle))); // it does not need to be explicitly stopped
1628  instance_ptr->unref(); // UNREF:START -- adjust extra reference number
1629  break;
1630  }
1631 
1632  uv_status(0);
1633  auto uv_ret = ::uv_poll_start(static_cast< uv_t* >(uv_handle), _events, poll_cb);
1634  if (uv_ret < 0)
1635  {
1636  uv_status(uv_ret);
1637  properties.opcmd_state = opcmd::UNKNOWN;
1638  instance_ptr->unref(); // UNREF:START_FAILURE -- release the extra reference on failure
1639  }
1640 
1641  return uv_ret;
1642  }
1643 
1644  /*! \brief Start the handle with the given callback.
1645  \details This is equivalent for
1646  ```
1647  poll.on_poll() = std::bind(
1648  std::forward< _Cb_ >(_cb), std::placeholders::_1, std::placeholders::_2, std::forward< _Args_ >(_args)...
1649  );
1650  poll.start(_events);
1651  ```
1652  \sa `poll::start()` */
1653  template< class _Cb_, typename... _Args_, typename = std::enable_if_t< std::is_convertible<
1654  decltype(std::bind(std::declval< _Cb_ >(), std::placeholders::_1, std::placeholders::_2, static_cast< _Args_&& >(std::declval< _Args_ >())...)),
1655  on_poll_t
1656  >::value > >
1657  int start(int _events, _Cb_ &&_cb, _Args_&&... _args) const
1658  {
1659  on_poll() = std::bind(std::forward< _Cb_ >(_cb), std::placeholders::_1, std::placeholders::_2, std::forward< _Args_ >(_args)...);
1660  return start(_events);
1661  }
1662 
1663  /*! \brief Stop the handle, the callback will no longer be called. */
1664  int stop() const noexcept
1665  {
1666  auto instance_ptr = instance::from(uv_handle);
1667  auto &opcmd_state = instance_ptr->properties().opcmd_state;
1668 
1669  auto opcmd_state0 = opcmd_state;
1670  opcmd_state = opcmd::STOP;
1671 
1672  auto uv_ret = uv_status(::uv_poll_stop(static_cast< uv_t* >(uv_handle)));
1673 
1674  switch (opcmd_state0)
1675  {
1676  case opcmd::UNKNOWN:
1677  case opcmd::STOP:
1678  break;
1679  case opcmd::START:
1680  instance_ptr->unref(); // UNREF:STOP -- release the reference from start()
1681  break;
1682  }
1683 
1684  return uv_ret;
1685  }
1686 
1687 public: /*conversion operators*/
1688  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
1689  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
1690 };
1691 
1692 template< typename >
1693 void poll::poll_cb(::uv_poll_t *_uv_handle, int _status, int _events)
1694 {
1695  auto instance_ptr = instance::from(_uv_handle);
1696  instance_ptr->uv_error = _status;
1697  auto &poll_cb = instance_ptr->properties().poll_cb;
1698  if (poll_cb) poll_cb(poll(_uv_handle), _events);
1699 }
1700 
1701 
1702 }
1703 
1704 
1705 #endif
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
int stop() const noexcept
Stop the handle, the callback will no longer be called.
on_exit_t & on_exit() const noexcept
Set the callback function called when the child process exits.
int start(int _events) const
Start the handle.
int start() const
Start the handle for watching for the signal.
on_idle_t & on_idle() const noexcept
Set the handle&#39;s callback.
int start(_Cb_ &&_cb, _Args_ &&... _args) const
Start the handle with the given callback.
Idle handle.
void set_working_dir(const char *_cwd) const noexcept
Set current working directory when spawning the child process.
int start(_Cb_ &&_cb, _Args_ &&... _args) const
Start the handle with the given signal callback.
::uv_handle_type type() const noexcept
The tag indicating the libuv type of the handle.
Process handle.
void set_environment(char *_envp[]) const noexcept
Set pointer to environment for the child process. If nullptr the parents environment is used...
int stop() const noexcept
Stop the handle, the callback will no longer be called.
on_timer_t & on_timer() const noexcept
Set the timer callback.
timer(uv::loop &_loop, uint64_t _repeat_interval=0)
Create a timer handle which has a given repeat interval.
int start(_Cb_ &&_cb, _Args_ &&... _args) const
Start the handle with the given callback.
Timer handle.
int start(_Cb_ &&_cb, _Args_ &&... _args) const
Start the handle with the given callback.
Prepare handle.
poll(uv::loop &_loop, ::uv_os_sock_t _socket)
Create a poll handle for a socket descriptor. (Windows only.)
check(uv::loop &_loop)
Create an check handle.
int uv_status() const noexcept
The status value returned by the last executed libuv API function on this handle. ...
The base class for the libuv handles.
Definition: handle-base.hpp:33
Check handle.
std::uintptr_t id() const noexcept
The unique ID of the instance managed by this handle variable or 0 if the handle is void...
int send() const
Wakeup the event loop and call the async callback.
Definition: handle-misc.hpp:94
Signal handle.
process(uv::loop &_loop)
Create a process handle.
on_check_t & on_check() const noexcept
Set the handle&#39;s callback.
void repeat_interval(uint64_t _value) noexcept
Set the timer repeat interval in milliseconds.
int pid() const noexcept
The PID of the child process. It is set after calling spawn().
int start(int _events, _Cb_ &&_cb, _Args_ &&... _args) const
Start the handle with the given callback.
void inherit_stdio(unsigned _target_fd_number, io _io) const
Set the io endpoint that should be available to the child process as the target stdio file descriptor...
void set_uid(::uv_uid_t _uid) const noexcept
Set the child process&#39; user id.
void set_gid(::uv_gid_t _gid) const noexcept
Set the child process&#39; group id.
int start() const
Start the handle.
int start(uint64_t _timeout, _Cb_ &&_cb, _Args_ &&... _args) const
Start the timer with the given callback.
prepare(uv::loop &_loop)
Create an prepare handle.
int stop() const noexcept
Stop the handle, the callback will no longer be called.
int start(int _signum, _Cb_ &&_cb, _Args_ &&... _args) const
Start the handle with the given signal callback, watching for the given signal number.
void inherit_stdio(unsigned _target_fd_number, ::uv_file _fd) const
Set the file descriptor that should be inherited by the child process as the target stdio descriptor ...
on_send_t & on_send() const noexcept
Set the async event callback.
Definition: handle-misc.hpp:90
The I/O event loop class.
Definition: loop.hpp:33
The base class for handles representing I/O endpoints: a file, TCP/UDP socket, pipe, TTY.
Definition: handle-io.hpp:25
A scoped reference counting guard.
Definition: utility.hpp:280
Async handle.
Definition: handle-misc.hpp:25
int start(uint64_t _timeout) const
Start the timer by scheduling a timer event after the _timeout interval expires.
Pipe handle.
on_poll_t & on_poll() const noexcept
Set the handle&#39;s callback.
int send(_Cb_ &&_cb, _Args_ &&... _args) const
Set the given async callback and send wakeup event to the target loop.
async(uv::loop &_loop)
Create an async handle.
Definition: handle-misc.hpp:78
on_signal_t & on_signal() const noexcept
Set the signal callback.
poll(uv::loop &_loop, int _fd)
Create a poll handle for a file descriptor (Windows and Unix-like systems) or for a socket descriptor...
int kill(int _signum) const noexcept
Send the specified signal to the child process.
int spawn(const char *_file, char *_argv[], ::uv_process_flags _flags=static_cast< ::uv_process_flags >(0)) const noexcept
Create and start a new child process.
uint64_t repeat_interval() const noexcept
Get the timer repeat interval in milliseconds.
on_prepare_t & on_prepare() const noexcept
Set the handle&#39;s callback.
static void disable_stdio_inheritance() noexcept
Force child processes spawned by this process not to inherit file descriptors/handles that this proce...
static int kill(int _pid, int _signum) noexcept
Send the specified signal to the given PID.
idle(uv::loop &_loop)
Create an idle handle.
signal(uv::loop &_loop, int _signum)
Create a signal handle watching for _signum signal.
int start() const
Start the handle.
int signum() const noexcept
Get the signal number being watched for by this handle.
int create_stdio_pipe(unsigned _target_fd_number, uv::loop &_pipe_loop, ::uv_stdio_flags _pipe_flags, bool _ipc=false) const
Create a pipe to the child process&#39; stdio fd number.
int stop() const noexcept
Stop the handle, the callback will no longer be called.
int start() const
Start the handle.
std::vector< io > & stdio() const noexcept
The stdio endpoints to be set for the child process.
int stop() const noexcept
Stop the handle, the callback will no longer be called.
int stop() const noexcept
Stop the timer, the callback will not be called anymore.