| // |
| // detail/impl/strand_service.ipp |
| // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| // |
| // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| // |
| |
| #ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP |
| #define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP |
| |
| #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
| # pragma once |
| #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
| |
| #include <boost/asio/detail/config.hpp> |
| #include <boost/asio/detail/call_stack.hpp> |
| #include <boost/asio/detail/strand_service.hpp> |
| |
| #include <boost/asio/detail/push_options.hpp> |
| |
| namespace boost { |
| namespace asio { |
| namespace detail { |
| |
| struct strand_service::on_do_complete_exit |
| { |
| io_service_impl* owner_; |
| strand_impl* impl_; |
| |
| ~on_do_complete_exit() |
| { |
| impl_->mutex_.lock(); |
| bool more_handlers = (--impl_->count_ > 0); |
| impl_->mutex_.unlock(); |
| |
| if (more_handlers) |
| owner_->post_immediate_completion(impl_); |
| } |
| }; |
| |
| strand_service::strand_service(boost::asio::io_service& io_service) |
| : boost::asio::detail::service_base<strand_service>(io_service), |
| io_service_(boost::asio::use_service<io_service_impl>(io_service)), |
| mutex_(), |
| salt_(0) |
| { |
| } |
| |
| void strand_service::shutdown_service() |
| { |
| op_queue<operation> ops; |
| |
| boost::asio::detail::mutex::scoped_lock lock(mutex_); |
| |
| for (std::size_t i = 0; i < num_implementations; ++i) |
| if (strand_impl* impl = implementations_[i].get()) |
| ops.push(impl->queue_); |
| } |
| |
| void strand_service::construct(strand_service::implementation_type& impl) |
| { |
| std::size_t salt = salt_++; |
| std::size_t index = reinterpret_cast<std::size_t>(&impl); |
| index += (reinterpret_cast<std::size_t>(&impl) >> 3); |
| index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); |
| index = index % num_implementations; |
| |
| boost::asio::detail::mutex::scoped_lock lock(mutex_); |
| |
| if (!implementations_[index]) |
| implementations_[index].reset(new strand_impl); |
| impl = implementations_[index].get(); |
| } |
| |
| void strand_service::do_complete(io_service_impl* owner, operation* base, |
| boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) |
| { |
| if (owner) |
| { |
| strand_impl* impl = static_cast<strand_impl*>(base); |
| |
| // Get the next handler to be executed. |
| impl->mutex_.lock(); |
| operation* o = impl->queue_.front(); |
| impl->queue_.pop(); |
| impl->mutex_.unlock(); |
| |
| // Indicate that this strand is executing on the current thread. |
| call_stack<strand_impl>::context ctx(impl); |
| |
| // Ensure the next handler, if any, is scheduled on block exit. |
| on_do_complete_exit on_exit = { owner, impl }; |
| (void)on_exit; |
| |
| o->complete(*owner); |
| } |
| } |
| |
| } // namespace detail |
| } // namespace asio |
| } // namespace boost |
| |
| #include <boost/asio/detail/pop_options.hpp> |
| |
| #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP |