]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/strand.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / asio / strand.hpp
CommitLineData
b32b8144
FG
1//
2// strand.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_STRAND_HPP
12#define BOOST_ASIO_STRAND_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/detail/strand_executor_service.hpp>
20#include <boost/asio/detail/type_traits.hpp>
20effc67
TL
21#include <boost/asio/execution/executor.hpp>
22#include <boost/asio/is_executor.hpp>
b32b8144
FG
23
24#include <boost/asio/detail/push_options.hpp>
25
26namespace boost {
27namespace asio {
28
29/// Provides serialised function invocation for any executor type.
30template <typename Executor>
31class strand
32{
33public:
34 /// The type of the underlying executor.
35 typedef Executor inner_executor_type;
36
37 /// Default constructor.
38 /**
39 * This constructor is only valid if the underlying executor type is default
40 * constructible.
41 */
42 strand()
43 : executor_(),
20effc67 44 impl_(strand::create_implementation(executor_))
b32b8144
FG
45 {
46 }
47
48 /// Construct a strand for the specified executor.
20effc67
TL
49 template <typename Executor1>
50 explicit strand(const Executor1& e,
51 typename enable_if<
52 conditional<
53 !is_same<Executor1, strand>::value,
54 is_convertible<Executor1, Executor>,
55 false_type
56 >::type::value
57 >::type* = 0)
b32b8144 58 : executor_(e),
20effc67 59 impl_(strand::create_implementation(executor_))
b32b8144
FG
60 {
61 }
62
63 /// Copy constructor.
64 strand(const strand& other) BOOST_ASIO_NOEXCEPT
65 : executor_(other.executor_),
66 impl_(other.impl_)
67 {
68 }
69
70 /// Converting constructor.
71 /**
72 * This constructor is only valid if the @c OtherExecutor type is convertible
73 * to @c Executor.
74 */
75 template <class OtherExecutor>
76 strand(
77 const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
78 : executor_(other.executor_),
79 impl_(other.impl_)
80 {
81 }
82
83 /// Assignment operator.
84 strand& operator=(const strand& other) BOOST_ASIO_NOEXCEPT
85 {
86 executor_ = other.executor_;
87 impl_ = other.impl_;
88 return *this;
89 }
90
91 /// Converting assignment operator.
92 /**
93 * This assignment operator is only valid if the @c OtherExecutor type is
94 * convertible to @c Executor.
95 */
96 template <class OtherExecutor>
97 strand& operator=(
98 const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
99 {
100 executor_ = other.executor_;
101 impl_ = other.impl_;
102 return *this;
103 }
104
105#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
106 /// Move constructor.
107 strand(strand&& other) BOOST_ASIO_NOEXCEPT
108 : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
109 impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_))
110 {
111 }
112
113 /// Converting move constructor.
114 /**
115 * This constructor is only valid if the @c OtherExecutor type is convertible
116 * to @c Executor.
117 */
118 template <class OtherExecutor>
119 strand(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
f67539c2 120 : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_)),
b32b8144
FG
121 impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_))
122 {
123 }
124
125 /// Move assignment operator.
126 strand& operator=(strand&& other) BOOST_ASIO_NOEXCEPT
127 {
f67539c2 128 executor_ = BOOST_ASIO_MOVE_CAST(Executor)(other.executor_);
b32b8144
FG
129 impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
130 return *this;
131 }
132
133 /// Converting move assignment operator.
134 /**
135 * This assignment operator is only valid if the @c OtherExecutor type is
136 * convertible to @c Executor.
137 */
138 template <class OtherExecutor>
f67539c2 139 strand& operator=(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
b32b8144 140 {
f67539c2 141 executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_);
b32b8144
FG
142 impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
143 return *this;
144 }
145#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
146
147 /// Destructor.
20effc67 148 ~strand() BOOST_ASIO_NOEXCEPT
b32b8144
FG
149 {
150 }
151
152 /// Obtain the underlying executor.
153 inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT
154 {
155 return executor_;
156 }
157
20effc67
TL
158 /// Forward a query to the underlying executor.
159 /**
160 * Do not call this function directly. It is intended for use with the
161 * execution::execute customisation point.
162 *
163 * For example:
164 * @code boost::asio::strand<my_executor_type> ex = ...;
165 * if (boost::asio::query(ex, boost::asio::execution::blocking)
166 * == boost::asio::execution::blocking.never)
167 * ... @endcode
168 */
169 template <typename Property>
170 typename enable_if<
171 can_query<const Executor&, Property>::value,
172 typename query_result<const Executor&, Property>::type
173 >::type query(const Property& p) const
174 BOOST_ASIO_NOEXCEPT_IF((
175 is_nothrow_query<const Executor&, Property>::value))
176 {
177 return boost::asio::query(executor_, p);
178 }
179
180 /// Forward a requirement to the underlying executor.
181 /**
182 * Do not call this function directly. It is intended for use with the
183 * boost::asio::require customisation point.
184 *
185 * For example:
186 * @code boost::asio::strand<my_executor_type> ex1 = ...;
187 * auto ex2 = boost::asio::require(ex1,
188 * boost::asio::execution::blocking.never); @endcode
189 */
190 template <typename Property>
191 typename enable_if<
192 can_require<const Executor&, Property>::value,
193 strand<typename decay<
194 typename require_result<const Executor&, Property>::type
195 >::type>
196 >::type require(const Property& p) const
197 BOOST_ASIO_NOEXCEPT_IF((
198 is_nothrow_require<const Executor&, Property>::value))
199 {
200 return strand<typename decay<
201 typename require_result<const Executor&, Property>::type
202 >::type>(boost::asio::require(executor_, p), impl_);
203 }
204
205 /// Forward a preference to the underlying executor.
206 /**
207 * Do not call this function directly. It is intended for use with the
208 * boost::asio::prefer customisation point.
209 *
210 * For example:
211 * @code boost::asio::strand<my_executor_type> ex1 = ...;
212 * auto ex2 = boost::asio::prefer(ex1,
213 * boost::asio::execution::blocking.never); @endcode
214 */
215 template <typename Property>
216 typename enable_if<
217 can_prefer<const Executor&, Property>::value,
218 strand<typename decay<
219 typename prefer_result<const Executor&, Property>::type
220 >::type>
221 >::type prefer(const Property& p) const
222 BOOST_ASIO_NOEXCEPT_IF((
223 is_nothrow_prefer<const Executor&, Property>::value))
224 {
225 return strand<typename decay<
226 typename prefer_result<const Executor&, Property>::type
227 >::type>(boost::asio::prefer(executor_, p), impl_);
228 }
229
230#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
231 /// Obtain the underlying execution context.
232 execution_context& context() const BOOST_ASIO_NOEXCEPT
233 {
234 return executor_.context();
235 }
236
237 /// Inform the strand that it has some outstanding work to do.
238 /**
239 * The strand delegates this call to its underlying executor.
240 */
241 void on_work_started() const BOOST_ASIO_NOEXCEPT
242 {
243 executor_.on_work_started();
244 }
245
246 /// Inform the strand that some work is no longer outstanding.
247 /**
248 * The strand delegates this call to its underlying executor.
249 */
250 void on_work_finished() const BOOST_ASIO_NOEXCEPT
251 {
252 executor_.on_work_finished();
253 }
20effc67
TL
254#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
255
256 /// Request the strand to invoke the given function object.
257 /**
258 * Do not call this function directly. It is intended for use with the
259 * execution::execute customisation point.
260 *
261 * For example:
262 * @code boost::asio::strand<my_executor_type> ex = ...;
263 * execution::execute(ex, my_function_object); @endcode
264 *
265 * This function is used to ask the strand to execute the given function
266 * object on its underlying executor. The function object will be executed
267 * according to the properties of the underlying executor.
268 *
269 * @param f The function object to be called. The executor will make
270 * a copy of the handler object as required. The function signature of the
271 * function object must be: @code void function(); @endcode
272 */
273 template <typename Function>
274 typename enable_if<
275 execution::can_execute<const Executor&, Function>::value
276 >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const
277 {
278 detail::strand_executor_service::execute(impl_,
279 executor_, BOOST_ASIO_MOVE_CAST(Function)(f));
280 }
b32b8144 281
20effc67 282#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
283 /// Request the strand to invoke the given function object.
284 /**
285 * This function is used to ask the strand to execute the given function
286 * object on its underlying executor. The function object will be executed
287 * inside this function if the strand is not otherwise busy and if the
288 * underlying executor's @c dispatch() function is also able to execute the
289 * function before returning.
290 *
291 * @param f The function object to be called. The executor will make
292 * a copy of the handler object as required. The function signature of the
293 * function object must be: @code void function(); @endcode
294 *
295 * @param a An allocator that may be used by the executor to allocate the
296 * internal storage needed for function invocation.
297 */
298 template <typename Function, typename Allocator>
299 void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
300 {
301 detail::strand_executor_service::dispatch(impl_,
302 executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
303 }
304
305 /// Request the strand to invoke the given function object.
306 /**
307 * This function is used to ask the executor to execute the given function
308 * object. The function object will never be executed inside this function.
309 * Instead, it will be scheduled by the underlying executor's defer function.
310 *
311 * @param f The function object to be called. The executor will make
312 * a copy of the handler object as required. The function signature of the
313 * function object must be: @code void function(); @endcode
314 *
315 * @param a An allocator that may be used by the executor to allocate the
316 * internal storage needed for function invocation.
317 */
318 template <typename Function, typename Allocator>
319 void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
320 {
321 detail::strand_executor_service::post(impl_,
322 executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
323 }
324
325 /// Request the strand to invoke the given function object.
326 /**
327 * This function is used to ask the executor to execute the given function
328 * object. The function object will never be executed inside this function.
329 * Instead, it will be scheduled by the underlying executor's defer function.
330 *
331 * @param f The function object to be called. The executor will make
332 * a copy of the handler object as required. The function signature of the
333 * function object must be: @code void function(); @endcode
334 *
335 * @param a An allocator that may be used by the executor to allocate the
336 * internal storage needed for function invocation.
337 */
338 template <typename Function, typename Allocator>
339 void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
340 {
341 detail::strand_executor_service::defer(impl_,
342 executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
343 }
20effc67 344#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
345
346 /// Determine whether the strand is running in the current thread.
347 /**
348 * @return @c true if the current thread is executing a function that was
349 * submitted to the strand using post(), dispatch() or defer(). Otherwise
350 * returns @c false.
351 */
352 bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT
353 {
354 return detail::strand_executor_service::running_in_this_thread(impl_);
355 }
356
357 /// Compare two strands for equality.
358 /**
359 * Two strands are equal if they refer to the same ordered, non-concurrent
360 * state.
361 */
362 friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
363 {
364 return a.impl_ == b.impl_;
365 }
366
367 /// Compare two strands for inequality.
368 /**
369 * Two strands are equal if they refer to the same ordered, non-concurrent
370 * state.
371 */
372 friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
373 {
374 return a.impl_ != b.impl_;
375 }
376
f67539c2 377#if defined(GENERATING_DOCUMENTATION)
b32b8144 378private:
f67539c2 379#endif // defined(GENERATING_DOCUMENTATION)
b32b8144
FG
380 typedef detail::strand_executor_service::implementation_type
381 implementation_type;
20effc67
TL
382
383 template <typename InnerExecutor>
384 static implementation_type create_implementation(const InnerExecutor& ex,
385 typename enable_if<
386 can_query<InnerExecutor, execution::context_t>::value
387 >::type* = 0)
388 {
389 return use_service<detail::strand_executor_service>(
390 boost::asio::query(ex, execution::context)).create_implementation();
391 }
392
393 template <typename InnerExecutor>
394 static implementation_type create_implementation(const InnerExecutor& ex,
395 typename enable_if<
396 !can_query<InnerExecutor, execution::context_t>::value
397 >::type* = 0)
398 {
399 return use_service<detail::strand_executor_service>(
400 ex.context()).create_implementation();
401 }
402
403 strand(const Executor& ex, const implementation_type& impl)
404 : executor_(ex),
405 impl_(impl)
406 {
407 }
408
409 Executor executor_;
b32b8144
FG
410 implementation_type impl_;
411};
412
92f5a8d4
TL
413/** @defgroup make_strand boost::asio::make_strand
414 *
415 * @brief The boost::asio::make_strand function creates a @ref strand object for
416 * an executor or execution context.
417 */
418/*@{*/
419
420/// Create a @ref strand object for an executor.
421template <typename Executor>
422inline strand<Executor> make_strand(const Executor& ex,
20effc67
TL
423 typename enable_if<
424 is_executor<Executor>::value || execution::is_executor<Executor>::value
425 >::type* = 0)
92f5a8d4
TL
426{
427 return strand<Executor>(ex);
428}
429
430/// Create a @ref strand object for an execution context.
431template <typename ExecutionContext>
432inline strand<typename ExecutionContext::executor_type>
433make_strand(ExecutionContext& ctx,
434 typename enable_if<
20effc67
TL
435 is_convertible<ExecutionContext&, execution_context&>::value
436 >::type* = 0)
92f5a8d4
TL
437{
438 return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
439}
440
441/*@}*/
442
20effc67
TL
443#if !defined(GENERATING_DOCUMENTATION)
444
445namespace traits {
446
447#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
448
449template <typename Executor>
450struct equality_comparable<strand<Executor> >
451{
452 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
453 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
454};
455
456#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
457
458#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
459
460template <typename Executor, typename Function>
461struct execute_member<strand<Executor>, Function,
462 typename enable_if<
463 execution::can_execute<const Executor&, Function>::value
464 >::type>
465{
466 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
467 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
468 typedef void result_type;
469};
470
471#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
472
473#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
474
475template <typename Executor, typename Property>
476struct query_member<strand<Executor>, Property,
477 typename enable_if<
478 can_query<const Executor&, Property>::value
479 >::type>
480{
481 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
482 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
483 (is_nothrow_query<Executor, Property>::value));
484 typedef typename query_result<Executor, Property>::type result_type;
485};
486
487#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
488
489#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
490
491template <typename Executor, typename Property>
492struct require_member<strand<Executor>, Property,
493 typename enable_if<
494 can_require<const Executor&, Property>::value
495 >::type>
496{
497 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
498 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
499 (is_nothrow_require<Executor, Property>::value));
500 typedef strand<typename decay<
501 typename require_result<Executor, Property>::type
502 >::type> result_type;
503};
504
505#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
506
507#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
508
509template <typename Executor, typename Property>
510struct prefer_member<strand<Executor>, Property,
511 typename enable_if<
512 can_prefer<const Executor&, Property>::value
513 >::type>
514{
515 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
516 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
517 (is_nothrow_prefer<Executor, Property>::value));
518 typedef strand<typename decay<
519 typename prefer_result<Executor, Property>::type
520 >::type> result_type;
521};
522
523#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
524
525} // namespace traits
526
527#endif // !defined(GENERATING_DOCUMENTATION)
528
b32b8144
FG
529} // namespace asio
530} // namespace boost
531
532#include <boost/asio/detail/pop_options.hpp>
533
534// If both io_context.hpp and strand.hpp have been included, automatically
535// include the header file needed for the io_context::strand class.
536#if !defined(BOOST_ASIO_NO_EXTENSIONS)
537# if defined(BOOST_ASIO_IO_CONTEXT_HPP)
538# include <boost/asio/io_context_strand.hpp>
539# endif // defined(BOOST_ASIO_IO_CONTEXT_HPP)
540#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
541
542#endif // BOOST_ASIO_STRAND_HPP