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