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