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