Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:39

0001 //
0002 // detail/handler_work.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 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_DETAIL_HANDLER_WORK_HPP
0012 #define BOOST_ASIO_DETAIL_HANDLER_WORK_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_allocator.hpp>
0020 #include <boost/asio/associated_executor.hpp>
0021 #include <boost/asio/associated_immediate_executor.hpp>
0022 #include <boost/asio/detail/initiate_dispatch.hpp>
0023 #include <boost/asio/detail/type_traits.hpp>
0024 #include <boost/asio/detail/work_dispatcher.hpp>
0025 #include <boost/asio/execution/allocator.hpp>
0026 #include <boost/asio/execution/blocking.hpp>
0027 #include <boost/asio/execution/executor.hpp>
0028 #include <boost/asio/execution/outstanding_work.hpp>
0029 #include <boost/asio/executor_work_guard.hpp>
0030 #include <boost/asio/prefer.hpp>
0031 
0032 #include <boost/asio/detail/push_options.hpp>
0033 
0034 namespace boost {
0035 namespace asio {
0036 
0037 class executor;
0038 class io_context;
0039 
0040 #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
0041 
0042 class any_completion_executor;
0043 class any_io_executor;
0044 
0045 #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
0046 
0047 namespace execution {
0048 
0049 template <typename...> class any_executor;
0050 
0051 } // namespace execution
0052 namespace detail {
0053 
0054 template <typename Executor, typename CandidateExecutor = void,
0055     typename IoContext = io_context,
0056     typename PolymorphicExecutor = executor, typename = void>
0057 class handler_work_base
0058 {
0059 public:
0060   explicit handler_work_base(int, int, const Executor& ex) noexcept
0061     : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0062   {
0063   }
0064 
0065   template <typename OtherExecutor>
0066   handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
0067       const OtherExecutor& /*candidate*/) noexcept
0068     : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0069   {
0070   }
0071 
0072   handler_work_base(const handler_work_base& other) noexcept
0073     : executor_(other.executor_)
0074   {
0075   }
0076 
0077   handler_work_base(handler_work_base&& other) noexcept
0078     : executor_(static_cast<executor_type&&>(other.executor_))
0079   {
0080   }
0081 
0082   bool owns_work() const noexcept
0083   {
0084     return true;
0085   }
0086 
0087   template <typename Function, typename Handler>
0088   void dispatch(Function& function, Handler& handler)
0089   {
0090     boost::asio::prefer(executor_,
0091         execution::allocator((get_associated_allocator)(handler))
0092       ).execute(static_cast<Function&&>(function));
0093   }
0094 
0095 private:
0096   typedef decay_t<
0097       prefer_result_t<Executor, execution::outstanding_work_t::tracked_t>
0098     > executor_type;
0099 
0100   executor_type executor_;
0101 };
0102 
0103 template <typename Executor, typename CandidateExecutor,
0104     typename IoContext, typename PolymorphicExecutor>
0105 class handler_work_base<Executor, CandidateExecutor,
0106     IoContext, PolymorphicExecutor,
0107     enable_if_t<
0108       !execution::is_executor<Executor>::value
0109         && (!is_same<Executor, PolymorphicExecutor>::value
0110           || !is_same<CandidateExecutor, void>::value)
0111     >
0112   >
0113 {
0114 public:
0115   explicit handler_work_base(int, int, const Executor& ex) noexcept
0116     : executor_(ex),
0117       owns_work_(true)
0118   {
0119     executor_.on_work_started();
0120   }
0121 
0122   handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
0123       const Executor& candidate) noexcept
0124     : executor_(ex),
0125       owns_work_(ex != candidate)
0126   {
0127     if (owns_work_)
0128       executor_.on_work_started();
0129   }
0130 
0131   template <typename OtherExecutor>
0132   handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
0133       const OtherExecutor& /*candidate*/) noexcept
0134     : executor_(ex),
0135       owns_work_(true)
0136   {
0137     executor_.on_work_started();
0138   }
0139 
0140   handler_work_base(const handler_work_base& other) noexcept
0141     : executor_(other.executor_),
0142       owns_work_(other.owns_work_)
0143   {
0144     if (owns_work_)
0145       executor_.on_work_started();
0146   }
0147 
0148   handler_work_base(handler_work_base&& other) noexcept
0149     : executor_(static_cast<Executor&&>(other.executor_)),
0150       owns_work_(other.owns_work_)
0151   {
0152     other.owns_work_ = false;
0153   }
0154 
0155   ~handler_work_base()
0156   {
0157     if (owns_work_)
0158       executor_.on_work_finished();
0159   }
0160 
0161   bool owns_work() const noexcept
0162   {
0163     return owns_work_;
0164   }
0165 
0166   template <typename Function, typename Handler>
0167   void dispatch(Function& function, Handler& handler)
0168   {
0169     executor_.dispatch(static_cast<Function&&>(function),
0170         boost::asio::get_associated_allocator(handler));
0171   }
0172 
0173 private:
0174   Executor executor_;
0175   bool owns_work_;
0176 };
0177 
0178 template <typename Executor, typename IoContext, typename PolymorphicExecutor>
0179 class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
0180     enable_if_t<
0181       is_same<
0182         Executor,
0183         typename IoContext::executor_type
0184       >::value
0185     >
0186   >
0187 {
0188 public:
0189   explicit handler_work_base(int, int, const Executor&)
0190   {
0191   }
0192 
0193   bool owns_work() const noexcept
0194   {
0195     return false;
0196   }
0197 
0198   template <typename Function, typename Handler>
0199   void dispatch(Function& function, Handler&)
0200   {
0201     // When using a native implementation, I/O completion handlers are
0202     // already dispatched according to the execution context's executor's
0203     // rules. We can call the function directly.
0204     static_cast<Function&&>(function)();
0205   }
0206 };
0207 
0208 template <typename Executor, typename IoContext>
0209 class handler_work_base<Executor, void, IoContext, Executor>
0210 {
0211 public:
0212   explicit handler_work_base(int, int, const Executor& ex) noexcept
0213 #if !defined(BOOST_ASIO_NO_TYPEID)
0214     : executor_(
0215         ex.target_type() == typeid(typename IoContext::executor_type)
0216           ? Executor() : ex)
0217 #else // !defined(BOOST_ASIO_NO_TYPEID)
0218     : executor_(ex)
0219 #endif // !defined(BOOST_ASIO_NO_TYPEID)
0220   {
0221     if (executor_)
0222       executor_.on_work_started();
0223   }
0224 
0225   handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
0226       const Executor& candidate) noexcept
0227     : executor_(ex != candidate ? ex : Executor())
0228   {
0229     if (executor_)
0230       executor_.on_work_started();
0231   }
0232 
0233   template <typename OtherExecutor>
0234   handler_work_base(const Executor& ex,
0235       const OtherExecutor&) noexcept
0236     : executor_(ex)
0237   {
0238     executor_.on_work_started();
0239   }
0240 
0241   handler_work_base(const handler_work_base& other) noexcept
0242     : executor_(other.executor_)
0243   {
0244     if (executor_)
0245       executor_.on_work_started();
0246   }
0247 
0248   handler_work_base(handler_work_base&& other) noexcept
0249     : executor_(static_cast<Executor&&>(other.executor_))
0250   {
0251   }
0252 
0253   ~handler_work_base()
0254   {
0255     if (executor_)
0256       executor_.on_work_finished();
0257   }
0258 
0259   bool owns_work() const noexcept
0260   {
0261     return !!executor_;
0262   }
0263 
0264   template <typename Function, typename Handler>
0265   void dispatch(Function& function, Handler& handler)
0266   {
0267     executor_.dispatch(static_cast<Function&&>(function),
0268         boost::asio::get_associated_allocator(handler));
0269   }
0270 
0271 private:
0272   Executor executor_;
0273 };
0274 
0275 template <typename... SupportableProperties, typename CandidateExecutor,
0276     typename IoContext, typename PolymorphicExecutor>
0277 class handler_work_base<execution::any_executor<SupportableProperties...>,
0278     CandidateExecutor, IoContext, PolymorphicExecutor>
0279 {
0280 public:
0281   typedef execution::any_executor<SupportableProperties...> executor_type;
0282 
0283   explicit handler_work_base(int, int, const executor_type& ex) noexcept
0284 #if !defined(BOOST_ASIO_NO_TYPEID)
0285     : executor_(
0286         ex.target_type() == typeid(typename IoContext::executor_type)
0287           ? executor_type()
0288           : boost::asio::prefer(ex, execution::outstanding_work.tracked))
0289 #else // !defined(BOOST_ASIO_NO_TYPEID)
0290     : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0291 #endif // !defined(BOOST_ASIO_NO_TYPEID)
0292   {
0293   }
0294 
0295   handler_work_base(bool base1_owns_work, const executor_type& ex,
0296       const executor_type& candidate) noexcept
0297     : executor_(
0298         !base1_owns_work && ex == candidate
0299           ? executor_type()
0300           : boost::asio::prefer(ex, execution::outstanding_work.tracked))
0301   {
0302   }
0303 
0304   template <typename OtherExecutor>
0305   handler_work_base(bool /*base1_owns_work*/, const executor_type& ex,
0306       const OtherExecutor& /*candidate*/) noexcept
0307     : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0308   {
0309   }
0310 
0311   handler_work_base(const handler_work_base& other) noexcept
0312     : executor_(other.executor_)
0313   {
0314   }
0315 
0316   handler_work_base(handler_work_base&& other) noexcept
0317     : executor_(static_cast<executor_type&&>(other.executor_))
0318   {
0319   }
0320 
0321   bool owns_work() const noexcept
0322   {
0323     return !!executor_;
0324   }
0325 
0326   template <typename Function, typename Handler>
0327   void dispatch(Function& function, Handler&)
0328   {
0329     executor_.execute(static_cast<Function&&>(function));
0330   }
0331 
0332 private:
0333   executor_type executor_;
0334 };
0335 
0336 #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
0337 
0338 template <typename Executor, typename CandidateExecutor,
0339     typename IoContext, typename PolymorphicExecutor>
0340 class handler_work_base<
0341     Executor, CandidateExecutor,
0342     IoContext, PolymorphicExecutor,
0343     enable_if_t<
0344       is_same<Executor, any_completion_executor>::value
0345         || is_same<Executor, any_io_executor>::value
0346     >
0347   >
0348 {
0349 public:
0350   typedef Executor executor_type;
0351 
0352   explicit handler_work_base(int, int,
0353       const executor_type& ex) noexcept
0354 #if !defined(BOOST_ASIO_NO_TYPEID)
0355     : executor_(
0356         ex.target_type() == typeid(typename IoContext::executor_type)
0357           ? executor_type()
0358           : boost::asio::prefer(ex, execution::outstanding_work.tracked))
0359 #else // !defined(BOOST_ASIO_NO_TYPEID)
0360     : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0361 #endif // !defined(BOOST_ASIO_NO_TYPEID)
0362   {
0363   }
0364 
0365   handler_work_base(bool base1_owns_work, const executor_type& ex,
0366       const executor_type& candidate) noexcept
0367     : executor_(
0368         !base1_owns_work && ex == candidate
0369           ? executor_type()
0370           : boost::asio::prefer(ex, execution::outstanding_work.tracked))
0371   {
0372   }
0373 
0374   template <typename OtherExecutor>
0375   handler_work_base(bool /*base1_owns_work*/, const executor_type& ex,
0376       const OtherExecutor& /*candidate*/) noexcept
0377     : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0378   {
0379   }
0380 
0381   handler_work_base(const handler_work_base& other) noexcept
0382     : executor_(other.executor_)
0383   {
0384   }
0385 
0386   handler_work_base(handler_work_base&& other) noexcept
0387     : executor_(static_cast<executor_type&&>(other.executor_))
0388   {
0389   }
0390 
0391   bool owns_work() const noexcept
0392   {
0393     return !!executor_;
0394   }
0395 
0396   template <typename Function, typename Handler>
0397   void dispatch(Function& function, Handler&)
0398   {
0399     executor_.execute(static_cast<Function&&>(function));
0400   }
0401 
0402 private:
0403   executor_type executor_;
0404 };
0405 
0406 #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
0407 
0408 template <typename Handler, typename IoExecutor, typename = void>
0409 class handler_work :
0410   handler_work_base<IoExecutor>,
0411   handler_work_base<associated_executor_t<Handler, IoExecutor>, IoExecutor>
0412 {
0413 public:
0414   typedef handler_work_base<IoExecutor> base1_type;
0415   typedef handler_work_base<associated_executor_t<Handler, IoExecutor>,
0416       IoExecutor> base2_type;
0417 
0418   handler_work(Handler& handler, const IoExecutor& io_ex) noexcept
0419     : base1_type(0, 0, io_ex),
0420       base2_type(base1_type::owns_work(),
0421           boost::asio::get_associated_executor(handler, io_ex), io_ex)
0422   {
0423   }
0424 
0425   template <typename Function>
0426   void complete(Function& function, Handler& handler)
0427   {
0428     if (!base1_type::owns_work() && !base2_type::owns_work())
0429     {
0430       // When using a native implementation, I/O completion handlers are
0431       // already dispatched according to the execution context's executor's
0432       // rules. We can call the function directly.
0433       static_cast<Function&&>(function)();
0434     }
0435     else
0436     {
0437       base2_type::dispatch(function, handler);
0438     }
0439   }
0440 };
0441 
0442 template <typename Handler, typename IoExecutor>
0443 class handler_work<
0444     Handler, IoExecutor,
0445     enable_if_t<
0446       is_same<
0447         typename associated_executor<Handler,
0448           IoExecutor>::asio_associated_executor_is_unspecialised,
0449         void
0450       >::value
0451     >
0452   > : handler_work_base<IoExecutor>
0453 {
0454 public:
0455   typedef handler_work_base<IoExecutor> base1_type;
0456 
0457   handler_work(Handler&, const IoExecutor& io_ex) noexcept
0458     : base1_type(0, 0, io_ex)
0459   {
0460   }
0461 
0462   template <typename Function>
0463   void complete(Function& function, Handler& handler)
0464   {
0465     if (!base1_type::owns_work())
0466     {
0467       // When using a native implementation, I/O completion handlers are
0468       // already dispatched according to the execution context's executor's
0469       // rules. We can call the function directly.
0470       static_cast<Function&&>(function)();
0471     }
0472     else
0473     {
0474       base1_type::dispatch(function, handler);
0475     }
0476   }
0477 };
0478 
0479 template <typename Handler, typename IoExecutor>
0480 class immediate_handler_work
0481 {
0482 public:
0483   typedef handler_work<Handler, IoExecutor> handler_work_type;
0484 
0485   explicit immediate_handler_work(handler_work_type&& w)
0486     : handler_work_(static_cast<handler_work_type&&>(w))
0487   {
0488   }
0489 
0490   template <typename Function>
0491   void complete(Function& function, Handler& handler, const void* io_ex)
0492   {
0493     typedef associated_immediate_executor_t<Handler, IoExecutor>
0494       immediate_ex_type;
0495 
0496     immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
0497         handler, *static_cast<const IoExecutor*>(io_ex));
0498 
0499     (initiate_dispatch_with_executor<immediate_ex_type>(immediate_ex))(
0500         static_cast<Function&&>(function));
0501   }
0502 
0503 private:
0504   handler_work_type handler_work_;
0505 };
0506 
0507 } // namespace detail
0508 } // namespace asio
0509 } // namespace boost
0510 
0511 #include <boost/asio/detail/pop_options.hpp>
0512 
0513 #endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP