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

source code of boost/libs/asio/include/boost/asio/executor_work_guard.hpp