File indexing completed on 2026-08-20 08:38:27
0001
0002
0003
0004
0005
0006
0007
0008
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
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
0040 #endif
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
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
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
0117
0118
0119
0120 auto initial_suspend() noexcept
0121 {
0122 return suspend_always();
0123 }
0124
0125
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
0191 #endif
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
0205 #endif
0206 };
0207 }
0208
0209
0210
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
0236
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
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
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
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
0350
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
0377
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
0405
0406
0407
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
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
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
0684 awaitable_thread(awaitable_thread&& other) noexcept
0685 : bottom_of_stack_(std::move(other.bottom_of_stack_))
0686 {
0687 }
0688
0689
0690
0691 ~awaitable_thread()
0692 {
0693 if (bottom_of_stack_.valid())
0694 {
0695
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
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
0771
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
1021 #endif
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
1030 #endif
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
1050 #endif
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
1069 #endif
1070 };
1071
1072 }
1073 }
1074 }
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 }
1088
1089 # else
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 }}
1100
1101 # endif
1102 #endif
1103
1104 #include <boost/asio/detail/pop_options.hpp>
1105
1106 #endif