| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #define cmUVHandlePtr_cxx |
| #include "cmUVHandlePtr.h" |
| |
| #include <cassert> |
| #include <cstdlib> |
| #include <mutex> |
| |
| #include <cm3p/uv.h> |
| |
| namespace cm { |
| |
| struct uv_loop_deleter |
| { |
| void operator()(uv_loop_t* loop) const; |
| }; |
| |
| void uv_loop_deleter::operator()(uv_loop_t* loop) const |
| { |
| uv_run(loop, UV_RUN_DEFAULT); |
| int result = uv_loop_close(loop); |
| (void)result; |
| assert(result >= 0); |
| free(loop); |
| } |
| |
| int uv_loop_ptr::init(void* data) |
| { |
| this->reset(); |
| |
| this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))), |
| uv_loop_deleter()); |
| this->loop->data = data; |
| |
| return uv_loop_init(this->loop.get()); |
| } |
| |
| void uv_loop_ptr::reset() |
| { |
| this->loop.reset(); |
| } |
| |
| uv_loop_ptr::operator uv_loop_t*() |
| { |
| return this->loop.get(); |
| } |
| |
| uv_loop_t* uv_loop_ptr::operator->() const noexcept |
| { |
| return this->loop.get(); |
| } |
| |
| uv_loop_t* uv_loop_ptr::get() const |
| { |
| return this->loop.get(); |
| } |
| |
| template <typename T> |
| static void handle_default_delete(T* type_handle) |
| { |
| auto handle = reinterpret_cast<uv_handle_t*>(type_handle); |
| if (handle) { |
| assert(!uv_is_closing(handle)); |
| if (!uv_is_closing(handle)) { |
| uv_close(handle, [](uv_handle_t* h) { free(h); }); |
| } |
| } |
| } |
| |
| /** |
| * Encapsulates delete logic for a given handle type T |
| */ |
| template <typename T> |
| struct uv_handle_deleter |
| { |
| void operator()(T* type_handle) const { handle_default_delete(type_handle); } |
| }; |
| |
| template <typename T> |
| void uv_handle_ptr_base_<T>::allocate(void* data) |
| { |
| reset(); |
| |
| /* |
| We use calloc since we know all these types are c structs |
| and we just want to 0 init them. New would do the same thing; |
| but casting from uv_handle_t to certain other types -- namely |
| uv_timer_t -- triggers a cast_align warning on certain systems. |
| */ |
| handle.reset(static_cast<T*>(calloc(1, sizeof(T))), uv_handle_deleter<T>()); |
| handle->data = data; |
| } |
| |
| template <typename T> |
| void uv_handle_ptr_base_<T>::reset() |
| { |
| handle.reset(); |
| } |
| |
| template <typename T> |
| uv_handle_ptr_base_<T>::operator uv_handle_t*() |
| { |
| return reinterpret_cast<uv_handle_t*>(handle.get()); |
| } |
| |
| template <typename T> |
| T* uv_handle_ptr_base_<T>::operator->() const noexcept |
| { |
| return handle.get(); |
| } |
| |
| template <typename T> |
| T* uv_handle_ptr_base_<T>::get() const |
| { |
| return handle.get(); |
| } |
| |
| template <typename T> |
| uv_handle_ptr_<T>::operator T*() const |
| { |
| return this->handle.get(); |
| } |
| |
| #ifndef CMAKE_BOOTSTRAP |
| template <> |
| struct uv_handle_deleter<uv_async_t> |
| { |
| /*** |
| * Wile uv_async_send is itself thread-safe, there are |
| * no strong guarantees that close hasn't already been |
| * called on the handle; and that it might be deleted |
| * as the send call goes through. This mutex guards |
| * against that. |
| * |
| * The shared_ptr here is to allow for copy construction |
| * which is mandated by the standard for Deleter on |
| * shared_ptrs. |
| */ |
| std::shared_ptr<std::mutex> handleMutex; |
| |
| uv_handle_deleter() |
| : handleMutex(std::make_shared<std::mutex>()) |
| { |
| } |
| |
| void operator()(uv_async_t* handle) |
| { |
| std::lock_guard<std::mutex> lock(*handleMutex); |
| handle_default_delete(handle); |
| } |
| }; |
| |
| void uv_async_ptr::send() |
| { |
| auto deleter = std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle); |
| assert(deleter); |
| |
| std::lock_guard<std::mutex> lock(*deleter->handleMutex); |
| if (this->handle) { |
| uv_async_send(*this); |
| } |
| } |
| |
| int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data) |
| { |
| allocate(data); |
| return uv_async_init(&loop, handle.get(), async_cb); |
| } |
| #endif |
| |
| template <> |
| struct uv_handle_deleter<uv_signal_t> |
| { |
| void operator()(uv_signal_t* handle) const |
| { |
| if (handle) { |
| uv_signal_stop(handle); |
| handle_default_delete(handle); |
| } |
| } |
| }; |
| |
| int uv_signal_ptr::init(uv_loop_t& loop, void* data) |
| { |
| allocate(data); |
| return uv_signal_init(&loop, handle.get()); |
| } |
| |
| int uv_signal_ptr::start(uv_signal_cb cb, int signum) |
| { |
| assert(handle); |
| return uv_signal_start(*this, cb, signum); |
| } |
| |
| void uv_signal_ptr::stop() |
| { |
| if (handle) { |
| uv_signal_stop(*this); |
| } |
| } |
| |
| int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data) |
| { |
| allocate(data); |
| return uv_pipe_init(&loop, *this, ipc); |
| } |
| |
| uv_pipe_ptr::operator uv_stream_t*() const |
| { |
| return reinterpret_cast<uv_stream_t*>(handle.get()); |
| } |
| |
| int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options, |
| void* data) |
| { |
| allocate(data); |
| return uv_spawn(&loop, *this, &options); |
| } |
| |
| int uv_timer_ptr::init(uv_loop_t& loop, void* data) |
| { |
| allocate(data); |
| return uv_timer_init(&loop, *this); |
| } |
| |
| int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat) |
| { |
| assert(handle); |
| return uv_timer_start(*this, cb, timeout, repeat); |
| } |
| |
| #ifndef CMAKE_BOOTSTRAP |
| uv_tty_ptr::operator uv_stream_t*() const |
| { |
| return reinterpret_cast<uv_stream_t*>(handle.get()); |
| } |
| |
| int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data) |
| { |
| allocate(data); |
| return uv_tty_init(&loop, *this, fd, readable); |
| } |
| #endif |
| |
| template class uv_handle_ptr_base_<uv_handle_t>; |
| |
| #define UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(NAME) \ |
| template class uv_handle_ptr_base_<uv_##NAME##_t>; \ |
| template class uv_handle_ptr_<uv_##NAME##_t>; |
| |
| UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(signal) |
| |
| UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe) |
| |
| UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream) |
| |
| UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process) |
| |
| UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer) |
| |
| #ifndef CMAKE_BOOTSTRAP |
| UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async) |
| |
| UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty) |
| #endif |
| } |