File indexing completed on 2025-09-15 08:29:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_IMPL_SPAWN_HPP
0012 #define BOOST_ASIO_IMPL_SPAWN_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 <tuple>
0020 #include <boost/asio/associated_allocator.hpp>
0021 #include <boost/asio/associated_cancellation_slot.hpp>
0022 #include <boost/asio/associated_executor.hpp>
0023 #include <boost/asio/async_result.hpp>
0024 #include <boost/asio/bind_executor.hpp>
0025 #include <boost/asio/detail/atomic_count.hpp>
0026 #include <boost/asio/detail/bind_handler.hpp>
0027 #include <boost/asio/detail/handler_cont_helpers.hpp>
0028 #include <boost/asio/detail/memory.hpp>
0029 #include <boost/asio/detail/noncopyable.hpp>
0030 #include <boost/asio/detail/type_traits.hpp>
0031 #include <boost/asio/detail/utility.hpp>
0032 #include <boost/asio/disposition.hpp>
0033 #include <boost/asio/error.hpp>
0034 #include <boost/system/system_error.hpp>
0035
0036 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0037 # include <boost/context/fiber.hpp>
0038 #endif
0039
0040 #include <boost/asio/detail/push_options.hpp>
0041
0042 namespace boost {
0043 namespace asio {
0044 namespace detail {
0045
0046 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0047 inline void spawned_thread_rethrow(void* ex)
0048 {
0049 if (*static_cast<exception_ptr*>(ex))
0050 rethrow_exception(*static_cast<exception_ptr*>(ex));
0051 }
0052 #endif
0053
0054 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0055
0056
0057 class spawned_fiber_thread : public spawned_thread_base
0058 {
0059 public:
0060 typedef boost::context::fiber fiber_type;
0061
0062 spawned_fiber_thread(fiber_type&& caller)
0063 : caller_(static_cast<fiber_type&&>(caller)),
0064 on_suspend_fn_(0),
0065 on_suspend_arg_(0)
0066 {
0067 }
0068
0069 template <typename StackAllocator, typename F>
0070 static spawned_thread_base* spawn(allocator_arg_t,
0071 StackAllocator&& stack_allocator,
0072 F&& f,
0073 cancellation_slot parent_cancel_slot = cancellation_slot(),
0074 cancellation_state cancel_state = cancellation_state())
0075 {
0076 spawned_fiber_thread* spawned_thread = 0;
0077 fiber_type callee(allocator_arg_t(),
0078 static_cast<StackAllocator&&>(stack_allocator),
0079 entry_point<decay_t<F>>(
0080 static_cast<F&&>(f), &spawned_thread));
0081 callee = fiber_type(static_cast<fiber_type&&>(callee)).resume();
0082 spawned_thread->callee_ = static_cast<fiber_type&&>(callee);
0083 spawned_thread->parent_cancellation_slot_ = parent_cancel_slot;
0084 spawned_thread->cancellation_state_ = cancel_state;
0085 return spawned_thread;
0086 }
0087
0088 template <typename F>
0089 static spawned_thread_base* spawn(F&& f,
0090 cancellation_slot parent_cancel_slot = cancellation_slot(),
0091 cancellation_state cancel_state = cancellation_state())
0092 {
0093 return spawn(allocator_arg_t(), boost::context::fixedsize_stack(),
0094 static_cast<F&&>(f), parent_cancel_slot, cancel_state);
0095 }
0096
0097 void resume()
0098 {
0099 callee_ = fiber_type(static_cast<fiber_type&&>(callee_)).resume();
0100 if (on_suspend_fn_)
0101 {
0102 void (*fn)(void*) = on_suspend_fn_;
0103 void* arg = on_suspend_arg_;
0104 on_suspend_fn_ = 0;
0105 fn(arg);
0106 }
0107 }
0108
0109 void suspend_with(void (*fn)(void*), void* arg)
0110 {
0111 if (throw_if_cancelled_)
0112 if (!!cancellation_state_.cancelled())
0113 throw_error(boost::asio::error::operation_aborted, "yield");
0114 has_context_switched_ = true;
0115 on_suspend_fn_ = fn;
0116 on_suspend_arg_ = arg;
0117 caller_ = fiber_type(static_cast<fiber_type&&>(caller_)).resume();
0118 }
0119
0120 void destroy()
0121 {
0122 fiber_type callee = static_cast<fiber_type&&>(callee_);
0123 if (terminal_)
0124 fiber_type(static_cast<fiber_type&&>(callee)).resume();
0125 }
0126
0127 private:
0128 template <typename Function>
0129 class entry_point
0130 {
0131 public:
0132 template <typename F>
0133 entry_point(F&& f,
0134 spawned_fiber_thread** spawned_thread_out)
0135 : function_(static_cast<F&&>(f)),
0136 spawned_thread_out_(spawned_thread_out)
0137 {
0138 }
0139
0140 fiber_type operator()(fiber_type&& caller)
0141 {
0142 Function function(static_cast<Function&&>(function_));
0143 spawned_fiber_thread spawned_thread(
0144 static_cast<fiber_type&&>(caller));
0145 *spawned_thread_out_ = &spawned_thread;
0146 spawned_thread_out_ = 0;
0147 spawned_thread.suspend();
0148 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0149 try
0150 #endif
0151 {
0152 function(&spawned_thread);
0153 spawned_thread.terminal_ = true;
0154 spawned_thread.suspend();
0155 }
0156 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0157 catch (const boost::context::detail::forced_unwind&)
0158 {
0159 throw;
0160 }
0161 catch (...)
0162 {
0163 exception_ptr ex = current_exception();
0164 spawned_thread.terminal_ = true;
0165 spawned_thread.suspend_with(spawned_thread_rethrow, &ex);
0166 }
0167 #endif
0168 return static_cast<fiber_type&&>(spawned_thread.caller_);
0169 }
0170
0171 private:
0172 Function function_;
0173 spawned_fiber_thread** spawned_thread_out_;
0174 };
0175
0176 fiber_type caller_;
0177 fiber_type callee_;
0178 void (*on_suspend_fn_)(void*);
0179 void* on_suspend_arg_;
0180 };
0181
0182 #endif
0183
0184 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0185 typedef spawned_fiber_thread default_spawned_thread_type;
0186 #else
0187 # error No spawn() implementation available
0188 #endif
0189
0190
0191 class spawned_thread_resumer
0192 {
0193 public:
0194 explicit spawned_thread_resumer(spawned_thread_base* spawned_thread)
0195 : spawned_thread_(spawned_thread)
0196 {
0197 }
0198
0199 spawned_thread_resumer(spawned_thread_resumer&& other) noexcept
0200 : spawned_thread_(other.spawned_thread_)
0201 {
0202 other.spawned_thread_ = 0;
0203 }
0204
0205 ~spawned_thread_resumer()
0206 {
0207 if (spawned_thread_)
0208 spawned_thread_->destroy();
0209 }
0210
0211 void operator()()
0212 {
0213 spawned_thread_->attach(&spawned_thread_);
0214 spawned_thread_->resume();
0215 }
0216
0217 private:
0218 spawned_thread_base* spawned_thread_;
0219 };
0220
0221
0222 class spawned_thread_destroyer
0223 {
0224 public:
0225 explicit spawned_thread_destroyer(spawned_thread_base* spawned_thread)
0226 : spawned_thread_(spawned_thread)
0227 {
0228 spawned_thread->detach();
0229 }
0230
0231 spawned_thread_destroyer(spawned_thread_destroyer&& other) noexcept
0232 : spawned_thread_(other.spawned_thread_)
0233 {
0234 other.spawned_thread_ = 0;
0235 }
0236
0237 ~spawned_thread_destroyer()
0238 {
0239 if (spawned_thread_)
0240 spawned_thread_->destroy();
0241 }
0242
0243 void operator()()
0244 {
0245 if (spawned_thread_)
0246 {
0247 spawned_thread_->destroy();
0248 spawned_thread_ = 0;
0249 }
0250 }
0251
0252 private:
0253 spawned_thread_base* spawned_thread_;
0254 };
0255
0256
0257 template <typename Executor>
0258 class spawn_handler_base
0259 {
0260 public:
0261 typedef Executor executor_type;
0262 typedef cancellation_slot cancellation_slot_type;
0263
0264 spawn_handler_base(const basic_yield_context<Executor>& yield)
0265 : yield_(yield),
0266 spawned_thread_(yield.spawned_thread_)
0267 {
0268 spawned_thread_->detach();
0269 }
0270
0271 spawn_handler_base(spawn_handler_base&& other) noexcept
0272 : yield_(other.yield_),
0273 spawned_thread_(other.spawned_thread_)
0274
0275 {
0276 other.spawned_thread_ = 0;
0277 }
0278
0279 ~spawn_handler_base()
0280 {
0281 if (spawned_thread_)
0282 (post)(yield_.executor_, spawned_thread_destroyer(spawned_thread_));
0283 }
0284
0285 executor_type get_executor() const noexcept
0286 {
0287 return yield_.executor_;
0288 }
0289
0290 cancellation_slot_type get_cancellation_slot() const noexcept
0291 {
0292 return spawned_thread_->get_cancellation_slot();
0293 }
0294
0295 void resume()
0296 {
0297 spawned_thread_resumer resumer(spawned_thread_);
0298 spawned_thread_ = 0;
0299 resumer();
0300 }
0301
0302 protected:
0303 const basic_yield_context<Executor>& yield_;
0304 spawned_thread_base* spawned_thread_;
0305 };
0306
0307
0308 template <typename Executor, typename Signature, typename = void>
0309 class spawn_handler;
0310
0311 template <typename Executor, typename R>
0312 class spawn_handler<Executor, R()>
0313 : public spawn_handler_base<Executor>
0314 {
0315 public:
0316 typedef void return_type;
0317
0318 struct result_type {};
0319
0320 spawn_handler(const basic_yield_context<Executor>& yield, result_type&)
0321 : spawn_handler_base<Executor>(yield)
0322 {
0323 }
0324
0325 void operator()()
0326 {
0327 this->resume();
0328 }
0329
0330 static return_type on_resume(result_type&)
0331 {
0332 }
0333 };
0334
0335 template <typename Executor, typename R>
0336 class spawn_handler<Executor, R(boost::system::error_code)>
0337 : public spawn_handler_base<Executor>
0338 {
0339 public:
0340 typedef void return_type;
0341 typedef boost::system::error_code* result_type;
0342
0343 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0344 : spawn_handler_base<Executor>(yield),
0345 result_(result)
0346 {
0347 }
0348
0349 void operator()(boost::system::error_code ec)
0350 {
0351 if (this->yield_.ec_)
0352 {
0353 *this->yield_.ec_ = ec;
0354 result_ = 0;
0355 }
0356 else
0357 result_ = &ec;
0358 this->resume();
0359 }
0360
0361 static return_type on_resume(result_type& result)
0362 {
0363 if (result)
0364 throw_error(*result);
0365 }
0366
0367 private:
0368 result_type& result_;
0369 };
0370
0371 template <typename Executor, typename R, typename Disposition>
0372 class spawn_handler<Executor, R(Disposition),
0373 enable_if_t<is_disposition<Disposition>::value>
0374 > : public spawn_handler_base<Executor>
0375 {
0376 public:
0377 typedef void return_type;
0378 typedef Disposition* result_type;
0379
0380 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0381 : spawn_handler_base<Executor>(yield),
0382 result_(result)
0383 {
0384 }
0385
0386 void operator()(Disposition d)
0387 {
0388 result_ = detail::addressof(d);
0389 this->resume();
0390 }
0391
0392 static return_type on_resume(result_type& result)
0393 {
0394 if (*result != no_error)
0395 boost::asio::throw_exception(static_cast<Disposition&&>(*result));
0396 }
0397
0398 private:
0399 result_type& result_;
0400 };
0401
0402 template <typename Executor, typename R, typename T>
0403 class spawn_handler<Executor, R(T),
0404 enable_if_t<!is_disposition<T>::value>
0405 > : public spawn_handler_base<Executor>
0406 {
0407 public:
0408 typedef T return_type;
0409 typedef return_type* result_type;
0410
0411 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0412 : spawn_handler_base<Executor>(yield),
0413 result_(result)
0414 {
0415 }
0416
0417 void operator()(T value)
0418 {
0419 result_ = detail::addressof(value);
0420 this->resume();
0421 }
0422
0423 static return_type on_resume(result_type& result)
0424 {
0425 return static_cast<return_type&&>(*result);
0426 }
0427
0428 private:
0429 result_type& result_;
0430 };
0431
0432 template <typename Executor, typename R, typename T>
0433 class spawn_handler<Executor, R(boost::system::error_code, T)>
0434 : public spawn_handler_base<Executor>
0435 {
0436 public:
0437 typedef T return_type;
0438
0439 struct result_type
0440 {
0441 boost::system::error_code* ec_;
0442 return_type* value_;
0443 };
0444
0445 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0446 : spawn_handler_base<Executor>(yield),
0447 result_(result)
0448 {
0449 }
0450
0451 void operator()(boost::system::error_code ec, T value)
0452 {
0453 if (this->yield_.ec_)
0454 {
0455 *this->yield_.ec_ = ec;
0456 result_.ec_ = 0;
0457 }
0458 else
0459 result_.ec_ = &ec;
0460 result_.value_ = detail::addressof(value);
0461 this->resume();
0462 }
0463
0464 static return_type on_resume(result_type& result)
0465 {
0466 if (result.ec_)
0467 throw_error(*result.ec_);
0468 return static_cast<return_type&&>(*result.value_);
0469 }
0470
0471 private:
0472 result_type& result_;
0473 };
0474
0475 template <typename Executor, typename R, typename Disposition, typename T>
0476 class spawn_handler<Executor, R(Disposition, T),
0477 enable_if_t<is_disposition<Disposition>::value>
0478 > : public spawn_handler_base<Executor>
0479 {
0480 public:
0481 typedef T return_type;
0482
0483 struct result_type
0484 {
0485 Disposition* disposition_;
0486 return_type* value_;
0487 };
0488
0489 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0490 : spawn_handler_base<Executor>(yield),
0491 result_(result)
0492 {
0493 }
0494
0495 void operator()(Disposition d, T value)
0496 {
0497 result_.disposition_ = detail::addressof(d);
0498 result_.value_ = detail::addressof(value);
0499 this->resume();
0500 }
0501
0502 static return_type on_resume(result_type& result)
0503 {
0504 if (*result.disposition_ != no_error)
0505 {
0506 boost::asio::throw_exception(
0507 static_cast<Disposition&&>(*result.disposition_));
0508 }
0509 return static_cast<return_type&&>(*result.value_);
0510 }
0511
0512 private:
0513 result_type& result_;
0514 };
0515
0516 template <typename Executor, typename R, typename T, typename... Ts>
0517 class spawn_handler<Executor, R(T, Ts...),
0518 enable_if_t<!is_disposition<T>::value>
0519 > : public spawn_handler_base<Executor>
0520 {
0521 public:
0522 typedef std::tuple<T, Ts...> return_type;
0523
0524 typedef return_type* result_type;
0525
0526 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0527 : spawn_handler_base<Executor>(yield),
0528 result_(result)
0529 {
0530 }
0531
0532 template <typename... Args>
0533 void operator()(Args&&... args)
0534 {
0535 return_type value(static_cast<Args&&>(args)...);
0536 result_ = detail::addressof(value);
0537 this->resume();
0538 }
0539
0540 static return_type on_resume(result_type& result)
0541 {
0542 return static_cast<return_type&&>(*result);
0543 }
0544
0545 private:
0546 result_type& result_;
0547 };
0548
0549 template <typename Executor, typename R, typename... Ts>
0550 class spawn_handler<Executor, R(boost::system::error_code, Ts...)>
0551 : public spawn_handler_base<Executor>
0552 {
0553 public:
0554 typedef std::tuple<Ts...> return_type;
0555
0556 struct result_type
0557 {
0558 boost::system::error_code* ec_;
0559 return_type* value_;
0560 };
0561
0562 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0563 : spawn_handler_base<Executor>(yield),
0564 result_(result)
0565 {
0566 }
0567
0568 template <typename... Args>
0569 void operator()(boost::system::error_code ec,
0570 Args&&... args)
0571 {
0572 return_type value(static_cast<Args&&>(args)...);
0573 if (this->yield_.ec_)
0574 {
0575 *this->yield_.ec_ = ec;
0576 result_.ec_ = 0;
0577 }
0578 else
0579 result_.ec_ = &ec;
0580 result_.value_ = detail::addressof(value);
0581 this->resume();
0582 }
0583
0584 static return_type on_resume(result_type& result)
0585 {
0586 if (result.ec_)
0587 throw_error(*result.ec_);
0588 return static_cast<return_type&&>(*result.value_);
0589 }
0590
0591 private:
0592 result_type& result_;
0593 };
0594
0595 template <typename Executor, typename R, typename Disposition, typename... Ts>
0596 class spawn_handler<Executor, R(Disposition, Ts...),
0597 enable_if_t<is_disposition<Disposition>::value>
0598 > : public spawn_handler_base<Executor>
0599 {
0600 public:
0601 typedef std::tuple<Ts...> return_type;
0602
0603 struct result_type
0604 {
0605 Disposition* disposition_;
0606 return_type* value_;
0607 };
0608
0609 spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0610 : spawn_handler_base<Executor>(yield),
0611 result_(result)
0612 {
0613 }
0614
0615 template <typename... Args>
0616 void operator()(Disposition d, Args&&... args)
0617 {
0618 return_type value(static_cast<Args&&>(args)...);
0619 result_.disposition_ = detail::addressof(d);
0620 result_.value_ = detail::addressof(value);
0621 this->resume();
0622 }
0623
0624 static return_type on_resume(result_type& result)
0625 {
0626 if (*result.disposition_ != no_error)
0627 {
0628 boost::asio::throw_exception(
0629 static_cast<Disposition&&>(*result.disposition_));
0630 }
0631 return static_cast<return_type&&>(*result.value_);
0632 }
0633
0634 private:
0635 result_type& result_;
0636 };
0637
0638 template <typename Executor, typename Signature>
0639 inline bool asio_handler_is_continuation(spawn_handler<Executor, Signature>*)
0640 {
0641 return true;
0642 }
0643
0644 }
0645
0646 #if !defined(GENERATING_DOCUMENTATION)
0647
0648 template <typename Executor, typename Signature>
0649 class async_result<basic_yield_context<Executor>, Signature>
0650 {
0651 public:
0652 typedef typename detail::spawn_handler<Executor, Signature> handler_type;
0653 typedef typename handler_type::return_type return_type;
0654
0655 #if defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
0656
0657 template <typename Initiation, typename... InitArgs>
0658 static return_type initiate(Initiation&& init,
0659 const basic_yield_context<Executor>& yield,
0660 InitArgs&&... init_args)
0661 {
0662 typename handler_type::result_type result
0663 = typename handler_type::result_type();
0664
0665 yield.spawned_thread_->suspend_with(
0666 [&]()
0667 {
0668 static_cast<Initiation&&>(init)(
0669 handler_type(yield, result),
0670 static_cast<InitArgs&&>(init_args)...);
0671 });
0672
0673 return handler_type::on_resume(result);
0674 }
0675
0676 #else
0677
0678 template <typename Initiation, typename... InitArgs>
0679 struct suspend_with_helper
0680 {
0681 typename handler_type::result_type& result_;
0682 Initiation&& init_;
0683 const basic_yield_context<Executor>& yield_;
0684 std::tuple<InitArgs&&...> init_args_;
0685
0686 template <std::size_t... I>
0687 void do_invoke(detail::index_sequence<I...>)
0688 {
0689 static_cast<Initiation&&>(init_)(
0690 handler_type(yield_, result_),
0691 static_cast<InitArgs&&>(std::get<I>(init_args_))...);
0692 }
0693
0694 void operator()()
0695 {
0696 this->do_invoke(detail::make_index_sequence<sizeof...(InitArgs)>());
0697 }
0698 };
0699
0700 template <typename Initiation, typename... InitArgs>
0701 static return_type initiate(Initiation&& init,
0702 const basic_yield_context<Executor>& yield,
0703 InitArgs&&... init_args)
0704 {
0705 typename handler_type::result_type result
0706 = typename handler_type::result_type();
0707
0708 yield.spawned_thread_->suspend_with(
0709 suspend_with_helper<Initiation, InitArgs...>{
0710 result, static_cast<Initiation&&>(init), yield,
0711 std::tuple<InitArgs&&...>(
0712 static_cast<InitArgs&&>(init_args)...)});
0713
0714 return handler_type::on_resume(result);
0715 }
0716
0717 #endif
0718 };
0719
0720 #endif
0721
0722 namespace detail {
0723
0724 template <typename Executor, typename Function, typename Handler>
0725 class spawn_entry_point
0726 {
0727 public:
0728 template <typename F, typename H>
0729 spawn_entry_point(const Executor& ex,
0730 F&& f, H&& h)
0731 : executor_(ex),
0732 function_(static_cast<F&&>(f)),
0733 handler_(static_cast<H&&>(h)),
0734 work_(handler_, executor_)
0735 {
0736 }
0737
0738 void operator()(spawned_thread_base* spawned_thread)
0739 {
0740 const basic_yield_context<Executor> yield(spawned_thread, executor_);
0741 this->call(yield,
0742 void_type<result_of_t<Function(basic_yield_context<Executor>)>>());
0743 }
0744
0745 private:
0746 void call(const basic_yield_context<Executor>& yield, void_type<void>)
0747 {
0748 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0749 try
0750 #endif
0751 {
0752 function_(yield);
0753 if (!yield.spawned_thread_->has_context_switched())
0754 (post)(yield);
0755 detail::binder1<Handler, exception_ptr>
0756 handler(handler_, exception_ptr());
0757 work_.complete(handler, handler.handler_);
0758 }
0759 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0760 # if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0761 catch (const boost::context::detail::forced_unwind&)
0762 {
0763 throw;
0764 }
0765 # endif
0766 catch (...)
0767 {
0768 exception_ptr ex = current_exception();
0769 if (!yield.spawned_thread_->has_context_switched())
0770 (post)(yield);
0771 detail::binder1<Handler, exception_ptr> handler(handler_, ex);
0772 work_.complete(handler, handler.handler_);
0773 }
0774 #endif
0775 }
0776
0777 template <typename T>
0778 void call(const basic_yield_context<Executor>& yield, void_type<T>)
0779 {
0780 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0781 try
0782 #endif
0783 {
0784 T result(function_(yield));
0785 if (!yield.spawned_thread_->has_context_switched())
0786 (post)(yield);
0787 detail::move_binder2<Handler, exception_ptr, T>
0788 handler(0, static_cast<Handler&&>(handler_),
0789 exception_ptr(), static_cast<T&&>(result));
0790 work_.complete(handler, handler.handler_);
0791 }
0792 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0793 # if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0794 catch (const boost::context::detail::forced_unwind&)
0795 {
0796 throw;
0797 }
0798 # endif
0799 catch (...)
0800 {
0801 exception_ptr ex = current_exception();
0802 if (!yield.spawned_thread_->has_context_switched())
0803 (post)(yield);
0804 detail::move_binder2<Handler, exception_ptr, T>
0805 handler(0, static_cast<Handler&&>(handler_), ex, T());
0806 work_.complete(handler, handler.handler_);
0807 }
0808 #endif
0809 }
0810
0811 Executor executor_;
0812 Function function_;
0813 Handler handler_;
0814 handler_work<Handler, Executor> work_;
0815 };
0816
0817 struct spawn_cancellation_signal_emitter
0818 {
0819 cancellation_signal* signal_;
0820 cancellation_type_t type_;
0821
0822 void operator()()
0823 {
0824 signal_->emit(type_);
0825 }
0826 };
0827
0828 template <typename Handler, typename Executor, typename = void>
0829 class spawn_cancellation_handler
0830 {
0831 public:
0832 spawn_cancellation_handler(const Handler&, const Executor& ex)
0833 : ex_(ex)
0834 {
0835 }
0836
0837 cancellation_slot slot()
0838 {
0839 return signal_.slot();
0840 }
0841
0842 void operator()(cancellation_type_t type)
0843 {
0844 spawn_cancellation_signal_emitter emitter = { &signal_, type };
0845 (dispatch)(ex_, emitter);
0846 }
0847
0848 private:
0849 cancellation_signal signal_;
0850 Executor ex_;
0851 };
0852
0853 template <typename Handler, typename Executor>
0854 class spawn_cancellation_handler<Handler, Executor,
0855 enable_if_t<
0856 is_same<
0857 typename associated_executor<Handler,
0858 Executor>::asio_associated_executor_is_unspecialised,
0859 void
0860 >::value
0861 >>
0862 {
0863 public:
0864 spawn_cancellation_handler(const Handler&, const Executor&)
0865 {
0866 }
0867
0868 cancellation_slot slot()
0869 {
0870 return signal_.slot();
0871 }
0872
0873 void operator()(cancellation_type_t type)
0874 {
0875 signal_.emit(type);
0876 }
0877
0878 private:
0879 cancellation_signal signal_;
0880 };
0881
0882 template <typename Executor>
0883 class initiate_spawn
0884 {
0885 public:
0886 typedef Executor executor_type;
0887
0888 explicit initiate_spawn(const executor_type& ex)
0889 : executor_(ex)
0890 {
0891 }
0892
0893 executor_type get_executor() const noexcept
0894 {
0895 return executor_;
0896 }
0897
0898 template <typename Handler, typename F>
0899 void operator()(Handler&& handler,
0900 F&& f) const
0901 {
0902 typedef decay_t<Handler> handler_type;
0903 typedef decay_t<F> function_type;
0904 typedef spawn_cancellation_handler<
0905 handler_type, Executor> cancel_handler_type;
0906
0907 associated_cancellation_slot_t<handler_type> slot
0908 = boost::asio::get_associated_cancellation_slot(handler);
0909
0910 cancel_handler_type* cancel_handler = slot.is_connected()
0911 ? &slot.template emplace<cancel_handler_type>(handler, executor_)
0912 : 0;
0913
0914 cancellation_slot proxy_slot(
0915 cancel_handler
0916 ? cancel_handler->slot()
0917 : cancellation_slot());
0918
0919 cancellation_state cancel_state(proxy_slot);
0920
0921 (dispatch)(executor_,
0922 spawned_thread_resumer(
0923 default_spawned_thread_type::spawn(
0924 spawn_entry_point<Executor, function_type, handler_type>(
0925 executor_, static_cast<F&&>(f),
0926 static_cast<Handler&&>(handler)),
0927 proxy_slot, cancel_state)));
0928 }
0929
0930 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0931
0932 template <typename Handler, typename StackAllocator, typename F>
0933 void operator()(Handler&& handler, allocator_arg_t,
0934 StackAllocator&& stack_allocator,
0935 F&& f) const
0936 {
0937 typedef decay_t<Handler> handler_type;
0938 typedef decay_t<F> function_type;
0939 typedef spawn_cancellation_handler<
0940 handler_type, Executor> cancel_handler_type;
0941
0942 associated_cancellation_slot_t<handler_type> slot
0943 = boost::asio::get_associated_cancellation_slot(handler);
0944
0945 cancel_handler_type* cancel_handler = slot.is_connected()
0946 ? &slot.template emplace<cancel_handler_type>(handler, executor_)
0947 : 0;
0948
0949 cancellation_slot proxy_slot(
0950 cancel_handler
0951 ? cancel_handler->slot()
0952 : cancellation_slot());
0953
0954 cancellation_state cancel_state(proxy_slot);
0955
0956 (dispatch)(executor_,
0957 spawned_thread_resumer(
0958 spawned_fiber_thread::spawn(allocator_arg_t(),
0959 static_cast<StackAllocator&&>(stack_allocator),
0960 spawn_entry_point<Executor, function_type, handler_type>(
0961 executor_, static_cast<F&&>(f),
0962 static_cast<Handler&&>(handler)),
0963 proxy_slot, cancel_state)));
0964 }
0965
0966 #endif
0967
0968 private:
0969 executor_type executor_;
0970 };
0971
0972 }
0973
0974 template <typename Executor, typename F,
0975 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0976 result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken>
0977 inline auto spawn(const Executor& ex, F&& function, CompletionToken&& token,
0978 constraint_t<
0979 is_executor<Executor>::value || execution::is_executor<Executor>::value
0980 >)
0981 -> decltype(
0982 async_initiate<CompletionToken,
0983 typename detail::spawn_signature<
0984 result_of_t<F(basic_yield_context<Executor>)>>::type>(
0985 declval<detail::initiate_spawn<Executor>>(),
0986 token, static_cast<F&&>(function)))
0987 {
0988 return async_initiate<CompletionToken,
0989 typename detail::spawn_signature<
0990 result_of_t<F(basic_yield_context<Executor>)>>::type>(
0991 detail::initiate_spawn<Executor>(ex),
0992 token, static_cast<F&&>(function));
0993 }
0994
0995 template <typename ExecutionContext, typename F,
0996 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0997 result_of_t<F(basic_yield_context<
0998 typename ExecutionContext::executor_type>)>>::type) CompletionToken>
0999 inline auto spawn(ExecutionContext& ctx, F&& function, CompletionToken&& token,
1000 constraint_t<
1001 is_convertible<ExecutionContext&, execution_context&>::value
1002 >)
1003 -> decltype(
1004 async_initiate<CompletionToken,
1005 typename detail::spawn_signature<
1006 result_of_t<F(basic_yield_context<
1007 typename ExecutionContext::executor_type>)>>::type>(
1008 declval<detail::initiate_spawn<
1009 typename ExecutionContext::executor_type>>(),
1010 token, static_cast<F&&>(function)))
1011 {
1012 return (spawn)(ctx.get_executor(), static_cast<F&&>(function),
1013 static_cast<CompletionToken&&>(token));
1014 }
1015
1016 template <typename Executor, typename F,
1017 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1018 result_of_t<F(basic_yield_context<Executor>)>>::type)
1019 CompletionToken>
1020 inline auto spawn(const basic_yield_context<Executor>& ctx,
1021 F&& function, CompletionToken&& token,
1022 constraint_t<
1023 is_executor<Executor>::value || execution::is_executor<Executor>::value
1024 >)
1025 -> decltype(
1026 async_initiate<CompletionToken,
1027 typename detail::spawn_signature<
1028 result_of_t<F(basic_yield_context<Executor>)>>::type>(
1029 declval<detail::initiate_spawn<Executor>>(),
1030 token, static_cast<F&&>(function)))
1031 {
1032 return (spawn)(ctx.get_executor(), static_cast<F&&>(function),
1033 static_cast<CompletionToken&&>(token));
1034 }
1035
1036 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
1037
1038 template <typename Executor, typename StackAllocator, typename F,
1039 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1040 result_of_t<F(basic_yield_context<Executor>)>>::type)
1041 CompletionToken>
1042 inline auto spawn(const Executor& ex, allocator_arg_t,
1043 StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
1044 constraint_t<
1045 is_executor<Executor>::value || execution::is_executor<Executor>::value
1046 >)
1047 -> decltype(
1048 async_initiate<CompletionToken,
1049 typename detail::spawn_signature<
1050 result_of_t<F(basic_yield_context<Executor>)>>::type>(
1051 declval<detail::initiate_spawn<Executor>>(),
1052 token, allocator_arg_t(),
1053 static_cast<StackAllocator&&>(stack_allocator),
1054 static_cast<F&&>(function)))
1055 {
1056 return async_initiate<CompletionToken,
1057 typename detail::spawn_signature<
1058 result_of_t<F(basic_yield_context<Executor>)>>::type>(
1059 detail::initiate_spawn<Executor>(ex), token, allocator_arg_t(),
1060 static_cast<StackAllocator&&>(stack_allocator),
1061 static_cast<F&&>(function));
1062 }
1063
1064 template <typename ExecutionContext, typename StackAllocator, typename F,
1065 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1066 result_of_t<F(basic_yield_context<
1067 typename ExecutionContext::executor_type>)>>::type) CompletionToken>
1068 inline auto spawn(ExecutionContext& ctx, allocator_arg_t,
1069 StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
1070 constraint_t<
1071 is_convertible<ExecutionContext&, execution_context&>::value
1072 >)
1073 -> decltype(
1074 async_initiate<CompletionToken,
1075 typename detail::spawn_signature<
1076 result_of_t<F(basic_yield_context<
1077 typename ExecutionContext::executor_type>)>>::type>(
1078 declval<detail::initiate_spawn<
1079 typename ExecutionContext::executor_type>>(),
1080 token, allocator_arg_t(),
1081 static_cast<StackAllocator&&>(stack_allocator),
1082 static_cast<F&&>(function)))
1083 {
1084 return (spawn)(ctx.get_executor(), allocator_arg_t(),
1085 static_cast<StackAllocator&&>(stack_allocator),
1086 static_cast<F&&>(function), static_cast<CompletionToken&&>(token));
1087 }
1088
1089 template <typename Executor, typename StackAllocator, typename F,
1090 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1091 result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken>
1092 inline auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
1093 StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
1094 constraint_t<
1095 is_executor<Executor>::value || execution::is_executor<Executor>::value
1096 >)
1097 -> decltype(
1098 async_initiate<CompletionToken,
1099 typename detail::spawn_signature<
1100 result_of_t<F(basic_yield_context<Executor>)>>::type>(
1101 declval<detail::initiate_spawn<Executor>>(), token,
1102 allocator_arg_t(), static_cast<StackAllocator&&>(stack_allocator),
1103 static_cast<F&&>(function)))
1104 {
1105 return (spawn)(ctx.get_executor(), allocator_arg_t(),
1106 static_cast<StackAllocator&&>(stack_allocator),
1107 static_cast<F&&>(function), static_cast<CompletionToken&&>(token));
1108 }
1109
1110 #endif
1111
1112 }
1113 }
1114
1115 #include <boost/asio/detail/pop_options.hpp>
1116
1117 #endif