File indexing completed on 2025-07-05 08:27:26
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/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
0037 #endif
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
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 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
0106
0107
0108
0109 auto initial_suspend() noexcept
0110 {
0111 return suspend_always();
0112 }
0113
0114
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
0184 #endif
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
0198 #endif
0199 };
0200 }
0201
0202
0203
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
0229
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
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
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
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
0343
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
0370
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
0398
0399
0400
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
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
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
0679 awaitable_thread(awaitable_thread&& other) noexcept
0680 : bottom_of_stack_(std::move(other.bottom_of_stack_))
0681 {
0682 }
0683
0684
0685
0686 ~awaitable_thread()
0687 {
0688 if (bottom_of_stack_.valid())
0689 {
0690
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
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
0766
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
1113 #endif
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
1122 #endif
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
1142 #endif
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
1161 #endif
1162 };
1163
1164 }
1165 }
1166 }
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 }
1180
1181 # else
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 }}
1192
1193 # endif
1194 #endif
1195
1196 #include <boost/asio/detail/pop_options.hpp>
1197
1198 #endif