strand_executor_service.hpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //
  2. // detail/impl/strand_executor_service.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2018 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_EXECUTOR_SERVICE_HPP
  11. #define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/call_stack.hpp>
  16. #include <boost/asio/detail/fenced_block.hpp>
  17. #include <boost/asio/detail/handler_invoke_helpers.hpp>
  18. #include <boost/asio/detail/recycling_allocator.hpp>
  19. #include <boost/asio/executor_work_guard.hpp>
  20. #include <boost/asio/detail/push_options.hpp>
  21. namespace boost {
  22. namespace asio {
  23. namespace detail {
  24. template <typename Executor>
  25. class strand_executor_service::invoker
  26. {
  27. public:
  28. invoker(const implementation_type& impl, Executor& ex)
  29. : impl_(impl),
  30. work_(ex)
  31. {
  32. }
  33. invoker(const invoker& other)
  34. : impl_(other.impl_),
  35. work_(other.work_)
  36. {
  37. }
  38. #if defined(BOOST_ASIO_HAS_MOVE)
  39. invoker(invoker&& other)
  40. : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)),
  41. work_(BOOST_ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_))
  42. {
  43. }
  44. #endif // defined(BOOST_ASIO_HAS_MOVE)
  45. struct on_invoker_exit
  46. {
  47. invoker* this_;
  48. ~on_invoker_exit()
  49. {
  50. this_->impl_->mutex_->lock();
  51. this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);
  52. bool more_handlers = this_->impl_->locked_ =
  53. !this_->impl_->ready_queue_.empty();
  54. this_->impl_->mutex_->unlock();
  55. if (more_handlers)
  56. {
  57. Executor ex(this_->work_.get_executor());
  58. recycling_allocator<void> allocator;
  59. ex.post(BOOST_ASIO_MOVE_CAST(invoker)(*this_), allocator);
  60. }
  61. }
  62. };
  63. void operator()()
  64. {
  65. // Indicate that this strand is executing on the current thread.
  66. call_stack<strand_impl>::context ctx(impl_.get());
  67. // Ensure the next handler, if any, is scheduled on block exit.
  68. on_invoker_exit on_exit = { this };
  69. (void)on_exit;
  70. // Run all ready handlers. No lock is required since the ready queue is
  71. // accessed only within the strand.
  72. boost::system::error_code ec;
  73. while (scheduler_operation* o = impl_->ready_queue_.front())
  74. {
  75. impl_->ready_queue_.pop();
  76. o->complete(impl_.get(), ec, 0);
  77. }
  78. }
  79. private:
  80. implementation_type impl_;
  81. executor_work_guard<Executor> work_;
  82. };
  83. template <typename Executor, typename Function, typename Allocator>
  84. void strand_executor_service::dispatch(const implementation_type& impl,
  85. Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
  86. {
  87. typedef typename decay<Function>::type function_type;
  88. // If we are already in the strand then the function can run immediately.
  89. if (call_stack<strand_impl>::contains(impl.get()))
  90. {
  91. // Make a local, non-const copy of the function.
  92. function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function));
  93. fenced_block b(fenced_block::full);
  94. boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
  95. return;
  96. }
  97. // Allocate and construct an operation to wrap the function.
  98. typedef executor_op<function_type, Allocator> op;
  99. typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
  100. p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
  101. BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
  102. "strand_executor", impl.get(), 0, "dispatch"));
  103. // Add the function to the strand and schedule the strand if required.
  104. bool first = enqueue(impl, p.p);
  105. p.v = p.p = 0;
  106. if (first)
  107. ex.dispatch(invoker<Executor>(impl, ex), a);
  108. }
  109. // Request invocation of the given function and return immediately.
  110. template <typename Executor, typename Function, typename Allocator>
  111. void strand_executor_service::post(const implementation_type& impl,
  112. Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
  113. {
  114. typedef typename decay<Function>::type function_type;
  115. // Allocate and construct an operation to wrap the function.
  116. typedef executor_op<function_type, Allocator> op;
  117. typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
  118. p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
  119. BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
  120. "strand_executor", impl.get(), 0, "post"));
  121. // Add the function to the strand and schedule the strand if required.
  122. bool first = enqueue(impl, p.p);
  123. p.v = p.p = 0;
  124. if (first)
  125. ex.post(invoker<Executor>(impl, ex), a);
  126. }
  127. // Request invocation of the given function and return immediately.
  128. template <typename Executor, typename Function, typename Allocator>
  129. void strand_executor_service::defer(const implementation_type& impl,
  130. Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
  131. {
  132. typedef typename decay<Function>::type function_type;
  133. // Allocate and construct an operation to wrap the function.
  134. typedef executor_op<function_type, Allocator> op;
  135. typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
  136. p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
  137. BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
  138. "strand_executor", impl.get(), 0, "defer"));
  139. // Add the function to the strand and schedule the strand if required.
  140. bool first = enqueue(impl, p.p);
  141. p.v = p.p = 0;
  142. if (first)
  143. ex.defer(invoker<Executor>(impl, ex), a);
  144. }
  145. } // namespace detail
  146. } // namespace asio
  147. } // namespace boost
  148. #include <boost/asio/detail/pop_options.hpp>
  149. #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP