uvcc
libuv C++ bindings
handle-base.hpp
1 
2 #ifndef UVCC_HANDLE_BASE__HPP
3 #define UVCC_HANDLE_BASE__HPP
4 
5 #include "uvcc/debug.hpp"
6 #include "uvcc/utility.hpp"
7 #include "uvcc/loop.hpp"
8 
9 #include <cstddef> // size_t offsetof
10 #include <cstdint> // uintptr_t
11 #include <uv.h>
12 
13 #ifdef _WIN32
14 #include <io.h> // _get_osfhandle()
15 #endif
16 
17 #include <functional> // function
18 #include <type_traits> // is_standard_layout enable_if_t is_same
19 #include <utility> // forward() swap()
20 
21 
22 #define HACK_UV_INTERFACE_PTR 1
23 
24 namespace uv
25 {
26 
27 
28 /*! \ingroup doxy_group__handle
29  \brief The base class for the libuv handles.
30  \details Derived classes conceptually are just interfaces to the data stored
31  in the base class, so there are no any virtual member functions.
32  \sa libuv API documentation: [`uv_handle_t` — Base handle](http://docs.libuv.org/en/v1.x/handle.html#uv-handle-t-base-handle). */
33 class handle
34 {
35  //! \cond
36  friend class loop;
37  friend class request;
38  //! \endcond
39 
40 public: /*types*/
41  using uv_t = ::uv_handle_t;
42  using on_destroy_t = std::function< void(void *_data) >;
43  /*!< \brief The function type of the callback called when the handle has been closed and about to be destroyed.
44  \sa libuv API documentation: [`uv_close_cb`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_close_cb),
45  [`uv_close()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_close). */
46 
47 protected: /*types*/
48  //! \cond internals
49  //! \addtogroup doxy_group__internals
50  //! \{
51 
52  struct properties {};
53  constexpr static const std::size_t MAX_PROPERTY_SIZE = 136 + sizeof(::uv_buf_t) + sizeof(::uv_fs_t);
54  constexpr static const std::size_t MAX_PROPERTY_ALIGN = 8;
55 
56  struct uv_interface
57  {
58  template< class _Handle_ >
59  static typename _Handle_::uv_interface& instance()
60  {
61  static typename _Handle_::uv_interface instance;
62  return instance;
63  }
64 
65  virtual ~uv_interface() = default;
66 
67  virtual void close(void*) noexcept = 0;
68  virtual ::uv_handle_type type(void*) const noexcept = 0;
69  virtual ::uv_loop_t* loop(void*) const noexcept = 0;
70  virtual void*& data(void*) noexcept = 0;
71  virtual int fileno(void*, ::uv_os_fd_t&) const noexcept = 0;
72  virtual int is_active(void*) const noexcept = 0;
73  virtual int is_closing(void*) const noexcept = 0;
74  virtual void ref(void*) const noexcept = 0;
75  virtual void unref(void*) const noexcept = 0;
76  virtual int has_ref(void*) const noexcept = 0;
77  };
78  struct uv_handle_interface;
79  struct uv_fs_interface;
80 
81  template< class _Handle_ > class instance
82  {
83  struct uv_t
84  {
85  template< typename _T_, typename = std::size_t > struct substitute { using type = void; };
86  template< typename _T_ > struct substitute< _T_, decltype(sizeof(typename _T_::uv_t)) > { using type = typename _T_::uv_t; };
87  template< typename _T_ > struct substitute< _T_, std::enable_if_t< std::is_same< typename _T_::uv_t, void >::value, std::size_t > >
88  {
89  using type = union {
90  ::uv_any_handle uv_handle_data;
91  ::uv_fs_t uv_fs_data;
92  };
93  }; // a specialization for `io` handle class
94  using type = typename substitute< _Handle_ >::type;
95  };
96 
97  public: /*data*/
98  mutable int uv_error = 0;
99  ref_count refs;
100  type_storage< on_destroy_t > destroy_cb_storage;
101  aligned_storage< MAX_PROPERTY_SIZE, MAX_PROPERTY_ALIGN > property_storage;
102 #ifndef HACK_UV_INTERFACE_PTR
103  handle::uv_interface *uv_interface_ptr = nullptr;
104 #else
105  typename _Handle_::uv_interface *uv_interface_ptr = nullptr;
106 #endif
107  loop::instance *loop_instance_ptr = nullptr;
108  //* all the fields placed before should have immutable layout size across the handle class hierarchy *//
109  alignas(greatest(alignof(::uv_any_handle), alignof(::uv_fs_t))) typename uv_t::type uv_handle_struct = { 0,};
110 
111  private: /*constructors*/
112  instance()
113  {
114  property_storage.reset< typename _Handle_::properties >();
115  uv_interface_ptr = &uv_interface::instance< _Handle_ >();
116  uvcc_debug_function_return("instance [0x%08tX] for handle [0x%08tX]", (ptrdiff_t)this, (ptrdiff_t)&uv_handle_struct);
117  }
118  template< typename... _Args_ > instance(_Args_&&... _args)
119  {
120  property_storage.reset< typename _Handle_::properties >(std::forward< _Args_ >(_args)...);
121  uv_interface_ptr = &uv_interface::instance< _Handle_ >();
122  uvcc_debug_function_return("instance [0x%08tX] for handle [0x%08tX]", (ptrdiff_t)this, (ptrdiff_t)&uv_handle_struct);
123  }
124 
125  public: /* constructors*/
126  ~instance()
127  {
128  uvcc_debug_function_enter("instance [0x%08tX] for handle [0x%08tX]", (ptrdiff_t)this, (ptrdiff_t)&uv_handle_struct);
129  unbook_loop();
130  }
131 
132  instance(const instance&) = delete;
133  instance& operator =(const instance&) = delete;
134 
135  instance(instance&&) = delete;
136  instance& operator =(instance&&) = delete;
137 
138  public: /*interface*/
139  static void* create() { return &(new instance)->uv_handle_struct; }
140  template< typename... _Args_ > static void* create(_Args_&&... _args)
141  {
142  return &(new instance(std::forward< _Args_ >(_args)...))->uv_handle_struct;
143  }
144 
145  constexpr static instance* from(void *_uv_handle) noexcept
146  {
147  static_assert(std::is_standard_layout< instance >::value, "not a standard layout type");
148  return reinterpret_cast< instance* >(static_cast< char* >(_uv_handle) - offsetof(instance, uv_handle_struct));
149  }
150 
151  typename _Handle_::properties& properties() noexcept
152  { return property_storage.get< typename _Handle_::properties >(); }
153 
154  typename _Handle_::uv_interface* uv_interface() const noexcept
155 #ifndef HACK_UV_INTERFACE_PTR
156  { return dynamic_cast/* from a virtual base */< typename _Handle_::uv_interface* >(uv_interface_ptr); }
157 #else
158  /* any uv_interface subclass is a __vptr only object with no any data members,
159  there is also no needs to switch between the actual __vtable targets
160  as far as uv_interface subclasses override only not defined pure virtual functions from their base classes,
161  so we can just use __vptr from the concrete uv_interface leaf subclass object
162  (and simply use it according to the one of the desired uv_interface base class context if ever necessary) */
163  { return uv_interface_ptr; }
164 #endif
165 
166  void ref()
167  {
168  uvcc_debug_function_enter("handle [0x%08tX]", (ptrdiff_t)&uv_handle_struct);
169  refs.inc();
170  }
171  void unref()
172  {
173  uvcc_debug_function_enter("handle [0x%08tX]", (ptrdiff_t)&uv_handle_struct);
174  auto nrefs = refs.dec();
175  uvcc_debug_condition(nrefs == 0, "handle [0x%08tX] (nrefs=%li)", (ptrdiff_t)&uv_handle_struct, nrefs);
176  if (nrefs == 0) uv_interface_ptr->close(&uv_handle_struct);
177  }
178 
179  void book_loop()
180  {
181  uvcc_debug_function_enter(
182  "handle [0x%08tX], loop [0x%08tX]", (ptrdiff_t)&uv_handle_struct, (ptrdiff_t)uv_interface_ptr->loop(&uv_handle_struct)
183  );
184  unbook_loop();
185  loop_instance_ptr = loop::instance::from(uv_interface_ptr->loop(&uv_handle_struct));
186  loop_instance_ptr->ref();
187  }
188  void unbook_loop()
189  {
190  uvcc_debug_do_if(loop_instance_ptr,
191  uvcc_debug_function_enter("handle [0x%08tX], loop [0x%08tX]", (ptrdiff_t)&uv_handle_struct, (ptrdiff_t)&loop_instance_ptr->uv_loop_struct)
192  );
193  if (loop_instance_ptr)
194  {
195  loop_instance_ptr->unref();
196  loop_instance_ptr = nullptr;
197  }
198  }
199  };
200  //! \cond
201  template< class _Handle_ > friend typename _Handle_::instance* debug::instance(_Handle_&) noexcept;
202  //! \endcond
203 
204  //! \}
205  //! \endcond
206 
207 protected: /*data*/
208  //! \cond
209  void *uv_handle;
210  //! \endcond
211 
212 protected: /*constructors*/
213  //! \cond
214  handle() noexcept : uv_handle(nullptr) {}
215 
216  explicit handle(uv_t *_uv_handle)
217  {
218  if (_uv_handle) instance< handle >::from(_uv_handle)->ref();
219  uv_handle = _uv_handle;
220  }
221  //! \endcond
222 
223 public: /*constructors*/
224  ~handle() { if (uv_handle) instance< handle >::from(uv_handle)->unref(); }
225 
226  handle(const handle &_that) : handle(static_cast< uv_t* >(_that.uv_handle)) {}
227  handle& operator =(const handle &_that)
228  {
229  if (this != &_that)
230  {
231  if (_that.uv_handle) instance< handle >::from(_that.uv_handle)->ref();
232  auto t = uv_handle;
233  uv_handle = _that.uv_handle;
234  if (t) instance< handle >::from(t)->unref();
235  }
236  return *this;
237  }
238 
239  handle(handle &&_that) noexcept : uv_handle(_that.uv_handle) { _that.uv_handle = nullptr; }
240  handle& operator =(handle &&_that) noexcept
241  {
242  if (this != &_that)
243  {
244  auto t = uv_handle;
245  uv_handle = _that.uv_handle;
246  _that.uv_handle = nullptr;
247  if (t) instance< handle >::from(t)->unref();
248  }
249  return *this;
250  }
251 
252 protected: /*functions*/
253  //! \cond
254  int uv_status(int _value) const noexcept
255  {
256  instance< handle >::from(uv_handle)->uv_error = _value;
257  return _value;
258  }
259  //! \endcond
260 
261 public: /*interface*/
262  void swap(handle &_that) noexcept { std::swap(uv_handle, _that.uv_handle); }
263 
264  /*! \brief The unique ID of the instance managed by this handle variable or **0** if the handle is void. */
265  std::uintptr_t id() const noexcept
266  {
267  return reinterpret_cast< std::uintptr_t >(
268  uv_handle ? instance< handle >::from(uv_handle) : 0
269  );
270  }
271 
272  /*! \brief The current number of existing references to the same object as this handle variable refers to. */
273  long nrefs() const noexcept { return instance< handle >::from(uv_handle)->refs.get_value(); }
274 
275  /*! \brief The status value returned by the last executed libuv API function on this handle. */
276  int uv_status() const noexcept { return instance< handle >::from(uv_handle)->uv_error; }
277 
278  on_destroy_t& on_destroy() const noexcept { return instance< handle >::from(uv_handle)->destroy_cb_storage.value(); }
279 
280  /*! \brief The tag indicating the libuv type of the handle. */
281  ::uv_handle_type type() const noexcept { return instance< handle >::from(uv_handle)->uv_interface()->type(uv_handle); }
282  /*! \brief A string containing the name of the handle type. */
283  const char* type_name() const noexcept
284  {
285  const char *ret;
286 
287  switch (type())
288  {
289  case UV_UNKNOWN_HANDLE: ret = "UNKNOWN"; break;
290 #define XX(X, x) case UV_##X: ret = #x; break;
291  UV_HANDLE_TYPE_MAP(XX)
292 #undef XX
293  case UV_FILE: ret = "file"; break;
294  default: ret = "<UNDEFINED>"; break;
295  }
296 
297  return ret;
298  }
299 
300  /*! \brief The libuv loop where the handle is running on.
301  \details It is guaranteed that it will be a valid instance at least within the callback of the requests
302  running on the handle. */
303  uv::loop loop() const noexcept { return uv::loop(instance< handle >::from(uv_handle)->uv_interface()->loop(uv_handle)); }
304 
305  /*! \name Functions to detach/attach a handle to the libuv loop for processing handle's events:
306  They provide access to the libuv API functions to reference/un-reference the given handle by the event loop
307  that the handle is running on:
308  [`uv_ref()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_ref),
309  [`uv_unref()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_unref),
310  [`uv_has_ref()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_has_ref).
311  \sa libuv API documentation: [Reference counting](http://docs.libuv.org/en/v1.x/handle.html#reference-counting). */
312  //! \{
313  void attached(bool _state) const noexcept
314  {
315  if (_state)
316  ::uv_ref(static_cast< uv_t* >(uv_handle));
317  else
318  ::uv_unref(static_cast< uv_t* >(uv_handle));
319  }
320  bool attached() const noexcept
321  {
322  return instance< handle >::from(uv_handle)->uv_interface()->has_ref(uv_handle);
323  }
324  //! \}
325 
326  /*! \brief The pointer to the user-defined arbitrary data. libuv and uvcc does not use this field. */
327  void*& data() const noexcept { return instance< handle >::from(uv_handle)->uv_interface()->data(uv_handle); }
328 
329  /*! \brief Check if the handle is active.
330  \sa libuv API documentation: [`uv_is_active()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_is_active). */
331  int is_active() const noexcept
332  { return uv_status(instance< handle >::from(uv_handle)->uv_interface()->is_active(uv_handle)); }
333  /*! \brief Check if the handle is closing or closed.
334  \sa libuv API documentation: [`uv_is_closing()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_is_closing). */
335  int is_closing() const noexcept
336  { return uv_status(instance< handle >::from(uv_handle)->uv_interface()->is_closing(uv_handle)); }
337 
338 #if 0
339  /*! \brief _Get_ the size of the send buffer that the operating system uses for the socket.
340  \sa libuv API documentation: [`uv_send_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_send_buffer_size). */
341  unsigned int send_buffer_size() const noexcept
342  {
343  unsigned int v = 0;
344  uv_status(::uv_send_buffer_size(static_cast< uv_t* >(uv_handle), (int*)&v));
345  return v;
346  }
347  /*! \brief _Set_ the size of the send buffer that the operating system uses for the socket.
348  \sa libuv API documentation: [`uv_send_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_send_buffer_size). */
349  void send_buffer_size(unsigned int _value) noexcept { uv_status(::uv_send_buffer_size(static_cast< uv_t* >(uv_handle), (int*)&_value)); }
350 
351  /*! \brief _Get_ the size of the receive buffer that the operating system uses for the socket.
352  \sa libuv API documentation: [`uv_recv_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_recv_buffer_size). */
353  unsigned int recv_buffer_size() const noexcept
354  {
355  unsigned int v = 0;
356  uv_status(::uv_recv_buffer_size(static_cast< uv_t* >(uv_handle), (int*)&v));
357  return v;
358  }
359  /*! \brief _Set_ the size of the receive buffer that the operating system uses for the socket.
360  \sa libuv API documentation: [`uv_recv_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_recv_buffer_size). */
361  void recv_buffer_size(unsigned int _value) noexcept { uv_status(::uv_recv_buffer_size(static_cast< uv_t* >(uv_handle), (int*)&_value)); }
362 #endif
363 
364  /*! \brief Get the platform dependent handle/file descriptor.
365  \sa libuv API documentation: [`uv_fileno()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_fileno). */
366  ::uv_os_fd_t fileno() const noexcept
367  {
368  ::uv_os_fd_t h;
369  uv_status(instance< handle >::from(uv_handle)->uv_interface()->fileno(uv_handle, h));
370  return h;
371  }
372 
373 public: /*conversion operators*/
374  explicit operator const uv_t*() const noexcept { return instance< handle >::from(uv_handle)->uv_interface()->type(uv_handle) == UV_FILE ? nullptr : static_cast< const uv_t* >(uv_handle); }
375  explicit operator uv_t*() noexcept { return instance< handle >::from(uv_handle)->uv_interface()->type(uv_handle) == UV_FILE ? nullptr : static_cast< uv_t* >(uv_handle); }
376 
377  /*! \brief Equivalent to `(id() and uv_status() >= 0)`. */
378  explicit operator bool() const noexcept { return (uv_handle and uv_status() >= 0); }
379 };
380 
381 
382 //! \cond internals
383 //! \addtogroup doxy_group__internals
384 //! \{
385 struct handle::uv_handle_interface : virtual uv_interface
386 {
387  template< typename = void > static void close_cb(::uv_handle_t*);
388 
389  void close(void *_uv_handle) noexcept override
390  {
391  auto uv_handle = static_cast< ::uv_handle_t* >(_uv_handle);
392  uvcc_debug_function_enter("%s handle [0x%08tX]", debug::handle_type_name(uv_handle), (ptrdiff_t)uv_handle);
393 
394  /*auto loop_alive = ::uv_loop_alive(uv_handle->loop);
395  uvcc_debug_condition(loop_alive, "is loop [0x%08tX] (stop_flag=%u) associated with handle [0x%08tX] alive", (ptrdiff_t)uv_handle->loop, uv_handle->loop->stop_flag, (ptrdiff_t)uv_handle);
396  if (loop_alive)
397  {
398  uvcc_debug_log_if(uv_handle->type == 0, "handle [0x%08tX]: don't call ::uv_close() for handle not having been initialized by libuv", (ptrdiff_t)uv_handle);
399  if (uv_handle->type != 0)
400  {
401  uvcc_debug_log_if(true, "handle [0x%08tX]: call close callback asynchronously", (ptrdiff_t)uv_handle);
402  ::uv_close(uv_handle, close_cb);
403  }
404  else
405  {
406  uvcc_debug_log_if(true, "handle [0x%08tX]: call close callback synchronously", (ptrdiff_t)uv_handle);
407  close_cb(uv_handle);
408  }
409  }
410  else*/
411  // the (loop_alive == 1) state or (stop_flag == 0) doesn't mean that loop is running or will be running,
412  // therefore don't let the destroy procedure ever to rely on the libuv loop
413  {
414  uvcc_debug_log_if(true, "handle [0x%08tX]: call close callback synchronously", (ptrdiff_t)uv_handle);
415 
416  uvcc_debug_log_if(uv_handle->type == 0, "handle [0x%08tX]: don't call ::uv_close() for handle not having been initialized by libuv", (ptrdiff_t)uv_handle);
417  if (uv_handle->type != 0) ::uv_close(uv_handle, nullptr);
418 
419  close_cb(uv_handle);
420  }
421  }
422 
423  ::uv_handle_type type(void *_uv_handle) const noexcept override { return static_cast< ::uv_handle_t* >(_uv_handle)->type; }
424  ::uv_loop_t* loop(void *_uv_handle) const noexcept override { return static_cast< ::uv_handle_t* >(_uv_handle)->loop; }
425  void*& data(void *_uv_handle) noexcept override { return static_cast< ::uv_handle_t* >(_uv_handle)->data; }
426 
427  int fileno(void *_uv_handle, ::uv_os_fd_t &_h) const noexcept override
428  {
429 #ifdef _WIN32
430  _h = INVALID_HANDLE_VALUE;
431 #else
432  _h = -1;
433 #endif
434  return ::uv_fileno(static_cast< ::uv_handle_t* >(_uv_handle), &_h);
435  }
436 
437  int is_active(void *_uv_handle) const noexcept override { return ::uv_is_active(static_cast< ::uv_handle_t* >(_uv_handle)); }
438  int is_closing(void *_uv_handle) const noexcept override { return ::uv_is_closing(static_cast< ::uv_handle_t* >(_uv_handle)); }
439 
440  void ref(void *_uv_handle) const noexcept override { ::uv_ref(static_cast< ::uv_handle_t* >(_uv_handle)); }
441  void unref(void *_uv_handle) const noexcept override { ::uv_unref(static_cast< ::uv_handle_t* >(_uv_handle)); }
442  int has_ref(void *_uv_handle) const noexcept override { return ::uv_has_ref(static_cast< ::uv_handle_t* >(_uv_handle)); }
443 };
444 //! \}
445 //! \endcond
446 
447 template< typename >
448 void handle::uv_handle_interface::close_cb(::uv_handle_t *_uv_handle)
449 {
450  uvcc_debug_function_enter("%s handle [0x%08tX]", debug::handle_type_name(_uv_handle), (ptrdiff_t)_uv_handle);
451 
452  auto instance_ptr = handle::instance< handle >::from(_uv_handle);
453 
454  auto &destroy_cb = instance_ptr->destroy_cb_storage.value();
455  if (destroy_cb) destroy_cb(_uv_handle->data);
456 
457  delete instance_ptr;
458 }
459 
460 
461 //! \cond internals
462 //! \addtogroup doxy_group__internals
463 //! \{
464 struct handle::uv_fs_interface : virtual uv_interface
465 {
466  void close(void *_uv_fs) noexcept override
467  {
468  uvcc_debug_function_enter("fs handle [0x%08tX]", (ptrdiff_t)_uv_fs);
469 
470  auto instance_ptr = handle::instance< handle >::from(_uv_fs);
471  auto uv_fs = static_cast< ::uv_fs_t* >(_uv_fs);
472  auto fd = static_cast< ::uv_file >(uv_fs->result);
473 
474  if (fd >= 0)
475  {
476  ::uv_fs_t req_close;
477  ::uv_fs_close(nullptr, &req_close, fd, nullptr); // XXX : nullptr for loop
478  ::uv_fs_req_cleanup(&req_close);
479  }
480 
481  auto &destroy_cb = instance_ptr->destroy_cb_storage.value();
482  if (destroy_cb) destroy_cb(uv_fs->data);
483 
484  ::uv_fs_req_cleanup(uv_fs);
485  delete instance_ptr;
486  }
487 
488  ::uv_handle_type type(void *_uv_fs) const noexcept override { return UV_FILE; }
489  ::uv_loop_t* loop(void *_uv_fs) const noexcept override { return static_cast< ::uv_fs_t* >(_uv_fs)->loop; }
490  void*& data(void *_uv_fs) noexcept override { return static_cast< ::uv_fs_t* >(_uv_fs)->data; }
491 
492  int fileno(void *_uv_fs, ::uv_os_fd_t &_h) const noexcept override
493  {
494  auto fd = static_cast< ::uv_file >(static_cast< ::uv_fs_t* >(_uv_fs)->result);
495 
496 #ifdef _WIN32
497  /*! \sa Windows: [`_get_osfhandle()`](https://msdn.microsoft.com/en-us/library/ks2530z6.aspx). */
498  _h = fd >= 0 ? (HANDLE)::_get_osfhandle(fd) : INVALID_HANDLE_VALUE;
499  return _h == INVALID_HANDLE_VALUE ? UV_EBADF : 0;
500 #else
501  _h = static_cast< ::uv_os_fd_t >(fd);
502  return _h == -1 ? UV_EBADF : 0;
503 #endif
504  }
505 
506  int is_active(void *_uv_fs) const noexcept override { return 0; }
507 
508  void ref(void *_uv_fs) const noexcept override {}
509  void unref(void *_uv_fs) const noexcept override {}
510  int has_ref(void *_uv_fs) const noexcept override { return 0; }
511 };
512 //! \}
513 //! \endcond
514 
515 
516 }
517 
518 
519 namespace std
520 {
521 
522 //! \ingroup doxy_group__handle
523 template<> inline void swap(uv::handle &_this, uv::handle &_that) noexcept { _this.swap(_that); }
524 
525 }
526 
527 
528 #endif
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
A wrapper providing the feature of being a standard layout type for the given type _T_...
Definition: utility.hpp:475
::uv_handle_type type() const noexcept
The tag indicating the libuv type of the 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
std::uintptr_t id() const noexcept
The unique ID of the instance managed by this handle variable or 0 if the handle is void...
long nrefs() const noexcept
The current number of existing references to the same object as this handle variable refers to...
The I/O event loop class.
Definition: loop.hpp:33
A reference counter with atomic increment/decrement.
Definition: utility.hpp:229
const char * type_name() const noexcept
A string containing the name of the handle type.
#define HACK_UV_INTERFACE_PTR
Definition: handle-base.hpp:22