Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-20 08:38:27

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