proxygen
Task.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 <experimental/coroutine>
19 #include <type_traits>
20 
21 #include <glog/logging.h>
22 
23 #include <folly/Executor.h>
24 #include <folly/Portability.h>
25 #include <folly/ScopeGuard.h>
26 #include <folly/Try.h>
30 #include <folly/futures/Future.h>
31 
32 namespace folly {
33 namespace coro {
34 
36 
37 template <typename T = void>
38 class Task;
39 
40 template <typename T = void>
42 
43 namespace detail {
44 
46  class FinalAwaiter {
47  public:
49  return false;
50  }
51 
52  template <typename Promise>
53  std::experimental::coroutine_handle<> await_suspend(
54  std::experimental::coroutine_handle<Promise> coro) noexcept {
55  TaskPromiseBase& promise = coro.promise();
56  return promise.continuation_;
57  }
58 
60  };
61 
62  friend class FinalAwaiter;
63 
64  protected:
65  TaskPromiseBase() noexcept : executor_(nullptr) {}
66 
67  public:
68  std::experimental::suspend_always initial_suspend() noexcept {
69  return {};
70  }
71 
73  return {};
74  }
75 
76  template <typename U>
77  auto await_transform(Task<U>&& t) noexcept;
78 
79  template <typename Awaitable>
80  auto await_transform(Awaitable&& awaitable) noexcept {
82  return co_viaIfAsync(executor_, static_cast<Awaitable&&>(awaitable));
83  }
84 
86  return AwaitableReady<folly::Executor*>{executor_};
87  }
88 
89  private:
90  template <typename T>
92 
93  template <typename T>
94  friend class folly::coro::Task;
95 
96  std::experimental::coroutine_handle<> continuation_;
98 };
99 
100 template <typename T>
101 class TaskPromise : public TaskPromiseBase {
102  public:
103  TaskPromise() noexcept = default;
104 
105  Task<T> get_return_object() noexcept;
106 
107  void unhandled_exception() noexcept {
108  result_.emplaceException(
109  exception_wrapper::from_exception_ptr(std::current_exception()));
110  }
111 
112  template <typename U>
113  void return_value(U&& value) {
114  static_assert(
116  "cannot convert return value to type T");
117  result_.emplace(static_cast<U&&>(value));
118  }
119 
121  return static_cast<T&&>(std::move(result_).value());
122  }
123 
124  private:
125  using StorageType = std::conditional_t<
127  std::reference_wrapper<std::remove_reference_t<T>>,
128  T>;
129 
131 };
132 
133 template <>
134 class TaskPromise<void> : public TaskPromiseBase {
135  public:
136  TaskPromise() noexcept = default;
137 
138  Task<void> get_return_object() noexcept;
139 
140  void unhandled_exception() noexcept {
141  result_.emplaceException(
142  exception_wrapper::from_exception_ptr(std::current_exception()));
143  }
144 
145  void return_void() noexcept {}
146 
147  void getResult() {
148  return std::move(result_).value();
149  }
150 
151  private:
153 };
154 
155 } // namespace detail
156 
163 template <typename T>
165  using handle_t = std::experimental::coroutine_handle<detail::TaskPromise<T>>;
166 
167  public:
169  if (coro_) {
170  coro_.destroy();
171  }
172  }
173 
175  : coro_(std::exchange(t.coro_, {})) {}
176 
178  swap(t);
179  return *this;
180  }
181 
183  return coro_.promise().executor_;
184  }
185 
187  std::swap(coro_, t.coro_);
188  }
189 
190  // Start execution of this task eagerly and return a folly::SemiFuture<T>
191  // that will complete with the result.
192  auto start() && {
193  return folly::coro::toSemiFuture(std::move(*this));
194  }
195 
196  class Awaiter {
197  public:
198  explicit Awaiter(handle_t coro) noexcept : coro_(coro) {}
199 
201  if (coro_) {
202  coro_.destroy();
203  }
204  }
205 
206  bool await_ready() const {
207  return false;
208  }
209 
211  std::experimental::coroutine_handle<> continuation) noexcept {
212  auto& promise = coro_.promise();
213  DCHECK(!promise.continuation_);
214  DCHECK(promise.executor_ != nullptr);
215 
216  promise.continuation_ = continuation;
217  promise.executor_->add(coro_);
218  }
219 
220  decltype(auto) await_resume() {
221  // Eagerly destroy the coroutine-frame once we have retrieved the result.
222  SCOPE_EXIT {
223  std::exchange(coro_, {}).destroy();
224  };
225  return coro_.promise().getResult();
226  }
227 
228  private:
230  };
231 
232  Awaiter operator co_await() && noexcept {
233  return Awaiter{std::exchange(coro_, {})};
234  }
235 
236  private:
237  friend class Task<T>;
238 
239  explicit TaskWithExecutor(handle_t coro) noexcept : coro_(coro) {}
240 
242 };
243 
261 template <typename T>
262 class FOLLY_NODISCARD Task {
263  public:
265 
266  private:
267  using handle_t = std::experimental::coroutine_handle<promise_type>;
268 
269  public:
270  Task(const Task& t) = delete;
271 
272  Task(Task&& t) noexcept : coro_(std::exchange(t.coro_, {})) {}
273 
274  ~Task() {
275  if (coro_) {
276  coro_.destroy();
277  }
278  }
279 
281  swap(t);
282  return *this;
283  }
284 
285  void swap(Task& t) noexcept {
286  std::swap(coro_, t.coro_);
287  }
288 
295  coro_.promise().executor_ = executor;
296  return TaskWithExecutor<T>{std::exchange(coro_, {})};
297  }
298 
299  private:
301  friend class detail::TaskPromise<T>;
302 
303  Task(handle_t coro) noexcept : coro_(coro) {}
304 
306 };
307 
308 template <typename T>
310  class Awaiter {
311  using handle_t =
312  std::experimental::coroutine_handle<detail::TaskPromise<T>>;
313 
314  public:
315  explicit Awaiter(handle_t coro) noexcept : coro_(coro) {}
316 
317  Awaiter(Awaiter&& other) noexcept : coro_(std::exchange(other.coro_, {})) {}
318 
319  Awaiter(const Awaiter&) = delete;
320 
321  ~Awaiter() {
322  if (coro_) {
323  coro_.destroy();
324  }
325  }
326 
327  bool await_ready() noexcept {
328  return false;
329  }
330 
331  handle_t await_suspend(
332  std::experimental::coroutine_handle<> continuation) noexcept {
333  coro_.promise().continuation_ = continuation;
334  return coro_;
335  }
336 
337  decltype(auto) await_resume() {
338  SCOPE_EXIT {
339  std::exchange(coro_, {}).destroy();
340  };
341  return coro_.promise().getResult();
342  }
343 
344  private:
345  handle_t coro_;
346  };
347 
348  t.coro_.promise().executor_ = executor_;
349  return Awaiter{std::exchange(t.coro_, {})};
350 }
351 
352 template <typename T>
354  return Task<T>{
355  std::experimental::coroutine_handle<detail::TaskPromise<T>>::from_promise(
356  *this)};
357 }
358 
360  return Task<void>{std::experimental::coroutine_handle<
361  detail::TaskPromise<void>>::from_promise(*this)};
362 }
363 
364 } // namespace coro
365 } // namespace folly
void swap(Task &t) noexcept
Definition: Task.h:285
TaskWithExecutor(handle_t coro) noexcept
Definition: Task.h:239
std::experimental::coroutine_handle continuation_
Definition: Task.h:96
auto await_transform(Task< U > &&t) noexcept
std::experimental::coroutine_handle< detail::TaskPromise< T >> handle_t
Definition: Task.h:165
#define FOLLY_NODISCARD
Definition: Portability.h:64
void unhandled_exception() noexcept
Definition: Task.h:107
FinalAwaiter final_suspend() noexcept
Definition: Task.h:72
void await_suspend(std::experimental::coroutine_handle<> continuation) noexcept
Definition: Task.h:210
void return_value(U &&value)
Definition: Task.h:113
Task(Task &&t) noexcept
Definition: Task.h:272
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
auto co_viaIfAsync(folly::Executor *executor, Awaitable &&awaitable) -> ViaIfAsyncAwaitable< Awaitable >
Definition: ViaIfAsync.h:247
static exception_wrapper from_exception_ptr(std::exception_ptr const &eptr) noexcept
std::experimental::coroutine_handle< promise_type > handle_t
Definition: Task.h:267
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
auto await_transform(Awaitable &&awaitable) noexcept
Definition: Task.h:80
requires E e noexcept(noexcept(s.error(std::move(e))))
handle_t coro_
Definition: Task.h:305
PUSHMI_INLINE_VAR constexpr __adl::get_executor_fn executor
static void destroy()
std::conditional_t< std::is_reference< T >::value, std::reference_wrapper< std::remove_reference_t< T >>, T > StorageType
Definition: Task.h:128
folly::Executor * executor_
Definition: Task.h:97
Try< StorageType > result_
Definition: Task.h:130
FOLLY_NODISCARD TaskWithExecutor< T > scheduleOn(Executor *executor)&&noexcept
Definition: Task.h:294
folly::Executor * executor() const noexcept
Definition: Task.h:182
static const char *const value
Definition: Conv.cpp:50
std::experimental::coroutine_handle await_suspend(std::experimental::coroutine_handle< Promise > coro) noexcept
Definition: Task.h:53
TaskWithExecutor(TaskWithExecutor &&t) noexcept
Definition: Task.h:174
Task & operator=(Task t) noexcept
Definition: Task.h:280
void swap(exception_wrapper &a, exception_wrapper &b) noexcept
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
TaskWithExecutor & operator=(TaskWithExecutor t) noexcept
Definition: Task.h:177
const
Definition: upload.py:398
auto await_transform(folly::coro::getCurrentExecutor) noexcept
Definition: Task.h:85
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
Task< T > get_return_object() noexcept
Definition: Task.h:353
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
Awaiter(handle_t coro) noexcept
Definition: Task.h:198
Task(handle_t coro) noexcept
Definition: Task.h:303
void swap(TaskWithExecutor &t) noexcept
Definition: Task.h:186
std::experimental::suspend_always initial_suspend() noexcept
Definition: Task.h:68