Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:35:18

0001 //
0002 // impl/awaitable.hpp
0003 // ~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IMPL_AWAITABLE_HPP
0012 #define BOOST_ASIO_IMPL_AWAITABLE_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <exception>
0020 #include <new>
0021 #include <tuple>
0022 #include <boost/asio/cancellation_signal.hpp>
0023 #include <boost/asio/cancellation_state.hpp>
0024 #include <boost/asio/detail/memory.hpp>
0025 #include <boost/asio/detail/thread_context.hpp>
0026 #include <boost/asio/detail/thread_info_base.hpp>
0027 #include <boost/asio/detail/throw_error.hpp>
0028 #include <boost/asio/detail/type_traits.hpp>
0029 #include <boost/asio/disposition.hpp>
0030 #include <boost/asio/error.hpp>
0031 #include <boost/asio/post.hpp>
0032 #include <boost/system/system_error.hpp>
0033 #include <boost/asio/this_coro.hpp>
0034 
0035 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0036 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0037 #  include <boost/asio/detail/source_location.hpp>
0038 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0039 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0040 
0041 #include <boost/asio/detail/push_options.hpp>
0042 
0043 namespace boost {
0044 namespace asio {
0045 namespace detail {
0046 
0047 struct awaitable_thread_has_context_switched {};
0048 template <typename, typename, typename> class awaitable_async_op_handler;
0049 template <typename, typename, typename> class awaitable_async_op;
0050 
0051 // An awaitable_thread represents a thread-of-execution that is composed of one
0052 // or more "stack frames", with each frame represented by an awaitable_frame.
0053 // All execution occurs in the context of the awaitable_thread's executor. An
0054 // awaitable_thread continues to "pump" the stack frames by repeatedly resuming
0055 // the top stack frame until the stack is empty, or until ownership of the
0056 // stack is transferred to another awaitable_thread object.
0057 //
0058 //                +------------------------------------+
0059 //                | top_of_stack_                      |
0060 //                |                                    V
0061 // +--------------+---+                            +-----------------+
0062 // |                  |                            |                 |
0063 // | awaitable_thread |<---------------------------+ awaitable_frame |
0064 // |                  |           attached_thread_ |                 |
0065 // +--------------+---+           (Set only when   +---+-------------+
0066 //                |               frames are being     |
0067 //                |               actively pumped      | caller_
0068 //                |               by a thread, and     |
0069 //                |               then only for        V
0070 //                |               the top frame.)  +-----------------+
0071 //                |                                |                 |
0072 //                |                                | awaitable_frame |
0073 //                |                                |                 |
0074 //                |                                +---+-------------+
0075 //                |                                    |
0076 //                |                                    | caller_
0077 //                |                                    :
0078 //                |                                    :
0079 //                |                                    |
0080 //                |                                    V
0081 //                |                                +-----------------+
0082 //                | bottom_of_stack_               |                 |
0083 //                +------------------------------->| awaitable_frame |
0084 //                                                 |                 |
0085 //                                                 +-----------------+
0086 
0087 template <typename Executor>
0088 class awaitable_frame_base
0089 {
0090 public:
0091 #if !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
0092   void* operator new(std::size_t size)
0093   {
0094     return boost::asio::detail::thread_info_base::allocate(
0095         boost::asio::detail::thread_info_base::awaitable_frame_tag(),
0096         boost::asio::detail::thread_context::top_of_thread_call_stack(),
0097         size);
0098   }
0099 
0100   void operator delete(void* pointer, std::size_t size)
0101   {
0102     boost::asio::detail::thread_info_base::deallocate(
0103         boost::asio::detail::thread_info_base::awaitable_frame_tag(),
0104         boost::asio::detail::thread_context::top_of_thread_call_stack(),
0105         pointer, size);
0106   }
0107 #endif // !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
0108 
0109   // The frame starts in a suspended state until the awaitable_thread object
0110   // pumps the stack.
0111   auto initial_suspend() noexcept
0112   {
0113     return suspend_always();
0114   }
0115 
0116   // On final suspension the frame is popped from the top of the stack.
0117   auto final_suspend() noexcept
0118   {
0119     struct result
0120     {
0121       awaitable_frame_base* this_;
0122 
0123       bool await_ready() const noexcept
0124       {
0125         return false;
0126       }
0127 
0128       void await_suspend(coroutine_handle<void>) noexcept
0129       {
0130         this->this_->pop_frame();
0131       }
0132 
0133       void await_resume() const noexcept
0134       {
0135       }
0136     };
0137 
0138     return result{this};
0139   }
0140 
0141   template <typename Disposition>
0142   void set_disposition(Disposition&& d) noexcept
0143   {
0144     pending_exception_ = (to_exception_ptr)(static_cast<Disposition&&>(d));
0145   }
0146 
0147   void unhandled_exception()
0148   {
0149     set_disposition(std::current_exception());
0150   }
0151 
0152   void rethrow_exception()
0153   {
0154     if (pending_exception_)
0155     {
0156       std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
0157       std::rethrow_exception(ex);
0158     }
0159   }
0160 
0161   void clear_cancellation_slot()
0162   {
0163     this->attached_thread_->entry_point()->cancellation_state_.slot().clear();
0164   }
0165 
0166   template <typename T>
0167   auto await_transform(awaitable<T, Executor> a) const
0168   {
0169     if (attached_thread_->entry_point()->throw_if_cancelled_)
0170       if (!!attached_thread_->get_cancellation_state().cancelled())
0171         throw_error(boost::asio::error::operation_aborted, "co_await");
0172     return a;
0173   }
0174 
0175   template <typename Op>
0176   auto await_transform(Op&& op,
0177       constraint_t<is_async_operation<Op>::value> = 0
0178 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0179 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0180       , detail::source_location location = detail::source_location::current()
0181 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0182 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0183     )
0184   {
0185     if (attached_thread_->entry_point()->throw_if_cancelled_)
0186       if (!!attached_thread_->get_cancellation_state().cancelled())
0187         throw_error(boost::asio::error::operation_aborted, "co_await");
0188 
0189     return awaitable_async_op<
0190       completion_signature_of_t<Op>, decay_t<Op>, Executor>{
0191         std::forward<Op>(op), this
0192 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0193 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0194         , location
0195 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
0196 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0197       };
0198   }
0199 
0200   // This await transformation obtains the associated executor of the thread of
0201   // execution.
0202   auto await_transform(this_coro::executor_t) noexcept
0203   {
0204     struct result
0205     {
0206       awaitable_frame_base* this_;
0207 
0208       bool await_ready() const noexcept
0209       {
0210         return true;
0211       }
0212 
0213       void await_suspend(coroutine_handle<void>) noexcept
0214       {
0215       }
0216 
0217       auto await_resume() const noexcept
0218       {
0219         return this_->attached_thread_->get_executor();
0220       }
0221     };
0222 
0223     return result{this};
0224   }
0225 
0226   // This await transformation obtains the associated cancellation state of the
0227   // thread of execution.
0228   auto await_transform(this_coro::cancellation_state_t) noexcept
0229   {
0230     struct result
0231     {
0232       awaitable_frame_base* this_;
0233 
0234       bool await_ready() const noexcept
0235       {
0236         return true;
0237       }
0238 
0239       void await_suspend(coroutine_handle<void>) noexcept
0240       {
0241       }
0242 
0243       auto await_resume() const noexcept
0244       {
0245         return this_->attached_thread_->get_cancellation_state();
0246       }
0247     };
0248 
0249     return result{this};
0250   }
0251 
0252   // This await transformation resets the associated cancellation state.
0253   auto await_transform(this_coro::reset_cancellation_state_0_t) noexcept
0254   {
0255     struct result
0256     {
0257       awaitable_frame_base* this_;
0258 
0259       bool await_ready() const noexcept
0260       {
0261         return true;
0262       }
0263 
0264       void await_suspend(coroutine_handle<void>) noexcept
0265       {
0266       }
0267 
0268       auto await_resume() const
0269       {
0270         return this_->attached_thread_->reset_cancellation_state();
0271       }
0272     };
0273 
0274     return result{this};
0275   }
0276 
0277   // This await transformation resets the associated cancellation state.
0278   template <typename Filter>
0279   auto await_transform(
0280       this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept
0281   {
0282     struct result
0283     {
0284       awaitable_frame_base* this_;
0285       Filter filter_;
0286 
0287       bool await_ready() const noexcept
0288       {
0289         return true;
0290       }
0291 
0292       void await_suspend(coroutine_handle<void>) noexcept
0293       {
0294       }
0295 
0296       auto await_resume()
0297       {
0298         return this_->attached_thread_->reset_cancellation_state(
0299             static_cast<Filter&&>(filter_));
0300       }
0301     };
0302 
0303     return result{this, static_cast<Filter&&>(reset.filter)};
0304   }
0305 
0306   // This await transformation resets the associated cancellation state.
0307   template <typename InFilter, typename OutFilter>
0308   auto await_transform(
0309       this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset)
0310     noexcept
0311   {
0312     struct result
0313     {
0314       awaitable_frame_base* this_;
0315       InFilter in_filter_;
0316       OutFilter out_filter_;
0317 
0318       bool await_ready() const noexcept
0319       {
0320         return true;
0321       }
0322 
0323       void await_suspend(coroutine_handle<void>) noexcept
0324       {
0325       }
0326 
0327       auto await_resume()
0328       {
0329         return this_->attached_thread_->reset_cancellation_state(
0330             static_cast<InFilter&&>(in_filter_),
0331             static_cast<OutFilter&&>(out_filter_));
0332       }
0333     };
0334 
0335     return result{this,
0336         static_cast<InFilter&&>(reset.in_filter),
0337         static_cast<OutFilter&&>(reset.out_filter)};
0338   }
0339 
0340   // This await transformation determines whether cancellation is propagated as
0341   // an exception.
0342   auto await_transform(this_coro::throw_if_cancelled_0_t)
0343     noexcept
0344   {
0345     struct result
0346     {
0347       awaitable_frame_base* this_;
0348 
0349       bool await_ready() const noexcept
0350       {
0351         return true;
0352       }
0353 
0354       void await_suspend(coroutine_handle<void>) noexcept
0355       {
0356       }
0357 
0358       auto await_resume()
0359       {
0360         return this_->attached_thread_->throw_if_cancelled();
0361       }
0362     };
0363 
0364     return result{this};
0365   }
0366 
0367   // This await transformation sets whether cancellation is propagated as an
0368   // exception.
0369   auto await_transform(this_coro::throw_if_cancelled_1_t throw_if_cancelled)
0370     noexcept
0371   {
0372     struct result
0373     {
0374       awaitable_frame_base* this_;
0375       bool value_;
0376 
0377       bool await_ready() const noexcept
0378       {
0379         return true;
0380       }
0381 
0382       void await_suspend(coroutine_handle<void>) noexcept
0383       {
0384       }
0385 
0386       auto await_resume()
0387       {
0388         this_->attached_thread_->throw_if_cancelled(value_);
0389       }
0390     };
0391 
0392     return result{this, throw_if_cancelled.value};
0393   }
0394 
0395   // This await transformation is used to run an async operation's initiation
0396   // function object after the coroutine has been suspended. This ensures that
0397   // immediate resumption of the coroutine in another thread does not cause a
0398   // race condition.
0399   template <typename Function>
0400   auto await_transform(Function f,
0401       enable_if_t<
0402         is_convertible<
0403           result_of_t<Function(awaitable_frame_base*)>,
0404           awaitable_thread<Executor>*
0405         >::value
0406       >* = nullptr)
0407   {
0408     struct result
0409     {
0410       Function function_;
0411       awaitable_frame_base* this_;
0412 
0413       bool await_ready() const noexcept
0414       {
0415         return false;
0416       }
0417 
0418       void await_suspend(coroutine_handle<void>) noexcept
0419       {
0420         this_->after_suspend(
0421             [](void* arg)
0422             {
0423               result* r = static_cast<result*>(arg);
0424               r->function_(r->this_);
0425             }, this);
0426       }
0427 
0428       void await_resume() const noexcept
0429       {
0430       }
0431     };
0432 
0433     return result{std::move(f), this};
0434   }
0435 
0436   // Access the awaitable thread's has_context_switched_ flag.
0437   auto await_transform(detail::awaitable_thread_has_context_switched) noexcept
0438   {
0439     struct result
0440     {
0441       awaitable_frame_base* this_;
0442 
0443       bool await_ready() const noexcept
0444       {
0445         return true;
0446       }
0447 
0448       void await_suspend(coroutine_handle<void>) noexcept
0449       {
0450       }
0451 
0452       bool& await_resume() const noexcept
0453       {
0454         return this_->attached_thread_->entry_point()->has_context_switched_;
0455       }
0456     };
0457 
0458     return result{this};
0459   }
0460 
0461   void attach_thread(awaitable_thread<Executor>* handler) noexcept
0462   {
0463     attached_thread_ = handler;
0464   }
0465 
0466   awaitable_thread<Executor>* detach_thread() noexcept
0467   {
0468     attached_thread_->entry_point()->has_context_switched_ = true;
0469     return std::exchange(attached_thread_, nullptr);
0470   }
0471 
0472   void push_frame(awaitable_frame_base<Executor>* caller) noexcept
0473   {
0474     caller_ = caller;
0475     attached_thread_ = caller_->attached_thread_;
0476     attached_thread_->entry_point()->top_of_stack_ = this;
0477     caller_->attached_thread_ = nullptr;
0478   }
0479 
0480   void pop_frame() noexcept
0481   {
0482     if (caller_)
0483       caller_->attached_thread_ = attached_thread_;
0484     attached_thread_->entry_point()->top_of_stack_ = caller_;
0485     attached_thread_ = nullptr;
0486     caller_ = nullptr;
0487   }
0488 
0489   struct resume_context
0490   {
0491     void (*after_suspend_fn_)(void*) = nullptr;
0492     void *after_suspend_arg_ = nullptr;
0493   };
0494 
0495   void resume()
0496   {
0497     resume_context context;
0498     resume_context_ = &context;
0499     coro_.resume();
0500     if (context.after_suspend_fn_)
0501       context.after_suspend_fn_(context.after_suspend_arg_);
0502   }
0503 
0504   void after_suspend(void (*fn)(void*), void* arg)
0505   {
0506     resume_context_->after_suspend_fn_ = fn;
0507     resume_context_->after_suspend_arg_ = arg;
0508   }
0509 
0510   void destroy()
0511   {
0512     coro_.destroy();
0513   }
0514 
0515 protected:
0516   coroutine_handle<void> coro_ = nullptr;
0517   awaitable_thread<Executor>* attached_thread_ = nullptr;
0518   awaitable_frame_base<Executor>* caller_ = nullptr;
0519   std::exception_ptr pending_exception_ = nullptr;
0520   resume_context* resume_context_ = nullptr;
0521 };
0522 
0523 template <typename T, typename Executor>
0524 class awaitable_frame
0525   : public awaitable_frame_base<Executor>
0526 {
0527 public:
0528   awaitable_frame() noexcept
0529   {
0530   }
0531 
0532   awaitable_frame(awaitable_frame&& other) noexcept
0533     : awaitable_frame_base<Executor>(std::move(other))
0534   {
0535   }
0536 
0537   ~awaitable_frame()
0538   {
0539     if (has_result_)
0540       std::launder(static_cast<T*>(static_cast<void*>(result_)))->~T();
0541   }
0542 
0543   awaitable<T, Executor> get_return_object() noexcept
0544   {
0545     this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
0546     return awaitable<T, Executor>(this);
0547   }
0548 
0549   template <typename U>
0550   void return_value(U&& u)
0551   {
0552     new (&result_) T(std::forward<U>(u));
0553     has_result_ = true;
0554   }
0555 
0556   template <typename... Us>
0557   void return_values(Us&&... us)
0558   {
0559     this->return_value(std::forward_as_tuple(std::forward<Us>(us)...));
0560   }
0561 
0562   T get()
0563   {
0564     this->caller_ = nullptr;
0565     this->rethrow_exception();
0566     return std::move(*std::launder(
0567           static_cast<T*>(static_cast<void*>(result_))));
0568   }
0569 
0570 private:
0571   alignas(T) unsigned char result_[sizeof(T)];
0572   bool has_result_ = false;
0573 };
0574 
0575 template <typename Executor>
0576 class awaitable_frame<void, Executor>
0577   : public awaitable_frame_base<Executor>
0578 {
0579 public:
0580   awaitable<void, Executor> get_return_object()
0581   {
0582     this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
0583     return awaitable<void, Executor>(this);
0584   }
0585 
0586   void return_void()
0587   {
0588   }
0589 
0590   void get()
0591   {
0592     this->caller_ = nullptr;
0593     this->rethrow_exception();
0594   }
0595 };
0596 
0597 struct awaitable_thread_entry_point {};
0598 
0599 template <typename Executor>
0600 class awaitable_frame<awaitable_thread_entry_point, Executor>
0601   : public awaitable_frame_base<Executor>
0602 {
0603 public:
0604   awaitable_frame()
0605     : top_of_stack_(0),
0606       has_executor_(false),
0607       has_context_switched_(false),
0608       throw_if_cancelled_(true)
0609   {
0610   }
0611 
0612   ~awaitable_frame()
0613   {
0614     if (has_executor_)
0615       u_.executor_.~Executor();
0616   }
0617 
0618   awaitable<awaitable_thread_entry_point, Executor> get_return_object()
0619   {
0620     this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
0621     return awaitable<awaitable_thread_entry_point, Executor>(this);
0622   }
0623 
0624   void return_void()
0625   {
0626   }
0627 
0628   void get()
0629   {
0630     this->caller_ = nullptr;
0631     this->rethrow_exception();
0632   }
0633 
0634 private:
0635   template <typename> friend class awaitable_frame_base;
0636   template <typename, typename, typename>
0637     friend class awaitable_async_op_handler;
0638   template <typename, typename> friend class awaitable_handler_base;
0639   template <typename> friend class awaitable_thread;
0640 
0641   union u
0642   {
0643     u() {}
0644     ~u() {}
0645     char c_;
0646     Executor executor_;
0647   } u_;
0648 
0649   awaitable_frame_base<Executor>* top_of_stack_;
0650   boost::asio::cancellation_slot parent_cancellation_slot_;
0651   boost::asio::cancellation_state cancellation_state_;
0652   bool has_executor_;
0653   bool has_context_switched_;
0654   bool throw_if_cancelled_;
0655 };
0656 
0657 template <typename Executor>
0658 class awaitable_thread
0659 {
0660 public:
0661   typedef Executor executor_type;
0662   typedef cancellation_slot cancellation_slot_type;
0663 
0664   // Construct from the entry point of a new thread of execution.
0665   awaitable_thread(awaitable<awaitable_thread_entry_point, Executor> p,
0666       const Executor& ex, cancellation_slot parent_cancel_slot,
0667       cancellation_state cancel_state)
0668     : bottom_of_stack_(std::move(p))
0669   {
0670     bottom_of_stack_.frame_->top_of_stack_ = bottom_of_stack_.frame_;
0671     new (&bottom_of_stack_.frame_->u_.executor_) Executor(ex);
0672     bottom_of_stack_.frame_->has_executor_ = true;
0673     bottom_of_stack_.frame_->parent_cancellation_slot_ = parent_cancel_slot;
0674     bottom_of_stack_.frame_->cancellation_state_ = cancel_state;
0675   }
0676 
0677   // Transfer ownership from another awaitable_thread.
0678   awaitable_thread(awaitable_thread&& other) noexcept
0679     : bottom_of_stack_(std::move(other.bottom_of_stack_))
0680   {
0681   }
0682 
0683   // Clean up with a last ditch effort to ensure the thread is unwound within
0684   // the context of the executor.
0685   ~awaitable_thread()
0686   {
0687     if (bottom_of_stack_.valid())
0688     {
0689       // Coroutine "stack unwinding" must be performed through the executor.
0690       auto* bottom_frame = bottom_of_stack_.frame_;
0691       (post)(bottom_frame->u_.executor_,
0692           [a = std::move(bottom_of_stack_)]() mutable
0693           {
0694             (void)awaitable<awaitable_thread_entry_point, Executor>(
0695                 std::move(a));
0696           });
0697     }
0698   }
0699 
0700   awaitable_frame<awaitable_thread_entry_point, Executor>* entry_point()
0701   {
0702     return bottom_of_stack_.frame_;
0703   }
0704 
0705   executor_type get_executor() const noexcept
0706   {
0707     return bottom_of_stack_.frame_->u_.executor_;
0708   }
0709 
0710   cancellation_state get_cancellation_state() const noexcept
0711   {
0712     return bottom_of_stack_.frame_->cancellation_state_;
0713   }
0714 
0715   void reset_cancellation_state()
0716   {
0717     bottom_of_stack_.frame_->cancellation_state_ =
0718       cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_);
0719   }
0720 
0721   template <typename Filter>
0722   void reset_cancellation_state(Filter&& filter)
0723   {
0724     bottom_of_stack_.frame_->cancellation_state_ =
0725       cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_,
0726         static_cast<Filter&&>(filter));
0727   }
0728 
0729   template <typename InFilter, typename OutFilter>
0730   void reset_cancellation_state(InFilter&& in_filter,
0731       OutFilter&& out_filter)
0732   {
0733     bottom_of_stack_.frame_->cancellation_state_ =
0734       cancellation_state(bottom_of_stack_.frame_->parent_cancellation_slot_,
0735         static_cast<InFilter&&>(in_filter),
0736         static_cast<OutFilter&&>(out_filter));
0737   }
0738 
0739   bool throw_if_cancelled() const
0740   {
0741     return bottom_of_stack_.frame_->throw_if_cancelled_;
0742   }
0743 
0744   void throw_if_cancelled(bool value)
0745   {
0746     bottom_of_stack_.frame_->throw_if_cancelled_ = value;
0747   }
0748 
0749   cancellation_slot_type get_cancellation_slot() const noexcept
0750   {
0751     return bottom_of_stack_.frame_->cancellation_state_.slot();
0752   }
0753 
0754   // Launch a new thread of execution.
0755   void launch()
0756   {
0757     bottom_of_stack_.frame_->top_of_stack_->attach_thread(this);
0758     pump();
0759   }
0760 
0761 protected:
0762   template <typename> friend class awaitable_frame_base;
0763 
0764   // Repeatedly resume the top stack frame until the stack is empty or until it
0765   // has been transferred to another resumable_thread object.
0766   void pump()
0767   {
0768     do
0769       bottom_of_stack_.frame_->top_of_stack_->resume();
0770     while (bottom_of_stack_.frame_ && bottom_of_stack_.frame_->top_of_stack_);
0771 
0772     if (bottom_of_stack_.frame_)
0773     {
0774       awaitable<awaitable_thread_entry_point, Executor> a(
0775           std::move(bottom_of_stack_));
0776       a.frame_->rethrow_exception();
0777     }
0778   }
0779 
0780   awaitable<awaitable_thread_entry_point, Executor> bottom_of_stack_;
0781 };
0782 
0783 template <typename Signature, typename Executor, typename = void>
0784 class awaitable_async_op_handler;
0785 
0786 template <typename R, typename Executor>
0787 class awaitable_async_op_handler<R(), Executor>
0788   : public awaitable_thread<Executor>
0789 {
0790 public:
0791   struct result_type {};
0792 
0793   awaitable_async_op_handler(
0794       awaitable_thread<Executor>* h, result_type&)
0795     : awaitable_thread<Executor>(std::move(*h))
0796   {
0797   }
0798 
0799   void operator()()
0800   {
0801     this->entry_point()->top_of_stack_->attach_thread(this);
0802     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0803     this->pump();
0804   }
0805 
0806   static void resume(result_type&)
0807   {
0808   }
0809 };
0810 
0811 template <typename R, typename T, typename Executor>
0812 class awaitable_async_op_handler<R(T), Executor,
0813     enable_if_t<!is_disposition<T>::value>>
0814   : public awaitable_thread<Executor>
0815 {
0816 public:
0817   typedef T* result_type;
0818 
0819   awaitable_async_op_handler(
0820       awaitable_thread<Executor>* h, result_type& result)
0821     : awaitable_thread<Executor>(std::move(*h)),
0822       result_(result)
0823   {
0824   }
0825 
0826   void operator()(T result)
0827   {
0828     result_ = detail::addressof(result);
0829     this->entry_point()->top_of_stack_->attach_thread(this);
0830     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0831     this->pump();
0832   }
0833 
0834   static T resume(result_type& result)
0835   {
0836     return std::move(*result);
0837   }
0838 
0839 private:
0840   result_type& result_;
0841 };
0842 
0843 template <typename R, typename Disposition, typename Executor>
0844 class awaitable_async_op_handler<R(Disposition), Executor,
0845     enable_if_t<is_disposition<Disposition>::value>>
0846   : public awaitable_thread<Executor>
0847 {
0848 public:
0849   typedef Disposition* result_type;
0850 
0851   awaitable_async_op_handler(
0852       awaitable_thread<Executor>* h, result_type& result)
0853     : awaitable_thread<Executor>(std::move(*h)),
0854       result_(result)
0855   {
0856   }
0857 
0858   void operator()(Disposition d)
0859   {
0860     result_ = detail::addressof(d);
0861     this->entry_point()->top_of_stack_->attach_thread(this);
0862     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0863     this->pump();
0864   }
0865 
0866   static void resume(result_type& result)
0867   {
0868     if (*result != no_error)
0869     {
0870       Disposition d = std::exchange(*result, Disposition());
0871       boost::asio::throw_exception(static_cast<Disposition&&>(d));
0872     }
0873   }
0874 
0875 private:
0876   result_type& result_;
0877 };
0878 
0879 template <typename R, typename Disposition, typename T, typename Executor>
0880 class awaitable_async_op_handler<R(Disposition, T), Executor,
0881     enable_if_t<is_disposition<Disposition>::value>>
0882   : public awaitable_thread<Executor>
0883 {
0884 public:
0885   struct result_type
0886   {
0887     Disposition* disposition_;
0888     T* value_;
0889   };
0890 
0891   awaitable_async_op_handler(
0892       awaitable_thread<Executor>* h, result_type& result)
0893     : awaitable_thread<Executor>(std::move(*h)),
0894       result_(result)
0895   {
0896   }
0897 
0898   void operator()(Disposition d, T value)
0899   {
0900     result_.disposition_ = detail::addressof(d);
0901     result_.value_ = detail::addressof(value);
0902     this->entry_point()->top_of_stack_->attach_thread(this);
0903     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0904     this->pump();
0905   }
0906 
0907   static T resume(result_type& result)
0908   {
0909     if (*result.disposition_ != no_error)
0910     {
0911       Disposition d = std::exchange(*result.disposition_, Disposition());
0912       boost::asio::throw_exception(static_cast<Disposition&&>(d));
0913     }
0914     return std::move(*result.value_);
0915   }
0916 
0917 private:
0918   result_type& result_;
0919 };
0920 
0921 template <typename R, typename T, typename... Ts, typename Executor>
0922 class awaitable_async_op_handler<R(T, Ts...), Executor,
0923     enable_if_t<!is_disposition<T>::value>>
0924   : public awaitable_thread<Executor>
0925 {
0926 public:
0927   typedef std::tuple<T, Ts...>* result_type;
0928 
0929   awaitable_async_op_handler(
0930       awaitable_thread<Executor>* h, result_type& result)
0931     : awaitable_thread<Executor>(std::move(*h)),
0932       result_(result)
0933   {
0934   }
0935 
0936   template <typename... Args>
0937   void operator()(Args&&... args)
0938   {
0939     std::tuple<T, Ts...> result(std::forward<Args>(args)...);
0940     result_ = detail::addressof(result);
0941     this->entry_point()->top_of_stack_->attach_thread(this);
0942     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0943     this->pump();
0944   }
0945 
0946   static std::tuple<T, Ts...> resume(result_type& result)
0947   {
0948     return std::move(*result);
0949   }
0950 
0951 private:
0952   result_type& result_;
0953 };
0954 
0955 template <typename R, typename Disposition, typename... Ts, typename Executor>
0956 class awaitable_async_op_handler<R(Disposition, Ts...), Executor,
0957     enable_if_t<is_disposition<Disposition>::value>>
0958   : public awaitable_thread<Executor>
0959 {
0960 public:
0961   struct result_type
0962   {
0963     Disposition* disposition_;
0964     std::tuple<Ts...>* value_;
0965   };
0966 
0967   awaitable_async_op_handler(
0968       awaitable_thread<Executor>* h, result_type& result)
0969     : awaitable_thread<Executor>(std::move(*h)),
0970       result_(result)
0971   {
0972   }
0973 
0974   template <typename... Args>
0975   void operator()(Disposition d, Args&&... args)
0976   {
0977     result_.disposition_ = detail::addressof(d);
0978     std::tuple<Ts...> value(std::forward<Args>(args)...);
0979     result_.value_ = detail::addressof(value);
0980     this->entry_point()->top_of_stack_->attach_thread(this);
0981     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0982     this->pump();
0983   }
0984 
0985   static std::tuple<Ts...> resume(result_type& result)
0986   {
0987     if (*result.disposition_ != no_error)
0988     {
0989       Disposition d = std::exchange(*result.disposition_, Disposition());
0990       boost::asio::throw_exception(static_cast<Disposition&&>(d));
0991     }
0992     return std::move(*result.value_);
0993   }
0994 
0995 private:
0996   result_type& result_;
0997 };
0998 
0999 template <typename Signature, typename Op, typename Executor>
1000 class awaitable_async_op
1001 {
1002 public:
1003   typedef awaitable_async_op_handler<Signature, Executor> handler_type;
1004 
1005   awaitable_async_op(Op&& o, awaitable_frame_base<Executor>* frame
1006 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1007 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1008       , const detail::source_location& location
1009 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1010 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1011     )
1012     : op_(std::forward<Op>(o)),
1013       frame_(frame),
1014       result_()
1015 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1016 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1017     , location_(location)
1018 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1019 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1020   {
1021   }
1022 
1023   bool await_ready() const noexcept
1024   {
1025     return false;
1026   }
1027 
1028   void await_suspend(coroutine_handle<void>)
1029   {
1030     frame_->after_suspend(
1031         [](void* arg)
1032         {
1033           awaitable_async_op* self = static_cast<awaitable_async_op*>(arg);
1034 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1035 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1036           BOOST_ASIO_HANDLER_LOCATION((self->location_.file_name(),
1037               self->location_.line(), self->location_.function_name()));
1038 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1039 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1040           std::forward<Op&&>(self->op_)(
1041               handler_type(self->frame_->detach_thread(), self->result_));
1042         }, this);
1043   }
1044 
1045   auto await_resume()
1046   {
1047     return handler_type::resume(result_);
1048   }
1049 
1050 private:
1051   Op&& op_;
1052   awaitable_frame_base<Executor>* frame_;
1053   typename handler_type::result_type result_;
1054 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1055 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1056   detail::source_location location_;
1057 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1058 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1059 };
1060 
1061 } // namespace detail
1062 } // namespace asio
1063 } // namespace boost
1064 
1065 #if !defined(GENERATING_DOCUMENTATION)
1066 # if defined(BOOST_ASIO_HAS_STD_COROUTINE)
1067 
1068 namespace std {
1069 
1070 template <typename T, typename Executor, typename... Args>
1071 struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
1072 {
1073   typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
1074 };
1075 
1076 } // namespace std
1077 
1078 # else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1079 
1080 namespace std { namespace experimental {
1081 
1082 template <typename T, typename Executor, typename... Args>
1083 struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
1084 {
1085   typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
1086 };
1087 
1088 }} // namespace std::experimental
1089 
1090 # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1091 #endif // !defined(GENERATING_DOCUMENTATION)
1092 
1093 #include <boost/asio/detail/pop_options.hpp>
1094 
1095 #endif // BOOST_ASIO_IMPL_AWAITABLE_HPP