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