awaitable.hpp 30 KB

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