awaitable.hpp 29 KB

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