Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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*) const
Unexecuted instantiation: cmUVHandlePtr.cxx:cm::handle_default_delete<uv_idle_s>(uv_idle_s*)::{lambda(uv_handle_s*)#1}::operator()(uv_handle_s*) const
Unexecuted instantiation: cmUVHandlePtr.cxx:cm::handle_default_delete<uv_signal_s>(uv_signal_s*)::{lambda(uv_handle_s*)#1}::operator()(uv_handle_s*) const
Unexecuted instantiation: cmUVHandlePtr.cxx:cm::handle_default_delete<uv_pipe_s>(uv_pipe_s*)::{lambda(uv_handle_s*)#1}::operator()(uv_handle_s*) const
Unexecuted instantiation: cmUVHandlePtr.cxx:cm::handle_default_delete<uv_stream_s>(uv_stream_s*)::{lambda(uv_handle_s*)#1}::operator()(uv_handle_s*) const
Unexecuted instantiation: cmUVHandlePtr.cxx:cm::handle_default_delete<uv_process_s>(uv_process_s*)::{lambda(uv_handle_s*)#1}::operator()(uv_handle_s*) const
Unexecuted instantiation: cmUVHandlePtr.cxx:cm::handle_default_delete<uv_timer_s>(uv_timer_s*)::{lambda(uv_handle_s*)#1}::operator()(uv_handle_s*) const
Unexecuted instantiation: cmUVHandlePtr.cxx:cm::handle_default_delete<uv_async_s>(uv_async_s*)::{lambda(uv_handle_s*)#1}::operator()(uv_handle_s*) const
Unexecuted 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
}