Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:27:26

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