File indexing completed on 2025-01-18 09:28:54
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 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
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>
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
1112 #endif
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
1121 #endif
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
1141 #endif
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
1160 #endif
1161 };
1162
1163 }
1164 }
1165 }
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 }
1179
1180 # else
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 }}
1191
1192 # endif
1193 #endif
1194
1195 #include <boost/asio/detail/pop_options.hpp>
1196
1197 #endif