proxygen
BlockingWait.h
Go to the documentation of this file.
1 /*
2  * Copyright 2018-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <folly/Try.h>
20 #include <folly/fibers/Baton.h>
22 
23 #include <cassert>
24 #include <exception>
25 #include <experimental/coroutine>
26 #include <type_traits>
27 #include <utility>
28 
29 namespace folly {
30 namespace coro {
31 
32 namespace detail {
33 
34 template <typename T>
36 
38  struct FinalAwaiter {
40  return false;
41  }
42  template <typename Promise>
44  std::experimental::coroutine_handle<Promise> coro) noexcept {
45  BlockingWaitPromiseBase& promise = coro.promise();
46  promise.baton_.post();
47  }
49  };
50 
51  public:
53 
54  std::experimental::suspend_always initial_suspend() {
55  return {};
56  }
57 
59  return {};
60  }
61 
62  protected:
63  void wait() noexcept {
64  baton_.wait();
65  }
66 
67  private:
69 };
70 
71 template <typename T>
73  public:
74  BlockingWaitPromise() noexcept = default;
75 
76  ~BlockingWaitPromise() = default;
77 
78  BlockingWaitTask<T> get_return_object() noexcept;
79 
80  void unhandled_exception() noexcept {
81  result_->emplaceException(
82  folly::exception_wrapper::from_exception_ptr(std::current_exception()));
83  }
84 
85  template <
86  typename U,
88  void return_value(U&& value) noexcept(
89  std::is_nothrow_constructible<T, U&&>::value) {
90  result_->emplace(static_cast<U&&>(value));
91  }
92 
94  folly::Try<T> result;
95  result_ = &result;
96  std::experimental::coroutine_handle<BlockingWaitPromise<T>>::from_promise(
97  *this)
98  .resume();
99  this->wait();
100  return result;
101  }
102 
103  T get() {
104  return getAsTry().value();
105  }
106 
107  private:
109 };
110 
111 template <typename T>
113  public:
114  BlockingWaitPromise() noexcept = default;
115 
116  ~BlockingWaitPromise() = default;
117 
118  BlockingWaitTask<T&> get_return_object() noexcept;
119 
120  void unhandled_exception() noexcept {
121  result_->emplaceException(
122  folly::exception_wrapper::from_exception_ptr(std::current_exception()));
123  }
124 
125  auto yield_value(T&& value) noexcept {
126  result_->emplace(std::ref(value));
127  return final_suspend();
128  }
129 
130  auto yield_value(T& value) noexcept {
131  result_->emplace(std::ref(value));
132  return final_suspend();
133  }
134 
135 #if 0
136  void return_value(T& value) noexcept {
137  result_->emplace(std::ref(value));
138  }
139 #endif
140 
141  void return_void() {
142  // This should never be reachable.
143  // The coroutine should either have suspended at co_yield or should have
144  // thrown an exception and skipped over the implicit co_return and
145  // gone straight to unhandled_exception().
146  std::abort();
147  }
148 
151  result_ = &result;
152  std::experimental::coroutine_handle<BlockingWaitPromise<T&>>::from_promise(
153  *this)
154  .resume();
155  this->wait();
156  return result;
157  }
158 
159  T& get() {
160  return getAsTry().value();
161  }
162 
163  private:
165 };
166 
167 template <>
168 class BlockingWaitPromise<void> final : public BlockingWaitPromiseBase {
169  public:
170  BlockingWaitPromise() = default;
171 
172  BlockingWaitTask<void> get_return_object() noexcept;
173 
174  void return_void() noexcept {}
175 
176  void unhandled_exception() noexcept {
177  result_->emplaceException(
178  exception_wrapper::from_exception_ptr(std::current_exception()));
179  }
180 
182  folly::Try<void> result;
183  result_ = &result;
184  std::experimental::coroutine_handle<
185  BlockingWaitPromise<void>>::from_promise(*this)
186  .resume();
187  this->wait();
188  return result;
189  }
190 
191  void get() {
192  return getAsTry().value();
193  }
194 
195  private:
197 };
198 
199 template <typename T>
200 class BlockingWaitTask {
201  public:
203  using handle_t = std::experimental::coroutine_handle<promise_type>;
204 
205  explicit BlockingWaitTask(handle_t coro) noexcept : coro_(coro) {}
206 
208  : coro_(std::exchange(other.coro_, {})) {}
209 
210  BlockingWaitTask& operator=(BlockingWaitTask&& other) noexcept = delete;
211 
213  if (coro_) {
214  coro_.destroy();
215  }
216  }
217 
218  decltype(auto) getAsTry() && {
219  return coro_.promise().getAsTry();
220  }
221 
222  decltype(auto) get() && {
223  return coro_.promise().get();
224  }
225 
226  private:
228 };
229 
230 template <typename T>
231 inline BlockingWaitTask<T>
233  return BlockingWaitTask<T>{
234  std::experimental::coroutine_handle<BlockingWaitPromise<T>>::from_promise(
235  *this)};
236 }
237 
238 template <typename T>
241  return BlockingWaitTask<T&>{std::experimental::coroutine_handle<
242  BlockingWaitPromise<T&>>::from_promise(*this)};
243 }
244 
247  return BlockingWaitTask<void>{std::experimental::coroutine_handle<
248  BlockingWaitPromise<void>>::from_promise(*this)};
249 }
250 
251 template <typename T>
253  using type = T;
254 };
255 
256 template <typename T>
257 struct decay_rvalue_reference<T&&> : std::decay<T> {};
258 
259 template <typename T>
261 
262 template <
263  typename Awaitable,
264  typename Result = await_result_t<Awaitable>,
266 auto makeBlockingWaitTask(Awaitable&& awaitable)
268  co_return co_await static_cast<Awaitable&&>(awaitable);
269 }
270 
271 template <
272  typename Awaitable,
273  typename Result = await_result_t<Awaitable>,
275 auto makeBlockingWaitTask(Awaitable&& awaitable)
277  co_yield co_await static_cast<Awaitable&&>(awaitable);
278 }
279 
280 template <
281  typename Awaitable,
282  typename Result = await_result_t<Awaitable>,
285  co_await static_cast<Awaitable&&>(awaitable);
286 }
287 
288 template <
289  typename Awaitable,
290  typename Result = await_result_t<Awaitable>,
292 auto makeRefBlockingWaitTask(Awaitable&& awaitable)
294  co_yield co_await static_cast<Awaitable&&>(awaitable);
295 }
296 
297 } // namespace detail
298 
312 template <typename Awaitable>
313 auto blockingWait(Awaitable&& awaitable)
315  return static_cast<std::add_rvalue_reference_t<await_result_t<Awaitable>>>(
316  detail::makeRefBlockingWaitTask(static_cast<Awaitable&&>(awaitable))
317  .get());
318 }
319 
320 } // namespace coro
321 } // namespace folly
folly::Try< std::reference_wrapper< T > > * result_
Definition: BlockingWait.h:164
void await_suspend(std::experimental::coroutine_handle< Promise > coro) noexcept
Definition: BlockingWait.h:43
BlockingWaitTask(BlockingWaitTask &&other) noexcept
Definition: BlockingWait.h:207
STL namespace.
static exception_wrapper from_exception_ptr(std::exception_ptr const &eptr) noexcept
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
typename await_result< Awaitable >::type await_result_t
Definition: Traits.h:194
std::experimental::suspend_always initial_suspend()
Definition: BlockingWait.h:54
BlockingWaitTask(handle_t coro) noexcept
Definition: BlockingWait.h:205
void return_value(U &&value) noexcept(std::is_nothrow_constructible< T, U && >::value)
Definition: BlockingWait.h:88
static const char *const value
Definition: Conv.cpp:50
Definition: Try.h:51
typename decay_rvalue_reference< T >::type decay_rvalue_reference_t
Definition: BlockingWait.h:260
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
std::experimental::coroutine_handle< promise_type > handle_t
Definition: BlockingWait.h:203
void value() const
Definition: Try.h:447
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
BlockingWaitTask< void > makeRefBlockingWaitTask(Awaitable &&awaitable)
Definition: BlockingWait.h:284
auto makeBlockingWaitTask(Awaitable &&awaitable) -> BlockingWaitTask< decay_rvalue_reference_t< Result >>
Definition: BlockingWait.h:266
BlockingWaitTask< T > get_return_object() noexcept
Definition: BlockingWait.h:232
PUSHMI_INLINE_VAR constexpr detail::get_fn< T > get
Definition: submit.h:391
auto blockingWait(Awaitable &&awaitable) -> detail::decay_rvalue_reference_t< await_result_t< Awaitable >>
Definition: BlockingWait.h:313
folly::Try< std::reference_wrapper< T > > getAsTry()
Definition: BlockingWait.h:149