Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // impl/thread_pool.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_IMPL_THREAD_POOL_HPP
0012 #define BOOST_ASIO_IMPL_THREAD_POOL_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/blocking_executor_op.hpp>
0019 #include <boost/asio/detail/executor_op.hpp>
0020 #include <boost/asio/detail/fenced_block.hpp>
0021 #include <boost/asio/detail/non_const_lvalue.hpp>
0022 #include <boost/asio/detail/type_traits.hpp>
0023 #include <boost/asio/execution_context.hpp>
0024 
0025 #include <boost/asio/detail/push_options.hpp>
0026 
0027 namespace boost {
0028 namespace asio {
0029 
0030 inline thread_pool::executor_type
0031 thread_pool::get_executor() noexcept
0032 {
0033   return executor_type(*this);
0034 }
0035 
0036 inline thread_pool::executor_type
0037 thread_pool::executor() noexcept
0038 {
0039   return executor_type(*this);
0040 }
0041 
0042 template <typename Allocator, unsigned int Bits>
0043 thread_pool::basic_executor_type<Allocator, Bits>&
0044 thread_pool::basic_executor_type<Allocator, Bits>::operator=(
0045     const basic_executor_type& other) noexcept
0046 {
0047   if (this != &other)
0048   {
0049     thread_pool* old_thread_pool = pool_;
0050     pool_ = other.pool_;
0051     allocator_ = other.allocator_;
0052     bits_ = other.bits_;
0053     if (Bits & outstanding_work_tracked)
0054     {
0055       if (pool_)
0056         pool_->scheduler_.work_started();
0057       if (old_thread_pool)
0058         old_thread_pool->scheduler_.work_finished();
0059     }
0060   }
0061   return *this;
0062 }
0063 
0064 template <typename Allocator, unsigned int Bits>
0065 thread_pool::basic_executor_type<Allocator, Bits>&
0066 thread_pool::basic_executor_type<Allocator, Bits>::operator=(
0067     basic_executor_type&& other) noexcept
0068 {
0069   if (this != &other)
0070   {
0071     thread_pool* old_thread_pool = pool_;
0072     pool_ = other.pool_;
0073     allocator_ = std::move(other.allocator_);
0074     bits_ = other.bits_;
0075     if (Bits & outstanding_work_tracked)
0076     {
0077       other.pool_ = 0;
0078       if (old_thread_pool)
0079         old_thread_pool->scheduler_.work_finished();
0080     }
0081   }
0082   return *this;
0083 }
0084 
0085 template <typename Allocator, unsigned int Bits>
0086 inline bool thread_pool::basic_executor_type<Allocator,
0087     Bits>::running_in_this_thread() const noexcept
0088 {
0089   return pool_->scheduler_.can_dispatch();
0090 }
0091 
0092 template <typename Allocator, unsigned int Bits>
0093 template <typename Function>
0094 void thread_pool::basic_executor_type<Allocator,
0095     Bits>::do_execute(Function&& f, false_type) const
0096 {
0097   typedef decay_t<Function> function_type;
0098 
0099   // Invoke immediately if the blocking.possibly property is enabled and we are
0100   // already inside the thread pool.
0101   if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch())
0102   {
0103     // Make a local, non-const copy of the function.
0104     function_type tmp(static_cast<Function&&>(f));
0105 
0106 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0107     try
0108     {
0109 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0110       detail::fenced_block b(detail::fenced_block::full);
0111       static_cast<function_type&&>(tmp)();
0112       return;
0113 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0114     }
0115     catch (...)
0116     {
0117       pool_->scheduler_.capture_current_exception();
0118       return;
0119     }
0120 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0121   }
0122 
0123   // Allocate and construct an operation to wrap the function.
0124   typedef detail::executor_op<function_type, Allocator> op;
0125   typename op::ptr p = { detail::addressof(allocator_),
0126       op::ptr::allocate(allocator_), 0 };
0127   p.p = new (p.v) op(static_cast<Function&&>(f), allocator_);
0128 
0129   if ((bits_ & relationship_continuation) != 0)
0130   {
0131     BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0132           "thread_pool", pool_, 0, "execute(blk=never,rel=cont)"));
0133   }
0134   else
0135   {
0136     BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0137           "thread_pool", pool_, 0, "execute(blk=never,rel=fork)"));
0138   }
0139 
0140   pool_->scheduler_.post_immediate_completion(p.p,
0141       (bits_ & relationship_continuation) != 0);
0142   p.v = p.p = 0;
0143 }
0144 
0145 template <typename Allocator, unsigned int Bits>
0146 template <typename Function>
0147 void thread_pool::basic_executor_type<Allocator,
0148     Bits>::do_execute(Function&& f, true_type) const
0149 {
0150   // Obtain a non-const instance of the function.
0151   detail::non_const_lvalue<Function> f2(f);
0152 
0153   // Invoke immediately if we are already inside the thread pool.
0154   if (pool_->scheduler_.can_dispatch())
0155   {
0156 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0157     try
0158     {
0159 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0160       detail::fenced_block b(detail::fenced_block::full);
0161       static_cast<decay_t<Function>&&>(f2.value)();
0162       return;
0163 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0164     }
0165     catch (...)
0166     {
0167       std::terminate();
0168     }
0169 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0170   }
0171 
0172   // Construct an operation to wrap the function.
0173   typedef decay_t<Function> function_type;
0174   detail::blocking_executor_op<function_type> op(f2.value);
0175 
0176   BOOST_ASIO_HANDLER_CREATION((*pool_, op,
0177         "thread_pool", pool_, 0, "execute(blk=always)"));
0178 
0179   pool_->scheduler_.post_immediate_completion(&op, false);
0180   op.wait();
0181 }
0182 
0183 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0184 template <typename Allocator, unsigned int Bits>
0185 inline thread_pool& thread_pool::basic_executor_type<
0186     Allocator, Bits>::context() const noexcept
0187 {
0188   return *pool_;
0189 }
0190 
0191 template <typename Allocator, unsigned int Bits>
0192 inline void thread_pool::basic_executor_type<Allocator,
0193     Bits>::on_work_started() const noexcept
0194 {
0195   pool_->scheduler_.work_started();
0196 }
0197 
0198 template <typename Allocator, unsigned int Bits>
0199 inline void thread_pool::basic_executor_type<Allocator,
0200     Bits>::on_work_finished() const noexcept
0201 {
0202   pool_->scheduler_.work_finished();
0203 }
0204 
0205 template <typename Allocator, unsigned int Bits>
0206 template <typename Function, typename OtherAllocator>
0207 void thread_pool::basic_executor_type<Allocator, Bits>::dispatch(
0208     Function&& f, const OtherAllocator& a) const
0209 {
0210   typedef decay_t<Function> function_type;
0211 
0212   // Invoke immediately if we are already inside the thread pool.
0213   if (pool_->scheduler_.can_dispatch())
0214   {
0215     // Make a local, non-const copy of the function.
0216     function_type tmp(static_cast<Function&&>(f));
0217 
0218     detail::fenced_block b(detail::fenced_block::full);
0219     static_cast<function_type&&>(tmp)();
0220     return;
0221   }
0222 
0223   // Allocate and construct an operation to wrap the function.
0224   typedef detail::executor_op<function_type, OtherAllocator> op;
0225   typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0226   p.p = new (p.v) op(static_cast<Function&&>(f), a);
0227 
0228   BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0229         "thread_pool", pool_, 0, "dispatch"));
0230 
0231   pool_->scheduler_.post_immediate_completion(p.p, false);
0232   p.v = p.p = 0;
0233 }
0234 
0235 template <typename Allocator, unsigned int Bits>
0236 template <typename Function, typename OtherAllocator>
0237 void thread_pool::basic_executor_type<Allocator, Bits>::post(
0238     Function&& f, const OtherAllocator& a) const
0239 {
0240   typedef decay_t<Function> function_type;
0241 
0242   // Allocate and construct an operation to wrap the function.
0243   typedef detail::executor_op<function_type, OtherAllocator> op;
0244   typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0245   p.p = new (p.v) op(static_cast<Function&&>(f), a);
0246 
0247   BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0248         "thread_pool", pool_, 0, "post"));
0249 
0250   pool_->scheduler_.post_immediate_completion(p.p, false);
0251   p.v = p.p = 0;
0252 }
0253 
0254 template <typename Allocator, unsigned int Bits>
0255 template <typename Function, typename OtherAllocator>
0256 void thread_pool::basic_executor_type<Allocator, Bits>::defer(
0257     Function&& f, const OtherAllocator& a) const
0258 {
0259   typedef decay_t<Function> function_type;
0260 
0261   // Allocate and construct an operation to wrap the function.
0262   typedef detail::executor_op<function_type, OtherAllocator> op;
0263   typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0264   p.p = new (p.v) op(static_cast<Function&&>(f), a);
0265 
0266   BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0267         "thread_pool", pool_, 0, "defer"));
0268 
0269   pool_->scheduler_.post_immediate_completion(p.p, true);
0270   p.v = p.p = 0;
0271 }
0272 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0273 
0274 } // namespace asio
0275 } // namespace boost
0276 
0277 #include <boost/asio/detail/pop_options.hpp>
0278 
0279 #endif // BOOST_ASIO_IMPL_THREAD_POOL_HPP