]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // detail/handler_work.hpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
f67539c2 | 5 | // Copyright (c) 2003-2020 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_DETAIL_HANDLER_WORK_HPP | |
12 | #define BOOST_ASIO_DETAIL_HANDLER_WORK_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 | #include <boost/asio/associated_executor.hpp> | |
20 | #include <boost/asio/detail/handler_invoke_helpers.hpp> | |
20effc67 TL |
21 | #include <boost/asio/detail/type_traits.hpp> |
22 | #include <boost/asio/execution/allocator.hpp> | |
23 | #include <boost/asio/execution/blocking.hpp> | |
24 | #include <boost/asio/execution/execute.hpp> | |
25 | #include <boost/asio/execution/executor.hpp> | |
26 | #include <boost/asio/execution/outstanding_work.hpp> | |
27 | #include <boost/asio/executor_work_guard.hpp> | |
28 | #include <boost/asio/prefer.hpp> | |
b32b8144 FG |
29 | |
30 | #include <boost/asio/detail/push_options.hpp> | |
31 | ||
32 | namespace boost { | |
33 | namespace asio { | |
20effc67 TL |
34 | |
35 | class executor; | |
36 | class io_context; | |
37 | ||
38 | namespace execution { | |
39 | ||
40 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
41 | ||
42 | template <typename...> class any_executor; | |
43 | ||
44 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
45 | ||
46 | template <typename, typename, typename, typename, typename, | |
47 | typename, typename, typename, typename> class any_executor; | |
48 | ||
49 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
50 | ||
51 | } // namespace execution | |
b32b8144 FG |
52 | namespace detail { |
53 | ||
20effc67 TL |
54 | template <typename Executor, typename CandidateExecutor = void, |
55 | typename IoContext = io_context, | |
56 | typename PolymorphicExecutor = executor, typename = void> | |
57 | class handler_work_base | |
b32b8144 FG |
58 | { |
59 | public: | |
20effc67 TL |
60 | explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT |
61 | : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) | |
92f5a8d4 TL |
62 | { |
63 | } | |
64 | ||
20effc67 TL |
65 | template <typename OtherExecutor> |
66 | handler_work_base(const Executor& ex, | |
67 | const OtherExecutor&) BOOST_ASIO_NOEXCEPT | |
68 | : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) | |
b32b8144 FG |
69 | { |
70 | } | |
71 | ||
20effc67 TL |
72 | handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT |
73 | : executor_(other.executor_) | |
b32b8144 | 74 | { |
92f5a8d4 TL |
75 | } |
76 | ||
20effc67 TL |
77 | #if defined(BOOST_ASIO_HAS_MOVE) |
78 | handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT | |
79 | : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_)) | |
92f5a8d4 | 80 | { |
b32b8144 | 81 | } |
20effc67 | 82 | #endif // defined(BOOST_ASIO_HAS_MOVE) |
b32b8144 | 83 | |
20effc67 | 84 | bool owns_work() const BOOST_ASIO_NOEXCEPT |
b32b8144 | 85 | { |
20effc67 | 86 | return true; |
b32b8144 FG |
87 | } |
88 | ||
20effc67 TL |
89 | template <typename Function, typename Handler> |
90 | void dispatch(Function& function, Handler& handler) | |
91 | { | |
92 | execution::execute( | |
93 | boost::asio::prefer(executor_, | |
94 | execution::blocking.possibly, | |
95 | execution::allocator((get_associated_allocator)(handler))), | |
96 | BOOST_ASIO_MOVE_CAST(Function)(function)); | |
97 | } | |
98 | ||
99 | private: | |
100 | typedef typename decay< | |
101 | typename prefer_result<Executor, | |
102 | execution::outstanding_work_t::tracked_t | |
103 | >::type | |
104 | >::type executor_type; | |
105 | ||
106 | executor_type executor_; | |
107 | }; | |
108 | ||
109 | template <typename Executor, typename CandidateExecutor, | |
110 | typename IoContext, typename PolymorphicExecutor> | |
111 | class handler_work_base<Executor, CandidateExecutor, | |
112 | IoContext, PolymorphicExecutor, | |
113 | typename enable_if< | |
114 | !execution::is_executor<Executor>::value | |
115 | && (!is_same<Executor, PolymorphicExecutor>::value | |
116 | || !is_same<CandidateExecutor, void>::value) | |
117 | >::type> | |
118 | { | |
119 | public: | |
120 | explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT | |
121 | : executor_(ex), | |
122 | owns_work_(true) | |
123 | { | |
124 | executor_.on_work_started(); | |
125 | } | |
126 | ||
127 | handler_work_base(const Executor& ex, | |
128 | const Executor& candidate) BOOST_ASIO_NOEXCEPT | |
129 | : executor_(ex), | |
130 | owns_work_(ex != candidate) | |
131 | { | |
132 | if (owns_work_) | |
133 | executor_.on_work_started(); | |
134 | } | |
135 | ||
136 | template <typename OtherExecutor> | |
137 | handler_work_base(const Executor& ex, | |
138 | const OtherExecutor&) BOOST_ASIO_NOEXCEPT | |
139 | : executor_(ex), | |
140 | owns_work_(true) | |
141 | { | |
142 | executor_.on_work_started(); | |
143 | } | |
144 | ||
145 | handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT | |
146 | : executor_(other.executor_), | |
147 | owns_work_(other.owns_work_) | |
148 | { | |
149 | if (owns_work_) | |
150 | executor_.on_work_started(); | |
151 | } | |
152 | ||
153 | #if defined(BOOST_ASIO_HAS_MOVE) | |
154 | handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT | |
155 | : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), | |
156 | owns_work_(other.owns_work_) | |
157 | { | |
158 | other.owns_work_ = false; | |
159 | } | |
160 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
161 | ||
162 | ~handler_work_base() | |
163 | { | |
164 | if (owns_work_) | |
165 | executor_.on_work_finished(); | |
166 | } | |
167 | ||
168 | bool owns_work() const BOOST_ASIO_NOEXCEPT | |
169 | { | |
170 | return owns_work_; | |
171 | } | |
172 | ||
173 | template <typename Function, typename Handler> | |
174 | void dispatch(Function& function, Handler& handler) | |
175 | { | |
176 | executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), | |
177 | boost::asio::get_associated_allocator(handler)); | |
178 | } | |
179 | ||
180 | private: | |
181 | Executor executor_; | |
182 | bool owns_work_; | |
183 | }; | |
184 | ||
185 | template <typename Executor, typename IoContext, typename PolymorphicExecutor> | |
186 | class handler_work_base<Executor, void, IoContext, PolymorphicExecutor, | |
187 | typename enable_if< | |
188 | is_same< | |
189 | Executor, | |
190 | typename IoContext::executor_type | |
191 | >::value | |
192 | >::type> | |
193 | { | |
194 | public: | |
195 | explicit handler_work_base(const Executor&) | |
196 | { | |
197 | } | |
198 | ||
199 | bool owns_work() const BOOST_ASIO_NOEXCEPT | |
200 | { | |
201 | return false; | |
202 | } | |
203 | ||
204 | template <typename Function, typename Handler> | |
205 | void dispatch(Function& function, Handler& handler) | |
206 | { | |
207 | // When using a native implementation, I/O completion handlers are | |
208 | // already dispatched according to the execution context's executor's | |
209 | // rules. We can call the function directly. | |
210 | boost_asio_handler_invoke_helpers::invoke(function, handler); | |
211 | } | |
212 | }; | |
213 | ||
214 | template <typename Executor, typename IoContext> | |
215 | class handler_work_base<Executor, void, IoContext, Executor> | |
216 | { | |
217 | public: | |
218 | explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT | |
219 | #if !defined(BOOST_ASIO_NO_TYPEID) | |
220 | : executor_( | |
221 | ex.target_type() == typeid(typename IoContext::executor_type) | |
222 | ? Executor() : ex) | |
223 | #else // !defined(BOOST_ASIO_NO_TYPEID) | |
224 | : executor_(ex) | |
225 | #endif // !defined(BOOST_ASIO_NO_TYPEID) | |
226 | { | |
227 | if (executor_) | |
228 | executor_.on_work_started(); | |
229 | } | |
230 | ||
231 | handler_work_base(const Executor& ex, | |
232 | const Executor& candidate) BOOST_ASIO_NOEXCEPT | |
233 | : executor_(ex != candidate ? ex : Executor()) | |
234 | { | |
235 | if (executor_) | |
236 | executor_.on_work_started(); | |
237 | } | |
238 | ||
239 | template <typename OtherExecutor> | |
240 | handler_work_base(const Executor& ex, | |
241 | const OtherExecutor&) BOOST_ASIO_NOEXCEPT | |
242 | : executor_(ex) | |
243 | { | |
244 | executor_.on_work_started(); | |
245 | } | |
246 | ||
247 | handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT | |
248 | : executor_(other.executor_) | |
249 | { | |
250 | if (executor_) | |
251 | executor_.on_work_started(); | |
252 | } | |
253 | ||
254 | #if defined(BOOST_ASIO_HAS_MOVE) | |
255 | handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT | |
256 | : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)) | |
257 | { | |
258 | } | |
259 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
260 | ||
261 | ~handler_work_base() | |
262 | { | |
263 | if (executor_) | |
264 | executor_.on_work_finished(); | |
265 | } | |
266 | ||
267 | bool owns_work() const BOOST_ASIO_NOEXCEPT | |
268 | { | |
269 | return !!executor_; | |
270 | } | |
271 | ||
272 | template <typename Function, typename Handler> | |
273 | void dispatch(Function& function, Handler& handler) | |
b32b8144 FG |
274 | { |
275 | executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), | |
92f5a8d4 | 276 | boost::asio::get_associated_allocator(handler)); |
b32b8144 FG |
277 | } |
278 | ||
279 | private: | |
20effc67 TL |
280 | Executor executor_; |
281 | }; | |
282 | ||
283 | template < | |
284 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
285 | typename... SupportableProperties, | |
286 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
287 | typename T1, typename T2, typename T3, typename T4, typename T5, | |
288 | typename T6, typename T7, typename T8, typename T9, | |
289 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
290 | typename IoContext, typename PolymorphicExecutor> | |
291 | class handler_work_base< | |
292 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
293 | execution::any_executor<SupportableProperties...>, | |
294 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
295 | execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>, | |
296 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
297 | void, IoContext, PolymorphicExecutor> | |
298 | { | |
299 | public: | |
300 | typedef | |
301 | #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
302 | execution::any_executor<SupportableProperties...> | |
303 | #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
304 | execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9> | |
305 | #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) | |
306 | executor_type; | |
307 | ||
308 | explicit handler_work_base(const executor_type& ex) BOOST_ASIO_NOEXCEPT | |
309 | #if !defined(BOOST_ASIO_NO_TYPEID) | |
310 | : executor_( | |
311 | ex.target_type() == typeid(typename IoContext::executor_type) | |
312 | ? executor_type() | |
313 | : boost::asio::prefer(ex, execution::outstanding_work.tracked)) | |
314 | #else // !defined(BOOST_ASIO_NO_TYPEID) | |
315 | : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) | |
316 | #endif // !defined(BOOST_ASIO_NO_TYPEID) | |
317 | { | |
318 | } | |
319 | ||
320 | handler_work_base(const executor_type& ex, | |
321 | const executor_type& candidate) BOOST_ASIO_NOEXCEPT | |
322 | : executor_(ex != candidate ? ex : executor_type()) | |
323 | { | |
324 | } | |
325 | ||
326 | template <typename OtherExecutor> | |
327 | handler_work_base(const executor_type& ex, | |
328 | const OtherExecutor&) BOOST_ASIO_NOEXCEPT | |
329 | : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) | |
330 | { | |
331 | } | |
332 | ||
333 | handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT | |
334 | : executor_(other.executor_) | |
335 | { | |
336 | } | |
337 | ||
338 | #if defined(BOOST_ASIO_HAS_MOVE) | |
339 | handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT | |
340 | : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_)) | |
341 | { | |
342 | } | |
343 | #endif // defined(BOOST_ASIO_HAS_MOVE) | |
b32b8144 | 344 | |
20effc67 TL |
345 | bool owns_work() const BOOST_ASIO_NOEXCEPT |
346 | { | |
347 | return !!executor_; | |
348 | } | |
349 | ||
350 | template <typename Function, typename Handler> | |
351 | void dispatch(Function& function, Handler& handler) | |
352 | { | |
353 | execution::execute( | |
354 | boost::asio::prefer(executor_, | |
355 | execution::blocking.possibly, | |
356 | execution::allocator((get_associated_allocator)(handler))), | |
357 | BOOST_ASIO_MOVE_CAST(Function)(function)); | |
358 | } | |
359 | ||
360 | private: | |
361 | executor_type executor_; | |
b32b8144 FG |
362 | }; |
363 | ||
20effc67 TL |
364 | template <typename Handler, typename IoExecutor, typename = void> |
365 | class handler_work : | |
366 | handler_work_base<IoExecutor>, | |
367 | handler_work_base<typename associated_executor< | |
368 | Handler, IoExecutor>::type, IoExecutor> | |
b32b8144 FG |
369 | { |
370 | public: | |
20effc67 TL |
371 | typedef handler_work_base<IoExecutor> base1_type; |
372 | typedef handler_work_base<typename associated_executor< | |
373 | Handler, IoExecutor>::type, IoExecutor> base2_type; | |
374 | ||
375 | handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT | |
376 | : base1_type(io_ex), | |
377 | base2_type(boost::asio::get_associated_executor(handler, io_ex), io_ex) | |
378 | { | |
379 | } | |
b32b8144 FG |
380 | |
381 | template <typename Function> | |
382 | void complete(Function& function, Handler& handler) | |
383 | { | |
20effc67 TL |
384 | if (!base1_type::owns_work() && !base2_type::owns_work()) |
385 | { | |
386 | // When using a native implementation, I/O completion handlers are | |
387 | // already dispatched according to the execution context's executor's | |
388 | // rules. We can call the function directly. | |
389 | boost_asio_handler_invoke_helpers::invoke(function, handler); | |
390 | } | |
391 | else | |
392 | { | |
393 | base2_type::dispatch(function, handler); | |
394 | } | |
b32b8144 | 395 | } |
20effc67 | 396 | }; |
b32b8144 | 397 | |
20effc67 TL |
398 | template <typename Handler, typename IoExecutor> |
399 | class handler_work< | |
400 | Handler, IoExecutor, | |
401 | typename enable_if< | |
402 | is_same< | |
403 | typename associated_executor<Handler, | |
404 | IoExecutor>::asio_associated_executor_is_unspecialised, | |
405 | void | |
406 | >::value | |
407 | >::type> : handler_work_base<IoExecutor> | |
408 | { | |
409 | public: | |
410 | typedef handler_work_base<IoExecutor> base1_type; | |
411 | ||
412 | handler_work(Handler&, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT | |
413 | : base1_type(io_ex) | |
414 | { | |
415 | } | |
416 | ||
417 | template <typename Function> | |
418 | void complete(Function& function, Handler& handler) | |
419 | { | |
420 | if (!base1_type::owns_work()) | |
421 | { | |
422 | // When using a native implementation, I/O completion handlers are | |
423 | // already dispatched according to the execution context's executor's | |
424 | // rules. We can call the function directly. | |
425 | boost_asio_handler_invoke_helpers::invoke(function, handler); | |
426 | } | |
427 | else | |
428 | { | |
429 | base1_type::dispatch(function, handler); | |
430 | } | |
431 | } | |
b32b8144 FG |
432 | }; |
433 | ||
434 | } // namespace detail | |
435 | } // namespace asio | |
436 | } // namespace boost | |
437 | ||
438 | #include <boost/asio/detail/pop_options.hpp> | |
439 | ||
440 | #endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP |