WPILibC++ 2023.4.3
Async.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_ASYNC_H_
6#define WPINET_UV_ASYNC_H_
7
8#include <uv.h>
9
10#include <memory>
11#include <thread>
12#include <tuple>
13#include <utility>
14#include <vector>
15
16#include <wpi/Signal.h>
17#include <wpi/mutex.h>
18
19#include "wpinet/uv/Handle.h"
20#include "wpinet/uv/Loop.h"
21
22namespace wpi::uv {
23
24/**
25 * Async handle.
26 * Async handles allow the user to "wakeup" the event loop and have a signal
27 * generated from another thread.
28 *
29 * Data may be passed into the callback called on the event loop by using
30 * template parameters. If data parameters are used, the async callback will
31 * be called once for every call to Send(). If no data parameters are used,
32 * the async callback may or may not be called for every call to Send() (e.g.
33 * the calls may be coaleasced).
34 */
35template <typename... T>
36class Async final : public HandleImpl<Async<T...>, uv_async_t> {
37 struct private_init {};
38
39 public:
40 Async(const std::shared_ptr<Loop>& loop, const private_init&)
41 : m_loop{loop} {}
42 ~Async() noexcept override {
43 if (auto loop = m_loop.lock()) {
44 this->Close();
45 } else {
46 this->ForceClosed();
47 }
48 }
49
50 /**
51 * Create an async handle.
52 *
53 * @param loop Loop object where this handle runs.
54 */
55 static std::shared_ptr<Async> Create(Loop& loop) {
56 return Create(loop.shared_from_this());
57 }
58
59 /**
60 * Create an async handle.
61 *
62 * @param loop Loop object where this handle runs.
63 */
64 static std::shared_ptr<Async> Create(const std::shared_ptr<Loop>& loop) {
65 if (loop->IsClosing()) {
66 return nullptr;
67 }
68 auto h = std::make_shared<Async>(loop, private_init{});
69 int err =
70 uv_async_init(loop->GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
71 auto& h = *static_cast<Async*>(handle->data);
72 std::scoped_lock lock(h.m_mutex);
73 for (auto&& v : h.m_data) {
74 std::apply(h.wakeup, v);
75 }
76 h.m_data.clear();
77 });
78 if (err < 0) {
79 loop->ReportError(err);
80 return nullptr;
81 }
82 h->Keep();
83 return h;
84 }
85
86 /**
87 * Wakeup the event loop and emit the event.
88 *
89 * It’s safe to call this function from any thread including the loop thread.
90 * An async event will be emitted on the loop thread.
91 */
92 template <typename... U>
93 void Send(U&&... u) {
94 auto loop = m_loop.lock();
95 if (loop->IsClosing()) {
96 return;
97 }
98 if (loop && loop->GetThreadId() == std::this_thread::get_id()) {
99 // called from within the loop, just call the function directly
100 wakeup(std::forward<U>(u)...);
101 return;
102 }
103
104 {
105 std::scoped_lock lock(m_mutex);
106 m_data.emplace_back(std::forward_as_tuple(std::forward<U>(u)...));
107 }
108 if (loop) {
109 this->Invoke(&uv_async_send, this->GetRaw());
110 }
111 }
112
113 /**
114 * Wakeup the event loop and emit the event.
115 * This function assumes the loop still exists, which makes it a bit faster.
116 *
117 * It’s safe to call this function from any thread.
118 * An async event will be emitted on the loop thread.
119 */
120 void UnsafeSend() { Invoke(&uv_async_send, this->GetRaw()); }
121
122 /**
123 * Signal generated (on event loop thread) when the async event occurs.
124 */
126
127 private:
128 wpi::mutex m_mutex;
129 std::vector<std::tuple<T...>> m_data;
130 std::weak_ptr<Loop> m_loop;
131};
132
133/**
134 * Async specialization for no data parameters. The async callback may or may
135 * not be called for every call to Send() (e.g. the calls may be coaleasced).
136 */
137template <>
138class Async<> final : public HandleImpl<Async<>, uv_async_t> {
139 struct private_init {};
140
141 public:
142 Async(const std::shared_ptr<Loop>& loop, const private_init&)
143 : m_loop(loop) {}
144 ~Async() noexcept override;
145
146 /**
147 * Create an async handle.
148 *
149 * @param loop Loop object where this handle runs.
150 */
151 static std::shared_ptr<Async> Create(Loop& loop) {
152 return Create(loop.shared_from_this());
153 }
154
155 /**
156 * Create an async handle.
157 *
158 * @param loop Loop object where this handle runs.
159 */
160 static std::shared_ptr<Async> Create(const std::shared_ptr<Loop>& loop);
161
162 /**
163 * Wakeup the event loop and emit the event.
164 *
165 * It’s safe to call this function from any thread.
166 * An async event will be emitted on the loop thread.
167 */
168 void Send() {
169 if (auto loop = m_loop.lock()) {
170 if (loop->IsClosing()) {
171 return;
172 }
173 if (loop->GetThreadId() == std::this_thread::get_id()) {
174 // called from within the loop, just call the function directly
175 wakeup();
176 } else {
177 Invoke(&uv_async_send, GetRaw());
178 }
179 }
180 }
181
182 /**
183 * Wakeup the event loop and emit the event.
184 * This function assumes the loop still exists, which makes it a bit faster.
185 *
186 * It’s safe to call this function from any thread.
187 * An async event will be emitted on the loop thread.
188 */
189 void UnsafeSend() { Invoke(&uv_async_send, GetRaw()); }
190
191 /**
192 * Signal generated (on event loop thread) when the async event occurs.
193 */
195
196 private:
197 std::weak_ptr<Loop> m_loop;
198};
199
200} // namespace wpi::uv
201
202#endif // WPINET_UV_ASYNC_H_
SignalBase is an implementation of the observer pattern, through the use of an emitting object and sl...
Definition: Signal.h:495
sig::Signal wakeup
Signal generated (on event loop thread) when the async event occurs.
Definition: Async.h:194
void UnsafeSend()
Wakeup the event loop and emit the event.
Definition: Async.h:189
void Send()
Wakeup the event loop and emit the event.
Definition: Async.h:168
static std::shared_ptr< Async > Create(const std::shared_ptr< Loop > &loop)
Create an async handle.
~Async() noexcept override
Async(const std::shared_ptr< Loop > &loop, const private_init &)
Definition: Async.h:142
Async handle.
Definition: Async.h:36
void Send(U &&... u)
Wakeup the event loop and emit the event.
Definition: Async.h:93
static std::shared_ptr< Async > Create(const std::shared_ptr< Loop > &loop)
Create an async handle.
Definition: Async.h:64
~Async() noexcept override
Definition: Async.h:42
static std::shared_ptr< Async > Create(Loop &loop)
Create an async handle.
Definition: Async.h:55
void UnsafeSend()
Wakeup the event loop and emit the event.
Definition: Async.h:120
Async(const std::shared_ptr< Loop > &loop, const private_init &)
Definition: Async.h:40
sig::Signal< T... > wakeup
Signal generated (on event loop thread) when the async event occurs.
Definition: Async.h:125
void ForceClosed() noexcept
Definition: Handle.h:245
void Close() noexcept
Request handle to be closed.
Handle.
Definition: Handle.h:273
Event loop.
Definition: Loop.h:37
std::vector< uint8_t > GetRaw(NT_Handle subentry, std::span< const uint8_t > defaultValue)
Get the last published value.
Definition: StdDeque.h:50
static constexpr const unit_t< compound_unit< energy::joule, time::seconds > > h(6.626070040e-34)
Planck constant.
Definition: ParallelTcpConnector.h:22
::std::mutex mutex
Definition: mutex.h:17
Definition: uv.h:852
UV_EXTERN int uv_async_init(uv_loop_t *, uv_async_t *async, uv_async_cb async_cb)
UV_EXTERN int uv_async_send(uv_async_t *async)