// // detail/impl/strand_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 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 #include #include #include 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(io_service), io_service_(boost::asio::use_service(io_service)), mutex_(), salt_(0) { } void strand_service::shutdown_service() { op_queue 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(&impl); index += (reinterpret_cast(&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(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::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 #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP