// | |
// 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 <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 |