cmUVHandlePtr.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #pragma once
  4. #include "cmConfigure.h" // IWYU pragma: keep
  5. #include <algorithm>
  6. #include <cstddef>
  7. #include <cstdint>
  8. #include <memory>
  9. #include <type_traits>
  10. #include "cm_uv.h"
  11. #define CM_PERFECT_FWD_CTOR(Class, FwdTo) \
  12. template <typename... Args> \
  13. Class(Args&&... args) \
  14. : FwdTo(std::forward<Args>(args)...) \
  15. { \
  16. }
  17. namespace cm {
  18. /***
  19. * RAII class to simplify and insure the safe usage of uv_*_t types. This
  20. * includes making sure resources are properly freed and contains casting
  21. * operators which allow for passing into relevant uv_* functions.
  22. *
  23. *@tparam T actual uv_*_t type represented.
  24. */
  25. template <typename T>
  26. class uv_handle_ptr_base_
  27. {
  28. protected:
  29. template <typename _T>
  30. friend class uv_handle_ptr_base_;
  31. /**
  32. * This must be a pointer type since the handle can outlive this class.
  33. * When uv_close is eventually called on the handle, the memory the
  34. * handle inhabits must be valid until the close callback is called
  35. * which can be later on in the loop.
  36. */
  37. std::shared_ptr<T> handle;
  38. /**
  39. * Allocate memory for the type and optionally set it's 'data' pointer.
  40. * Protected since this should only be called for an appropriate 'init'
  41. * call.
  42. *
  43. * @param data data pointer to set
  44. */
  45. void allocate(void* data = nullptr);
  46. public:
  47. CM_DISABLE_COPY(uv_handle_ptr_base_)
  48. uv_handle_ptr_base_(uv_handle_ptr_base_&&) noexcept;
  49. uv_handle_ptr_base_& operator=(uv_handle_ptr_base_&&) noexcept;
  50. /**
  51. * This move constructor allows us to move out of a more specialized
  52. * uv type into a less specialized one. The only constraint is that
  53. * the right hand side is castable to T.
  54. *
  55. * This allows you to return uv_handle_ptr or uv_stream_ptr from a function
  56. * that initializes something like uv_pipe_ptr or uv_tcp_ptr and interact
  57. * and clean up after it without caring about the exact type.
  58. */
  59. template <typename S, typename = typename std::enable_if<
  60. std::is_rvalue_reference<S&&>::value>::type>
  61. uv_handle_ptr_base_(S&& rhs)
  62. {
  63. // This will force a compiler error if rhs doesn't have a casting
  64. // operator to get T*
  65. this->handle = std::shared_ptr<T>(rhs.handle, rhs);
  66. rhs.handle.reset();
  67. }
  68. // Dtor and ctor need to be inline defined like this for default ctors and
  69. // dtors to work.
  70. uv_handle_ptr_base_() {}
  71. uv_handle_ptr_base_(std::nullptr_t) {}
  72. ~uv_handle_ptr_base_() { reset(); }
  73. /**
  74. * Properly close the handle if needed and sets the inner handle to nullptr
  75. */
  76. void reset();
  77. /**
  78. * Allow less verbose calling of uv_handle_* functions
  79. * @return reinterpreted handle
  80. */
  81. operator uv_handle_t*();
  82. T* get() const;
  83. T* operator->() const noexcept;
  84. };
  85. template <typename T>
  86. inline uv_handle_ptr_base_<T>::uv_handle_ptr_base_(
  87. uv_handle_ptr_base_<T>&&) noexcept = default;
  88. template <typename T>
  89. inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=(
  90. uv_handle_ptr_base_<T>&&) noexcept = default;
  91. /**
  92. * While uv_handle_ptr_base_ only exposes uv_handle_t*, this exposes uv_T_t*
  93. * too. It is broken out like this so we can reuse most of the code for the
  94. * uv_handle_ptr class.
  95. */
  96. template <typename T>
  97. class uv_handle_ptr_ : public uv_handle_ptr_base_<T>
  98. {
  99. template <typename _T>
  100. friend class uv_handle_ptr_;
  101. public:
  102. CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<T>);
  103. /***
  104. * Allow less verbose calling of uv_<T> functions
  105. * @return reinterpreted handle
  106. */
  107. operator T*() const;
  108. };
  109. /***
  110. * This specialization is required to avoid duplicate 'operator uv_handle_t*()'
  111. * declarations
  112. */
  113. template <>
  114. class uv_handle_ptr_<uv_handle_t> : public uv_handle_ptr_base_<uv_handle_t>
  115. {
  116. public:
  117. CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<uv_handle_t>);
  118. };
  119. class uv_async_ptr : public uv_handle_ptr_<uv_async_t>
  120. {
  121. public:
  122. CM_PERFECT_FWD_CTOR(uv_async_ptr, uv_handle_ptr_<uv_async_t>);
  123. int init(uv_loop_t& loop, uv_async_cb async_cb, void* data = nullptr);
  124. void send();
  125. };
  126. struct uv_signal_ptr : public uv_handle_ptr_<uv_signal_t>
  127. {
  128. CM_PERFECT_FWD_CTOR(uv_signal_ptr, uv_handle_ptr_<uv_signal_t>);
  129. int init(uv_loop_t& loop, void* data = nullptr);
  130. int start(uv_signal_cb cb, int signum);
  131. void stop();
  132. };
  133. struct uv_pipe_ptr : public uv_handle_ptr_<uv_pipe_t>
  134. {
  135. CM_PERFECT_FWD_CTOR(uv_pipe_ptr, uv_handle_ptr_<uv_pipe_t>);
  136. operator uv_stream_t*() const;
  137. int init(uv_loop_t& loop, int ipc, void* data = nullptr);
  138. };
  139. struct uv_process_ptr : public uv_handle_ptr_<uv_process_t>
  140. {
  141. CM_PERFECT_FWD_CTOR(uv_process_ptr, uv_handle_ptr_<uv_process_t>);
  142. int spawn(uv_loop_t& loop, uv_process_options_t const& options,
  143. void* data = nullptr);
  144. };
  145. struct uv_timer_ptr : public uv_handle_ptr_<uv_timer_t>
  146. {
  147. CM_PERFECT_FWD_CTOR(uv_timer_ptr, uv_handle_ptr_<uv_timer_t>);
  148. int init(uv_loop_t& loop, void* data = nullptr);
  149. int start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat);
  150. };
  151. struct uv_tty_ptr : public uv_handle_ptr_<uv_tty_t>
  152. {
  153. CM_PERFECT_FWD_CTOR(uv_tty_ptr, uv_handle_ptr_<uv_tty_t>);
  154. operator uv_stream_t*() const;
  155. int init(uv_loop_t& loop, int fd, int readable, void* data = nullptr);
  156. };
  157. typedef uv_handle_ptr_<uv_stream_t> uv_stream_ptr;
  158. typedef uv_handle_ptr_<uv_handle_t> uv_handle_ptr;
  159. #ifndef cmUVHandlePtr_cxx
  160. extern template class uv_handle_ptr_base_<uv_handle_t>;
  161. #define UV_HANDLE_PTR_INSTANTIATE_EXTERN(NAME) \
  162. extern template class uv_handle_ptr_base_<uv_##NAME##_t>; \
  163. extern template class uv_handle_ptr_<uv_##NAME##_t>;
  164. UV_HANDLE_PTR_INSTANTIATE_EXTERN(async)
  165. UV_HANDLE_PTR_INSTANTIATE_EXTERN(signal)
  166. UV_HANDLE_PTR_INSTANTIATE_EXTERN(pipe)
  167. UV_HANDLE_PTR_INSTANTIATE_EXTERN(process)
  168. UV_HANDLE_PTR_INSTANTIATE_EXTERN(stream)
  169. UV_HANDLE_PTR_INSTANTIATE_EXTERN(timer)
  170. UV_HANDLE_PTR_INSTANTIATE_EXTERN(tty)
  171. #undef UV_HANDLE_PTR_INSTANTIATE_EXTERN
  172. #endif
  173. }