awaitable.hpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. //
  2. // impl/awaitable.hpp
  3. // ~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 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. std::launder(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(*std::launder(
  484. static_cast<T*>(static_cast<void*>(result_))));
  485. }
  486. private:
  487. alignas(T) unsigned char result_[sizeof(T)];
  488. bool has_result_ = false;
  489. };
  490. template <typename Executor>
  491. class awaitable_frame<void, Executor>
  492. : public awaitable_frame_base<Executor>
  493. {
  494. public:
  495. awaitable<void, Executor> get_return_object()
  496. {
  497. this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
  498. return awaitable<void, Executor>(this);
  499. };
  500. void return_void()
  501. {
  502. }
  503. void get()
  504. {
  505. this->caller_ = nullptr;
  506. this->rethrow_exception();
  507. }
  508. };
  509. struct awaitable_thread_entry_point {};
  510. template <typename Executor>
  511. class awaitable_frame<awaitable_thread_entry_point, Executor>
  512. : public awaitable_frame_base<Executor>
  513. {
  514. public:
  515. awaitable_frame()
  516. : top_of_stack_(0),
  517. has_executor_(false),
  518. has_context_switched_(false),
  519. throw_if_cancelled_(true)
  520. {
  521. }
  522. ~awaitable_frame()
  523. {
  524. if (has_executor_)
  525. u_.executor_.~Executor();
  526. }
  527. awaitable<awaitable_thread_entry_point, Executor> get_return_object()
  528. {
  529. this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
  530. return awaitable<awaitable_thread_entry_point, Executor>(this);
  531. };
  532. void return_void()
  533. {
  534. }
  535. void get()
  536. {
  537. this->caller_ = nullptr;
  538. this->rethrow_exception();
  539. }
  540. private:
  541. template <typename> friend class awaitable_frame_base;
  542. template <typename, typename> friend class awaitable_async_op_handler;
  543. template <typename, typename> friend class awaitable_handler_base;
  544. template <typename> friend class awaitable_thread;
  545. union u
  546. {
  547. u() {}
  548. ~u() {}
  549. char c_;
  550. Executor executor_;
  551. } u_;
  552. awaitable_frame_base<Executor>* top_of_stack_;
  553. boost::asio::cancellation_slot parent_cancellation_slot_;
  554. boost::asio::cancellation_state cancellation_state_;
  555. bool has_executor_;
  556. bool has_context_switched_;
  557. bool throw_if_cancelled_;
  558. };
  559. template <typename Executor>
  560. class awaitable_thread
  561. {
  562. public:
  563. typedef Executor executor_type;
  564. typedef cancellation_slot cancellation_slot_type;
  565. // Construct from the entry point of a new thread of execution.
  566. awaitable_thread(awaitable<awaitable_thread_entry_point, Executor> p,
  567. const Executor& ex, cancellation_slot parent_cancel_slot,
  568. cancellation_state cancel_state)
  569. : bottom_of_stack_(std::move(p))
  570. {
  571. bottom_of_stack_.frame_->top_of_stack_ = bottom_of_stack_.frame_;
  572. new (&bottom_of_stack_.frame_->u_.executor_) Executor(ex);
  573. bottom_of_stack_.frame_->has_executor_ = true;
  574. bottom_of_stack_.frame_->parent_cancellation_slot_ = parent_cancel_slot;
  575. bottom_of_stack_.frame_->cancellation_state_ = cancel_state;
  576. }
  577. // Transfer ownership from another awaitable_thread.
  578. awaitable_thread(awaitable_thread&& other) noexcept
  579. : bottom_of_stack_(std::move(other.bottom_of_stack_))
  580. {
  581. }
  582. // Clean up with a last ditch effort to ensure the thread is unwound within
  583. // the context of the executor.
  584. ~awaitable_thread()
  585. {
  586. if (bottom_of_stack_.valid())
  587. {
  588. // Coroutine "stack unwinding" must be performed through the executor.
  589. auto* bottom_frame = bottom_of_stack_.frame_;
  590. (post)(bottom_frame->u_.executor_,
  591. [a = std::move(bottom_of_stack_)]() mutable
  592. {
  593. (void)awaitable<awaitable_thread_entry_point, Executor>(
  594. std::move(a));
  595. });
  596. }
  597. }
  598. awaitable_frame<awaitable_thread_entry_point, Executor>* entry_point()
  599. {
  600. return bottom_of_stack_.frame_;
  601. }
  602. executor_type get_executor() const noexcept
  603. {
  604. return bottom_of_stack_.frame_->u_.executor_;
  605. }
  606. cancellation_state get_cancellation_state() const noexcept
  607. {
  608. return bottom_of_stack_.frame_->cancellation_state_;
  609. }
  610. void reset_cancellation_state()
  611. {
  612. bottom_of_stack_.frame_->cancellation_state_ =
  613. cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_);
  614. }
  615. template <typename Filter>
  616. void reset_cancellation_state(Filter&& filter)
  617. {
  618. bottom_of_stack_.frame_->cancellation_state_ =
  619. cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_,
  620. static_cast<Filter&&>(filter));
  621. }
  622. template <typename InFilter, typename OutFilter>
  623. void reset_cancellation_state(InFilter&& in_filter,
  624. OutFilter&& out_filter)
  625. {
  626. bottom_of_stack_.frame_->cancellation_state_ =
  627. cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_,
  628. static_cast<InFilter&&>(in_filter),
  629. static_cast<OutFilter&&>(out_filter));
  630. }
  631. bool throw_if_cancelled() const
  632. {
  633. return bottom_of_stack_.frame_->throw_if_cancelled_;
  634. }
  635. void throw_if_cancelled(bool value)
  636. {
  637. bottom_of_stack_.frame_->throw_if_cancelled_ = value;
  638. }
  639. cancellation_slot_type get_cancellation_slot() const noexcept
  640. {
  641. return bottom_of_stack_.frame_->cancellation_state_.slot();
  642. }
  643. // Launch a new thread of execution.
  644. void launch()
  645. {
  646. bottom_of_stack_.frame_->top_of_stack_->attach_thread(this);
  647. pump();
  648. }
  649. protected:
  650. template <typename> friend class awaitable_frame_base;
  651. // Repeatedly resume the top stack frame until the stack is empty or until it
  652. // has been transferred to another resumable_thread object.
  653. void pump()
  654. {
  655. do
  656. bottom_of_stack_.frame_->top_of_stack_->resume();
  657. while (bottom_of_stack_.frame_ && bottom_of_stack_.frame_->top_of_stack_);
  658. if (bottom_of_stack_.frame_)
  659. {
  660. awaitable<awaitable_thread_entry_point, Executor> a(
  661. std::move(bottom_of_stack_));
  662. a.frame_->rethrow_exception();
  663. }
  664. }
  665. awaitable<awaitable_thread_entry_point, Executor> bottom_of_stack_;
  666. };
  667. template <typename Signature, typename Executor>
  668. class awaitable_async_op_handler;
  669. template <typename R, typename Executor>
  670. class awaitable_async_op_handler<R(), Executor>
  671. : public awaitable_thread<Executor>
  672. {
  673. public:
  674. struct result_type {};
  675. awaitable_async_op_handler(
  676. awaitable_thread<Executor>* h, result_type&)
  677. : awaitable_thread<Executor>(std::move(*h))
  678. {
  679. }
  680. void operator()()
  681. {
  682. this->entry_point()->top_of_stack_->attach_thread(this);
  683. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  684. this->pump();
  685. }
  686. static void resume(result_type&)
  687. {
  688. }
  689. };
  690. template <typename R, typename Executor>
  691. class awaitable_async_op_handler<R(boost::system::error_code), Executor>
  692. : public awaitable_thread<Executor>
  693. {
  694. public:
  695. typedef boost::system::error_code* result_type;
  696. awaitable_async_op_handler(
  697. awaitable_thread<Executor>* h, result_type& result)
  698. : awaitable_thread<Executor>(std::move(*h)),
  699. result_(result)
  700. {
  701. }
  702. void operator()(boost::system::error_code ec)
  703. {
  704. result_ = &ec;
  705. this->entry_point()->top_of_stack_->attach_thread(this);
  706. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  707. this->pump();
  708. }
  709. static void resume(result_type& result)
  710. {
  711. throw_error(*result);
  712. }
  713. private:
  714. result_type& result_;
  715. };
  716. template <typename R, typename Executor>
  717. class awaitable_async_op_handler<R(std::exception_ptr), Executor>
  718. : public awaitable_thread<Executor>
  719. {
  720. public:
  721. typedef std::exception_ptr* result_type;
  722. awaitable_async_op_handler(
  723. awaitable_thread<Executor>* h, result_type& result)
  724. : awaitable_thread<Executor>(std::move(*h)),
  725. result_(result)
  726. {
  727. }
  728. void operator()(std::exception_ptr ex)
  729. {
  730. result_ = &ex;
  731. this->entry_point()->top_of_stack_->attach_thread(this);
  732. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  733. this->pump();
  734. }
  735. static void resume(result_type& result)
  736. {
  737. if (*result)
  738. {
  739. std::exception_ptr ex = std::exchange(*result, nullptr);
  740. std::rethrow_exception(ex);
  741. }
  742. }
  743. private:
  744. result_type& result_;
  745. };
  746. template <typename R, typename T, typename Executor>
  747. class awaitable_async_op_handler<R(T), Executor>
  748. : public awaitable_thread<Executor>
  749. {
  750. public:
  751. typedef T* result_type;
  752. awaitable_async_op_handler(
  753. awaitable_thread<Executor>* h, result_type& result)
  754. : awaitable_thread<Executor>(std::move(*h)),
  755. result_(result)
  756. {
  757. }
  758. void operator()(T result)
  759. {
  760. result_ = &result;
  761. this->entry_point()->top_of_stack_->attach_thread(this);
  762. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  763. this->pump();
  764. }
  765. static T resume(result_type& result)
  766. {
  767. return std::move(*result);
  768. }
  769. private:
  770. result_type& result_;
  771. };
  772. template <typename R, typename T, typename Executor>
  773. class awaitable_async_op_handler<R(boost::system::error_code, T), Executor>
  774. : public awaitable_thread<Executor>
  775. {
  776. public:
  777. struct result_type
  778. {
  779. boost::system::error_code* ec_;
  780. T* value_;
  781. };
  782. awaitable_async_op_handler(
  783. awaitable_thread<Executor>* h, result_type& result)
  784. : awaitable_thread<Executor>(std::move(*h)),
  785. result_(result)
  786. {
  787. }
  788. void operator()(boost::system::error_code ec, T value)
  789. {
  790. result_.ec_ = &ec;
  791. result_.value_ = &value;
  792. this->entry_point()->top_of_stack_->attach_thread(this);
  793. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  794. this->pump();
  795. }
  796. static T resume(result_type& result)
  797. {
  798. throw_error(*result.ec_);
  799. return std::move(*result.value_);
  800. }
  801. private:
  802. result_type& result_;
  803. };
  804. template <typename R, typename T, typename Executor>
  805. class awaitable_async_op_handler<R(std::exception_ptr, T), Executor>
  806. : public awaitable_thread<Executor>
  807. {
  808. public:
  809. struct result_type
  810. {
  811. std::exception_ptr* ex_;
  812. T* value_;
  813. };
  814. awaitable_async_op_handler(
  815. awaitable_thread<Executor>* h, result_type& result)
  816. : awaitable_thread<Executor>(std::move(*h)),
  817. result_(result)
  818. {
  819. }
  820. void operator()(std::exception_ptr ex, T value)
  821. {
  822. result_.ex_ = &ex;
  823. result_.value_ = &value;
  824. this->entry_point()->top_of_stack_->attach_thread(this);
  825. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  826. this->pump();
  827. }
  828. static T resume(result_type& result)
  829. {
  830. if (*result.ex_)
  831. {
  832. std::exception_ptr ex = std::exchange(*result.ex_, nullptr);
  833. std::rethrow_exception(ex);
  834. }
  835. return std::move(*result.value_);
  836. }
  837. private:
  838. result_type& result_;
  839. };
  840. template <typename R, typename... Ts, typename Executor>
  841. class awaitable_async_op_handler<R(Ts...), Executor>
  842. : public awaitable_thread<Executor>
  843. {
  844. public:
  845. typedef std::tuple<Ts...>* result_type;
  846. awaitable_async_op_handler(
  847. awaitable_thread<Executor>* h, result_type& result)
  848. : awaitable_thread<Executor>(std::move(*h)),
  849. result_(result)
  850. {
  851. }
  852. template <typename... Args>
  853. void operator()(Args&&... args)
  854. {
  855. std::tuple<Ts...> result(std::forward<Args>(args)...);
  856. result_ = &result;
  857. this->entry_point()->top_of_stack_->attach_thread(this);
  858. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  859. this->pump();
  860. }
  861. static std::tuple<Ts...> resume(result_type& result)
  862. {
  863. return std::move(*result);
  864. }
  865. private:
  866. result_type& result_;
  867. };
  868. template <typename R, typename... Ts, typename Executor>
  869. class awaitable_async_op_handler<R(boost::system::error_code, Ts...), Executor>
  870. : public awaitable_thread<Executor>
  871. {
  872. public:
  873. struct result_type
  874. {
  875. boost::system::error_code* ec_;
  876. std::tuple<Ts...>* value_;
  877. };
  878. awaitable_async_op_handler(
  879. awaitable_thread<Executor>* h, result_type& result)
  880. : awaitable_thread<Executor>(std::move(*h)),
  881. result_(result)
  882. {
  883. }
  884. template <typename... Args>
  885. void operator()(boost::system::error_code ec, Args&&... args)
  886. {
  887. result_.ec_ = &ec;
  888. std::tuple<Ts...> value(std::forward<Args>(args)...);
  889. result_.value_ = &value;
  890. this->entry_point()->top_of_stack_->attach_thread(this);
  891. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  892. this->pump();
  893. }
  894. static std::tuple<Ts...> resume(result_type& result)
  895. {
  896. throw_error(*result.ec_);
  897. return std::move(*result.value_);
  898. }
  899. private:
  900. result_type& result_;
  901. };
  902. template <typename R, typename... Ts, typename Executor>
  903. class awaitable_async_op_handler<R(std::exception_ptr, Ts...), Executor>
  904. : public awaitable_thread<Executor>
  905. {
  906. public:
  907. struct result_type
  908. {
  909. std::exception_ptr* ex_;
  910. std::tuple<Ts...>* value_;
  911. };
  912. awaitable_async_op_handler(
  913. awaitable_thread<Executor>* h, result_type& result)
  914. : awaitable_thread<Executor>(std::move(*h)),
  915. result_(result)
  916. {
  917. }
  918. template <typename... Args>
  919. void operator()(std::exception_ptr ex, Args&&... args)
  920. {
  921. result_.ex_ = &ex;
  922. std::tuple<Ts...> value(std::forward<Args>(args)...);
  923. result_.value_ = &value;
  924. this->entry_point()->top_of_stack_->attach_thread(this);
  925. this->entry_point()->top_of_stack_->clear_cancellation_slot();
  926. this->pump();
  927. }
  928. static std::tuple<Ts...> resume(result_type& result)
  929. {
  930. if (*result.ex_)
  931. {
  932. std::exception_ptr ex = std::exchange(*result.ex_, nullptr);
  933. std::rethrow_exception(ex);
  934. }
  935. return std::move(*result.value_);
  936. }
  937. private:
  938. result_type& result_;
  939. };
  940. template <typename Signature, typename Op, typename Executor>
  941. class awaitable_async_op
  942. {
  943. public:
  944. typedef awaitable_async_op_handler<Signature, Executor> handler_type;
  945. awaitable_async_op(Op&& o, awaitable_frame_base<Executor>* frame
  946. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  947. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  948. , const detail::source_location& location
  949. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  950. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  951. )
  952. : op_(std::forward<Op>(o)),
  953. frame_(frame),
  954. result_()
  955. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  956. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  957. , location_(location)
  958. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  959. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  960. {
  961. }
  962. bool await_ready() const noexcept
  963. {
  964. return false;
  965. }
  966. void await_suspend(coroutine_handle<void>)
  967. {
  968. frame_->after_suspend(
  969. [](void* arg)
  970. {
  971. awaitable_async_op* self = static_cast<awaitable_async_op*>(arg);
  972. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  973. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  974. BOOST_ASIO_HANDLER_LOCATION((self->location_.file_name(),
  975. self->location_.line(), self->location_.function_name()));
  976. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  977. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  978. std::forward<Op&&>(self->op_)(
  979. handler_type(self->frame_->detach_thread(), self->result_));
  980. }, this);
  981. }
  982. auto await_resume()
  983. {
  984. return handler_type::resume(result_);
  985. }
  986. private:
  987. Op&& op_;
  988. awaitable_frame_base<Executor>* frame_;
  989. typename handler_type::result_type result_;
  990. #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  991. # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  992. detail::source_location location_;
  993. # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
  994. #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
  995. };
  996. } // namespace detail
  997. } // namespace asio
  998. } // namespace boost
  999. #if !defined(GENERATING_DOCUMENTATION)
  1000. # if defined(BOOST_ASIO_HAS_STD_COROUTINE)
  1001. namespace std {
  1002. template <typename T, typename Executor, typename... Args>
  1003. struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
  1004. {
  1005. typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
  1006. };
  1007. } // namespace std
  1008. # else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  1009. namespace std { namespace experimental {
  1010. template <typename T, typename Executor, typename... Args>
  1011. struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
  1012. {
  1013. typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
  1014. };
  1015. }} // namespace std::experimental
  1016. # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
  1017. #endif // !defined(GENERATING_DOCUMENTATION)
  1018. #include <boost/asio/detail/pop_options.hpp>
  1019. #endif // BOOST_ASIO_IMPL_AWAITABLE_HPP