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