• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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