File indexing completed on 2025-01-18 09:28:39
0001
0002
0003
0004
0005
0006
0007
0008
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
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
0046
0047 namespace execution {
0048
0049 template <typename...> class any_executor;
0050
0051 }
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 , const Executor& ex,
0067 const OtherExecutor& ) 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 , 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 , const Executor& ex,
0133 const OtherExecutor& ) 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
0202
0203
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
0218 : executor_(ex)
0219 #endif
0220 {
0221 if (executor_)
0222 executor_.on_work_started();
0223 }
0224
0225 handler_work_base(bool , 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
0290 : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0291 #endif
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 , const executor_type& ex,
0306 const OtherExecutor& ) 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
0360 : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0361 #endif
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 , const executor_type& ex,
0376 const OtherExecutor& ) 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
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
0431
0432
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
0468
0469
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 }
0508 }
0509 }
0510
0511 #include <boost/asio/detail/pop_options.hpp>
0512
0513 #endif