WPILibC++ 2024.3.2
Loop.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_LOOP_H_
6#define WPINET_UV_LOOP_H_
7
8#include <uv.h>
9
10#include <atomic>
11#include <chrono>
12#include <functional>
13#include <memory>
14#include <thread>
15#include <utility>
16
17#include <wpi/Signal.h>
18#include <wpi/function_ref.h>
19
20#include "wpinet/uv/Error.h"
21
22namespace wpi::uv {
23
24class Handle;
25
26/**
27 * Event loop.
28 *
29 * The event loop is the central part of uv functionality. It takes care of
30 * polling for I/O and scheduling signals to be generated based on different
31 * sources of events.
32 *
33 * The event loop is not moveable, copyable, or directly constructible. Use
34 * Create() to create an event loop, or GetDefault() to get the default loop
35 * if you know your program will only have a single one.
36 */
37class Loop final : public std::enable_shared_from_this<Loop> {
38 struct private_init {};
39
40 public:
41 using Time = std::chrono::duration<uint64_t, std::milli>;
42
43 enum Mode {
47 };
48
49 explicit Loop(const private_init&) noexcept;
50
51 Loop(const Loop&) = delete;
52 Loop& operator=(const Loop&) = delete;
53 Loop(Loop&& oth) = delete;
54 Loop& operator=(Loop&& oth) = delete;
55
56 ~Loop() noexcept;
57
58 /**
59 * Create a new event loop. The created loop is not the default event loop.
60 *
61 * @return The newly created loop. May return nullptr if a failure occurs.
62 */
63 static std::shared_ptr<Loop> Create();
64
65 /**
66 * Create the default event loop. Only use this event loop if a single loop
67 * is needed for the entire application.
68 *
69 * @return The newly created loop. May return nullptr if a failure occurs.
70 */
71 static std::shared_ptr<Loop> GetDefault();
72
73 /**
74 * Set the loop closing flag.
75 *
76 * This will prevent new handles from being created on the loop.
77 */
78 void SetClosing() { m_closing = true; }
79
80 /**
81 * Return the loop closed flag.
82 *
83 * @return True if SetClosed() has been called.
84 */
85 bool IsClosing() const { return m_closing; }
86
87 /**
88 * Release all internal loop resources.
89 *
90 * Call this function only when the loop has finished executing and all open
91 * handles and requests have been closed, or the loop will emit an error.
92 *
93 * error() will be emitted in case of errors.
94 */
95 void Close();
96
97 /**
98 * Run the event loop.
99 *
100 * Available modes are:
101 *
102 * * `Loop::kDefault`: Run the event loop until there are no
103 * active and referenced handles or requests.
104 * * `Loop::kOnce`: Run a single event loop iteration. Note that this
105 * function blocksif there are no pending callbacks.
106 * * `Loop::kNoWait`: Run a single event loop iteration, but don't block
107 * if there are no pending callbacks.
108 *
109 * @return True when done, false in all other cases.
110 */
111 bool Run(Mode mode = kDefault) {
112 m_tid = std::this_thread::get_id();
113 int rv = uv_run(m_loop, static_cast<uv_run_mode>(static_cast<int>(mode)));
114 m_tid = std::thread::id{};
115 return rv == 0;
116 }
117
118 /**
119 * Check if there are active resources.
120 *
121 * @return True if there are active resources in the loop.
122 */
123 bool IsAlive() const noexcept { return uv_loop_alive(m_loop) != 0; }
124
125 /**
126 * Stop the event loop.
127 *
128 * This will cause Run() to end as soon as possible.
129 * This will happen not sooner than the next loop iteration.
130 * If this function was called before blocking for I/O, the loop won’t block
131 * for I/O on this iteration.
132 */
133 void Stop() noexcept { uv_stop(m_loop); }
134
135 /**
136 * Get backend file descriptor.
137 *
138 * Only kqueue, epoll and event ports are supported.
139 * This can be used in conjunction with `run(Loop::kNoWait)` to poll
140 * in one thread and run the event loop’s callbacks in another.
141 *
142 * @return The backend file descriptor.
143 */
144 int GetDescriptor() const noexcept { return uv_backend_fd(m_loop); }
145
146 /**
147 * Get the poll timeout.
148 *
149 * @return A `std::pair` composed of a boolean value that is true in case of
150 * valid timeout, false otherwise, and the timeout
151 * (`std::chrono::duration<uint64_t, std::milli>`).
152 */
153 std::pair<bool, Time> GetTimeout() const noexcept {
154 auto to = uv_backend_timeout(m_loop);
155 return std::make_pair(to == -1, Time{to});
156 }
157
158 /**
159 * Return the current timestamp in milliseconds.
160 *
161 * The timestamp is cached at the start of the event loop tick.
162 * The timestamp increases monotonically from some arbitrary point in
163 * time.
164 * Don’t make assumptions about the starting point, you will only get
165 * disappointed.
166 *
167 * @return The current timestamp in milliseconds (actual type is
168 * `std::chrono::duration<uint64_t, std::milli>`).
169 */
170 Time Now() const noexcept { return Time{uv_now(m_loop)}; }
171
172 /**
173 * Update the event loop’s concept of _now_.
174 *
175 * The current time is cached at the start of the event loop tick in order
176 * to reduce the number of time-related system calls.
177 * You won’t normally need to call this function unless you have callbacks
178 * that block the event loop for longer periods of time, where _longer_ is
179 * somewhat subjective but probably on the order of a millisecond or more.
180 */
181 void UpdateTime() noexcept { uv_update_time(m_loop); }
182
183 /**
184 * Walk the list of handles.
185 *
186 * The callback will be executed once for each handle that is still active.
187 *
188 * @param callback A function to be invoked once for each active handle.
189 */
190 void Walk(function_ref<void(Handle&)> callback);
191
192 /**
193 * Reinitialize any kernel state necessary in the child process after
194 * a fork(2) system call.
195 *
196 * Previously started watchers will continue to be started in the child
197 * process.
198 *
199 * It is necessary to explicitly call this function on every event loop
200 * created in the parent process that you plan to continue to use in the
201 * child, including the default loop (even if you don’t continue to use it
202 * in the parent). This function must be called before calling any API
203 * function using the loop in the child. Failure to do so will result in
204 * undefined behaviour, possibly including duplicate events delivered to
205 * both parent and child or aborting the child process.
206 *
207 * When possible, it is preferred to create a new loop in the child process
208 * instead of reusing a loop created in the parent. New loops created in the
209 * child process after the fork should not use this function.
210 *
211 * Note that this function is not implemented on Windows.
212 * Note also that this function is experimental in `libuv`. It may contain
213 * bugs, and is subject to change or removal. API and ABI stability is not
214 * guaranteed.
215 *
216 * error() will be emitted in case of errors.
217 */
218 void Fork();
219
220 /**
221 * Get the underlying event loop data structure.
222 *
223 * @return The underlying event loop data structure.
224 */
225 uv_loop_t* GetRaw() const noexcept { return m_loop; }
226
227 /**
228 * Gets user-defined data.
229 * @return User-defined data if any, nullptr otherwise.
230 */
231 template <typename T = void>
232 std::shared_ptr<T> GetData() const {
233 return std::static_pointer_cast<T>(m_data);
234 }
235
236 /**
237 * Sets user-defined data.
238 * @param data User-defined arbitrary data.
239 */
240 void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
241
242 /**
243 * Get the thread id of the loop thread. If the loop is not currently
244 * running, returns default-constructed thread id.
245 */
246 std::thread::id GetThreadId() const { return m_tid; }
247
248 /**
249 * Error signal
250 */
252
253 /**
254 * Reports error.
255 * @param err Error code
256 */
257 void ReportError(int err) { error(Error(err)); }
258
259 private:
260 std::shared_ptr<void> m_data;
261 uv_loop_t* m_loop;
262 uv_loop_t m_loopStruct;
263 std::atomic<std::thread::id> m_tid;
264 bool m_closing = false;
265};
266
267} // namespace wpi::uv
268
269#endif // WPINET_UV_LOOP_H_
An efficient, type-erasing, non-owning reference to a callable.
Definition: function_ref.h:31
SignalBase is an implementation of the observer pattern, through the use of an emitting object and sl...
Definition: Signal.h:495
Error code.
Definition: Error.h:15
Handle.
Definition: Handle.h:34
Event loop.
Definition: Loop.h:37
Mode
Definition: Loop.h:43
@ kDefault
Definition: Loop.h:44
@ kOnce
Definition: Loop.h:45
@ kNoWait
Definition: Loop.h:46
void ReportError(int err)
Reports error.
Definition: Loop.h:257
Loop(Loop &&oth)=delete
std::thread::id GetThreadId() const
Get the thread id of the loop thread.
Definition: Loop.h:246
void Fork()
Reinitialize any kernel state necessary in the child process after a fork(2) system call.
std::chrono::duration< uint64_t, std::milli > Time
Definition: Loop.h:41
void SetClosing()
Set the loop closing flag.
Definition: Loop.h:78
static std::shared_ptr< Loop > Create()
Create a new event loop.
std::shared_ptr< T > GetData() const
Gets user-defined data.
Definition: Loop.h:232
int GetDescriptor() const noexcept
Get backend file descriptor.
Definition: Loop.h:144
Loop(const Loop &)=delete
void Close()
Release all internal loop resources.
uv_loop_t * GetRaw() const noexcept
Get the underlying event loop data structure.
Definition: Loop.h:225
Time Now() const noexcept
Return the current timestamp in milliseconds.
Definition: Loop.h:170
bool IsAlive() const noexcept
Check if there are active resources.
Definition: Loop.h:123
static std::shared_ptr< Loop > GetDefault()
Create the default event loop.
void UpdateTime() noexcept
Update the event loop’s concept of now.
Definition: Loop.h:181
void SetData(std::shared_ptr< void > data)
Sets user-defined data.
Definition: Loop.h:240
Loop & operator=(Loop &&oth)=delete
Loop(const private_init &) noexcept
bool Run(Mode mode=kDefault)
Run the event loop.
Definition: Loop.h:111
void Stop() noexcept
Stop the event loop.
Definition: Loop.h:133
void Walk(function_ref< void(Handle &)> callback)
Walk the list of handles.
~Loop() noexcept
bool IsClosing() const
Return the loop closed flag.
Definition: Loop.h:85
sig::Signal< Error > error
Error signal.
Definition: Loop.h:251
Loop & operator=(const Loop &)=delete
std::pair< bool, Time > GetTimeout() const noexcept
Get the poll timeout.
Definition: Loop.h:153
Definition: array.h:89
Definition: WebSocket.h:27
Definition: uv.h:1859
UV_EXTERN void uv_stop(uv_loop_t *)
uv_run_mode
Definition: uv.h:263
@ UV_RUN_NOWAIT
Definition: uv.h:266
@ UV_RUN_ONCE
Definition: uv.h:265
@ UV_RUN_DEFAULT
Definition: uv.h:264
UV_EXTERN int uv_backend_timeout(const uv_loop_t *)
UV_EXTERN int uv_backend_fd(const uv_loop_t *)
UV_EXTERN int uv_run(uv_loop_t *, uv_run_mode mode)
UV_EXTERN uint64_t uv_now(const uv_loop_t *)
UV_EXTERN int uv_loop_alive(const uv_loop_t *loop)
UV_EXTERN void uv_update_time(uv_loop_t *)