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