Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:54

0001 //
0002 // impl/awaitable.hpp
0003 // ~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 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       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(*static_cast<T*>(static_cast<void*>(result_)));
0569   }
0570 
0571 private:
0572   alignas(T) unsigned char result_[sizeof(T)];
0573   bool has_result_ = false;
0574 };
0575 
0576 template <typename Executor>
0577 class awaitable_frame<void, Executor>
0578   : public awaitable_frame_base<Executor>
0579 {
0580 public:
0581   awaitable<void, Executor> get_return_object()
0582   {
0583     this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
0584     return awaitable<void, Executor>(this);
0585   };
0586 
0587   void return_void()
0588   {
0589   }
0590 
0591   void get()
0592   {
0593     this->caller_ = nullptr;
0594     this->rethrow_exception();
0595   }
0596 };
0597 
0598 struct awaitable_thread_entry_point {};
0599 
0600 template <typename Executor>
0601 class awaitable_frame<awaitable_thread_entry_point, Executor>
0602   : public awaitable_frame_base<Executor>
0603 {
0604 public:
0605   awaitable_frame()
0606     : top_of_stack_(0),
0607       has_executor_(false),
0608       has_context_switched_(false),
0609       throw_if_cancelled_(true)
0610   {
0611   }
0612 
0613   ~awaitable_frame()
0614   {
0615     if (has_executor_)
0616       u_.executor_.~Executor();
0617   }
0618 
0619   awaitable<awaitable_thread_entry_point, Executor> get_return_object()
0620   {
0621     this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
0622     return awaitable<awaitable_thread_entry_point, Executor>(this);
0623   };
0624 
0625   void return_void()
0626   {
0627   }
0628 
0629   void get()
0630   {
0631     this->caller_ = nullptr;
0632     this->rethrow_exception();
0633   }
0634 
0635 private:
0636   template <typename> friend class awaitable_frame_base;
0637   template <typename, typename> 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>
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 Executor>
0812 class awaitable_async_op_handler<R(boost::system::error_code), Executor>
0813   : public awaitable_thread<Executor>
0814 {
0815 public:
0816   typedef boost::system::error_code* result_type;
0817 
0818   awaitable_async_op_handler(
0819       awaitable_thread<Executor>* h, result_type& result)
0820     : awaitable_thread<Executor>(std::move(*h)),
0821       result_(result)
0822   {
0823   }
0824 
0825   void operator()(boost::system::error_code ec)
0826   {
0827     result_ = &ec;
0828     this->entry_point()->top_of_stack_->attach_thread(this);
0829     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0830     this->pump();
0831   }
0832 
0833   static void resume(result_type& result)
0834   {
0835     throw_error(*result);
0836   }
0837 
0838 private:
0839   result_type& result_;
0840 };
0841 
0842 template <typename R, typename Executor>
0843 class awaitable_async_op_handler<R(std::exception_ptr), Executor>
0844   : public awaitable_thread<Executor>
0845 {
0846 public:
0847   typedef std::exception_ptr* result_type;
0848 
0849   awaitable_async_op_handler(
0850       awaitable_thread<Executor>* h, result_type& result)
0851     : awaitable_thread<Executor>(std::move(*h)),
0852       result_(result)
0853   {
0854   }
0855 
0856   void operator()(std::exception_ptr ex)
0857   {
0858     result_ = &ex;
0859     this->entry_point()->top_of_stack_->attach_thread(this);
0860     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0861     this->pump();
0862   }
0863 
0864   static void resume(result_type& result)
0865   {
0866     if (*result)
0867     {
0868       std::exception_ptr ex = std::exchange(*result, nullptr);
0869       std::rethrow_exception(ex);
0870     }
0871   }
0872 
0873 private:
0874   result_type& result_;
0875 };
0876 
0877 template <typename R, typename T, typename Executor>
0878 class awaitable_async_op_handler<R(T), Executor>
0879   : public awaitable_thread<Executor>
0880 {
0881 public:
0882   typedef T* result_type;
0883 
0884   awaitable_async_op_handler(
0885       awaitable_thread<Executor>* h, result_type& result)
0886     : awaitable_thread<Executor>(std::move(*h)),
0887       result_(result)
0888   {
0889   }
0890 
0891   void operator()(T result)
0892   {
0893     result_ = &result;
0894     this->entry_point()->top_of_stack_->attach_thread(this);
0895     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0896     this->pump();
0897   }
0898 
0899   static T resume(result_type& result)
0900   {
0901     return std::move(*result);
0902   }
0903 
0904 private:
0905   result_type& result_;
0906 };
0907 
0908 template <typename R, typename T, typename Executor>
0909 class awaitable_async_op_handler<R(boost::system::error_code, T), Executor>
0910   : public awaitable_thread<Executor>
0911 {
0912 public:
0913   struct result_type
0914   {
0915     boost::system::error_code* ec_;
0916     T* value_;
0917   };
0918 
0919   awaitable_async_op_handler(
0920       awaitable_thread<Executor>* h, result_type& result)
0921     : awaitable_thread<Executor>(std::move(*h)),
0922       result_(result)
0923   {
0924   }
0925 
0926   void operator()(boost::system::error_code ec, T value)
0927   {
0928     result_.ec_ = &ec;
0929     result_.value_ = &value;
0930     this->entry_point()->top_of_stack_->attach_thread(this);
0931     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0932     this->pump();
0933   }
0934 
0935   static T resume(result_type& result)
0936   {
0937     throw_error(*result.ec_);
0938     return std::move(*result.value_);
0939   }
0940 
0941 private:
0942   result_type& result_;
0943 };
0944 
0945 template <typename R, typename T, typename Executor>
0946 class awaitable_async_op_handler<R(std::exception_ptr, T), Executor>
0947   : public awaitable_thread<Executor>
0948 {
0949 public:
0950   struct result_type
0951   {
0952     std::exception_ptr* ex_;
0953     T* value_;
0954   };
0955 
0956   awaitable_async_op_handler(
0957       awaitable_thread<Executor>* h, result_type& result)
0958     : awaitable_thread<Executor>(std::move(*h)),
0959       result_(result)
0960   {
0961   }
0962 
0963   void operator()(std::exception_ptr ex, T value)
0964   {
0965     result_.ex_ = &ex;
0966     result_.value_ = &value;
0967     this->entry_point()->top_of_stack_->attach_thread(this);
0968     this->entry_point()->top_of_stack_->clear_cancellation_slot();
0969     this->pump();
0970   }
0971 
0972   static T resume(result_type& result)
0973   {
0974     if (*result.ex_)
0975     {
0976       std::exception_ptr ex = std::exchange(*result.ex_, nullptr);
0977       std::rethrow_exception(ex);
0978     }
0979     return std::move(*result.value_);
0980   }
0981 
0982 private:
0983   result_type& result_;
0984 };
0985 
0986 template <typename R, typename... Ts, typename Executor>
0987 class awaitable_async_op_handler<R(Ts...), Executor>
0988   : public awaitable_thread<Executor>
0989 {
0990 public:
0991   typedef std::tuple<Ts...>* result_type;
0992 
0993   awaitable_async_op_handler(
0994       awaitable_thread<Executor>* h, result_type& result)
0995     : awaitable_thread<Executor>(std::move(*h)),
0996       result_(result)
0997   {
0998   }
0999 
1000   template <typename... Args>
1001   void operator()(Args&&... args)
1002   {
1003     std::tuple<Ts...> result(std::forward<Args>(args)...);
1004     result_ = &result;
1005     this->entry_point()->top_of_stack_->attach_thread(this);
1006     this->entry_point()->top_of_stack_->clear_cancellation_slot();
1007     this->pump();
1008   }
1009 
1010   static std::tuple<Ts...> resume(result_type& result)
1011   {
1012     return std::move(*result);
1013   }
1014 
1015 private:
1016   result_type& result_;
1017 };
1018 
1019 template <typename R, typename... Ts, typename Executor>
1020 class awaitable_async_op_handler<R(boost::system::error_code, Ts...), Executor>
1021   : public awaitable_thread<Executor>
1022 {
1023 public:
1024   struct result_type
1025   {
1026     boost::system::error_code* ec_;
1027     std::tuple<Ts...>* value_;
1028   };
1029 
1030   awaitable_async_op_handler(
1031       awaitable_thread<Executor>* h, result_type& result)
1032     : awaitable_thread<Executor>(std::move(*h)),
1033       result_(result)
1034   {
1035   }
1036 
1037   template <typename... Args>
1038   void operator()(boost::system::error_code ec, Args&&... args)
1039   {
1040     result_.ec_ = &ec;
1041     std::tuple<Ts...> value(std::forward<Args>(args)...);
1042     result_.value_ = &value;
1043     this->entry_point()->top_of_stack_->attach_thread(this);
1044     this->entry_point()->top_of_stack_->clear_cancellation_slot();
1045     this->pump();
1046   }
1047 
1048   static std::tuple<Ts...> resume(result_type& result)
1049   {
1050     throw_error(*result.ec_);
1051     return std::move(*result.value_);
1052   }
1053 
1054 private:
1055   result_type& result_;
1056 };
1057 
1058 template <typename R, typename... Ts, typename Executor>
1059 class awaitable_async_op_handler<R(std::exception_ptr, Ts...), Executor>
1060   : public awaitable_thread<Executor>
1061 {
1062 public:
1063   struct result_type
1064   {
1065     std::exception_ptr* ex_;
1066     std::tuple<Ts...>* value_;
1067   };
1068 
1069   awaitable_async_op_handler(
1070       awaitable_thread<Executor>* h, result_type& result)
1071     : awaitable_thread<Executor>(std::move(*h)),
1072       result_(result)
1073   {
1074   }
1075 
1076   template <typename... Args>
1077   void operator()(std::exception_ptr ex, Args&&... args)
1078   {
1079     result_.ex_ = &ex;
1080     std::tuple<Ts...> value(std::forward<Args>(args)...);
1081     result_.value_ = &value;
1082     this->entry_point()->top_of_stack_->attach_thread(this);
1083     this->entry_point()->top_of_stack_->clear_cancellation_slot();
1084     this->pump();
1085   }
1086 
1087   static std::tuple<Ts...> resume(result_type& result)
1088   {
1089     if (*result.ex_)
1090     {
1091       std::exception_ptr ex = std::exchange(*result.ex_, nullptr);
1092       std::rethrow_exception(ex);
1093     }
1094     return std::move(*result.value_);
1095   }
1096 
1097 private:
1098   result_type& result_;
1099 };
1100 
1101 template <typename Signature, typename Op, typename Executor>
1102 class awaitable_async_op
1103 {
1104 public:
1105   typedef awaitable_async_op_handler<Signature, Executor> handler_type;
1106 
1107   awaitable_async_op(Op&& o, awaitable_frame_base<Executor>* frame
1108 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1109 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1110       , const detail::source_location& location
1111 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1112 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1113     )
1114     : op_(std::forward<Op>(o)),
1115       frame_(frame),
1116       result_()
1117 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1118 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1119     , location_(location)
1120 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1121 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1122   {
1123   }
1124 
1125   bool await_ready() const noexcept
1126   {
1127     return false;
1128   }
1129 
1130   void await_suspend(coroutine_handle<void>)
1131   {
1132     frame_->after_suspend(
1133         [](void* arg)
1134         {
1135           awaitable_async_op* self = static_cast<awaitable_async_op*>(arg);
1136 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1137 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1138           BOOST_ASIO_HANDLER_LOCATION((self->location_.file_name(),
1139               self->location_.line(), self->location_.function_name()));
1140 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1141 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1142           std::forward<Op&&>(self->op_)(
1143               handler_type(self->frame_->detach_thread(), self->result_));
1144         }, this);
1145   }
1146 
1147   auto await_resume()
1148   {
1149     return handler_type::resume(result_);
1150   }
1151 
1152 private:
1153   Op&& op_;
1154   awaitable_frame_base<Executor>* frame_;
1155   typename handler_type::result_type result_;
1156 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1157 # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1158   detail::source_location location_;
1159 # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
1160 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
1161 };
1162 
1163 } // namespace detail
1164 } // namespace asio
1165 } // namespace boost
1166 
1167 #if !defined(GENERATING_DOCUMENTATION)
1168 # if defined(BOOST_ASIO_HAS_STD_COROUTINE)
1169 
1170 namespace std {
1171 
1172 template <typename T, typename Executor, typename... Args>
1173 struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
1174 {
1175   typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
1176 };
1177 
1178 } // namespace std
1179 
1180 # else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1181 
1182 namespace std { namespace experimental {
1183 
1184 template <typename T, typename Executor, typename... Args>
1185 struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...>
1186 {
1187   typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type;
1188 };
1189 
1190 }} // namespace std::experimental
1191 
1192 # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
1193 #endif // !defined(GENERATING_DOCUMENTATION)
1194 
1195 #include <boost/asio/detail/pop_options.hpp>
1196 
1197 #endif // BOOST_ASIO_IMPL_AWAITABLE_HPP