| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file LICENSE.rst or https://cmake.org/licensing for details. */
- #define cmUVHandlePtr_cxx
- #include "cmUVHandlePtr.h"
- #include <cassert>
- #include <cstdlib>
- #include <mutex>
- #include <utility>
- #include <cm/memory>
- #include <cm3p/uv.h>
- namespace cm {
- template <typename T>
- struct uv_handle_deleter;
- 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*() const
- {
- return this->loop.get();
- }
- uv_loop_t* uv_loop_ptr::operator->() const noexcept
- {
- return this->loop.get();
- }
- uv_loop_t& uv_loop_ptr::operator*() const
- {
- return *this->loop;
- }
- 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)
- {
- this->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.
- */
- this->handle.reset(static_cast<T*>(calloc(1, sizeof(T))),
- uv_handle_deleter<T>());
- this->handle->data = data;
- }
- template <typename T>
- uv_handle_ptr_base_<T>::operator bool() const
- {
- return this->handle.get();
- }
- template <typename T>
- void uv_handle_ptr_base_<T>::reset()
- {
- this->handle.reset();
- }
- template <typename T>
- uv_handle_ptr_base_<T>::operator uv_handle_t*() const
- {
- return reinterpret_cast<uv_handle_t*>(this->handle.get());
- }
- template <typename T>
- T* uv_handle_ptr_base_<T>::operator->() const noexcept
- {
- return this->handle.get();
- }
- template <typename T>
- T* uv_handle_ptr_base_<T>::get() const
- {
- return this->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>
- {
- /***
- * While 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(*this->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)
- {
- this->allocate(data);
- return uv_async_init(&loop, this->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)
- {
- this->allocate(data);
- return uv_signal_init(&loop, this->handle.get());
- }
- int uv_signal_ptr::start(uv_signal_cb cb, int signum)
- {
- assert(this->handle);
- return uv_signal_start(*this, cb, signum);
- }
- void uv_signal_ptr::stop()
- {
- if (this->handle) {
- uv_signal_stop(*this);
- }
- }
- int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data)
- {
- this->allocate(data);
- return uv_pipe_init(&loop, *this, ipc);
- }
- uv_pipe_ptr::operator uv_stream_t*() const
- {
- return reinterpret_cast<uv_stream_t*>(this->handle.get());
- }
- int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options,
- void* data)
- {
- this->allocate(data);
- return uv_spawn(&loop, *this, &options);
- }
- int uv_timer_ptr::init(uv_loop_t& loop, void* data)
- {
- this->allocate(data);
- return uv_timer_init(&loop, *this);
- }
- int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat,
- uv_update_time update_time)
- {
- assert(this->handle);
- if (update_time == uv_update_time::yes) {
- ::uv_update_time(this->handle->loop);
- }
- return uv_timer_start(*this, cb, timeout, repeat);
- }
- void uv_timer_ptr::stop()
- {
- assert(this->handle);
- uv_timer_stop(*this);
- }
- #ifndef CMAKE_BOOTSTRAP
- uv_tty_ptr::operator uv_stream_t*() const
- {
- return reinterpret_cast<uv_stream_t*>(this->handle.get());
- }
- int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data)
- {
- this->allocate(data);
- return uv_tty_init(&loop, *this, fd, readable);
- }
- #endif
- int uv_idle_ptr::init(uv_loop_t& loop, void* data)
- {
- this->allocate(data);
- return uv_idle_init(&loop, *this);
- }
- int uv_idle_ptr::start(uv_idle_cb cb)
- {
- assert(this->handle);
- return uv_idle_start(*this, cb);
- }
- void uv_idle_ptr::stop()
- {
- assert(this->handle);
- uv_idle_stop(*this);
- }
- 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(idle)
- 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
- namespace {
- struct write_req : public uv_write_t
- {
- std::weak_ptr<std::function<void(int)>> cb_;
- write_req(std::weak_ptr<std::function<void(int)>> wcb)
- : cb_(std::move(wcb))
- {
- }
- };
- void write_req_cb(uv_write_t* req, int status)
- {
- // Ownership has been transferred from the event loop.
- std::unique_ptr<write_req> self(static_cast<write_req*>(req));
- // Notify the original uv_write caller if it is still interested.
- if (auto cb = self->cb_.lock()) {
- (*cb)(status);
- }
- }
- }
- int uv_write(uv_stream_t* handle, uv_buf_t const bufs[], unsigned int nbufs,
- std::weak_ptr<std::function<void(int)>> cb)
- {
- auto req = cm::make_unique<write_req>(std::move(cb));
- int status = uv_write(req.get(), handle, bufs, nbufs, write_req_cb);
- if (status == 0) {
- // Ownership has been transferred to the event loop.
- static_cast<void>(req.release());
- }
- return status;
- }
- }
|