/Src/Dependencies/Boost/boost/asio/detail/impl/strand_service.ipp

http://hadesmem.googlecode.com/ · C++ Header · 147 lines · 98 code · 29 blank · 20 comment · 12 complexity · 20777d92954edefe9b86d8b6bec0bee4 MD5 · raw file

  1. //
  2. // detail/impl/strand_service.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
  11. #define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/detail/call_stack.hpp>
  17. #include <boost/asio/detail/strand_service.hpp>
  18. #include <boost/asio/detail/push_options.hpp>
  19. namespace boost {
  20. namespace asio {
  21. namespace detail {
  22. struct strand_service::on_do_complete_exit
  23. {
  24. io_service_impl* owner_;
  25. strand_impl* impl_;
  26. ~on_do_complete_exit()
  27. {
  28. impl_->mutex_.lock();
  29. bool more_handlers = (--impl_->count_ > 0);
  30. impl_->mutex_.unlock();
  31. if (more_handlers)
  32. owner_->post_immediate_completion(impl_);
  33. }
  34. };
  35. strand_service::strand_service(boost::asio::io_service& io_service)
  36. : boost::asio::detail::service_base<strand_service>(io_service),
  37. io_service_(boost::asio::use_service<io_service_impl>(io_service)),
  38. mutex_(),
  39. salt_(0)
  40. {
  41. }
  42. void strand_service::shutdown_service()
  43. {
  44. op_queue<operation> ops;
  45. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  46. for (std::size_t i = 0; i < num_implementations; ++i)
  47. if (strand_impl* impl = implementations_[i].get())
  48. ops.push(impl->queue_);
  49. }
  50. void strand_service::construct(strand_service::implementation_type& impl)
  51. {
  52. std::size_t salt = salt_++;
  53. std::size_t index = reinterpret_cast<std::size_t>(&impl);
  54. index += (reinterpret_cast<std::size_t>(&impl) >> 3);
  55. index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2);
  56. index = index % num_implementations;
  57. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  58. if (!implementations_[index].get())
  59. implementations_[index].reset(new strand_impl);
  60. impl = implementations_[index].get();
  61. }
  62. bool strand_service::do_dispatch(implementation_type& impl, operation* op)
  63. {
  64. // If we are running inside the io_service, and no other handler is queued
  65. // or running, then the handler can run immediately.
  66. bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_);
  67. impl->mutex_.lock();
  68. bool first = (++impl->count_ == 1);
  69. if (can_dispatch && first)
  70. {
  71. // Immediate invocation is allowed.
  72. impl->mutex_.unlock();
  73. return true;
  74. }
  75. // Immediate invocation is not allowed, so enqueue for later.
  76. impl->queue_.push(op);
  77. impl->mutex_.unlock();
  78. // The first handler to be enqueued is responsible for scheduling the
  79. // strand.
  80. if (first)
  81. io_service_.post_immediate_completion(impl);
  82. return false;
  83. }
  84. void strand_service::do_post(implementation_type& impl, operation* op)
  85. {
  86. // Add the handler to the queue.
  87. impl->mutex_.lock();
  88. bool first = (++impl->count_ == 1);
  89. impl->queue_.push(op);
  90. impl->mutex_.unlock();
  91. // The first handler to be enqueue is responsible for scheduling the strand.
  92. if (first)
  93. io_service_.post_immediate_completion(impl);
  94. }
  95. void strand_service::do_complete(io_service_impl* owner, operation* base,
  96. boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
  97. {
  98. if (owner)
  99. {
  100. strand_impl* impl = static_cast<strand_impl*>(base);
  101. // Get the next handler to be executed.
  102. impl->mutex_.lock();
  103. operation* o = impl->queue_.front();
  104. impl->queue_.pop();
  105. impl->mutex_.unlock();
  106. // Indicate that this strand is executing on the current thread.
  107. call_stack<strand_impl>::context ctx(impl);
  108. // Ensure the next handler, if any, is scheduled on block exit.
  109. on_do_complete_exit on_exit = { owner, impl };
  110. (void)on_exit;
  111. o->complete(*owner);
  112. }
  113. }
  114. } // namespace detail
  115. } // namespace asio
  116. } // namespace boost
  117. #include <boost/asio/detail/pop_options.hpp>
  118. #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP