awaitable.hpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. //
  2. // impl/awaitable.hpp
  3. // ~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_IMPL_AWAITABLE_HPP
  11. #define BOOST_ASIO_IMPL_AWAITABLE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <exception>
  17. #include <new>
  18. #include <tuple>
  19. #include <boost/asio/cancellation_signal.hpp>
  20. #include <boost/asio/cancellation_state.hpp>
  21. #include <boost/asio/detail/thread_context.hpp>
  22. #include <boost/asio/detail/thread_info_base.hpp>
  23. #include <boost/asio/detail/throw_error.hpp>
  24. #include <boost/asio/detail/type_traits.hpp>
  25. #include <boost/asio/error.hpp>
  26. #include <boost/asio/post.hpp>
  27. #include <boost/system/system_error.hpp>
  28. #include <boost/asio/this_coro.hpp>
  29. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  30. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  31. # include <boost/asio/detail/source_location.hpp>
  32. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  33. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  34. #include <boost/asio/detail/push_options.hpp>
  35. namespace boost {
  36. namespace asio {
  37. namespace detail {
  38. struct awaitable_thread_has_context_switched {};
  39. template <typename, typename> class awaitable_async_op_handler;
  40. template <typename, typename, typename> class awaitable_async_op;
  41. // An awaitable_thread represents a thread-of-execution that is composed of one
  42. // or more "stack frames", with each frame represented by an awaitable_frame.
  43. // All execution occurs in the context of the awaitable_thread's executor. An
  44. // awaitable_thread continues to "pump" the stack frames by repeatedly resuming
  45. // the top stack frame until the stack is empty, or until ownership of the
  46. // stack is transferred to another awaitable_thread object.
  47. //
  48. // +------------------------------------+
  49. // | top_of_stack_ |
  50. // | V
  51. // +--------------+---+ +-----------------+
  52. // | | | |
  53. // | awaitable_thread |<---------------------------+ awaitable_frame |
  54. // | | attached_thread_ | |
  55. // +--------------+---+ (Set only when +---+-------------+
  56. // | frames are being |
  57. // | actively pumped | caller_
  58. // | by a thread, and |
  59. // | then only for V
  60. // | the top frame.) +-----------------+
  61. // | | |
  62. // | | awaitable_frame |
  63. // | | |
  64. // | +---+-------------+
  65. // | |
  66. // | | caller_
  67. // | :
  68. // | :
  69. // | |
  70. // | V
  71. // | +-----------------+
  72. // | bottom_of_stack_ | |
  73. // +------------------------------->| awaitable_frame |
  74. // | |
  75. // +-----------------+
  76. template <typename Executor>
  77. class awaitable_frame_base
  78. {
  79. public:
  80. #if !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
  81. void* operator new(std::size_t size)
  82. {
  83. return boost::asio::detail::thread_info_base::allocate(
  84. boost::asio::detail::thread_info_base::awaitable_frame_tag(),
  85. boost::asio::detail::thread_context::top_of_thread_call_stack(),
  86. size);
  87. }
  88. void operator delete(void* pointer, std::size_t size)
  89. {
  90. boost::asio::detail::thread_info_base::deallocate(
  91. boost::asio::detail::thread_info_base::awaitable_frame_tag(),
  92. boost::asio::detail::thread_context::top_of_thread_call_stack(),
  93. pointer, size);
  94. }
  95. #endif // !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
  96. // The frame starts in a suspended state until the awaitable_thread object
  97. // pumps the stack.
  98. auto initial_suspend() noexcept
  99. {
  100. return suspend_always();
  101. }
  102. // On final suspension the frame is popped from the top of the stack.
  103. auto final_suspend() noexcept
  104. {
  105. struct result
  106. {
  107. awaitable_frame_base* this_;
  108. bool await_ready() const noexcept
  109. {
  110. return false;
  111. }
  112. void await_suspend(coroutine_handle<void>) noexcept
  113. {
  114. this->this_->pop_frame();
  115. }
  116. void await_resume() const noexcept
  117. {
  118. }
  119. };
  120. return result{this};
  121. }
  122. void set_except(std::exception_ptr e) noexcept
  123. {
  124. pending_exception_ = e;
  125. }
  126. void set_error(const boost::system::error_code& ec)
  127. {
  128. this->set_except(std::make_exception_ptr(boost::system::system_error(ec)));
  129. }
  130. void unhandled_exception()
  131. {
  132. set_except(std::current_exception());
  133. }
  134. void rethrow_exception()
  135. {
  136. if (pending_exception_)
  137. {
  138. std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
  139. std::rethrow_exception(ex);
  140. }
  141. }
  142. void clear_cancellation_slot()
  143. {
  144. this->attached_thread_->entry_point()->cancellation_state_.slot().clear();
  145. }
  146. template <typename T>
  147. auto await_transform(awaitable<T, Executor> a) const
  148. {
  149. if (attached_thread_->entry_point()->throw_if_cancelled_)
  150. if (!!attached_thread_->get_cancellation_state().cancelled())
  151. throw_error(boost::asio::error::operation_aborted, "co_await");
  152. return a;
  153. }
  154. template <typename Op>
  155. auto await_transform(Op&& op,
  156. constraint_t<is_async_operation<Op>::value> = 0
  157. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  158. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  159. , detail::source_location location = detail::source_location::current()
  160. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  161. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  162. )
  163. {
  164. if (attached_thread_->entry_point()->throw_if_cancelled_)
  165. if (!!attached_thread_->get_cancellation_state().cancelled())
  166. throw_error(boost::asio::error::operation_aborted, "co_await");
  167. return awaitable_async_op<
  168. completion_signature_of_t<Op>, decay_t<Op>, Executor>{
  169. std::forward<Op>(op), this
  170. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  171. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  172. , location
  173. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  174. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  175. };
  176. }
  177. // This await transformation obtains the associated executor of the thread of
  178. // execution.
  179. auto await_transform(this_coro::executor_t) noexcept
  180. {
  181. struct result
  182. {
  183. awaitable_frame_base* this_;
  184. bool await_ready() const noexcept
  185. {
  186. return true;
  187. }
  188. void await_suspend(coroutine_handle<void>) noexcept
  189. {
  190. }
  191. auto await_resume() const noexcept
  192. {
  193. return this_->attached_thread_->get_executor();
  194. }
  195. };
  196. return result{this};
  197. }
  198. // This await transformation obtains the associated cancellation state of the
  199. // thread of execution.
  200. auto await_transform(this_coro::cancellation_state_t) noexcept
  201. {
  202. struct result
  203. {
  204. awaitable_frame_base* this_;
  205. bool await_ready() const noexcept
  206. {
  207. return true;
  208. }
  209. void await_suspend(coroutine_handle<void>) noexcept
  210. {
  211. }
  212. auto await_resume() const noexcept
  213. {
  214. return this_->attached_thread_->get_cancellation_state();
  215. }
  216. };
  217. return result{this};
  218. }
  219. // This await transformation resets the associated cancellation state.
  220. auto await_transform(this_coro::reset_cancellation_state_0_t) noexcept
  221. {
  222. struct result
  223. {
  224. awaitable_frame_base* this_;
  225. bool await_ready() const noexcept
  226. {
  227. return true;
  228. }
  229. void await_suspend(coroutine_handle<void>) noexcept
  230. {
  231. }
  232. auto await_resume() const
  233. {
  234. return this_->attached_thread_->reset_cancellation_state();
  235. }
  236. };
  237. return result{this};
  238. }
  239. // This await transformation resets the associated cancellation state.
  240. template <typename Filter>
  241. auto await_transform(
  242. this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept
  243. {
  244. struct result
  245. {
  246. awaitable_frame_base* this_;
  247. Filter filter_;
  248. bool await_ready() const noexcept
  249. {
  250. return true;
  251. }
  252. void await_suspend(coroutine_handle<void>) noexcept
  253. {
  254. }
  255. auto await_resume()
  256. {
  257. return this_->attached_thread_->reset_cancellation_state(
  258. static_cast<Filter&&>(filter_));
  259. }
  260. };
  261. return result{this, static_cast<Filter&&>(reset.filter)};
  262. }
  263. // This await transformation resets the associated cancellation state.
  264. template <typename InFilter, typename OutFilter>
  265. auto await_transform(
  266. this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset)
  267. noexcept
  268. {
  269. struct result
  270. {
  271. awaitable_frame_base* this_;
  272. InFilter in_filter_;
  273. OutFilter out_filter_;
  274. bool await_ready() const noexcept
  275. {
  276. return true;
  277. }
  278. void await_suspend(coroutine_handle<void>) noexcept
  279. {
  280. }
  281. auto await_resume()
  282. {
  283. return this_->attached_thread_->reset_cancellation_state(
  284. static_cast<InFilter&&>(in_filter_),
  285. static_cast<OutFilter&&>(out_filter_));
  286. }
  287. };
  288. return result{this,
  289. static_cast<InFilter&&>(reset.in_filter),
  290. static_cast<OutFilter&&>(reset.out_filter)};
  291. }
  292. // This await transformation determines whether cancellation is propagated as
  293. // an exception.
  294. auto await_transform(this_coro::throw_if_cancelled_0_t)
  295. noexcept
  296. {
  297. struct result
  298. {
  299. awaitable_frame_base* this_;
  300. bool await_ready() const noexcept
  301. {
  302. return true;
  303. }
  304. void await_suspend(coroutine_handle<void>) noexcept
  305. {
  306. }
  307. auto await_resume()
  308. {
  309. return this_->attached_thread_->throw_if_cancelled();
  310. }
  311. };
  312. return result{this};
  313. }
  314. // This await transformation sets whether cancellation is propagated as an
  315. // exception.
  316. auto await_transform(this_coro::throw_if_cancelled_1_t throw_if_cancelled)
  317. noexcept
  318. {
  319. struct result
  320. {
  321. awaitable_frame_base* this_;
  322. bool value_;
  323. bool await_ready() const noexcept
  324. {
  325. return true;
  326. }
  327. void await_suspend(coroutine_handle<void>) noexcept
  328. {
  329. }
  330. auto await_resume()
  331. {
  332. this_->attached_thread_->throw_if_cancelled(value_);
  333. }
  334. };
  335. return result{this, throw_if_cancelled.value};
  336. }
  337. // This await transformation is used to run an async operation's initiation
  338. // function object after the coroutine has been suspended. This ensures that
  339. // immediate resumption of the coroutine in another thread does not cause a
  340. // race condition.
  341. template <typename Function>
  342. auto await_transform(Function f,
  343. enable_if_t<
  344. is_convertible<
  345. result_of_t<Function(awaitable_frame_base*)>,
  346. awaitable_thread<Executor>*
  347. >::value
  348. >* = nullptr)
  349. {
  350. struct result
  351. {
  352. Function function_;
  353. awaitable_frame_base* this_;
  354. bool await_ready() const noexcept
  355. {
  356. return false;
  357. }
  358. void await_suspend(coroutine_handle<void>) noexcept
  359. {
  360. this_->after_suspend(
  361. [](void* arg)
  362. {
  363. result* r = static_cast<result*>(arg);
  364. r->function_(r->this_);
  365. }, this);
  366. }
  367. void await_resume() const noexcept
  368. {
  369. }
  370. };
  371. return result{std::move(f), this};
  372. }
  373. // Access the awaitable thread's has_context_switched_ flag.
  374. auto await_transform(detail::awaitable_thread_has_context_switched) noexcept
  375. {
  376. struct result
  377. {
  378. awaitable_frame_base* this_;
  379. bool await_ready() const noexcept
  380. {
  381. return true;
  382. }
  383. void await_suspend(coroutine_handle<void>) noexcept
  384. {
  385. }
  386. bool& await_resume() const noexcept
  387. {
  388. return this_->attached_thread_->entry_point()->has_context_switched_;
  389. }
  390. };
  391. return result{this};
  392. }
  393. void attach_thread(awaitable_thread<Executor>* handler) noexcept
  394. {
  395. attached_thread_ = handler;
  396. }
  397. awaitable_thread<Executor>* detach_thread() noexcept
  398. {
  399. attached_thread_->entry_point()->has_context_switched_ = true;
  400. return std::exchange(attached_thread_, nullptr);
  401. }
  402. void push_frame(awaitable_frame_base<Executor>* caller) noexcept
  403. {
  404. caller_ = caller;
  405. attached_thread_ = caller_->attached_thread_;
  406. attached_thread_->entry_point()->top_of_stack_ = this;
  407. caller_->attached_thread_ = nullptr;
  408. }
  409. void pop_frame() noexcept
  410. {
  411. if (caller_)
  412. caller_->attached_thread_ = attached_thread_;
  413. attached_thread_->entry_point()->top_of_stack_ = caller_;
  414. attached_thread_ = nullptr;
  415. caller_ = nullptr;
  416. }
  417. struct resume_context
  418. {
  419. void (*after_suspend_fn_)(void*) = nullptr;
  420. void *after_suspend_arg_ = nullptr;
  421. };
  422. void resume()
  423. {
  424. resume_context context;
  425. resume_context_ = &context;
  426. coro_.resume();
  427. if (context.after_suspend_fn_)
  428. context.after_suspend_fn_(context.after_suspend_arg_);
  429. }
  430. void after_suspend(void (*fn)(void*), void* arg)
  431. {
  432. resume_context_->after_suspend_fn_ = fn;
  433. resume_context_->after_suspend_arg_ = arg;
  434. }
  435. void destroy()
  436. {
  437. coro_.destroy();
  438. }
  439. protected:
  440. coroutine_handle<void> coro_ = nullptr;
  441. awaitable_thread<Executor>* attached_thread_ = nullptr;
  442. awaitable_frame_base<Executor>* caller_ = nullptr;
  443. std::exception_ptr pending_exception_ = nullptr;
  444. resume_context* resume_context_ = nullptr;
  445. };
  446. template <typename T, typename Executor>
  447. class awaitable_frame
  448. : public awaitable_frame_base<Executor>
  449. {
  450. public:
  451. awaitable_frame() noexcept
  452. {
  453. }
  454. awaitable_frame(awaitable_frame&& other) noexcept
  455. : awaitable_frame_base<Executor>(std::move(other))
  456. {
  457. }
  458. ~awaitable_frame()
  459. {
  460. if (has_result_)
  461. static_cast<T*>(static_cast<void*>(result_))->~T();
  462. }
  463. awaitable<T, Executor> get_return_object() noexcept
  464. {
  465. this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
  466. return awaitable<T, Executor>(this);
  467. };
  468. template <typename U>
  469. void return_value(U&& u)
  470. {
  471. new (&result_) T(std::forward<U>(u));
  472. has_result_ = true;
  473. }
  474. template <typename... Us>
  475. void return_values(Us&&... us)
  476. {
  477. this->return_value(std::forward_as_tuple(std::forward<Us>(us)...));
  478. }
  479. T get()
  480. {
  481. this->caller_ = nullptr;
  482. this->rethrow_exception();
  483. return std::move(*static_cast<T*>(static_cast<void*>(result_)));
  484. }
  485. private:
  486. alignas(T) unsigned char result_[sizeof(T)];
  487. bool has_result_ = false;
  488. };
  489. template <typename Executor>
  490. class awaitable_frame<void, Executor>
  491. : public awaitable_frame_base<Executor>
  492. {
  493. public:
  494. awaitable<void, Executor> get_return_object()
  495. {
  496. this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
  497. return awaitable<void, Executor>(this);
  498. };
  499. void return_void()
  500. {
  501. }
  502. void get()
  503. {
  504. this->caller_ = nullptr;
  505. this->rethrow_exception();
  506. }
  507. };
  508. struct awaitable_thread_entry_point {};
  509. template <typename Executor>
  510. class awaitable_frame<awaitable_thread_entry_point, Executor>
  511. : public awaitable_frame_base<Executor>
  512. {
  513. public:
  514. awaitable_frame()
  515. : top_of_stack_(0),
  516. has_executor_(false),
  517. has_context_switched_(false),
  518. throw_if_cancelled_(true)
  519. {
  520. }
  521. ~awaitable_frame()
  522. {
  523. if (has_executor_)
  524. u_.executor_.~Executor();
  525. }
  526. awaitable<awaitable_thread_entry_point, Executor> get_return_object()
  527. {
  528. this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
  529. return awaitable<awaitable_thread_entry_point, Executor>(this);
  530. };
  531. void return_void()
  532. {
  533. }
  534. void get()
  535. {
  536. this->caller_ = nullptr;
  537. this->rethrow_exception();
  538. }
  539. private:
  540. template <typename> friend class awaitable_frame_base;
  541. template <typename, typename> friend class awaitable_async_op_handler;
  542. template <typename, typename> friend class awaitable_handler_base;
  543. template <typename> friend class awaitable_thread;
  544. union u
  545. {
  546. u() {}
  547. ~u() {}
  548. char c_;
  549. Executor executor_;
  550. } u_;
  551. awaitable_frame_base<Executor>* top_of_stack_;
  552. boost::asio::cancellation_slot parent_cancellation_slot_;
  553. boost::asio::cancellation_state cancellation_state_;
  554. bool has_executor_;
  555. bool has_context_switched_;
  556. bool throw_if_cancelled_;
  557. };
  558. template <typename Executor>
  559. class awaitable_thread
  560. {
  561. public:
  562. typedef Executor executor_type;
  563. typedef cancellation_slot cancellation_slot_type;
  564. // Construct from the entry point of a new thread of execution.
  565. awaitable_thread(awaitable<awaitable_thread_entry_point, Executor> p,
  566. const Executor& ex, cancellation_slot parent_cancel_slot,
  567. cancellation_state cancel_state)
  568. : bottom_of_stack_(std::move(p))
  569. {
  570. bottom_of_stack_.frame_->top_of_stack_ = bottom_of_stack_.frame_;
  571. new (&bottom_of_stack_.frame_->u_.executor_) Executor(ex);
  572. bottom_of_stack_.frame_->has_executor_ = true;
  573. bottom_of_stack_.frame_->parent_cancellation_slot_ = parent_cancel_slot;
  574. bottom_of_stack_.frame_->cancellation_state_ = cancel_state;
  575. }
  576. // Transfer ownership from another awaitable_thread.
  577. awaitable_thread(awaitable_thread&& other) noexcept
  578. : bottom_of_stack_(std::move(other.bottom_of_stack_))
  579. {
  580. }
  581. // Clean up with a last ditch effort to ensure the thread is unwound within
  582. // the context of the executor.
  583. ~awaitable_thread()
  584. {
  585. if (bottom_of_stack_.valid())
  586. {
  587. // Coroutine "stack unwinding" must be performed through the executor.
  588. auto* bottom_frame = bottom_of_stack_.frame_;
  589. (post)(bottom_frame->u_.executor_,
  590. [a = std::move(bottom_of_stack_)]() mutable
  591. {
  592. (void)awaitable<awaitable_thread_entry_point, Executor>(
  593. std::move(a));
  594. });
  595. }
  596. }
  597. awaitable_frame<awaitable_thread_entry_point, Executor>* entry_point()
  598. {
  599. return bottom_of_stack_.frame_;
  600. }
  601. executor_type get_executor() const noexcept
  602. {
  603. return bottom_of_stack_.frame_->u_.executor_;
  604. }
  605. cancellation_state get_cancellation_state() const noexcept
  606. {
  607. return bottom_of_stack_.frame_->cancellation_state_;
  608. }
  609. void reset_cancellation_state()
  610. {
  611. bottom_of_stack_.frame_->cancellation_state_ =
  612. cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_);
  613. }
  614. template <typename Filter>
  615. void reset_cancellation_state(Filter&& filter)
  616. {
  617. bottom_of_stack_.frame_->cancellation_state_ =
  618. cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_,
  619. static_cast<Filter&&>(filter));
  620. }
  621. template <typename InFilter, typename OutFilter>
  622. void reset_cancellation_state(InFilter&& in_filter,
  623. OutFilter&& out_filter)
  624. {
  625. bottom_of_stack_.frame_->cancellation_state_ =
  626. cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_,
  627. static_cast<InFilter&&>(in_filter),
  628. static_cast<OutFilter&&>(out_filter));
  629. }
  630. bool throw_if_cancelled() const
  631. {
  632. return bottom_of_stack_.frame_->throw_if_cancelled_;
  633. }
  634. void throw_if_cancelled(bool value)
  635. {
  636. bottom_of_stack_.frame_->throw_if_cancelled_ = value;
  637. }
  638. cancellation_slot_type get_cancellation_slot() const noexcept
  639. {
  640. return bottom_of_stack_.frame_->cancellation_state_.slot();
  641. }
  642. // Launch a new thread of execution.
  643. void launch()
  644. {
  645. bottom_of_stack_.frame_->top_of_stack_->attach_thread(this);
  646. pump();
  647. }
  648. protected:
  649. template <typename> friend class awaitable_frame_base;
  650. // Repeatedly resume the top stack frame until the stack is empty or until it
  651. // has been transferred to another resumable_thread object.
  652. void pump()
  653. {
  654. do
  655. bottom_of_stack_.frame_->top_of_stack_->resume();
  656. while (bottom_of_stack_.frame_ && bottom_of_stack_.frame_->top_of_stack_);
  657. if (bottom_of_stack_.frame_)
  658. {
  659. awaitable<awaitable_thread_entry_point, Executor> a(
  660. std::move(bottom_of_stack_));
  661. a.frame_->rethrow_exception();
  662. }
  663. }
  664. awaitable<awaitable_thread_entry_point, Executor> bottom_of_stack_;
  665. };
  666. template <typename Signature, typename Executor>
  667. class awaitable_async_op_handler;
  668. template <typename R, typename Executor>
  669. class awaitable_async_op_handler<R(), Executor>
  670. : public awaitable_thread<Executor>
  671. {
  672. public:
  673. struct result_type {};
  674. awaitable_async_op_handler(
  675. awaitable_thread<Executor>* h, result_type&)
  676. : awaitable_thread<Executor>(std::move(*h))
  677. {
  678. }
  679. void operator()()
  680. {
  681. this->entry_point()->top_of_stack_->attach_thread(this);
  682. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  683. this->pump();
  684. }
  685. static void resume(result_type&)
  686. {
  687. }
  688. };
  689. template <typename R, typename Executor>
  690. class awaitable_async_op_handler<R(boost::system::error_code), Executor>
  691. : public awaitable_thread<Executor>
  692. {
  693. public:
  694. typedef boost::system::error_code* result_type;
  695. awaitable_async_op_handler(
  696. awaitable_thread<Executor>* h, result_type& result)
  697. : awaitable_thread<Executor>(std::move(*h)),
  698. result_(result)
  699. {
  700. }
  701. void operator()(boost::system::error_code ec)
  702. {
  703. result_ = &ec;
  704. this->entry_point()->top_of_stack_->attach_thread(this);
  705. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  706. this->pump();
  707. }
  708. static void resume(result_type& result)
  709. {
  710. throw_error(*result);
  711. }
  712. private:
  713. result_type& result_;
  714. };
  715. template <typename R, typename Executor>
  716. class awaitable_async_op_handler<R(std::exception_ptr), Executor>
  717. : public awaitable_thread<Executor>
  718. {
  719. public:
  720. typedef std::exception_ptr* result_type;
  721. awaitable_async_op_handler(
  722. awaitable_thread<Executor>* h, result_type& result)
  723. : awaitable_thread<Executor>(std::move(*h)),
  724. result_(result)
  725. {
  726. }
  727. void operator()(std::exception_ptr ex)
  728. {
  729. result_ = &ex;
  730. this->entry_point()->top_of_stack_->attach_thread(this);
  731. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  732. this->pump();
  733. }
  734. static void resume(result_type& result)
  735. {
  736. if (*result)
  737. {
  738. std::exception_ptr ex = std::exchange(*result, nullptr);
  739. std::rethrow_exception(ex);
  740. }
  741. }
  742. private:
  743. result_type& result_;
  744. };
  745. template <typename R, typename T, typename Executor>
  746. class awaitable_async_op_handler<R(T), Executor>
  747. : public awaitable_thread<Executor>
  748. {
  749. public:
  750. typedef T* result_type;
  751. awaitable_async_op_handler(
  752. awaitable_thread<Executor>* h, result_type& result)
  753. : awaitable_thread<Executor>(std::move(*h)),
  754. result_(result)
  755. {
  756. }
  757. void operator()(T result)
  758. {
  759. result_ = &result;
  760. this->entry_point()->top_of_stack_->attach_thread(this);
  761. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  762. this->pump();
  763. }
  764. static T resume(result_type& result)
  765. {
  766. return std::move(*result);
  767. }
  768. private:
  769. result_type& result_;
  770. };
  771. template <typename R, typename T, typename Executor>
  772. class awaitable_async_op_handler<R(boost::system::error_code, T), Executor>
  773. : public awaitable_thread<Executor>
  774. {
  775. public:
  776. struct result_type
  777. {
  778. boost::system::error_code* ec_;
  779. T* value_;
  780. };
  781. awaitable_async_op_handler(
  782. awaitable_thread<Executor>* h, result_type& result)
  783. : awaitable_thread<Executor>(std::move(*h)),
  784. result_(result)
  785. {
  786. }
  787. void operator()(boost::system::error_code ec, T value)
  788. {
  789. result_.ec_ = &ec;
  790. result_.value_ = &value;
  791. this->entry_point()->top_of_stack_->attach_thread(this);
  792. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  793. this->pump();
  794. }
  795. static T resume(result_type& result)
  796. {
  797. throw_error(*result.ec_);
  798. return std::move(*result.value_);
  799. }
  800. private:
  801. result_type& result_;
  802. };
  803. template <typename R, typename T, typename Executor>
  804. class awaitable_async_op_handler<R(std::exception_ptr, T), Executor>
  805. : public awaitable_thread<Executor>
  806. {
  807. public:
  808. struct result_type
  809. {
  810. std::exception_ptr* ex_;
  811. T* value_;
  812. };
  813. awaitable_async_op_handler(
  814. awaitable_thread<Executor>* h, result_type& result)
  815. : awaitable_thread<Executor>(std::move(*h)),
  816. result_(result)
  817. {
  818. }
  819. void operator()(std::exception_ptr ex, T value)
  820. {
  821. result_.ex_ = &ex;
  822. result_.value_ = &value;
  823. this->entry_point()->top_of_stack_->attach_thread(this);
  824. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  825. this->pump();
  826. }
  827. static T resume(result_type& result)
  828. {
  829. if (*result.ex_)
  830. {
  831. std::exception_ptr ex = std::exchange(*result.ex_, nullptr);
  832. std::rethrow_exception(ex);
  833. }
  834. return std::move(*result.value_);
  835. }
  836. private:
  837. result_type& result_;
  838. };
  839. template <typename R, typename... Ts, typename Executor>
  840. class awaitable_async_op_handler<R(Ts...), Executor>
  841. : public awaitable_thread<Executor>
  842. {
  843. public:
  844. typedef std::tuple<Ts...>* result_type;
  845. awaitable_async_op_handler(
  846. awaitable_thread<Executor>* h, result_type& result)
  847. : awaitable_thread<Executor>(std::move(*h)),
  848. result_(result)
  849. {
  850. }
  851. template <typename... Args>
  852. void operator()(Args&&... args)
  853. {
  854. std::tuple<Ts...> result(std::forward<Args>(args)...);
  855. result_ = &result;
  856. this->entry_point()->top_of_stack_->attach_thread(this);
  857. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  858. this->pump();
  859. }
  860. static std::tuple<Ts...> resume(result_type& result)
  861. {
  862. return std::move(*result);
  863. }
  864. private:
  865. result_type& result_;
  866. };
  867. template <typename R, typename... Ts, typename Executor>
  868. class awaitable_async_op_handler<R(boost::system::error_code, Ts...), Executor>
  869. : public awaitable_thread<Executor>
  870. {
  871. public:
  872. struct result_type
  873. {
  874. boost::system::error_code* ec_;
  875. std::tuple<Ts...>* value_;
  876. };
  877. awaitable_async_op_handler(
  878. awaitable_thread<Executor>* h, result_type& result)
  879. : awaitable_thread<Executor>(std::move(*h)),
  880. result_(result)
  881. {
  882. }
  883. template <typename... Args>
  884. void operator()(boost::system::error_code ec, Args&&... args)
  885. {
  886. result_.ec_ = &ec;
  887. std::tuple<Ts...> value(std::forward<Args>(args)...);
  888. result_.value_ = &value;
  889. this->entry_point()->top_of_stack_->attach_thread(this);
  890. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  891. this->pump();
  892. }
  893. static std::tuple<Ts...> resume(result_type& result)
  894. {
  895. throw_error(*result.ec_);
  896. return std::move(*result.value_);
  897. }
  898. private:
  899. result_type& result_;
  900. };
  901. template <typename R, typename... Ts, typename Executor>
  902. class awaitable_async_op_handler<R(std::exception_ptr, Ts...), Executor>
  903. : public awaitable_thread<Executor>
  904. {
  905. public:
  906. struct result_type
  907. {
  908. std::exception_ptr* ex_;
  909. std::tuple<Ts...>* value_;
  910. };
  911. awaitable_async_op_handler(
  912. awaitable_thread<Executor>* h, result_type& result)
  913. : awaitable_thread<Executor>(std::move(*h)),
  914. result_(result)
  915. {
  916. }
  917. template <typename... Args>
  918. void operator()(std::exception_ptr ex, Args&&... args)
  919. {
  920. result_.ex_ = &ex;
  921. std::tuple<Ts...> value(std::forward<Args>(args)...);
  922. result_.value_ = &value;
  923. this->entry_point()->top_of_stack_->attach_thread(this);
  924. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  925. this->pump();
  926. }
  927. static std::tuple<Ts...> resume(result_type& result)
  928. {
  929. if (*result.ex_)
  930. {
  931. std::exception_ptr ex = std::exchange(*result.ex_, nullptr);
  932. std::rethrow_exception(ex);
  933. }
  934. return std::move(*result.value_);
  935. }
  936. private:
  937. result_type& result_;
  938. };
  939. template <typename Signature, typename Op, typename Executor>
  940. class awaitable_async_op
  941. {
  942. public:
  943. typedef awaitable_async_op_handler<Signature, Executor> handler_type;
  944. awaitable_async_op(Op&& o, awaitable_frame_base<Executor>* frame
  945. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  946. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  947. , const detail::source_location& location
  948. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  949. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  950. )
  951. : op_(std::forward<Op>(o)),
  952. frame_(frame),
  953. result_()
  954. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  955. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  956. , location_(location)
  957. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  958. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  959. {
  960. }
  961. bool await_ready() const noexcept
  962. {
  963. return false;
  964. }
  965. void await_suspend(coroutine_handle<void>)
  966. {
  967. frame_->after_suspend(
  968. [](void* arg)
  969. {
  970. awaitable_async_op* self = static_cast<awaitable_async_op*>(arg);
  971. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  972. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  973. BOOST_ASIO_HANDLER_LOCATION((self->location_.file_name(),
  974. self->location_.line(), self->location_.function_name()));
  975. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  976. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  977. std::forward<Op&&>(self->op_)(
  978. handler_type(self->frame_->detach_thread(), self->result_));
  979. }, this);
  980. }
  981. auto await_resume()
  982. {
  983. return handler_type::resume(result_);
  984. }
  985. private:
  986. Op&& op_;
  987. awaitable_frame_base<Executor>* frame_;
  988. typename handler_type::result_type result_;
  989. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  990. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  991. detail::source_location location_;
  992. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  993. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  994. };
  995. } // namespace detail
  996. } // namespace asio
  997. } // namespace boost
  998. #if !defined(GENERATING_DOCUMENTATION)
  999. # if defined(BOOST_ASIO_HAS_STD_COROUTINE)
  1000. namespace std {
  1001. template <typename T, typename Executor, typename... Args>
  1002. struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
  1003. {
  1004. typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
  1005. };
  1006. } // namespace std
  1007. # else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  1008. namespace std { namespace experimental {
  1009. template <typename T, typename Executor, typename... Args>
  1010. struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
  1011. {
  1012. typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
  1013. };
  1014. }} // namespace std::experimental
  1015. # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  1016. #endif // !defined(GENERATING_DOCUMENTATION)
  1017. #include <boost/asio/detail/pop_options.hpp>
  1018. #endif // BOOST_ASIO_IMPL_AWAITABLE_HPP