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