• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // execution/blocking_adaptation.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_EXECUTION_BLOCKING_ADAPTATION_HPP
12 #define BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_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/event.hpp>
20 #include <boost/asio/detail/mutex.hpp>
21 #include <boost/asio/detail/type_traits.hpp>
22 #include <boost/asio/execution/execute.hpp>
23 #include <boost/asio/execution/executor.hpp>
24 #include <boost/asio/execution/scheduler.hpp>
25 #include <boost/asio/execution/sender.hpp>
26 #include <boost/asio/is_applicable_property.hpp>
27 #include <boost/asio/prefer.hpp>
28 #include <boost/asio/query.hpp>
29 #include <boost/asio/require.hpp>
30 #include <boost/asio/traits/prefer_member.hpp>
31 #include <boost/asio/traits/query_free.hpp>
32 #include <boost/asio/traits/query_member.hpp>
33 #include <boost/asio/traits/query_static_constexpr_member.hpp>
34 #include <boost/asio/traits/require_member.hpp>
35 #include <boost/asio/traits/static_query.hpp>
36 #include <boost/asio/traits/static_require.hpp>
37 
38 #include <boost/asio/detail/push_options.hpp>
39 
40 namespace boost {
41 namespace asio {
42 
43 #if defined(GENERATING_DOCUMENTATION)
44 
45 namespace execution {
46 
47 /// A property to describe whether automatic adaptation of an executor is
48 /// allowed in order to apply the blocking_adaptation_t::allowed_t property.
49 struct blocking_adaptation_t
50 {
51   /// The blocking_adaptation_t property applies to executors, senders, and
52   /// schedulers.
53   template <typename T>
54   static constexpr bool is_applicable_property_v =
55     is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
56 
57   /// The top-level blocking_adaptation_t property cannot be required.
58   static constexpr bool is_requirable = false;
59 
60   /// The top-level blocking_adaptation_t property cannot be preferred.
61   static constexpr bool is_preferable = false;
62 
63   /// The type returned by queries against an @c any_executor.
64   typedef blocking_adaptation_t polymorphic_query_result_type;
65 
66   /// A sub-property that indicates that automatic adaptation is not allowed.
67   struct disallowed_t
68   {
69     /// The blocking_adaptation_t::disallowed_t property applies to executors,
70     /// senders, and schedulers.
71     template <typename T>
72     static constexpr bool is_applicable_property_v =
73       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
74 
75     /// The blocking_adaptation_t::disallowed_t property can be required.
76     static constexpr bool is_requirable = true;
77 
78     /// The blocking_adaptation_t::disallowed_t property can be preferred.
79     static constexpr bool is_preferable = true;
80 
81     /// The type returned by queries against an @c any_executor.
82     typedef blocking_adaptation_t polymorphic_query_result_type;
83 
84     /// Default constructor.
85     constexpr disallowed_t();
86 
87     /// Get the value associated with a property object.
88     /**
89      * @returns disallowed_t();
90      */
91     static constexpr blocking_adaptation_t value();
92   };
93 
94   /// A sub-property that indicates that automatic adaptation is allowed.
95   struct allowed_t
96   {
97     /// The blocking_adaptation_t::allowed_t property applies to executors,
98     /// senders, and schedulers.
99     template <typename T>
100     static constexpr bool is_applicable_property_v =
101       is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
102 
103     /// The blocking_adaptation_t::allowed_t property can be required.
104     static constexpr bool is_requirable = true;
105 
106     /// The blocking_adaptation_t::allowed_t property can be preferred.
107     static constexpr bool is_preferable = false;
108 
109     /// The type returned by queries against an @c any_executor.
110     typedef blocking_adaptation_t polymorphic_query_result_type;
111 
112     /// Default constructor.
113     constexpr allowed_t();
114 
115     /// Get the value associated with a property object.
116     /**
117      * @returns allowed_t();
118      */
119     static constexpr blocking_adaptation_t value();
120   };
121 
122   /// A special value used for accessing the blocking_adaptation_t::disallowed_t
123   /// property.
124   static constexpr disallowed_t disallowed;
125 
126   /// A special value used for accessing the blocking_adaptation_t::allowed_t
127   /// property.
128   static constexpr allowed_t allowed;
129 
130   /// Default constructor.
131   constexpr blocking_adaptation_t();
132 
133   /// Construct from a sub-property value.
134   constexpr blocking_adaptation_t(disallowed_t);
135 
136   /// Construct from a sub-property value.
137   constexpr blocking_adaptation_t(allowed_t);
138 
139   /// Compare property values for equality.
140   friend constexpr bool operator==(
141       const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;
142 
143   /// Compare property values for inequality.
144   friend constexpr bool operator!=(
145       const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;
146 };
147 
148 /// A special value used for accessing the blocking_adaptation_t property.
149 constexpr blocking_adaptation_t blocking_adaptation;
150 
151 } // namespace execution
152 
153 #else // defined(GENERATING_DOCUMENTATION)
154 
155 namespace execution {
156 namespace detail {
157 namespace blocking_adaptation {
158 
159 template <int I> struct disallowed_t;
160 template <int I> struct allowed_t;
161 
162 } // namespace blocking_adaptation
163 
164 template <int I = 0>
165 struct blocking_adaptation_t
166 {
167 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
168   template <typename T>
169   BOOST_ASIO_STATIC_CONSTEXPR(bool,
170     is_applicable_property_v = is_executor<T>::value
171       || is_sender<T>::value || is_scheduler<T>::value);
172 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
173 
174   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);
175   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
176   typedef blocking_adaptation_t polymorphic_query_result_type;
177 
178   typedef detail::blocking_adaptation::disallowed_t<I> disallowed_t;
179   typedef detail::blocking_adaptation::allowed_t<I> allowed_t;
180 
181   BOOST_ASIO_CONSTEXPR blocking_adaptation_t()
182     : value_(-1)
183   {
184   }
185 
186   BOOST_ASIO_CONSTEXPR blocking_adaptation_t(disallowed_t)
187     : value_(0)
188   {
189   }
190 
191   BOOST_ASIO_CONSTEXPR blocking_adaptation_t(allowed_t)
192     : value_(1)
193   {
194   }
195 
196 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
197   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
198   template <typename T>
199   static BOOST_ASIO_CONSTEXPR
200   typename traits::query_static_constexpr_member<
201       T, blocking_adaptation_t>::result_type
202   static_query()
203     BOOST_ASIO_NOEXCEPT_IF((
204       traits::query_static_constexpr_member<
205         T, blocking_adaptation_t
206       >::is_noexcept))
207   {
208     return traits::query_static_constexpr_member<
209         T, blocking_adaptation_t>::value();
210   }
211 
212   template <typename T>
213   static BOOST_ASIO_CONSTEXPR
214   typename traits::static_query<T, disallowed_t>::result_type
215   static_query(
216       typename enable_if<
217         !traits::query_static_constexpr_member<
218             T, blocking_adaptation_t>::is_valid
219           && !traits::query_member<T, blocking_adaptation_t>::is_valid
220           && traits::static_query<T, disallowed_t>::is_valid
221       >::type* = 0) BOOST_ASIO_NOEXCEPT
222   {
223     return traits::static_query<T, disallowed_t>::value();
224   }
225 
226   template <typename T>
227   static BOOST_ASIO_CONSTEXPR
228   typename traits::static_query<T, allowed_t>::result_type
229   static_query(
230       typename enable_if<
231         !traits::query_static_constexpr_member<
232             T, blocking_adaptation_t>::is_valid
233           && !traits::query_member<T, blocking_adaptation_t>::is_valid
234           && !traits::static_query<T, disallowed_t>::is_valid
235           && traits::static_query<T, allowed_t>::is_valid
236       >::type* = 0) BOOST_ASIO_NOEXCEPT
237   {
238     return traits::static_query<T, allowed_t>::value();
239   }
240 
241   template <typename E,
242       typename T = decltype(blocking_adaptation_t::static_query<E>())>
243   static BOOST_ASIO_CONSTEXPR const T static_query_v
244     = blocking_adaptation_t::static_query<E>();
245 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
246        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
247 
248   friend BOOST_ASIO_CONSTEXPR bool operator==(
249       const blocking_adaptation_t& a, const blocking_adaptation_t& b)
250   {
251     return a.value_ == b.value_;
252   }
253 
254   friend BOOST_ASIO_CONSTEXPR bool operator!=(
255       const blocking_adaptation_t& a, const blocking_adaptation_t& b)
256   {
257     return a.value_ != b.value_;
258   }
259 
260   struct convertible_from_blocking_adaptation_t
261   {
262     BOOST_ASIO_CONSTEXPR convertible_from_blocking_adaptation_t(
263         blocking_adaptation_t)
264     {
265     }
266   };
267 
268   template <typename Executor>
269   friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query(
270       const Executor& ex, convertible_from_blocking_adaptation_t,
271       typename enable_if<
272         can_query<const Executor&, disallowed_t>::value
273       >::type* = 0)
274 #if !defined(__clang__) // Clang crashes if noexcept is used here.
275 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
276     BOOST_ASIO_NOEXCEPT_IF((
277       is_nothrow_query<const Executor&,
278         blocking_adaptation_t<>::disallowed_t>::value))
279 #else // defined(BOOST_ASIO_MSVC)
280     BOOST_ASIO_NOEXCEPT_IF((
281       is_nothrow_query<const Executor&, disallowed_t>::value))
282 #endif // defined(BOOST_ASIO_MSVC)
283 #endif // !defined(__clang__)
284   {
285     return boost::asio::query(ex, disallowed_t());
286   }
287 
288   template <typename Executor>
289   friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query(
290       const Executor& ex, convertible_from_blocking_adaptation_t,
291       typename enable_if<
292         !can_query<const Executor&, disallowed_t>::value
293           && can_query<const Executor&, allowed_t>::value
294       >::type* = 0)
295 #if !defined(__clang__) // Clang crashes if noexcept is used here.
296 #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified.
297     BOOST_ASIO_NOEXCEPT_IF((
298       is_nothrow_query<const Executor&,
299         blocking_adaptation_t<>::allowed_t>::value))
300 #else // defined(BOOST_ASIO_MSVC)
301     BOOST_ASIO_NOEXCEPT_IF((
302       is_nothrow_query<const Executor&, allowed_t>::value))
303 #endif // defined(BOOST_ASIO_MSVC)
304 #endif // !defined(__clang__)
305   {
306     return boost::asio::query(ex, allowed_t());
307   }
308 
309   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed);
310   BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed);
311 
312 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
313   static const blocking_adaptation_t instance;
314 #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR)
315 
316 private:
317   int value_;
318 };
319 
320 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
321   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
322 template <int I> template <typename E, typename T>
323 const T blocking_adaptation_t<I>::static_query_v;
324 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
325        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
326 
327 #if !defined(BOOST_ASIO_HAS_CONSTEXPR)
328 template <int I>
329 const blocking_adaptation_t<I> blocking_adaptation_t<I>::instance;
330 #endif
331 
332 template <int I>
333 const typename blocking_adaptation_t<I>::disallowed_t
334 blocking_adaptation_t<I>::disallowed;
335 
336 template <int I>
337 const typename blocking_adaptation_t<I>::allowed_t
338 blocking_adaptation_t<I>::allowed;
339 
340 namespace blocking_adaptation {
341 
342 template <int I = 0>
343 struct disallowed_t
344 {
345 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
346   template <typename T>
347   BOOST_ASIO_STATIC_CONSTEXPR(bool,
348     is_applicable_property_v = is_executor<T>::value
349       || is_sender<T>::value || is_scheduler<T>::value);
350 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
351 
352   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
353   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
354   typedef blocking_adaptation_t<I> polymorphic_query_result_type;
355 
356   BOOST_ASIO_CONSTEXPR disallowed_t()
357   {
358   }
359 
360 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
361   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
362   template <typename T>
363   static BOOST_ASIO_CONSTEXPR
364   typename traits::query_static_constexpr_member<T, disallowed_t>::result_type
365   static_query()
366     BOOST_ASIO_NOEXCEPT_IF((
367       traits::query_static_constexpr_member<T, disallowed_t>::is_noexcept))
368   {
369     return traits::query_static_constexpr_member<T, disallowed_t>::value();
370   }
371 
372   template <typename T>
373   static BOOST_ASIO_CONSTEXPR disallowed_t static_query(
374       typename enable_if<
375         !traits::query_static_constexpr_member<T, disallowed_t>::is_valid
376           && !traits::query_member<T, disallowed_t>::is_valid
377           && !traits::query_free<T, disallowed_t>::is_valid
378           && !can_query<T, allowed_t<I> >::value
379       >::type* = 0) BOOST_ASIO_NOEXCEPT
380   {
381     return disallowed_t();
382   }
383 
384   template <typename E, typename T = decltype(disallowed_t::static_query<E>())>
385   static BOOST_ASIO_CONSTEXPR const T static_query_v
386     = disallowed_t::static_query<E>();
387 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
388        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
389 
390   static BOOST_ASIO_CONSTEXPR blocking_adaptation_t<I> value()
391   {
392     return disallowed_t();
393   }
394 
395   friend BOOST_ASIO_CONSTEXPR bool operator==(
396       const disallowed_t&, const disallowed_t&)
397   {
398     return true;
399   }
400 
401   friend BOOST_ASIO_CONSTEXPR bool operator!=(
402       const disallowed_t&, const disallowed_t&)
403   {
404     return false;
405   }
406 };
407 
408 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
409   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
410 template <int I> template <typename E, typename T>
411 const T disallowed_t<I>::static_query_v;
412 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
413        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
414 
415 template <typename Executor>
416 class adapter
417 {
418 public:
419   adapter(int, const Executor& e) BOOST_ASIO_NOEXCEPT
420     : executor_(e)
421   {
422   }
423 
424   adapter(const adapter& other) BOOST_ASIO_NOEXCEPT
425     : executor_(other.executor_)
426   {
427   }
428 
429 #if defined(BOOST_ASIO_HAS_MOVE)
430   adapter(adapter&& other) BOOST_ASIO_NOEXCEPT
431     : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_))
432   {
433   }
434 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
435 
436   template <int I>
437   static BOOST_ASIO_CONSTEXPR allowed_t<I> query(
438       blocking_adaptation_t<I>) BOOST_ASIO_NOEXCEPT
439   {
440     return allowed_t<I>();
441   }
442 
443   template <int I>
444   static BOOST_ASIO_CONSTEXPR allowed_t<I> query(
445       allowed_t<I>) BOOST_ASIO_NOEXCEPT
446   {
447     return allowed_t<I>();
448   }
449 
450   template <int I>
451   static BOOST_ASIO_CONSTEXPR allowed_t<I> query(
452       disallowed_t<I>) BOOST_ASIO_NOEXCEPT
453   {
454     return allowed_t<I>();
455   }
456 
457   template <typename Property>
458   typename enable_if<
459     can_query<const Executor&, Property>::value,
460     typename query_result<const Executor&, Property>::type
461   >::type query(const Property& p) const
462     BOOST_ASIO_NOEXCEPT_IF((
463       is_nothrow_query<const Executor&, Property>::value))
464   {
465     return boost::asio::query(executor_, p);
466   }
467 
468   template <int I>
469   Executor require(disallowed_t<I>) const BOOST_ASIO_NOEXCEPT
470   {
471     return executor_;
472   }
473 
474   template <typename Property>
475   typename enable_if<
476     can_require<const Executor&, Property>::value,
477     adapter<typename decay<
478       typename require_result<const Executor&, Property>::type
479     >::type>
480   >::type require(const Property& p) const
481     BOOST_ASIO_NOEXCEPT_IF((
482       is_nothrow_require<const Executor&, Property>::value))
483   {
484     return adapter<typename decay<
485       typename require_result<const Executor&, Property>::type
486         >::type>(0, boost::asio::require(executor_, p));
487   }
488 
489   template <typename Property>
490   typename enable_if<
491     can_prefer<const Executor&, Property>::value,
492     adapter<typename decay<
493       typename prefer_result<const Executor&, Property>::type
494     >::type>
495   >::type prefer(const Property& p) const
496     BOOST_ASIO_NOEXCEPT_IF((
497       is_nothrow_prefer<const Executor&, Property>::value))
498   {
499     return adapter<typename decay<
500       typename prefer_result<const Executor&, Property>::type
501         >::type>(0, boost::asio::prefer(executor_, p));
502   }
503 
504   template <typename Function>
505   typename enable_if<
506     execution::can_execute<const Executor&, Function>::value
507   >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const
508   {
509     execution::execute(executor_, BOOST_ASIO_MOVE_CAST(Function)(f));
510   }
511 
512   friend bool operator==(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
513   {
514     return a.executor_ == b.executor_;
515   }
516 
517   friend bool operator!=(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT
518   {
519     return a.executor_ != b.executor_;
520   }
521 
522 private:
523   Executor executor_;
524 };
525 
526 template <int I = 0>
527 struct allowed_t
528 {
529 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
530   template <typename T>
531   BOOST_ASIO_STATIC_CONSTEXPR(bool,
532     is_applicable_property_v = is_executor<T>::value
533       || is_sender<T>::value || is_scheduler<T>::value);
534 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
535 
536   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
537   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
538   typedef blocking_adaptation_t<I> polymorphic_query_result_type;
539 
540   BOOST_ASIO_CONSTEXPR allowed_t()
541   {
542   }
543 
544 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
545   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
546   template <typename T>
547   static BOOST_ASIO_CONSTEXPR
548   typename traits::query_static_constexpr_member<T, allowed_t>::result_type
549   static_query()
550     BOOST_ASIO_NOEXCEPT_IF((
551       traits::query_static_constexpr_member<T, allowed_t>::is_noexcept))
552   {
553     return traits::query_static_constexpr_member<T, allowed_t>::value();
554   }
555 
556   template <typename E, typename T = decltype(allowed_t::static_query<E>())>
557   static BOOST_ASIO_CONSTEXPR const T static_query_v
558     = allowed_t::static_query<E>();
559 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
560        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
561 
562   static BOOST_ASIO_CONSTEXPR blocking_adaptation_t<I> value()
563   {
564     return allowed_t();
565   }
566 
567   friend BOOST_ASIO_CONSTEXPR bool operator==(
568       const allowed_t&, const allowed_t&)
569   {
570     return true;
571   }
572 
573   friend BOOST_ASIO_CONSTEXPR bool operator!=(
574       const allowed_t&, const allowed_t&)
575   {
576     return false;
577   }
578 
579   template <typename Executor>
580   friend adapter<Executor> require(
581       const Executor& e, const allowed_t&,
582       typename enable_if<
583         is_executor<Executor>::value
584       >::type* = 0)
585   {
586     return adapter<Executor>(0, e);
587   }
588 };
589 
590 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
591   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
592 template <int I> template <typename E, typename T>
593 const T allowed_t<I>::static_query_v;
594 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
595        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
596 
597 template <typename Function>
598 class blocking_execute_state
599 {
600 public:
601   template <typename F>
602   blocking_execute_state(BOOST_ASIO_MOVE_ARG(F) f)
603     : func_(BOOST_ASIO_MOVE_CAST(F)(f)),
604       is_complete_(false)
605   {
606   }
607 
608   template <typename Executor>
609   void execute_and_wait(BOOST_ASIO_MOVE_ARG(Executor) ex)
610   {
611     handler h = { this };
612     execution::execute(BOOST_ASIO_MOVE_CAST(Executor)(ex), h);
613     boost::asio::detail::mutex::scoped_lock lock(mutex_);
614     while (!is_complete_)
615       event_.wait(lock);
616   }
617 
618   struct cleanup
619   {
620     ~cleanup()
621     {
622       boost::asio::detail::mutex::scoped_lock lock(state_->mutex_);
623       state_->is_complete_ = true;
624       state_->event_.unlock_and_signal_one_for_destruction(lock);
625     }
626 
627     blocking_execute_state* state_;
628   };
629 
630   struct handler
631   {
632     void operator()()
633     {
634       cleanup c = { state_ };
635       state_->func_();
636     }
637 
638     blocking_execute_state* state_;
639   };
640 
641   Function func_;
642   boost::asio::detail::mutex mutex_;
643   boost::asio::detail::event event_;
644   bool is_complete_;
645 };
646 
647 template <typename Executor, typename Function>
648 void blocking_execute(
649     BOOST_ASIO_MOVE_ARG(Executor) ex,
650     BOOST_ASIO_MOVE_ARG(Function) func)
651 {
652   typedef typename decay<Function>::type func_t;
653   blocking_execute_state<func_t> state(BOOST_ASIO_MOVE_CAST(Function)(func));
654   state.execute_and_wait(ex);
655 }
656 
657 } // namespace blocking_adaptation
658 } // namespace detail
659 
660 typedef detail::blocking_adaptation_t<> blocking_adaptation_t;
661 
662 #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
663 constexpr blocking_adaptation_t blocking_adaptation;
664 #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
665 namespace { static const blocking_adaptation_t&
666   blocking_adaptation = blocking_adaptation_t::instance; }
667 #endif
668 
669 } // namespace execution
670 
671 #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
672 
673 template <typename T>
674 struct is_applicable_property<T, execution::blocking_adaptation_t>
675   : integral_constant<bool,
676       execution::is_executor<T>::value
677         || execution::is_sender<T>::value
678         || execution::is_scheduler<T>::value>
679 {
680 };
681 
682 template <typename T>
683 struct is_applicable_property<T, execution::blocking_adaptation_t::disallowed_t>
684   : integral_constant<bool,
685       execution::is_executor<T>::value
686         || execution::is_sender<T>::value
687         || execution::is_scheduler<T>::value>
688 {
689 };
690 
691 template <typename T>
692 struct is_applicable_property<T, execution::blocking_adaptation_t::allowed_t>
693   : integral_constant<bool,
694       execution::is_executor<T>::value
695         || execution::is_sender<T>::value
696         || execution::is_scheduler<T>::value>
697 {
698 };
699 
700 #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
701 
702 namespace traits {
703 
704 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
705 
706 template <typename T>
707 struct query_free_default<T, execution::blocking_adaptation_t,
708   typename enable_if<
709     can_query<T, execution::blocking_adaptation_t::disallowed_t>::value
710   >::type>
711 {
712   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
713   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T,
714       execution::blocking_adaptation_t::disallowed_t>::value));
715 
716   typedef execution::blocking_adaptation_t result_type;
717 };
718 
719 template <typename T>
720 struct query_free_default<T, execution::blocking_adaptation_t,
721   typename enable_if<
722     !can_query<T, execution::blocking_adaptation_t::disallowed_t>::value
723       && can_query<T, execution::blocking_adaptation_t::allowed_t>::value
724   >::type>
725 {
726   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
727   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
728     (is_nothrow_query<T, execution::blocking_adaptation_t::allowed_t>::value));
729 
730   typedef execution::blocking_adaptation_t result_type;
731 };
732 
733 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)
734 
735 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
736   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
737 
738 template <typename T>
739 struct static_query<T, execution::blocking_adaptation_t,
740   typename enable_if<
741     traits::query_static_constexpr_member<T,
742       execution::blocking_adaptation_t>::is_valid
743   >::type>
744 {
745   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
746   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
747 
748   typedef typename traits::query_static_constexpr_member<T,
749     execution::blocking_adaptation_t>::result_type result_type;
750 
751   static BOOST_ASIO_CONSTEXPR result_type value()
752   {
753     return traits::query_static_constexpr_member<T,
754       execution::blocking_adaptation_t>::value();
755   }
756 };
757 
758 template <typename T>
759 struct static_query<T, execution::blocking_adaptation_t,
760   typename enable_if<
761     !traits::query_static_constexpr_member<T,
762         execution::blocking_adaptation_t>::is_valid
763       && !traits::query_member<T,
764         execution::blocking_adaptation_t>::is_valid
765       && traits::static_query<T,
766         execution::blocking_adaptation_t::disallowed_t>::is_valid
767   >::type>
768 {
769   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
770   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
771 
772   typedef typename traits::static_query<T,
773     execution::blocking_adaptation_t::disallowed_t>::result_type result_type;
774 
775   static BOOST_ASIO_CONSTEXPR result_type value()
776   {
777     return traits::static_query<T,
778         execution::blocking_adaptation_t::disallowed_t>::value();
779   }
780 };
781 
782 template <typename T>
783 struct static_query<T, execution::blocking_adaptation_t,
784   typename enable_if<
785     !traits::query_static_constexpr_member<T,
786         execution::blocking_adaptation_t>::is_valid
787       && !traits::query_member<T,
788         execution::blocking_adaptation_t>::is_valid
789       && !traits::static_query<T,
790         execution::blocking_adaptation_t::disallowed_t>::is_valid
791       && traits::static_query<T,
792         execution::blocking_adaptation_t::allowed_t>::is_valid
793   >::type>
794 {
795   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
796   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
797 
798   typedef typename traits::static_query<T,
799     execution::blocking_adaptation_t::allowed_t>::result_type result_type;
800 
801   static BOOST_ASIO_CONSTEXPR result_type value()
802   {
803     return traits::static_query<T,
804         execution::blocking_adaptation_t::allowed_t>::value();
805   }
806 };
807 
808 template <typename T>
809 struct static_query<T, execution::blocking_adaptation_t::disallowed_t,
810   typename enable_if<
811     traits::query_static_constexpr_member<T,
812       execution::blocking_adaptation_t::disallowed_t>::is_valid
813   >::type>
814 {
815   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
816   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
817 
818   typedef typename traits::query_static_constexpr_member<T,
819     execution::blocking_adaptation_t::disallowed_t>::result_type result_type;
820 
821   static BOOST_ASIO_CONSTEXPR result_type value()
822   {
823     return traits::query_static_constexpr_member<T,
824       execution::blocking_adaptation_t::disallowed_t>::value();
825   }
826 };
827 
828 template <typename T>
829 struct static_query<T, execution::blocking_adaptation_t::disallowed_t,
830   typename enable_if<
831     !traits::query_static_constexpr_member<T,
832         execution::blocking_adaptation_t::disallowed_t>::is_valid
833       && !traits::query_member<T,
834         execution::blocking_adaptation_t::disallowed_t>::is_valid
835       && !traits::query_free<T,
836         execution::blocking_adaptation_t::disallowed_t>::is_valid
837       && !can_query<T, execution::blocking_adaptation_t::allowed_t>::value
838   >::type>
839 {
840   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
841   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
842 
843   typedef execution::blocking_adaptation_t::disallowed_t result_type;
844 
845   static BOOST_ASIO_CONSTEXPR result_type value()
846   {
847     return result_type();
848   }
849 };
850 
851 template <typename T>
852 struct static_query<T, execution::blocking_adaptation_t::allowed_t,
853   typename enable_if<
854     traits::query_static_constexpr_member<T,
855       execution::blocking_adaptation_t::allowed_t>::is_valid
856   >::type>
857 {
858   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
859   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
860 
861   typedef typename traits::query_static_constexpr_member<T,
862     execution::blocking_adaptation_t::allowed_t>::result_type result_type;
863 
864   static BOOST_ASIO_CONSTEXPR result_type value()
865   {
866     return traits::query_static_constexpr_member<T,
867       execution::blocking_adaptation_t::allowed_t>::value();
868   }
869 };
870 
871 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
872        //   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
873 
874 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
875 
876 template <typename T>
877 struct static_require<T, execution::blocking_adaptation_t::disallowed_t,
878   typename enable_if<
879     static_query<T, execution::blocking_adaptation_t::disallowed_t>::is_valid
880   >::type>
881 {
882   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
883     (is_same<typename static_query<T,
884       execution::blocking_adaptation_t::disallowed_t>::result_type,
885         execution::blocking_adaptation_t::disallowed_t>::value));
886 };
887 
888 template <typename T>
889 struct static_require<T, execution::blocking_adaptation_t::allowed_t,
890   typename enable_if<
891     static_query<T, execution::blocking_adaptation_t::allowed_t>::is_valid
892   >::type>
893 {
894   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid =
895     (is_same<typename static_query<T,
896       execution::blocking_adaptation_t::allowed_t>::result_type,
897         execution::blocking_adaptation_t::allowed_t>::value));
898 };
899 
900 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)
901 
902 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
903 
904 template <typename T>
905 struct require_free_default<T, execution::blocking_adaptation_t::allowed_t,
906   typename enable_if<
907     is_same<T, typename decay<T>::type>::value
908       && execution::is_executor<T>::value
909   >::type>
910 {
911   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
912   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
913   typedef execution::detail::blocking_adaptation::adapter<T> result_type;
914 };
915 
916 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)
917 
918 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
919 
920 template <typename Executor>
921 struct equality_comparable<
922   execution::detail::blocking_adaptation::adapter<Executor> >
923 {
924   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
925   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
926 };
927 
928 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
929 
930 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
931 
932 template <typename Executor, typename Function>
933 struct execute_member<
934   execution::detail::blocking_adaptation::adapter<Executor>, Function>
935 {
936   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
937   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
938   typedef void result_type;
939 };
940 
941 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
942 
943 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
944 
945 template <typename Executor, int I>
946 struct query_static_constexpr_member<
947   execution::detail::blocking_adaptation::adapter<Executor>,
948   execution::detail::blocking_adaptation_t<I> >
949 {
950   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
951   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
952   typedef execution::blocking_adaptation_t::allowed_t result_type;
953 
954   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
955   {
956     return result_type();
957   }
958 };
959 
960 template <typename Executor, int I>
961 struct query_static_constexpr_member<
962   execution::detail::blocking_adaptation::adapter<Executor>,
963   execution::detail::blocking_adaptation::allowed_t<I> >
964 {
965   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
966   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
967   typedef execution::blocking_adaptation_t::allowed_t result_type;
968 
969   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
970   {
971     return result_type();
972   }
973 };
974 
975 template <typename Executor, int I>
976 struct query_static_constexpr_member<
977   execution::detail::blocking_adaptation::adapter<Executor>,
978   execution::detail::blocking_adaptation::disallowed_t<I> >
979 {
980   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
981   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
982   typedef execution::blocking_adaptation_t::allowed_t result_type;
983 
984   static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
985   {
986     return result_type();
987   }
988 };
989 
990 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
991 
992 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
993 
994 template <typename Executor, typename Property>
995 struct query_member<
996   execution::detail::blocking_adaptation::adapter<Executor>, Property,
997   typename enable_if<
998     can_query<const Executor&, Property>::value
999   >::type>
1000 {
1001   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1002   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1003       (is_nothrow_query<Executor, Property>::value));
1004   typedef typename query_result<Executor, Property>::type result_type;
1005 };
1006 
1007 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1008 
1009 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1010 
1011 template <typename Executor, int I>
1012 struct require_member<
1013   execution::detail::blocking_adaptation::adapter<Executor>,
1014   execution::detail::blocking_adaptation::disallowed_t<I> >
1015 {
1016   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1017   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1018   typedef Executor result_type;
1019 };
1020 
1021 template <typename Executor, typename Property>
1022 struct require_member<
1023   execution::detail::blocking_adaptation::adapter<Executor>, Property,
1024   typename enable_if<
1025     can_require<const Executor&, Property>::value
1026   >::type>
1027 {
1028   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1029   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1030       (is_nothrow_require<Executor, Property>::value));
1031   typedef execution::detail::blocking_adaptation::adapter<typename decay<
1032     typename require_result<Executor, Property>::type
1033       >::type> result_type;
1034 };
1035 
1036 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1037 
1038 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1039 
1040 template <typename Executor, typename Property>
1041 struct prefer_member<
1042   execution::detail::blocking_adaptation::adapter<Executor>, Property,
1043   typename enable_if<
1044     can_prefer<const Executor&, Property>::value
1045   >::type>
1046 {
1047   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1048   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
1049       (is_nothrow_prefer<Executor, Property>::value));
1050   typedef execution::detail::blocking_adaptation::adapter<typename decay<
1051     typename prefer_result<Executor, Property>::type
1052       >::type> result_type;
1053 };
1054 
1055 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
1056 
1057 } // namespace traits
1058 
1059 #endif // defined(GENERATING_DOCUMENTATION)
1060 
1061 } // namespace asio
1062 } // namespace boost
1063 
1064 #include <boost/asio/detail/pop_options.hpp>
1065 
1066 #endif // BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP
1067