File indexing completed on 2025-12-16 09:43:01
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
0012 #define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/fenced_block.hpp>
0019 #include <boost/asio/detail/recycling_allocator.hpp>
0020 #include <boost/asio/executor_work_guard.hpp>
0021 #include <boost/asio/defer.hpp>
0022 #include <boost/asio/dispatch.hpp>
0023 #include <boost/asio/post.hpp>
0024
0025 #include <boost/asio/detail/push_options.hpp>
0026
0027 namespace boost {
0028 namespace asio {
0029 namespace detail {
0030
0031 template <typename F, typename Allocator>
0032 class strand_executor_service::allocator_binder
0033 {
0034 public:
0035 typedef Allocator allocator_type;
0036
0037 allocator_binder(F&& f, const Allocator& a)
0038 : f_(static_cast<F&&>(f)),
0039 allocator_(a)
0040 {
0041 }
0042
0043 allocator_binder(const allocator_binder& other)
0044 : f_(other.f_),
0045 allocator_(other.allocator_)
0046 {
0047 }
0048
0049 allocator_binder(allocator_binder&& other)
0050 : f_(static_cast<F&&>(other.f_)),
0051 allocator_(static_cast<allocator_type&&>(other.allocator_))
0052 {
0053 }
0054
0055 allocator_type get_allocator() const noexcept
0056 {
0057 return allocator_;
0058 }
0059
0060 void operator()()
0061 {
0062 f_();
0063 }
0064
0065 private:
0066 F f_;
0067 allocator_type allocator_;
0068 };
0069
0070 template <typename Executor>
0071 class strand_executor_service::invoker<Executor,
0072 enable_if_t<
0073 execution::is_executor<Executor>::value
0074 >>
0075 {
0076 public:
0077 invoker(const implementation_type& impl, Executor& ex)
0078 : impl_(impl),
0079 executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
0080 {
0081 }
0082
0083 invoker(const invoker& other)
0084 : impl_(other.impl_),
0085 executor_(other.executor_)
0086 {
0087 }
0088
0089 invoker(invoker&& other)
0090 : impl_(static_cast<implementation_type&&>(other.impl_)),
0091 executor_(static_cast<executor_type&&>(other.executor_))
0092 {
0093 }
0094
0095 struct on_invoker_exit
0096 {
0097 invoker* this_;
0098
0099 ~on_invoker_exit()
0100 {
0101 if (push_waiting_to_ready(this_->impl_))
0102 {
0103 recycling_allocator<void> allocator;
0104 executor_type ex = this_->executor_;
0105 boost::asio::prefer(
0106 boost::asio::require(
0107 static_cast<executor_type&&>(ex),
0108 execution::blocking.never),
0109 execution::allocator(allocator)
0110 ).execute(static_cast<invoker&&>(*this_));
0111 }
0112 }
0113 };
0114
0115 void operator()()
0116 {
0117
0118 on_invoker_exit on_exit = { this };
0119 (void)on_exit;
0120
0121 run_ready_handlers(impl_);
0122 }
0123
0124 private:
0125 typedef decay_t<
0126 prefer_result_t<
0127 Executor,
0128 execution::outstanding_work_t::tracked_t
0129 >
0130 > executor_type;
0131
0132 implementation_type impl_;
0133 executor_type executor_;
0134 };
0135
0136 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0137
0138 template <typename Executor>
0139 class strand_executor_service::invoker<Executor,
0140 enable_if_t<
0141 !execution::is_executor<Executor>::value
0142 >>
0143 {
0144 public:
0145 invoker(const implementation_type& impl, Executor& ex)
0146 : impl_(impl),
0147 work_(ex)
0148 {
0149 }
0150
0151 invoker(const invoker& other)
0152 : impl_(other.impl_),
0153 work_(other.work_)
0154 {
0155 }
0156
0157 invoker(invoker&& other)
0158 : impl_(static_cast<implementation_type&&>(other.impl_)),
0159 work_(static_cast<executor_work_guard<Executor>&&>(other.work_))
0160 {
0161 }
0162
0163 struct on_invoker_exit
0164 {
0165 invoker* this_;
0166
0167 ~on_invoker_exit()
0168 {
0169 if (push_waiting_to_ready(this_->impl_))
0170 {
0171 Executor ex(this_->work_.get_executor());
0172 recycling_allocator<void> allocator;
0173 ex.post(static_cast<invoker&&>(*this_), allocator);
0174 }
0175 }
0176 };
0177
0178 void operator()()
0179 {
0180
0181 on_invoker_exit on_exit = { this };
0182 (void)on_exit;
0183
0184 run_ready_handlers(impl_);
0185 }
0186
0187 private:
0188 implementation_type impl_;
0189 executor_work_guard<Executor> work_;
0190 };
0191
0192 #endif
0193
0194 template <typename Executor, typename Function>
0195 inline void strand_executor_service::execute(const implementation_type& impl,
0196 Executor& ex, Function&& function,
0197 enable_if_t<
0198 can_query<Executor, execution::allocator_t<void>>::value
0199 >*)
0200 {
0201 return strand_executor_service::do_execute(impl, ex,
0202 static_cast<Function&&>(function),
0203 boost::asio::query(ex, execution::allocator));
0204 }
0205
0206 template <typename Executor, typename Function>
0207 inline void strand_executor_service::execute(const implementation_type& impl,
0208 Executor& ex, Function&& function,
0209 enable_if_t<
0210 !can_query<Executor, execution::allocator_t<void>>::value
0211 >*)
0212 {
0213 return strand_executor_service::do_execute(impl, ex,
0214 static_cast<Function&&>(function),
0215 std::allocator<void>());
0216 }
0217
0218 template <typename Executor, typename Function, typename Allocator>
0219 void strand_executor_service::do_execute(const implementation_type& impl,
0220 Executor& ex, Function&& function, const Allocator& a)
0221 {
0222 typedef decay_t<Function> function_type;
0223
0224
0225
0226 if (boost::asio::query(ex, execution::blocking) != execution::blocking.never
0227 && running_in_this_thread(impl))
0228 {
0229
0230 function_type tmp(static_cast<Function&&>(function));
0231
0232 fenced_block b(fenced_block::full);
0233 static_cast<function_type&&>(tmp)();
0234 return;
0235 }
0236
0237
0238 typedef executor_op<function_type, Allocator> op;
0239 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0240 p.p = new (p.v) op(static_cast<Function&&>(function), a);
0241
0242 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
0243 "strand_executor", impl.get(), 0, "execute"));
0244
0245
0246 bool first = enqueue(impl, p.p);
0247 p.v = p.p = 0;
0248 if (first)
0249 {
0250 ex.execute(invoker<Executor>(impl, ex));
0251 }
0252 }
0253
0254 template <typename Executor, typename Function, typename Allocator>
0255 void strand_executor_service::dispatch(const implementation_type& impl,
0256 Executor& ex, Function&& function, const Allocator& a)
0257 {
0258 typedef decay_t<Function> function_type;
0259
0260
0261 if (running_in_this_thread(impl))
0262 {
0263
0264 function_type tmp(static_cast<Function&&>(function));
0265
0266 fenced_block b(fenced_block::full);
0267 static_cast<function_type&&>(tmp)();
0268 return;
0269 }
0270
0271
0272 typedef executor_op<function_type, Allocator> op;
0273 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0274 p.p = new (p.v) op(static_cast<Function&&>(function), a);
0275
0276 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
0277 "strand_executor", impl.get(), 0, "dispatch"));
0278
0279
0280 bool first = enqueue(impl, p.p);
0281 p.v = p.p = 0;
0282 if (first)
0283 {
0284 boost::asio::dispatch(ex,
0285 allocator_binder<invoker<Executor>, Allocator>(
0286 invoker<Executor>(impl, ex), a));
0287 }
0288 }
0289
0290
0291 template <typename Executor, typename Function, typename Allocator>
0292 void strand_executor_service::post(const implementation_type& impl,
0293 Executor& ex, Function&& function, const Allocator& a)
0294 {
0295 typedef decay_t<Function> function_type;
0296
0297
0298 typedef executor_op<function_type, Allocator> op;
0299 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0300 p.p = new (p.v) op(static_cast<Function&&>(function), a);
0301
0302 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
0303 "strand_executor", impl.get(), 0, "post"));
0304
0305
0306 bool first = enqueue(impl, p.p);
0307 p.v = p.p = 0;
0308 if (first)
0309 {
0310 boost::asio::post(ex,
0311 allocator_binder<invoker<Executor>, Allocator>(
0312 invoker<Executor>(impl, ex), a));
0313 }
0314 }
0315
0316
0317 template <typename Executor, typename Function, typename Allocator>
0318 void strand_executor_service::defer(const implementation_type& impl,
0319 Executor& ex, Function&& function, const Allocator& a)
0320 {
0321 typedef decay_t<Function> function_type;
0322
0323
0324 typedef executor_op<function_type, Allocator> op;
0325 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0326 p.p = new (p.v) op(static_cast<Function&&>(function), a);
0327
0328 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
0329 "strand_executor", impl.get(), 0, "defer"));
0330
0331
0332 bool first = enqueue(impl, p.p);
0333 p.v = p.p = 0;
0334 if (first)
0335 {
0336 boost::asio::defer(ex,
0337 allocator_binder<invoker<Executor>, Allocator>(
0338 invoker<Executor>(impl, ex), a));
0339 }
0340 }
0341
0342 }
0343 }
0344 }
0345
0346 #include <boost/asio/detail/pop_options.hpp>
0347
0348 #endif