WPILibC++  2019.1.1-beta-4-27-ga2368a6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
AsyncFunction.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2018 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/STLExtras.h"
22 #include "wpi/future.h"
23 #include "wpi/mutex.h"
24 #include "wpi/uv/Handle.h"
25 #include "wpi/uv/Loop.h"
26 
27 namespace wpi {
28 namespace uv {
29 
30 template <typename T>
32 
38 template <typename R, typename... T>
39 class AsyncFunction<R(T...)> final
40  : public HandleImpl<AsyncFunction<R(T...)>, uv_async_t> {
41  struct private_init {};
42 
43  public:
44  AsyncFunction(const std::shared_ptr<Loop>& loop,
45  std::function<void(promise<R>, T...)> func, const private_init&)
46  : wakeup{func}, m_loop{loop} {}
47  ~AsyncFunction() noexcept override {
48  if (auto loop = m_loop.lock())
49  this->Close();
50  else
51  this->ForceClosed();
52  }
53 
63  static std::shared_ptr<AsyncFunction> Create(
64  Loop& loop, std::function<void(promise<R>, T...)> func = nullptr) {
65  return Create(loop.shared_from_this(), std::move(func));
66  }
67 
77  static std::shared_ptr<AsyncFunction> Create(
78  const std::shared_ptr<Loop>& loop,
79  std::function<void(promise<R>, T...)> func = nullptr) {
80  auto h =
81  std::make_shared<AsyncFunction>(loop, std::move(func), private_init{});
82  int err =
83  uv_async_init(loop->GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
84  auto& h = *static_cast<AsyncFunction*>(handle->data);
85  std::unique_lock<wpi::mutex> lock(h.m_mutex);
86 
87  if (!h.m_params.empty()) {
88  // for each set of parameters in the input queue, call the wakeup
89  // function and put the result in the output queue if the caller is
90  // waiting for it
91  for (auto&& v : h.m_params) {
92  auto p = h.m_promises.CreatePromise(v.first);
93  if (h.wakeup)
94  apply_tuple(h.wakeup,
95  std::tuple_cat(std::make_tuple(std::move(p)),
96  std::move(v.second)));
97  }
98  h.m_params.clear();
99  // wake up any threads that might be waiting for the result
100  lock.unlock();
101  h.m_promises.Notify();
102  }
103  });
104  if (err < 0) {
105  loop->ReportError(err);
106  return nullptr;
107  }
108  h->Keep();
109  return h;
110  }
111 
122  template <typename... U>
123  future<R> Call(U&&... u) {
124  // create the future
125  uint64_t req = m_promises.CreateRequest();
126 
127  auto loop = m_loop.lock();
128  if (loop && loop->GetThreadId() == std::this_thread::get_id()) {
129  // called from within the loop, just call the function directly
130  wakeup(m_promises.CreatePromise(req), std::forward<U>(u)...);
131  return m_promises.CreateFuture(req);
132  }
133 
134  // add the parameters to the input queue
135  {
136  std::lock_guard<wpi::mutex> lock(m_mutex);
137  m_params.emplace_back(std::piecewise_construct,
138  std::forward_as_tuple(req),
139  std::forward_as_tuple(std::forward<U>(u)...));
140  }
141 
142  // signal the loop
143  if (loop) this->Invoke(&uv_async_send, this->GetRaw());
144 
145  // return future
146  return m_promises.CreateFuture(req);
147  }
148 
149  template <typename... U>
150  future<R> operator()(U&&... u) {
151  return Call(std::forward<U>(u)...);
152  }
153 
157  std::function<void(promise<R>, T...)> wakeup;
158 
159  private:
160  wpi::mutex m_mutex;
161  std::vector<std::pair<uint64_t, std::tuple<T...>>> m_params;
162  PromiseFactory<R> m_promises;
163  std::weak_ptr<Loop> m_loop;
164 };
165 
166 } // namespace uv
167 } // namespace wpi
168 
169 #endif // WPIUTIL_WPI_UV_ASYNCFUNCTION_H_
future< R > Call(U &&...u)
Wakeup the event loop, call the async function, and return a future for the result.
Definition: AsyncFunction.h:123
Definition: AsyncFunction.h:31
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:77
Handle.
Definition: Handle.h:249
WPILib C++ utilities (wpiutil) namespace.
Definition: SmallString.h:21
A lightweight version of std::promise.
Definition: future.h:33
auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl(std::forward< F >(f), std::forward< Tuple >(t), build_index_impl< std::tuple_size< typename std::decay< Tuple >::type >::value >
Given an input tuple (a1, a2, ..., an), pass the arguments of the tuple variadically to f as if by ca...
Definition: STLExtras.h:1209
static std::shared_ptr< AsyncFunction > Create(Loop &loop, std::function< void(promise< R >, T...)> func=nullptr)
Create an async handle.
Definition: AsyncFunction.h:63
Definition: uv.h:768
Event loop.
Definition: Loop.h:39
A lightweight version of std::future.
Definition: future.h:30
std::function< void(promise< R >, T...)> wakeup
Function called (on event loop thread) when the async is called.
Definition: AsyncFunction.h:157