1 //
2 // executor_work_guard.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 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_EXECUTOR_WORK_GUARD_HPP
12 #define BOOST_ASIO_EXECUTOR_WORK_GUARD_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/config.hpp>
19
20 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
21
22 #include <boost/asio/associated_executor.hpp>
23 #include <boost/asio/detail/type_traits.hpp>
24 #include <boost/asio/execution.hpp>
25 #include <boost/asio/is_executor.hpp>
26
27 #include <boost/asio/detail/push_options.hpp>
28
29 namespace boost {
30 namespace asio {
31
32 #if !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL)
33 #define BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL
34
35 template <typename Executor, typename = void>
36 class executor_work_guard;
37
38 #endif // !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL)
39
40 /// An object of type @c executor_work_guard controls ownership of executor work
41 /// within a scope.
42 #if defined(GENERATING_DOCUMENTATION)
43 template <typename Executor>
44 #else // defined(GENERATING_DOCUMENTATION)
45 template <typename Executor, typename>
46 #endif // defined(GENERATING_DOCUMENTATION)
47 class executor_work_guard
48 {
49 public:
50 /// The underlying executor type.
51 typedef Executor executor_type;
52
53 /// Constructs a @c executor_work_guard object for the specified executor.
54 /**
55 * Stores a copy of @c e and calls <tt>on_work_started()</tt> on it.
56 */
executor_work_guard(const executor_type & e)57 explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT
58 : executor_(e),
59 owns_(true)
60 {
61 executor_.on_work_started();
62 }
63
64 /// Copy constructor.
executor_work_guard(const executor_work_guard & other)65 executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT
66 : executor_(other.executor_),
67 owns_(other.owns_)
68 {
69 if (owns_)
70 executor_.on_work_started();
71 }
72
73 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
74 /// Move constructor.
executor_work_guard(executor_work_guard && other)75 executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT
76 : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
77 owns_(other.owns_)
78 {
79 other.owns_ = false;
80 }
81 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
82
83 /// Destructor.
84 /**
85 * Unless the object has already been reset, or is in a moved-from state,
86 * calls <tt>on_work_finished()</tt> on the stored executor.
87 */
~executor_work_guard()88 ~executor_work_guard()
89 {
90 if (owns_)
91 executor_.on_work_finished();
92 }
93
94 /// Obtain the associated executor.
get_executor() const95 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
96 {
97 return executor_;
98 }
99
100 /// Whether the executor_work_guard object owns some outstanding work.
owns_work() const101 bool owns_work() const BOOST_ASIO_NOEXCEPT
102 {
103 return owns_;
104 }
105
106 /// Indicate that the work is no longer outstanding.
107 /**
108 * Unless the object has already been reset, or is in a moved-from state,
109 * calls <tt>on_work_finished()</tt> on the stored executor.
110 */
reset()111 void reset() BOOST_ASIO_NOEXCEPT
112 {
113 if (owns_)
114 {
115 executor_.on_work_finished();
116 owns_ = false;
117 }
118 }
119
120 private:
121 // Disallow assignment.
122 executor_work_guard& operator=(const executor_work_guard&);
123
124 executor_type executor_;
125 bool owns_;
126 };
127
128 #if !defined(GENERATING_DOCUMENTATION)
129
130 template <typename Executor>
131 class executor_work_guard<Executor,
132 typename enable_if<
133 !is_executor<Executor>::value && execution::is_executor<Executor>::value
134 >::type>
135 {
136 public:
137 typedef Executor executor_type;
138
executor_work_guard(const executor_type & e)139 explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT
140 : executor_(e),
141 owns_(true)
142 {
143 new (&work_) work_type(boost::asio::prefer(executor_,
144 execution::outstanding_work.tracked));
145 }
146
executor_work_guard(const executor_work_guard & other)147 executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT
148 : executor_(other.executor_),
149 owns_(other.owns_)
150 {
151 if (owns_)
152 {
153 new (&work_) work_type(boost::asio::prefer(executor_,
154 execution::outstanding_work.tracked));
155 }
156 }
157
158 #if defined(BOOST_ASIO_HAS_MOVE)
executor_work_guard(executor_work_guard && other)159 executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT
160 : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
161 owns_(other.owns_)
162 {
163 if (owns_)
164 {
165 new (&work_) work_type(
166 BOOST_ASIO_MOVE_CAST(work_type)(
167 *static_cast<work_type*>(
168 static_cast<void*>(&other.work_))));
169 other.owns_ = false;
170 }
171 }
172 #endif // defined(BOOST_ASIO_HAS_MOVE)
173
~executor_work_guard()174 ~executor_work_guard()
175 {
176 if (owns_)
177 static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();
178 }
179
get_executor() const180 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
181 {
182 return executor_;
183 }
184
owns_work() const185 bool owns_work() const BOOST_ASIO_NOEXCEPT
186 {
187 return owns_;
188 }
189
reset()190 void reset() BOOST_ASIO_NOEXCEPT
191 {
192 if (owns_)
193 {
194 static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();
195 owns_ = false;
196 }
197 }
198
199 private:
200 // Disallow assignment.
201 executor_work_guard& operator=(const executor_work_guard&);
202
203 typedef typename decay<
204 typename prefer_result<
205 const executor_type&,
206 execution::outstanding_work_t::tracked_t
207 >::type
208 >::type work_type;
209
210 executor_type executor_;
211 typename aligned_storage<sizeof(work_type),
212 alignment_of<work_type>::value>::type work_;
213 bool owns_;
214 };
215
216 #endif // !defined(GENERATING_DOCUMENTATION)
217
218 /// Create an @ref executor_work_guard object.
219 template <typename Executor>
make_work_guard(const Executor & ex,typename enable_if<is_executor<Executor>::value||execution::is_executor<Executor>::value>::type * =0)220 inline executor_work_guard<Executor> make_work_guard(const Executor& ex,
221 typename enable_if<
222 is_executor<Executor>::value || execution::is_executor<Executor>::value
223 >::type* = 0)
224 {
225 return executor_work_guard<Executor>(ex);
226 }
227
228 /// Create an @ref executor_work_guard object.
229 template <typename ExecutionContext>
230 inline executor_work_guard<typename ExecutionContext::executor_type>
make_work_guard(ExecutionContext & ctx,typename enable_if<is_convertible<ExecutionContext &,execution_context &>::value>::type * =0)231 make_work_guard(ExecutionContext& ctx,
232 typename enable_if<
233 is_convertible<ExecutionContext&, execution_context&>::value
234 >::type* = 0)
235 {
236 return executor_work_guard<typename ExecutionContext::executor_type>(
237 ctx.get_executor());
238 }
239
240 /// Create an @ref executor_work_guard object.
241 template <typename T>
242 inline executor_work_guard<typename associated_executor<T>::type>
make_work_guard(const T & t,typename enable_if<!is_executor<T>::value &&!execution::is_executor<T>::value &&!is_convertible<T &,execution_context &>::value>::type * =0)243 make_work_guard(const T& t,
244 typename enable_if<
245 !is_executor<T>::value && !execution::is_executor<T>::value
246 && !is_convertible<T&, execution_context&
247 >::value>::type* = 0)
248 {
249 return executor_work_guard<typename associated_executor<T>::type>(
250 associated_executor<T>::get(t));
251 }
252
253 /// Create an @ref executor_work_guard object.
254 template <typename T, typename Executor>
255 inline executor_work_guard<typename associated_executor<T, Executor>::type>
make_work_guard(const T & t,const Executor & ex,typename enable_if<is_executor<Executor>::value||execution::is_executor<Executor>::value>::type * =0)256 make_work_guard(const T& t, const Executor& ex,
257 typename enable_if<
258 is_executor<Executor>::value || execution::is_executor<Executor>::value
259 >::type* = 0)
260 {
261 return executor_work_guard<typename associated_executor<T, Executor>::type>(
262 associated_executor<T, Executor>::get(t, ex));
263 }
264
265 /// Create an @ref executor_work_guard object.
266 template <typename T, typename ExecutionContext>
267 inline executor_work_guard<typename associated_executor<T,
268 typename ExecutionContext::executor_type>::type>
make_work_guard(const T & t,ExecutionContext & ctx,typename enable_if<!is_executor<T>::value &&!execution::is_executor<T>::value &&!is_convertible<T &,execution_context &>::value && is_convertible<ExecutionContext &,execution_context &>::value>::type * =0)269 make_work_guard(const T& t, ExecutionContext& ctx,
270 typename enable_if<
271 !is_executor<T>::value && !execution::is_executor<T>::value
272 && !is_convertible<T&, execution_context&>::value
273 && is_convertible<ExecutionContext&, execution_context&>::value
274 >::type* = 0)
275 {
276 return executor_work_guard<typename associated_executor<T,
277 typename ExecutionContext::executor_type>::type>(
278 associated_executor<T, typename ExecutionContext::executor_type>::get(
279 t, ctx.get_executor()));
280 }
281
282 } // namespace asio
283 } // namespace boost
284
285 #include <boost/asio/detail/pop_options.hpp>
286
287 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
288
289 #endif // BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP
290