WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
Handle.hpp
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <cstdlib>
8#include <functional>
9#include <memory>
10#include <string_view>
11#include <utility>
12
13#include <uv.h>
14
15#include "wpi/net/uv/Buffer.hpp"
16#include "wpi/net/uv/Error.hpp"
17#include "wpi/net/uv/Loop.hpp"
18#include "wpi/util/Signal.h"
19
20namespace wpi::util {
21class Logger;
22} // namespace wpi::util
23
24namespace wpi::net::uv {
25
26/**
27 * Handle.
28 * Handles are not moveable or copyable and cannot be directly constructed.
29 * This class provides shared_ptr ownership and shared_from_this.
30 * Use the specific handle type Create() functions to create handles.
31 */
32class Handle : public std::enable_shared_from_this<Handle> {
33 public:
35
36 Handle(const Handle&) = delete;
37 Handle(Handle&&) = delete;
38 Handle& operator=(const Handle&) = delete;
39 Handle& operator=(Handle&&) = delete;
40 virtual ~Handle() noexcept;
41
42 /**
43 * Get the type of the handle.
44 *
45 * A base handle offers no functionality to promote it to the actual handle
46 * type. By means of this function, the type of the underlying handle as
47 * specified by Type is made available.
48 *
49 * @return The actual type of the handle.
50 */
51 Type GetType() const noexcept { return m_uv_handle->type; }
52
53 /**
54 * Get the name of the type of the handle. E.g. "pipe" for pipe handles.
55 */
56 std::string_view GetTypeName() const noexcept {
57 return uv_handle_type_name(m_uv_handle->type);
58 }
59
60 /**
61 * Get the loop where this handle runs.
62 *
63 * @return The loop.
64 */
65 std::shared_ptr<Loop> GetLoop() const noexcept {
66 return GetLoopRef().shared_from_this();
67 }
68
69 /**
70 * Get the loop where this handle runs.
71 *
72 * @return The loop.
73 */
74 Loop& GetLoopRef() const noexcept {
75 return *static_cast<Loop*>(m_uv_handle->loop->data);
76 }
77
78 /**
79 * Check if the handle is active.
80 *
81 * What _active_ means depends on the type of handle:
82 *
83 * * An AsyncHandle handle is always active and cannot be deactivated,
84 * except by closing it with uv_close().
85 * * A PipeHandle, TcpHandle, UDPHandle, etc. handle - basically any handle
86 * that deals with I/O - is active when it is doing something that involves
87 * I/O, like reading, writing, connecting, accepting new connections, etc.
88 * * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
89 * has been started with a call to `Start()`.
90 *
91 * Rule of thumb: if a handle of type `FooHandle` has a `Start()` member
92 * method, then it’s active from the moment that method is called. Likewise,
93 * `Stop()` deactivates the handle again.
94 *
95 * @return True if the handle is active, false otherwise.
96 */
97 bool IsActive() const noexcept { return uv_is_active(m_uv_handle) != 0; }
98
99 /**
100 * Check if a handle is closing or closed.
101 *
102 * This function should only be used between the initialization of the
103 * handle and the arrival of the close callback.
104 *
105 * @return True if the handle is closing or closed, false otherwise.
106 */
107 bool IsClosing() const noexcept {
108 return m_closed || uv_is_closing(m_uv_handle) != 0;
109 }
110
111 /**
112 * Request handle to be closed.
113 *
114 * This **must** be called on each handle before memory is released.
115 * In-progress requests are cancelled and this can result in error() being
116 * emitted.
117 *
118 * The handle will emit closed() when finished.
119 */
120 void Close() noexcept;
121
122 /**
123 * Set if the loop is closing.
124 *
125 * This is set during EventLoopRunner.Stop(), and can be used for other cases
126 * to indicate the loop should be closing. For instance for a uv_walk loop can
127 * use this to close existing handles.
128 *
129 * @param loopClosing true to set the loop currently in closing stages.
130 */
131 void SetLoopClosing(bool loopClosing) noexcept {
132 m_loopClosing = loopClosing;
133 }
134
135 /**
136 * Get the loop closing status.
137 *
138 * This can be used from closed() in order to tell if a closing loop is the
139 * reason for the close, or another reason.
140 *
141 * @return true if the loop is closing, otherwise false.
142 */
143 bool IsLoopClosing() const noexcept { return m_loopClosing; }
144
145 /**
146 * Reference the given handle.
147 *
148 * References are idempotent, that is, if a handle is already referenced
149 * calling this function again will have no effect.
150 */
151 void Reference() noexcept { uv_ref(m_uv_handle); }
152
153 /**
154 * Unreference the given handle.
155 *
156 * References are idempotent, that is, if a handle is not referenced calling
157 * this function again will have no effect.
158 */
159 void Unreference() noexcept { uv_unref(m_uv_handle); }
160
161 /**
162 * Check if the given handle is referenced.
163 * @return True if the handle is referenced, false otherwise.
164 */
165 bool HasReference() const noexcept { return uv_has_ref(m_uv_handle) != 0; }
166
167 /**
168 * Return the size of the underlying handle type.
169 * @return The size of the underlying handle type.
170 */
171 size_t RawSize() const noexcept { return uv_handle_size(m_uv_handle->type); }
172
173 /**
174 * Get the underlying handle data structure.
175 *
176 * @return The underlying handle data structure.
177 */
178 uv_handle_t* GetRawHandle() const noexcept { return m_uv_handle; }
179
180 /**
181 * Set the functions used for allocating and releasing buffers. The size
182 * passed to the allocator function is a "suggested" size--it's just an
183 * indication, not related in any way to the pending data to be read. The
184 * user is free to allocate the amount of memory they decide. For example,
185 * applications with custom allocation schemes may decide to use a different
186 * size which matches the memory chunks they already have for other purposes.
187 *
188 * @warning Be very careful changing the allocator after the loop has started
189 * running; there are no interlocks between this and buffers currently in
190 * flight.
191 *
192 * @param alloc Allocation function
193 * @param dealloc Deallocation function
194 */
195 void SetBufferAllocator(std::function<Buffer(size_t)> alloc,
196 std::function<void(Buffer&)> dealloc) {
197 m_allocBuf = std::move(alloc);
198 m_freeBuf = std::move(dealloc);
199 }
200
201 /**
202 * Free a buffer. Uses the function provided to SetBufFree() or
203 * Buffer::Deallocate by default.
204 *
205 * @param buf The buffer
206 */
207 void FreeBuf(Buffer& buf) const noexcept { m_freeBuf(buf); }
208
209 /**
210 * Gets user-defined data.
211 * @return User-defined data if any, nullptr otherwise.
212 */
213 template <typename T = void>
214 std::shared_ptr<T> GetData() const {
215 return std::static_pointer_cast<T>(m_data);
216 }
217
218 /**
219 * Sets user-defined data.
220 * @param data User-defined arbitrary data.
221 */
222 void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
223
224 /**
225 * Sets logger.
226 * @param logger Logger
227 */
228 void SetLogger(wpi::util::Logger* logger) { m_logger = logger; }
229
230 /**
231 * Gets logger.
232 * @return Logger, or nullptr if none set
233 */
234 wpi::util::Logger* GetLogger() const { return m_logger; }
235
236 /**
237 * Error signal
238 */
240
241 /**
242 * Closed signal
243 */
245
246 /**
247 * Report an error.
248 * @param err Error code
249 */
250 void ReportError(int err) const { error(Error(err)); }
251
252 protected:
253 explicit Handle(uv_handle_t* uv_handle) : m_uv_handle{uv_handle} {
254 m_uv_handle->data = this;
255 }
256
257 void Keep() noexcept { m_self = shared_from_this(); }
258 void Release() noexcept { m_self.reset(); }
259 void ForceClosed() noexcept { m_closed = true; }
260
261 static void AllocBuf(uv_handle_t* handle, size_t size, uv_buf_t* buf);
262 static void DefaultFreeBuf(Buffer& buf);
263
264 template <typename F, typename... Args>
265 bool Invoke(F&& f, Args&&... args) const {
266 auto err = std::forward<F>(f)(std::forward<Args>(args)...);
267 if (err < 0) {
269 }
270 return err == 0;
271 }
272
273 private:
274 std::shared_ptr<Handle> m_self;
275 uv_handle_t* m_uv_handle;
276 bool m_closed = false;
277 bool m_loopClosing = false;
278 std::function<Buffer(size_t)> m_allocBuf{&Buffer::Allocate};
279 std::function<void(Buffer&)> m_freeBuf{&DefaultFreeBuf};
280 std::shared_ptr<void> m_data;
281 wpi::util::Logger* m_logger = nullptr;
282};
283
284/**
285 * Handle.
286 */
287template <typename T, typename U>
288class HandleImpl : public Handle {
289 public:
290 std::shared_ptr<T> shared_from_this() {
291 return std::static_pointer_cast<T>(Handle::shared_from_this());
292 }
293
294 std::shared_ptr<const T> shared_from_this() const {
295 return std::static_pointer_cast<const T>(Handle::shared_from_this());
296 }
297
298 /**
299 * Get the underlying handle data structure.
300 *
301 * @return The underlying handle data structure.
302 */
303 U* GetRaw() const noexcept {
304 return reinterpret_cast<U*>(this->GetRawHandle());
305 }
306
307 protected:
308 HandleImpl() : Handle{static_cast<uv_handle_t*>(std::malloc(sizeof(U)))} {}
309};
310
311} // namespace wpi::net::uv
Data buffer.
Definition Buffer.hpp:22
static Buffer Allocate(size_t size)
Definition Buffer.hpp:64
std::shared_ptr< Loop > GetLoop() const noexcept
Get the loop where this handle runs.
Definition Handle.hpp:65
virtual ~Handle() noexcept
Loop & GetLoopRef() const noexcept
Get the loop where this handle runs.
Definition Handle.hpp:74
void SetBufferAllocator(std::function< Buffer(size_t)> alloc, std::function< void(Buffer &)> dealloc)
Set the functions used for allocating and releasing buffers.
Definition Handle.hpp:195
wpi::util::sig::Signal closed
Closed signal.
Definition Handle.hpp:244
void ForceClosed() noexcept
Definition Handle.hpp:259
bool Invoke(F &&f, Args &&... args) const
Definition Handle.hpp:265
void Unreference() noexcept
Unreference the given handle.
Definition Handle.hpp:159
Handle & operator=(Handle &&)=delete
void FreeBuf(Buffer &buf) const noexcept
Free a buffer.
Definition Handle.hpp:207
Handle & operator=(const Handle &)=delete
void Release() noexcept
Definition Handle.hpp:258
bool HasReference() const noexcept
Check if the given handle is referenced.
Definition Handle.hpp:165
static void AllocBuf(uv_handle_t *handle, size_t size, uv_buf_t *buf)
Handle(uv_handle_t *uv_handle)
Definition Handle.hpp:253
void Reference() noexcept
Reference the given handle.
Definition Handle.hpp:151
wpi::util::Logger * GetLogger() const
Gets logger.
Definition Handle.hpp:234
uv_handle_type Type
Definition Handle.hpp:34
void SetLogger(wpi::util::Logger *logger)
Sets logger.
Definition Handle.hpp:228
std::string_view GetTypeName() const noexcept
Get the name of the type of the handle.
Definition Handle.hpp:56
void SetData(std::shared_ptr< void > data)
Sets user-defined data.
Definition Handle.hpp:222
void Close() noexcept
Request handle to be closed.
Type GetType() const noexcept
Get the type of the handle.
Definition Handle.hpp:51
uv_handle_t * GetRawHandle() const noexcept
Get the underlying handle data structure.
Definition Handle.hpp:178
void Keep() noexcept
Definition Handle.hpp:257
size_t RawSize() const noexcept
Return the size of the underlying handle type.
Definition Handle.hpp:171
std::shared_ptr< T > GetData() const
Gets user-defined data.
Definition Handle.hpp:214
bool IsLoopClosing() const noexcept
Get the loop closing status.
Definition Handle.hpp:143
wpi::util::sig::Signal< Error > error
Error signal.
Definition Handle.hpp:239
void ReportError(int err) const
Report an error.
Definition Handle.hpp:250
bool IsActive() const noexcept
Check if the handle is active.
Definition Handle.hpp:97
void SetLoopClosing(bool loopClosing) noexcept
Set if the loop is closing.
Definition Handle.hpp:131
Handle(const Handle &)=delete
Handle(Handle &&)=delete
static void DefaultFreeBuf(Buffer &buf)
bool IsClosing() const noexcept
Check if a handle is closing or closed.
Definition Handle.hpp:107
std::shared_ptr< const T > shared_from_this() const
Definition Handle.hpp:294
std::shared_ptr< T > shared_from_this()
Definition Handle.hpp:290
U * GetRaw() const noexcept
Get the underlying handle data structure.
Definition Handle.hpp:303
HandleImpl()
Definition Handle.hpp:308
Event loop.
Definition Loop.hpp:35
Definition Logger.hpp:26
Error
Definition def.inc:106
Definition StringMap.hpp:773
Definition Errors.hpp:112
Definition Prepare.hpp:14
SignalBase< detail::NullMutex, T... > Signal
Specialization of SignalBase to be used in single threaded contexts.
Definition Signal.h:809
Definition raw_os_ostream.hpp:19
UV_EXTERN int uv_is_active(const uv_handle_t *handle)
UV_EXTERN const char * uv_handle_type_name(uv_handle_type type)
uv_handle_type
Definition uv.h:195
UV_EXTERN void uv_ref(uv_handle_t *)
UV_EXTERN size_t uv_handle_size(uv_handle_type type)
struct uv_handle_s uv_handle_t
Definition uv.h:216
UV_EXTERN void uv_unref(uv_handle_t *)
UV_EXTERN int uv_is_closing(const uv_handle_t *handle)
UV_EXTERN int uv_has_ref(const uv_handle_t *)