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