cmUVHandlePtr.cxx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #define cmUVHandlePtr_cxx
  4. #include "cmUVHandlePtr.h"
  5. #include <cassert>
  6. #include <cstdlib>
  7. #include <mutex>
  8. #include <utility>
  9. #include <cm/memory>
  10. #include <cm3p/uv.h>
  11. namespace cm {
  12. template <typename T>
  13. struct uv_handle_deleter;
  14. struct uv_loop_deleter
  15. {
  16. void operator()(uv_loop_t* loop) const;
  17. };
  18. void uv_loop_deleter::operator()(uv_loop_t* loop) const
  19. {
  20. uv_run(loop, UV_RUN_DEFAULT);
  21. int result = uv_loop_close(loop);
  22. (void)result;
  23. assert(result >= 0);
  24. free(loop);
  25. }
  26. int uv_loop_ptr::init(void* data)
  27. {
  28. this->reset();
  29. this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))),
  30. uv_loop_deleter());
  31. this->loop->data = data;
  32. return uv_loop_init(this->loop.get());
  33. }
  34. void uv_loop_ptr::reset()
  35. {
  36. this->loop.reset();
  37. }
  38. uv_loop_ptr::operator uv_loop_t*() const
  39. {
  40. return this->loop.get();
  41. }
  42. uv_loop_t* uv_loop_ptr::operator->() const noexcept
  43. {
  44. return this->loop.get();
  45. }
  46. uv_loop_t& uv_loop_ptr::operator*() const
  47. {
  48. return *this->loop;
  49. }
  50. uv_loop_t* uv_loop_ptr::get() const
  51. {
  52. return this->loop.get();
  53. }
  54. template <typename T>
  55. static void handle_default_delete(T* type_handle)
  56. {
  57. auto* handle = reinterpret_cast<uv_handle_t*>(type_handle);
  58. if (handle) {
  59. assert(!uv_is_closing(handle));
  60. if (!uv_is_closing(handle)) {
  61. uv_close(handle, [](uv_handle_t* h) { free(h); });
  62. }
  63. }
  64. }
  65. /**
  66. * Encapsulates delete logic for a given handle type T
  67. */
  68. template <typename T>
  69. struct uv_handle_deleter
  70. {
  71. void operator()(T* type_handle) const { handle_default_delete(type_handle); }
  72. };
  73. template <typename T>
  74. void uv_handle_ptr_base_<T>::allocate(void* data)
  75. {
  76. this->reset();
  77. /*
  78. We use calloc since we know all these types are c structs
  79. and we just want to 0 init them. New would do the same thing;
  80. but casting from uv_handle_t to certain other types -- namely
  81. uv_timer_t -- triggers a cast_align warning on certain systems.
  82. */
  83. this->handle.reset(static_cast<T*>(calloc(1, sizeof(T))),
  84. uv_handle_deleter<T>());
  85. this->handle->data = data;
  86. }
  87. template <typename T>
  88. uv_handle_ptr_base_<T>::operator bool() const
  89. {
  90. return this->handle.get();
  91. }
  92. template <typename T>
  93. void uv_handle_ptr_base_<T>::reset()
  94. {
  95. this->handle.reset();
  96. }
  97. template <typename T>
  98. uv_handle_ptr_base_<T>::operator uv_handle_t*() const
  99. {
  100. return reinterpret_cast<uv_handle_t*>(this->handle.get());
  101. }
  102. template <typename T>
  103. T* uv_handle_ptr_base_<T>::operator->() const noexcept
  104. {
  105. return this->handle.get();
  106. }
  107. template <typename T>
  108. T* uv_handle_ptr_base_<T>::get() const
  109. {
  110. return this->handle.get();
  111. }
  112. template <typename T>
  113. uv_handle_ptr_<T>::operator T*() const
  114. {
  115. return this->handle.get();
  116. }
  117. #ifndef CMAKE_BOOTSTRAP
  118. template <>
  119. struct uv_handle_deleter<uv_async_t>
  120. {
  121. /***
  122. * While uv_async_send is itself thread-safe, there are
  123. * no strong guarantees that close hasn't already been
  124. * called on the handle; and that it might be deleted
  125. * as the send call goes through. This mutex guards
  126. * against that.
  127. *
  128. * The shared_ptr here is to allow for copy construction
  129. * which is mandated by the standard for Deleter on
  130. * shared_ptrs.
  131. */
  132. std::shared_ptr<std::mutex> handleMutex;
  133. uv_handle_deleter()
  134. : handleMutex(std::make_shared<std::mutex>())
  135. {
  136. }
  137. void operator()(uv_async_t* handle)
  138. {
  139. std::lock_guard<std::mutex> lock(*this->handleMutex);
  140. handle_default_delete(handle);
  141. }
  142. };
  143. void uv_async_ptr::send()
  144. {
  145. auto* deleter =
  146. std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle);
  147. assert(deleter);
  148. std::lock_guard<std::mutex> lock(*deleter->handleMutex);
  149. if (this->handle) {
  150. uv_async_send(*this);
  151. }
  152. }
  153. int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data)
  154. {
  155. this->allocate(data);
  156. return uv_async_init(&loop, this->handle.get(), async_cb);
  157. }
  158. #endif
  159. template <>
  160. struct uv_handle_deleter<uv_signal_t>
  161. {
  162. void operator()(uv_signal_t* handle) const
  163. {
  164. if (handle) {
  165. uv_signal_stop(handle);
  166. handle_default_delete(handle);
  167. }
  168. }
  169. };
  170. int uv_signal_ptr::init(uv_loop_t& loop, void* data)
  171. {
  172. this->allocate(data);
  173. return uv_signal_init(&loop, this->handle.get());
  174. }
  175. int uv_signal_ptr::start(uv_signal_cb cb, int signum)
  176. {
  177. assert(this->handle);
  178. return uv_signal_start(*this, cb, signum);
  179. }
  180. void uv_signal_ptr::stop()
  181. {
  182. if (this->handle) {
  183. uv_signal_stop(*this);
  184. }
  185. }
  186. int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data)
  187. {
  188. this->allocate(data);
  189. return uv_pipe_init(&loop, *this, ipc);
  190. }
  191. uv_pipe_ptr::operator uv_stream_t*() const
  192. {
  193. return reinterpret_cast<uv_stream_t*>(this->handle.get());
  194. }
  195. int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options,
  196. void* data)
  197. {
  198. this->allocate(data);
  199. return uv_spawn(&loop, *this, &options);
  200. }
  201. int uv_timer_ptr::init(uv_loop_t& loop, void* data)
  202. {
  203. this->allocate(data);
  204. return uv_timer_init(&loop, *this);
  205. }
  206. int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat,
  207. uv_update_time update_time)
  208. {
  209. assert(this->handle);
  210. if (update_time == uv_update_time::yes) {
  211. ::uv_update_time(this->handle->loop);
  212. }
  213. return uv_timer_start(*this, cb, timeout, repeat);
  214. }
  215. void uv_timer_ptr::stop()
  216. {
  217. assert(this->handle);
  218. uv_timer_stop(*this);
  219. }
  220. #ifndef CMAKE_BOOTSTRAP
  221. uv_tty_ptr::operator uv_stream_t*() const
  222. {
  223. return reinterpret_cast<uv_stream_t*>(this->handle.get());
  224. }
  225. int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data)
  226. {
  227. this->allocate(data);
  228. return uv_tty_init(&loop, *this, fd, readable);
  229. }
  230. #endif
  231. int uv_idle_ptr::init(uv_loop_t& loop, void* data)
  232. {
  233. this->allocate(data);
  234. return uv_idle_init(&loop, *this);
  235. }
  236. int uv_idle_ptr::start(uv_idle_cb cb)
  237. {
  238. assert(this->handle);
  239. return uv_idle_start(*this, cb);
  240. }
  241. void uv_idle_ptr::stop()
  242. {
  243. assert(this->handle);
  244. uv_idle_stop(*this);
  245. }
  246. template class uv_handle_ptr_base_<uv_handle_t>;
  247. #define UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(NAME) \
  248. template class uv_handle_ptr_base_<uv_##NAME##_t>; \
  249. template class uv_handle_ptr_<uv_##NAME##_t>;
  250. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(idle)
  251. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(signal)
  252. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe)
  253. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream)
  254. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process)
  255. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer)
  256. #ifndef CMAKE_BOOTSTRAP
  257. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
  258. UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty)
  259. #endif
  260. namespace {
  261. struct write_req : public uv_write_t
  262. {
  263. std::weak_ptr<std::function<void(int)>> cb_;
  264. write_req(std::weak_ptr<std::function<void(int)>> wcb)
  265. : cb_(std::move(wcb))
  266. {
  267. }
  268. };
  269. void write_req_cb(uv_write_t* req, int status)
  270. {
  271. // Ownership has been transferred from the event loop.
  272. std::unique_ptr<write_req> self(static_cast<write_req*>(req));
  273. // Notify the original uv_write caller if it is still interested.
  274. if (auto cb = self->cb_.lock()) {
  275. (*cb)(status);
  276. }
  277. }
  278. }
  279. int uv_write(uv_stream_t* handle, uv_buf_t const bufs[], unsigned int nbufs,
  280. std::weak_ptr<std::function<void(int)>> cb)
  281. {
  282. auto req = cm::make_unique<write_req>(std::move(cb));
  283. int status = uv_write(req.get(), handle, bufs, nbufs, write_req_cb);
  284. if (status == 0) {
  285. // Ownership has been transferred to the event loop.
  286. static_cast<void>(req.release());
  287. }
  288. return status;
  289. }
  290. }