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