]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // executor_work_guard.hpp | |
20effc67 | 3 | // ~~~~~~~~~~~~~~~~~~~~~~~ |
b32b8144 | 4 | // |
1e59de90 | 5 | // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
b32b8144 FG |
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> | |
20effc67 | 19 | |
b32b8144 FG |
20 | #include <boost/asio/associated_executor.hpp> |
21 | #include <boost/asio/detail/type_traits.hpp> | |
20effc67 | 22 | #include <boost/asio/execution.hpp> |
b32b8144 FG |
23 | #include <boost/asio/is_executor.hpp> |
24 | ||
25 | #include <boost/asio/detail/push_options.hpp> | |
26 | ||
27 | namespace boost { | |
28 | namespace asio { | |
29 | ||
20effc67 TL |
30 | #if !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) |
31 | #define BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL | |
32 | ||
1e59de90 | 33 | template <typename Executor, typename = void, typename = void> |
20effc67 TL |
34 | class executor_work_guard; |
35 | ||
36 | #endif // !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) | |
37 | ||
20effc67 | 38 | #if defined(GENERATING_DOCUMENTATION) |
1e59de90 TL |
39 | |
40 | /// An object of type @c executor_work_guard controls ownership of outstanding | |
41 | /// executor work within a scope. | |
b32b8144 FG |
42 | template <typename Executor> |
43 | class executor_work_guard | |
44 | { | |
45 | public: | |
46 | /// The underlying executor type. | |
47 | typedef Executor executor_type; | |
48 | ||
49 | /// Constructs a @c executor_work_guard object for the specified executor. | |
50 | /** | |
51 | * Stores a copy of @c e and calls <tt>on_work_started()</tt> on it. | |
52 | */ | |
1e59de90 TL |
53 | explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT; |
54 | ||
55 | /// Copy constructor. | |
56 | executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT; | |
57 | ||
58 | /// Move constructor. | |
59 | executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT; | |
60 | ||
61 | /// Destructor. | |
62 | /** | |
63 | * Unless the object has already been reset, or is in a moved-from state, | |
64 | * calls <tt>on_work_finished()</tt> on the stored executor. | |
65 | */ | |
66 | ~executor_work_guard(); | |
67 | ||
68 | /// Obtain the associated executor. | |
69 | executor_type get_executor() const BOOST_ASIO_NOEXCEPT; | |
70 | ||
71 | /// Whether the executor_work_guard object owns some outstanding work. | |
72 | bool owns_work() const BOOST_ASIO_NOEXCEPT; | |
73 | ||
74 | /// Indicate that the work is no longer outstanding. | |
75 | /** | |
76 | * Unless the object has already been reset, or is in a moved-from state, | |
77 | * calls <tt>on_work_finished()</tt> on the stored executor. | |
78 | */ | |
79 | void reset() BOOST_ASIO_NOEXCEPT; | |
80 | }; | |
81 | ||
82 | #endif // defined(GENERATING_DOCUMENTATION) | |
83 | ||
84 | #if !defined(GENERATING_DOCUMENTATION) | |
85 | ||
86 | #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) | |
87 | ||
88 | template <typename Executor> | |
89 | class executor_work_guard<Executor, | |
90 | typename enable_if< | |
91 | is_executor<Executor>::value | |
92 | >::type> | |
93 | { | |
94 | public: | |
95 | typedef Executor executor_type; | |
96 | ||
b32b8144 FG |
97 | explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT |
98 | : executor_(e), | |
99 | owns_(true) | |
100 | { | |
101 | executor_.on_work_started(); | |
102 | } | |
103 | ||
b32b8144 FG |
104 | executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT |
105 | : executor_(other.executor_), | |
106 | owns_(other.owns_) | |
107 | { | |
108 | if (owns_) | |
109 | executor_.on_work_started(); | |
110 | } | |
111 | ||
1e59de90 | 112 | #if defined(BOOST_ASIO_HAS_MOVE) |
92f5a8d4 | 113 | executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT |
b32b8144 FG |
114 | : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), |
115 | owns_(other.owns_) | |
116 | { | |
117 | other.owns_ = false; | |
118 | } | |
1e59de90 | 119 | #endif // defined(BOOST_ASIO_HAS_MOVE) |
b32b8144 | 120 | |
b32b8144 FG |
121 | ~executor_work_guard() |
122 | { | |
123 | if (owns_) | |
124 | executor_.on_work_finished(); | |
125 | } | |
126 | ||
b32b8144 FG |
127 | executor_type get_executor() const BOOST_ASIO_NOEXCEPT |
128 | { | |
129 | return executor_; | |
130 | } | |
131 | ||
b32b8144 FG |
132 | bool owns_work() const BOOST_ASIO_NOEXCEPT |
133 | { | |
134 | return owns_; | |
135 | } | |
136 | ||
b32b8144 FG |
137 | void reset() BOOST_ASIO_NOEXCEPT |
138 | { | |
139 | if (owns_) | |
140 | { | |
141 | executor_.on_work_finished(); | |
142 | owns_ = false; | |
143 | } | |
144 | } | |
145 | ||
146 | private: | |
147 | // Disallow assignment. | |
148 | executor_work_guard& operator=(const executor_work_guard&); | |
149 | ||
150 | executor_type executor_; | |
151 | bool owns_; | |
152 | }; | |
153 | ||
1e59de90 | 154 | #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
20effc67 TL |
155 | |
156 | template <typename Executor> | |
157 | class executor_work_guard<Executor, | |
158 | typename enable_if< | |
1e59de90 TL |
159 | !is_executor<Executor>::value |
160 | >::type, | |
161 | typename enable_if< | |
162 | execution::is_executor<Executor>::value | |
20effc67 TL |
163 | >::type> |
164 | { | |
165 | public: | |
166 | typedef Executor executor_type; | |
167 | ||
168 | explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT | |
169 | : executor_(e), | |
170 | owns_(true) | |
171 | { | |
172 | new (&work_) work_type(boost::asio::prefer(executor_, | |
173 | execution::outstanding_work.tracked)); | |
174 | } | |
175 | ||
176 | executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT | |
177 | : executor_(other.executor_), | |
178 | owns_(other.owns_) | |
179 | { | |
180 | if (owns_) | |
181 | { | |
182 | new (&work_) work_type(boost::asio::prefer(executor_, | |
183 | execution::outstanding_work.tracked)); | |
184 | } | |
185 | } | |
186 | ||
187 | #if defined(BOOST_ASIO_HAS_MOVE) | |
188 | executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT | |
189 | : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), | |
190 | owns_(other.owns_) | |
191 | { | |
192 | if (owns_) | |
193 | { | |
194 | new (&work_) work_type( | |
195 | BOOST_ASIO_MOVE_CAST(work_type)( | |
196 | *static_cast<work_type*>( | |
197 | static_cast<void*>(&other.work_)))); | |
198 | other.owns_ = false; | |
199 | } | |
200 | } | |
201 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
202 | ||
203 | ~executor_work_guard() | |
204 | { | |
205 | if (owns_) | |
206 | static_cast<work_type*>(static_cast<void*>(&work_))->~work_type(); | |
207 | } | |
208 | ||
209 | executor_type get_executor() const BOOST_ASIO_NOEXCEPT | |
210 | { | |
211 | return executor_; | |
212 | } | |
213 | ||
214 | bool owns_work() const BOOST_ASIO_NOEXCEPT | |
215 | { | |
216 | return owns_; | |
217 | } | |
218 | ||
219 | void reset() BOOST_ASIO_NOEXCEPT | |
220 | { | |
221 | if (owns_) | |
222 | { | |
223 | static_cast<work_type*>(static_cast<void*>(&work_))->~work_type(); | |
224 | owns_ = false; | |
225 | } | |
226 | } | |
227 | ||
228 | private: | |
229 | // Disallow assignment. | |
230 | executor_work_guard& operator=(const executor_work_guard&); | |
231 | ||
232 | typedef typename decay< | |
233 | typename prefer_result< | |
234 | const executor_type&, | |
235 | execution::outstanding_work_t::tracked_t | |
236 | >::type | |
237 | >::type work_type; | |
238 | ||
239 | executor_type executor_; | |
240 | typename aligned_storage<sizeof(work_type), | |
241 | alignment_of<work_type>::value>::type work_; | |
242 | bool owns_; | |
243 | }; | |
244 | ||
245 | #endif // !defined(GENERATING_DOCUMENTATION) | |
246 | ||
b32b8144 | 247 | /// Create an @ref executor_work_guard object. |
1e59de90 TL |
248 | /** |
249 | * @param ex An executor. | |
250 | * | |
251 | * @returns A work guard constructed with the specified executor. | |
252 | */ | |
b32b8144 | 253 | template <typename Executor> |
1e59de90 TL |
254 | BOOST_ASIO_NODISCARD inline executor_work_guard<Executor> |
255 | make_work_guard(const Executor& ex, | |
256 | typename constraint< | |
20effc67 | 257 | is_executor<Executor>::value || execution::is_executor<Executor>::value |
1e59de90 | 258 | >::type = 0) |
b32b8144 FG |
259 | { |
260 | return executor_work_guard<Executor>(ex); | |
261 | } | |
262 | ||
263 | /// Create an @ref executor_work_guard object. | |
1e59de90 TL |
264 | /** |
265 | * @param ctx An execution context, from which an executor will be obtained. | |
266 | * | |
267 | * @returns A work guard constructed with the execution context's executor, | |
268 | * obtained by performing <tt>ctx.get_executor()</tt>. | |
269 | */ | |
b32b8144 | 270 | template <typename ExecutionContext> |
1e59de90 TL |
271 | BOOST_ASIO_NODISCARD inline |
272 | executor_work_guard<typename ExecutionContext::executor_type> | |
b32b8144 | 273 | make_work_guard(ExecutionContext& ctx, |
1e59de90 | 274 | typename constraint< |
20effc67 | 275 | is_convertible<ExecutionContext&, execution_context&>::value |
1e59de90 | 276 | >::type = 0) |
b32b8144 FG |
277 | { |
278 | return executor_work_guard<typename ExecutionContext::executor_type>( | |
279 | ctx.get_executor()); | |
280 | } | |
281 | ||
282 | /// Create an @ref executor_work_guard object. | |
1e59de90 TL |
283 | /** |
284 | * @param t An arbitrary object, such as a completion handler, for which the | |
285 | * associated executor will be obtained. | |
286 | * | |
287 | * @returns A work guard constructed with the associated executor of the object | |
288 | * @c t, which is obtained as if by calling <tt>get_associated_executor(t)</tt>. | |
289 | */ | |
b32b8144 | 290 | template <typename T> |
1e59de90 TL |
291 | BOOST_ASIO_NODISCARD inline |
292 | executor_work_guard<typename associated_executor<T>::type> | |
b32b8144 | 293 | make_work_guard(const T& t, |
1e59de90 TL |
294 | typename constraint< |
295 | !is_executor<T>::value | |
296 | >::type = 0, | |
297 | typename constraint< | |
298 | !execution::is_executor<T>::value | |
299 | >::type = 0, | |
300 | typename constraint< | |
301 | !is_convertible<T&, execution_context&>::value | |
302 | >::type = 0) | |
b32b8144 FG |
303 | { |
304 | return executor_work_guard<typename associated_executor<T>::type>( | |
305 | associated_executor<T>::get(t)); | |
306 | } | |
307 | ||
308 | /// Create an @ref executor_work_guard object. | |
1e59de90 TL |
309 | /** |
310 | * @param t An arbitrary object, such as a completion handler, for which the | |
311 | * associated executor will be obtained. | |
312 | * | |
313 | * @param ex An executor to be used as the candidate object when determining the | |
314 | * associated executor. | |
315 | * | |
316 | * @returns A work guard constructed with the associated executor of the object | |
317 | * @c t, which is obtained as if by calling <tt>get_associated_executor(t, | |
318 | * ex)</tt>. | |
319 | */ | |
b32b8144 | 320 | template <typename T, typename Executor> |
1e59de90 TL |
321 | BOOST_ASIO_NODISCARD inline |
322 | executor_work_guard<typename associated_executor<T, Executor>::type> | |
b32b8144 | 323 | make_work_guard(const T& t, const Executor& ex, |
1e59de90 | 324 | typename constraint< |
20effc67 | 325 | is_executor<Executor>::value || execution::is_executor<Executor>::value |
1e59de90 | 326 | >::type = 0) |
b32b8144 FG |
327 | { |
328 | return executor_work_guard<typename associated_executor<T, Executor>::type>( | |
329 | associated_executor<T, Executor>::get(t, ex)); | |
330 | } | |
331 | ||
332 | /// Create an @ref executor_work_guard object. | |
1e59de90 TL |
333 | /** |
334 | * @param t An arbitrary object, such as a completion handler, for which the | |
335 | * associated executor will be obtained. | |
336 | * | |
337 | * @param ctx An execution context, from which an executor is obtained to use as | |
338 | * the candidate object for determining the associated executor. | |
339 | * | |
340 | * @returns A work guard constructed with the associated executor of the object | |
341 | * @c t, which is obtained as if by calling <tt>get_associated_executor(t, | |
342 | * ctx.get_executor())</tt>. | |
343 | */ | |
b32b8144 | 344 | template <typename T, typename ExecutionContext> |
1e59de90 | 345 | BOOST_ASIO_NODISCARD inline executor_work_guard<typename associated_executor<T, |
b32b8144 FG |
346 | typename ExecutionContext::executor_type>::type> |
347 | make_work_guard(const T& t, ExecutionContext& ctx, | |
1e59de90 TL |
348 | typename constraint< |
349 | !is_executor<T>::value | |
350 | >::type = 0, | |
351 | typename constraint< | |
352 | !execution::is_executor<T>::value | |
353 | >::type = 0, | |
354 | typename constraint< | |
355 | !is_convertible<T&, execution_context&>::value | |
356 | >::type = 0, | |
357 | typename constraint< | |
358 | is_convertible<ExecutionContext&, execution_context&>::value | |
359 | >::type = 0) | |
b32b8144 FG |
360 | { |
361 | return executor_work_guard<typename associated_executor<T, | |
362 | typename ExecutionContext::executor_type>::type>( | |
363 | associated_executor<T, typename ExecutionContext::executor_type>::get( | |
364 | t, ctx.get_executor())); | |
365 | } | |
366 | ||
367 | } // namespace asio | |
368 | } // namespace boost | |
369 | ||
370 | #include <boost/asio/detail/pop_options.hpp> | |
371 | ||
372 | #endif // BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP |