Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:27:27

0001 //
0002 // impl/co_spawn.hpp
0003 // ~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IMPL_CO_SPAWN_HPP
0012 #define BOOST_ASIO_IMPL_CO_SPAWN_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/associated_cancellation_slot.hpp>
0020 #include <boost/asio/awaitable.hpp>
0021 #include <boost/asio/detail/memory.hpp>
0022 #include <boost/asio/detail/recycling_allocator.hpp>
0023 #include <boost/asio/dispatch.hpp>
0024 #include <boost/asio/execution/outstanding_work.hpp>
0025 #include <boost/asio/post.hpp>
0026 #include <boost/asio/prefer.hpp>
0027 #include <boost/asio/use_awaitable.hpp>
0028 
0029 #include <boost/asio/detail/push_options.hpp>
0030 
0031 namespace boost {
0032 namespace asio {
0033 namespace detail {
0034 
0035 template <typename Executor, typename = void>
0036 class co_spawn_work_guard
0037 {
0038 public:
0039   typedef decay_t<
0040       prefer_result_t<Executor,
0041         execution::outstanding_work_t::tracked_t
0042       >
0043     > executor_type;
0044 
0045   co_spawn_work_guard(const Executor& ex)
0046     : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0047   {
0048   }
0049 
0050   executor_type get_executor() const noexcept
0051   {
0052     return executor_;
0053   }
0054 
0055 private:
0056   executor_type executor_;
0057 };
0058 
0059 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0060 
0061 template <typename Executor>
0062 struct co_spawn_work_guard<Executor,
0063     enable_if_t<
0064       !execution::is_executor<Executor>::value
0065     >> : executor_work_guard<Executor>
0066 {
0067   co_spawn_work_guard(const Executor& ex)
0068     : executor_work_guard<Executor>(ex)
0069   {
0070   }
0071 };
0072 
0073 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0074 
0075 template <typename Handler, typename Executor,
0076     typename Function, typename = void>
0077 struct co_spawn_state
0078 {
0079   template <typename H, typename F>
0080   co_spawn_state(H&& h, const Executor& ex, F&& f)
0081     : handler(std::forward<H>(h)),
0082       spawn_work(ex),
0083       handler_work(boost::asio::get_associated_executor(handler, ex)),
0084       function(std::forward<F>(f))
0085   {
0086   }
0087 
0088   Handler handler;
0089   co_spawn_work_guard<Executor> spawn_work;
0090   co_spawn_work_guard<associated_executor_t<Handler, Executor>> handler_work;
0091   Function function;
0092 };
0093 
0094 template <typename Handler, typename Executor, typename Function>
0095 struct co_spawn_state<Handler, Executor, Function,
0096     enable_if_t<
0097       is_same<
0098         typename associated_executor<Handler,
0099           Executor>::asio_associated_executor_is_unspecialised,
0100         void
0101       >::value
0102     >>
0103 {
0104   template <typename H, typename F>
0105   co_spawn_state(H&& h, const Executor& ex, F&& f)
0106     : handler(std::forward<H>(h)),
0107       handler_work(ex),
0108       function(std::forward<F>(f))
0109   {
0110   }
0111 
0112   Handler handler;
0113   co_spawn_work_guard<Executor> handler_work;
0114   Function function;
0115 };
0116 
0117 struct co_spawn_dispatch
0118 {
0119   template <typename CompletionToken>
0120   auto operator()(CompletionToken&& token) const
0121     -> decltype(boost::asio::dispatch(std::forward<CompletionToken>(token)))
0122   {
0123     return boost::asio::dispatch(std::forward<CompletionToken>(token));
0124   }
0125 };
0126 
0127 struct co_spawn_post
0128 {
0129   template <typename CompletionToken>
0130   auto operator()(CompletionToken&& token) const
0131     -> decltype(boost::asio::post(std::forward<CompletionToken>(token)))
0132   {
0133     return boost::asio::post(std::forward<CompletionToken>(token));
0134   }
0135 };
0136 
0137 template <typename T, typename Handler, typename Executor, typename Function>
0138 awaitable<awaitable_thread_entry_point, Executor> co_spawn_entry_point(
0139     awaitable<T, Executor>*, co_spawn_state<Handler, Executor, Function> s)
0140 {
0141   (void) co_await co_spawn_dispatch{};
0142 
0143   (co_await awaitable_thread_has_context_switched{}) = false;
0144   std::exception_ptr e = nullptr;
0145   bool done = false;
0146 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0147   try
0148 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0149   {
0150     T t = co_await s.function();
0151 
0152     done = true;
0153 
0154     bool switched = (co_await awaitable_thread_has_context_switched{});
0155     if (!switched)
0156     {
0157       co_await this_coro::throw_if_cancelled(false);
0158       (void) co_await co_spawn_post();
0159     }
0160 
0161     (dispatch)(s.handler_work.get_executor(),
0162         [handler = std::move(s.handler), t = std::move(t)]() mutable
0163         {
0164           std::move(handler)(std::exception_ptr(), std::move(t));
0165         });
0166 
0167     co_return;
0168   }
0169 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0170   catch (...)
0171   {
0172     if (done)
0173       throw;
0174 
0175     e = std::current_exception();
0176   }
0177 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0178 
0179   bool switched = (co_await awaitable_thread_has_context_switched{});
0180   if (!switched)
0181   {
0182     co_await this_coro::throw_if_cancelled(false);
0183     (void) co_await co_spawn_post();
0184   }
0185 
0186   (dispatch)(s.handler_work.get_executor(),
0187       [handler = std::move(s.handler), e]() mutable
0188       {
0189         std::move(handler)(e, T());
0190       });
0191 }
0192 
0193 template <typename Handler, typename Executor, typename Function>
0194 awaitable<awaitable_thread_entry_point, Executor> co_spawn_entry_point(
0195     awaitable<void, Executor>*, co_spawn_state<Handler, Executor, Function> s)
0196 {
0197   (void) co_await co_spawn_dispatch{};
0198 
0199   (co_await awaitable_thread_has_context_switched{}) = false;
0200   std::exception_ptr e = nullptr;
0201 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0202   try
0203 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0204   {
0205     co_await s.function();
0206   }
0207 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0208   catch (...)
0209   {
0210     e = std::current_exception();
0211   }
0212 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0213 
0214   bool switched = (co_await awaitable_thread_has_context_switched{});
0215   if (!switched)
0216   {
0217     co_await this_coro::throw_if_cancelled(false);
0218     (void) co_await co_spawn_post();
0219   }
0220 
0221   (dispatch)(s.handler_work.get_executor(),
0222       [handler = std::move(s.handler), e]() mutable
0223       {
0224         std::move(handler)(e);
0225       });
0226 }
0227 
0228 template <typename T, typename Executor>
0229 class awaitable_as_function
0230 {
0231 public:
0232   explicit awaitable_as_function(awaitable<T, Executor>&& a)
0233     : awaitable_(std::move(a))
0234   {
0235   }
0236 
0237   awaitable<T, Executor> operator()()
0238   {
0239     return std::move(awaitable_);
0240   }
0241 
0242 private:
0243   awaitable<T, Executor> awaitable_;
0244 };
0245 
0246 template <typename Handler, typename Executor, typename = void>
0247 class co_spawn_cancellation_handler
0248 {
0249 public:
0250   co_spawn_cancellation_handler(const Handler&, const Executor& ex)
0251     : signal_(detail::allocate_shared<cancellation_signal>(
0252           detail::recycling_allocator<cancellation_signal,
0253             detail::thread_info_base::cancellation_signal_tag>())),
0254       ex_(ex)
0255   {
0256   }
0257 
0258   cancellation_slot slot()
0259   {
0260     return signal_->slot();
0261   }
0262 
0263   void operator()(cancellation_type_t type)
0264   {
0265     shared_ptr<cancellation_signal> sig = signal_;
0266     boost::asio::dispatch(ex_, [sig, type]{ sig->emit(type); });
0267   }
0268 
0269 private:
0270   shared_ptr<cancellation_signal> signal_;
0271   Executor ex_;
0272 };
0273 
0274 template <typename Handler, typename Executor>
0275 class co_spawn_cancellation_handler<Handler, Executor,
0276     enable_if_t<
0277       is_same<
0278         typename associated_executor<Handler,
0279           Executor>::asio_associated_executor_is_unspecialised,
0280         void
0281       >::value
0282     >>
0283 {
0284 public:
0285   co_spawn_cancellation_handler(const Handler&, const Executor&)
0286   {
0287   }
0288 
0289   cancellation_slot slot()
0290   {
0291     return signal_.slot();
0292   }
0293 
0294   void operator()(cancellation_type_t type)
0295   {
0296     signal_.emit(type);
0297   }
0298 
0299 private:
0300   cancellation_signal signal_;
0301 };
0302 
0303 template <typename Executor>
0304 class initiate_co_spawn
0305 {
0306 public:
0307   typedef Executor executor_type;
0308 
0309   template <typename OtherExecutor>
0310   explicit initiate_co_spawn(const OtherExecutor& ex)
0311     : ex_(ex)
0312   {
0313   }
0314 
0315   executor_type get_executor() const noexcept
0316   {
0317     return ex_;
0318   }
0319 
0320   template <typename Handler, typename F>
0321   void operator()(Handler&& handler, F&& f) const
0322   {
0323     typedef result_of_t<F()> awaitable_type;
0324     typedef decay_t<Handler> handler_type;
0325     typedef decay_t<F> function_type;
0326     typedef co_spawn_cancellation_handler<
0327       handler_type, Executor> cancel_handler_type;
0328 
0329     auto slot = boost::asio::get_associated_cancellation_slot(handler);
0330     cancel_handler_type* cancel_handler = slot.is_connected()
0331       ? &slot.template emplace<cancel_handler_type>(handler, ex_)
0332       : nullptr;
0333 
0334     cancellation_slot proxy_slot(
0335         cancel_handler
0336           ? cancel_handler->slot()
0337           : cancellation_slot());
0338 
0339     cancellation_state cancel_state(proxy_slot);
0340 
0341     auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),
0342         co_spawn_state<handler_type, Executor, function_type>(
0343           std::forward<Handler>(handler), ex_, std::forward<F>(f)));
0344     awaitable_handler<executor_type, void>(std::move(a),
0345         ex_, proxy_slot, cancel_state).launch();
0346   }
0347 
0348 private:
0349   Executor ex_;
0350 };
0351 
0352 } // namespace detail
0353 
0354 template <typename Executor, typename T, typename AwaitableExecutor,
0355     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0356       void(std::exception_ptr, T)) CompletionToken>
0357 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0358     CompletionToken, void(std::exception_ptr, T))
0359 co_spawn(const Executor& ex,
0360     awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
0361     constraint_t<
0362       (is_executor<Executor>::value || execution::is_executor<Executor>::value)
0363         && is_convertible<Executor, AwaitableExecutor>::value
0364     >)
0365 {
0366   return async_initiate<CompletionToken, void(std::exception_ptr, T)>(
0367       detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
0368       token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a)));
0369 }
0370 
0371 template <typename Executor, typename AwaitableExecutor,
0372     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0373       void(std::exception_ptr)) CompletionToken>
0374 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0375     CompletionToken, void(std::exception_ptr))
0376 co_spawn(const Executor& ex,
0377     awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
0378     constraint_t<
0379       (is_executor<Executor>::value || execution::is_executor<Executor>::value)
0380         && is_convertible<Executor, AwaitableExecutor>::value
0381     >)
0382 {
0383   return async_initiate<CompletionToken, void(std::exception_ptr)>(
0384       detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
0385       token, detail::awaitable_as_function<
0386         void, AwaitableExecutor>(std::move(a)));
0387 }
0388 
0389 template <typename ExecutionContext, typename T, typename AwaitableExecutor,
0390     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0391       void(std::exception_ptr, T)) CompletionToken>
0392 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0393     CompletionToken, void(std::exception_ptr, T))
0394 co_spawn(ExecutionContext& ctx,
0395     awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
0396     constraint_t<
0397       is_convertible<ExecutionContext&, execution_context&>::value
0398         && is_convertible<typename ExecutionContext::executor_type,
0399           AwaitableExecutor>::value
0400     >)
0401 {
0402   return (co_spawn)(ctx.get_executor(), std::move(a),
0403       std::forward<CompletionToken>(token));
0404 }
0405 
0406 template <typename ExecutionContext, typename AwaitableExecutor,
0407     BOOST_ASIO_COMPLETION_TOKEN_FOR(
0408       void(std::exception_ptr)) CompletionToken>
0409 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
0410     CompletionToken, void(std::exception_ptr))
0411 co_spawn(ExecutionContext& ctx,
0412     awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
0413     constraint_t<
0414       is_convertible<ExecutionContext&, execution_context&>::value
0415         && is_convertible<typename ExecutionContext::executor_type,
0416           AwaitableExecutor>::value
0417     >)
0418 {
0419   return (co_spawn)(ctx.get_executor(), std::move(a),
0420       std::forward<CompletionToken>(token));
0421 }
0422 
0423 template <typename Executor, typename F,
0424     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
0425       result_of_t<F()>>::type) CompletionToken>
0426 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
0427     typename detail::awaitable_signature<result_of_t<F()>>::type)
0428 co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
0429     constraint_t<
0430       is_executor<Executor>::value || execution::is_executor<Executor>::value
0431     >)
0432 {
0433   return async_initiate<CompletionToken,
0434     typename detail::awaitable_signature<result_of_t<F()>>::type>(
0435       detail::initiate_co_spawn<
0436         typename result_of_t<F()>::executor_type>(ex),
0437       token, std::forward<F>(f));
0438 }
0439 
0440 template <typename ExecutionContext, typename F,
0441     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
0442       result_of_t<F()>>::type) CompletionToken>
0443 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
0444     typename detail::awaitable_signature<result_of_t<F()>>::type)
0445 co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
0446     constraint_t<
0447       is_convertible<ExecutionContext&, execution_context&>::value
0448     >)
0449 {
0450   return (co_spawn)(ctx.get_executor(), std::forward<F>(f),
0451       std::forward<CompletionToken>(token));
0452 }
0453 
0454 } // namespace asio
0455 } // namespace boost
0456 
0457 #include <boost/asio/detail/pop_options.hpp>
0458 
0459 #endif // BOOST_ASIO_IMPL_CO_SPAWN_HPP