WPILibC++  2020.3.2
AsyncFunction.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #ifndef WPIUTIL_WPI_UV_ASYNCFUNCTION_H_
9 #define WPIUTIL_WPI_UV_ASYNCFUNCTION_H_
10 
11 #include <stdint.h>
12 #include <uv.h>
13 
14 #include <functional>
15 #include <memory>
16 #include <thread>
17 #include <tuple>
18 #include <utility>
19 #include <vector>
20 
21 #include "wpi/future.h"
22 #include "wpi/mutex.h"
23 #include "wpi/uv/Handle.h"
24 #include "wpi/uv/Loop.h"
25 
26 namespace wpi {
27 namespace uv {
28 
29 template <typename T>
31 
37 template <typename R, typename... T>
38 class AsyncFunction<R(T...)> final
39  : public HandleImpl<AsyncFunction<R(T...)>, uv_async_t> {
40  struct private_init {};
41 
42  public:
43  AsyncFunction(const std::shared_ptr<Loop>& loop,
44  std::function<void(promise<R>, T...)> func, const private_init&)
45  : wakeup{func}, m_loop{loop} {}
46  ~AsyncFunction() noexcept override {
47  if (auto loop = m_loop.lock())
48  this->Close();
49  else
50  this->ForceClosed();
51  }
52 
62  static std::shared_ptr<AsyncFunction> Create(
63  Loop& loop, std::function<void(promise<R>, T...)> func = nullptr) {
64  return Create(loop.shared_from_this(), std::move(func));
65  }
66 
76  static std::shared_ptr<AsyncFunction> Create(
77  const std::shared_ptr<Loop>& loop,
78  std::function<void(promise<R>, T...)> func = nullptr) {
79  auto h =
80  std::make_shared<AsyncFunction>(loop, std::move(func), private_init{});
81  int err =
82  uv_async_init(loop->GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
83  auto& h = *static_cast<AsyncFunction*>(handle->data);
84  std::unique_lock lock(h.m_mutex);
85 
86  if (!h.m_params.empty()) {
87  // for each set of parameters in the input queue, call the wakeup
88  // function and put the result in the output queue if the caller is
89  // waiting for it
90  for (auto&& v : h.m_params) {
91  auto p = h.m_promises.CreatePromise(v.first);
92  if (h.wakeup)
93  std::apply(h.wakeup,
94  std::tuple_cat(std::make_tuple(std::move(p)),
95  std::move(v.second)));
96  }
97  h.m_params.clear();
98  // wake up any threads that might be waiting for the result
99  lock.unlock();
100  h.m_promises.Notify();
101  }
102  });
103  if (err < 0) {
104  loop->ReportError(err);
105  return nullptr;
106  }
107  h->Keep();
108  return h;
109  }
110 
121  template <typename... U>
122  future<R> Call(U&&... u) {
123  // create the future
124  uint64_t req = m_promises.CreateRequest();
125 
126  auto loop = m_loop.lock();
127  if (loop && loop->GetThreadId() == std::this_thread::get_id()) {
128  // called from within the loop, just call the function directly
129  wakeup(m_promises.CreatePromise(req), std::forward<U>(u)...);
130  return m_promises.CreateFuture(req);
131  }
132 
133  // add the parameters to the input queue
134  {
135  std::scoped_lock lock(m_mutex);
136  m_params.emplace_back(std::piecewise_construct,
137  std::forward_as_tuple(req),
138  std::forward_as_tuple(std::forward<U>(u)...));
139  }
140 
141  // signal the loop
142  if (loop) this->Invoke(&uv_async_send, this->GetRaw());
143 
144  // return future
145  return m_promises.CreateFuture(req);
146  }
147 
148  template <typename... U>
149  future<R> operator()(U&&... u) {
150  return Call(std::forward<U>(u)...);
151  }
152 
156  std::function<void(promise<R>, T...)> wakeup;
157 
158  private:
159  wpi::mutex m_mutex;
160  std::vector<std::pair<uint64_t, std::tuple<T...>>> m_params;
161  PromiseFactory<R> m_promises;
162  std::weak_ptr<Loop> m_loop;
163 };
164 
165 } // namespace uv
166 } // namespace wpi
167 
168 #endif // WPIUTIL_WPI_UV_ASYNCFUNCTION_H_
wpi::uv::AsyncFunction< R(T...)>::Create
static std::shared_ptr< AsyncFunction > Create(const std::shared_ptr< Loop > &loop, std::function< void(promise< R >, T...)> func=nullptr)
Create an async handle.
Definition: AsyncFunction.h:76
wpi::uv::AsyncFunction< R(T...)>::wakeup
std::function< void(promise< R >, T...)> wakeup
Function called (on event loop thread) when the async is called.
Definition: AsyncFunction.h:156
wpi::PromiseFactory< R >
wpi::promise
A lightweight version of std::promise.
Definition: future.h:33
wpi
WPILib C++ utilities (wpiutil) namespace.
Definition: EventLoopRunner.h:17
wpi::future
A lightweight version of std::future.
Definition: future.h:30
wpi::uv::AsyncFunction
Definition: AsyncFunction.h:30
wpi::uv::HandleImpl
Handle.
Definition: Handle.h:273
wpi::uv::AsyncFunction< R(T...)>::Call
future< R > Call(U &&... u)
Wakeup the event loop, call the async function, and return a future for the result.
Definition: AsyncFunction.h:122
wpi::uv::Loop
Event loop.
Definition: Loop.h:39
wpi::uv::AsyncFunction< R(T...)>::Create
static std::shared_ptr< AsyncFunction > Create(Loop &loop, std::function< void(promise< R >, T...)> func=nullptr)
Create an async handle.
Definition: AsyncFunction.h:62