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