Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/c++/15/experimental/executor
1 // <experimental/executor> -*- C++ -*- 2 3 // Copyright (C) 2015-2025 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file experimental/executor 26 * This is a TS C++ Library header. 27 * @ingroup networking-ts 28 */ 29 30 #ifndef _GLIBCXX_EXPERIMENTAL_EXECUTOR 31 #define _GLIBCXX_EXPERIMENTAL_EXECUTOR 1 32 33 #ifdef _GLIBCXX_SYSHDR 34 #pragma GCC system_header 35 #endif 36 37 #include <bits/requires_hosted.h> // experimental is currently omitted 38 39 #if __cplusplus >= 201402L 40 41 #include <algorithm> 42 #include <condition_variable> 43 #include <functional> 44 #include <future> 45 #include <list> 46 #include <queue> 47 #include <thread> 48 #include <tuple> 49 #include <unordered_map> 50 #include <experimental/netfwd> 51 #include <bits/unique_ptr.h> 52 #include <experimental/bits/net.h> 53 54 namespace std _GLIBCXX_VISIBILITY(default) 55 { 56 _GLIBCXX_BEGIN_NAMESPACE_VERSION 57 namespace experimental 58 { 59 namespace net 60 { 61 inline namespace v1 62 { 63 64 /** @addtogroup networking-ts 65 * @{ 66 */ 67 68 /// Customization point for asynchronous operations. 69 template<typename _CompletionToken, typename _Signature, typename = void> 70 class async_result; 71 72 /// Convenience utility to help implement asynchronous operations. 73 template<typename _CompletionToken, typename _Signature> 74 class async_completion; 75 76 template<typename _Tp, typename _ProtoAlloc, typename = __void_t<>> 77 struct __associated_allocator_impl 78 { 79 using type = _ProtoAlloc; 80 81 static type 82 _S_get(const _Tp&, const _ProtoAlloc& __a) noexcept { return __a; } 83 }; 84 85 template<typename _Tp, typename _ProtoAlloc> 86 struct __associated_allocator_impl<_Tp, _ProtoAlloc, 87 __void_t<typename _Tp::allocator_type>> 88 { 89 using type = typename _Tp::allocator_type; 90 91 static type 92 _S_get(const _Tp& __t, const _ProtoAlloc&) noexcept 93 { return __t.get_allocator(); } 94 }; 95 96 /// Helper to associate an allocator with a type. 97 template<typename _Tp, typename _ProtoAllocator = allocator<void>> 98 struct associated_allocator 99 : __associated_allocator_impl<_Tp, _ProtoAllocator> 100 { 101 static auto 102 get(const _Tp& __t, 103 const _ProtoAllocator& __a = _ProtoAllocator()) noexcept 104 { 105 using _Impl = __associated_allocator_impl<_Tp, _ProtoAllocator>; 106 return _Impl::_S_get(__t, __a); 107 } 108 }; 109 110 /// Alias template for associated_allocator. 111 template<typename _Tp, typename _ProtoAllocator = allocator<void>> 112 using associated_allocator_t 113 = typename associated_allocator<_Tp, _ProtoAllocator>::type; 114 115 // get_associated_allocator: 116 117 template<typename _Tp> 118 inline associated_allocator_t<_Tp> 119 get_associated_allocator(const _Tp& __t) noexcept 120 { return associated_allocator<_Tp>::get(__t); } 121 122 template<typename _Tp, typename _ProtoAllocator> 123 inline associated_allocator_t<_Tp, _ProtoAllocator> 124 get_associated_allocator(const _Tp& __t, 125 const _ProtoAllocator& __a) noexcept 126 { return associated_allocator<_Tp, _ProtoAllocator>::get(__t, __a); } 127 128 enum class fork_event { prepare, parent, child }; 129 130 /// An extensible, type-safe, polymorphic set of services. 131 class execution_context; 132 133 class service_already_exists : public logic_error 134 { 135 public: 136 // _GLIBCXX_RESOLVE_LIB_DEFECTS 137 // 3414. service_already_exists has no usable constructors 138 service_already_exists() : logic_error("service already exists") { } 139 }; 140 141 template<typename _Tp> struct is_executor; 142 143 struct executor_arg_t { }; 144 145 constexpr executor_arg_t executor_arg = executor_arg_t(); 146 147 /// Trait for determining whether to construct an object with an executor. 148 template<typename _Tp, typename _Executor> struct uses_executor; 149 150 template<typename _Tp, typename _Executor, typename = __void_t<>> 151 struct __associated_executor_impl 152 { 153 using type = _Executor; 154 155 static type 156 _S_get(const _Tp&, const _Executor& __e) noexcept { return __e; } 157 }; 158 159 template<typename _Tp, typename _Executor> 160 struct __associated_executor_impl<_Tp, _Executor, 161 __void_t<typename _Tp::executor_type>> 162 { 163 using type = typename _Tp::executor_type; 164 165 static type 166 _S_get(const _Tp& __t, const _Executor&) noexcept 167 { return __t.get_executor(); } 168 }; 169 170 /// Helper to associate an executor with a type. 171 template<typename _Tp, typename _Executor = system_executor> 172 struct associated_executor 173 : __associated_executor_impl<_Tp, _Executor> 174 { 175 static auto 176 get(const _Tp& __t, const _Executor& __e = _Executor()) noexcept 177 { return __associated_executor_impl<_Tp, _Executor>::_S_get(__t, __e); } 178 }; 179 180 181 template<typename _Tp, typename _Executor = system_executor> 182 using associated_executor_t 183 = typename associated_executor<_Tp, _Executor>::type; 184 185 template<typename _ExecutionContext> 186 using __is_exec_context 187 = is_convertible<_ExecutionContext&, execution_context&>; 188 189 template<typename _Tp> 190 using __executor_t = typename _Tp::executor_type; 191 192 // get_associated_executor: 193 194 template<typename _Tp> 195 inline associated_executor_t<_Tp> 196 get_associated_executor(const _Tp& __t) noexcept 197 { return associated_executor<_Tp>::get(__t); } 198 199 template<typename _Tp, typename _Executor> 200 inline 201 enable_if_t<is_executor<_Executor>::value, 202 associated_executor_t<_Tp, _Executor>> 203 get_associated_executor(const _Tp& __t, const _Executor& __ex) 204 { return associated_executor<_Tp, _Executor>::get(__t, __ex); } 205 206 template<typename _Tp, typename _ExecutionContext> 207 inline 208 enable_if_t<__is_exec_context<_ExecutionContext>::value, 209 associated_executor_t<_Tp, __executor_t<_ExecutionContext>>> 210 get_associated_executor(const _Tp& __t, _ExecutionContext& __ctx) noexcept 211 { return net::get_associated_executor(__t, __ctx.get_executor()); } 212 213 214 /// Helper to bind an executor to an object or function. 215 template<typename _Tp, typename _Executor> 216 class executor_binder; 217 218 template<typename _Tp, typename _Executor, typename _Signature> 219 class async_result<executor_binder<_Tp, _Executor>, _Signature>; 220 221 template<typename _Tp, typename _Executor, typename _ProtoAllocator> 222 struct associated_allocator<executor_binder<_Tp, _Executor>, 223 _ProtoAllocator>; 224 225 template<typename _Tp, typename _Executor, typename _Executor1> 226 struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>; 227 228 // bind_executor: 229 230 template<typename _Executor, typename _Tp> 231 inline 232 enable_if_t<is_executor<_Executor>::value, 233 executor_binder<decay_t<_Tp>, _Executor>> 234 bind_executor(const _Executor& __ex, _Tp&& __t) 235 { return { std::forward<_Tp>(__t), __ex }; } 236 237 template<typename _ExecutionContext, typename _Tp> 238 inline 239 enable_if_t<__is_exec_context<_ExecutionContext>::value, 240 executor_binder<decay_t<_Tp>, __executor_t<_ExecutionContext>>> 241 bind_executor(_ExecutionContext& __ctx, _Tp&& __t) 242 { return { __ctx.get_executor(), forward<_Tp>(__t) }; } 243 244 245 /// A scope-guard type to record when work is started and finished. 246 template<typename _Executor> 247 class executor_work_guard; 248 249 // make_work_guard: 250 251 template<typename _Executor> 252 inline 253 enable_if_t<is_executor<_Executor>::value, executor_work_guard<_Executor>> 254 make_work_guard(const _Executor& __ex) 255 { return executor_work_guard<_Executor>(__ex); } 256 257 template<typename _ExecutionContext> 258 inline 259 enable_if_t<__is_exec_context<_ExecutionContext>::value, 260 executor_work_guard<__executor_t<_ExecutionContext>>> 261 make_work_guard(_ExecutionContext& __ctx) 262 { return net::make_work_guard(__ctx.get_executor()); } 263 264 template<typename _Tp> 265 inline 266 enable_if_t<__not_<__or_<is_executor<_Tp>, __is_exec_context<_Tp>>>::value, 267 executor_work_guard<associated_executor_t<_Tp>>> 268 make_work_guard(const _Tp& __t) 269 { return net::get_associated_executor(__t); } 270 271 template<typename _Tp, typename _Up> 272 auto 273 make_work_guard(const _Tp& __t, _Up&& __u) 274 -> decltype(net::make_work_guard( 275 net::get_associated_executor(__t, forward<_Up>(__u)))) 276 { 277 return net::make_work_guard( 278 net::get_associated_executor(__t, forward<_Up>(__u))); 279 } 280 281 /// Allows function objects to execute on any thread. 282 class system_executor; 283 284 /// The execution context associated with system_executor objects. 285 class system_context; 286 287 inline bool 288 operator==(const system_executor&, const system_executor&) { return true; } 289 290 inline bool 291 operator!=(const system_executor&, const system_executor&) { return false; } 292 293 /// Exception thrown by empty executors. 294 class bad_executor; 295 296 /// Polymorphic wrapper for types satisfying the Executor requirements. 297 class executor; 298 299 bool 300 operator==(const executor&, const executor&) noexcept; 301 302 bool 303 operator==(const executor&, nullptr_t) noexcept; 304 305 bool 306 operator==(nullptr_t, const executor&) noexcept; 307 308 bool 309 operator!=(const executor&, const executor&) noexcept; 310 311 bool 312 operator!=(const executor&, nullptr_t) noexcept; 313 314 bool 315 operator!=(nullptr_t, const executor&) noexcept; 316 317 void swap(executor&, executor&) noexcept; 318 319 // dispatch: 320 321 template<typename _CompletionToken> 322 __deduced_t<_CompletionToken, void()> 323 dispatch(_CompletionToken&& __token); 324 325 template<typename _Executor, typename _CompletionToken> 326 __deduced_t<_CompletionToken, void()> 327 dispatch(const _Executor& __ex, _CompletionToken&& __token); 328 329 template<typename _ExecutionContext, typename _CompletionToken> 330 __deduced_t<_CompletionToken, void()> 331 dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token); 332 333 // post: 334 335 template<typename _CompletionToken> 336 __deduced_t<_CompletionToken, void()> 337 post(_CompletionToken&& __token); 338 template<typename _Executor, typename _CompletionToken> 339 enable_if_t<is_executor<_Executor>::value, 340 __deduced_t<_CompletionToken, void()>> 341 post(const _Executor& __ex, _CompletionToken&& __token); 342 template<typename _ExecutionContext, typename _CompletionToken> 343 enable_if_t<__is_exec_context<_ExecutionContext>::value, 344 __deduced_t<_CompletionToken, void()>> 345 post(_ExecutionContext& __ctx, _CompletionToken&& __token); 346 347 // defer: 348 349 template<typename _CompletionToken> 350 __deduced_t<_CompletionToken, void()> 351 defer(_CompletionToken&& __token); 352 template<typename _Executor, typename _CompletionToken> 353 __deduced_t<_CompletionToken, void()> 354 defer(const _Executor& __ex, _CompletionToken&& __token); 355 template<typename _ExecutionContext, typename _CompletionToken> 356 __deduced_t<_CompletionToken, void()> 357 defer(_ExecutionContext& __ctx, _CompletionToken&& __token); 358 359 template<typename _Executor> 360 class strand; 361 362 template<typename _Executor> 363 bool 364 operator==(const strand<_Executor>& __a, const strand<_Executor>& __b); 365 366 template<typename _Executor> 367 bool 368 operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b) 369 { return !(__a == __b); } 370 371 template<typename _CompletionToken, typename _Signature, typename> 372 class async_result 373 { 374 public: 375 using completion_handler_type = _CompletionToken; 376 using return_type = void; 377 378 explicit async_result(completion_handler_type&) {} 379 async_result(const async_result&) = delete; 380 async_result& operator=(const async_result&) = delete; 381 382 return_type get() {} 383 }; 384 385 template<typename _CompletionToken, typename _Signature> 386 class async_completion 387 { 388 using __result_type 389 = async_result<decay_t<_CompletionToken>, _Signature>; 390 391 public: 392 using completion_handler_type 393 = typename __result_type::completion_handler_type; 394 395 private: 396 using __handler_type = __conditional_t< 397 is_same<_CompletionToken, completion_handler_type>::value, 398 completion_handler_type&, 399 completion_handler_type>; 400 401 public: 402 explicit 403 async_completion(_CompletionToken& __t) 404 : completion_handler(std::forward<__handler_type>(__t)), 405 result(completion_handler) 406 { } 407 408 async_completion(const async_completion&) = delete; 409 async_completion& operator=(const async_completion&) = delete; 410 411 __handler_type completion_handler; 412 __result_type result; 413 }; 414 415 416 class execution_context 417 { 418 public: 419 class service 420 { 421 protected: 422 // construct / copy / destroy: 423 424 explicit 425 service(execution_context& __owner) : _M_context(__owner) { } 426 427 service(const service&) = delete; 428 service& operator=(const service&) = delete; 429 430 virtual ~service() { } // TODO should not be inline 431 432 // service observers: 433 434 execution_context& context() const noexcept { return _M_context; } 435 436 private: 437 // service operations: 438 439 virtual void shutdown() noexcept = 0; 440 virtual void notify_fork(fork_event) { } 441 442 friend class execution_context; 443 execution_context& _M_context; 444 }; 445 446 // construct / copy / destroy: 447 448 execution_context() { } 449 450 execution_context(const execution_context&) = delete; 451 execution_context& operator=(const execution_context&) = delete; 452 453 virtual ~execution_context() 454 { 455 shutdown(); 456 destroy(); 457 } 458 459 // execution context operations: 460 461 void 462 notify_fork(fork_event __e) 463 { 464 auto __l = [=](auto& __svc) { __svc._M_ptr->notify_fork(__e); }; 465 if (__e == fork_event::prepare) 466 std::for_each(_M_services.rbegin(), _M_services.rend(), __l); 467 else 468 std::for_each(_M_services.begin(), _M_services.end(), __l); 469 } 470 471 protected: 472 // execution context protected operations: 473 474 void 475 shutdown() 476 { 477 std::for_each(_M_services.rbegin(), _M_services.rend(), 478 [=](auto& __svc) { 479 if (__svc._M_active) 480 { 481 __svc._M_ptr->shutdown(); 482 __svc._M_active = false; 483 } 484 }); 485 } 486 487 void 488 destroy() 489 { 490 while (_M_services.size()) 491 _M_services.pop_back(); 492 _M_keys.clear(); 493 } 494 495 protected: 496 497 template<typename _Service> 498 static void 499 _S_deleter(service* __svc) { delete static_cast<_Service*>(__svc); } 500 501 struct _ServicePtr 502 { 503 template<typename _Service> 504 explicit 505 _ServicePtr(_Service* __svc) 506 : _M_ptr(__svc, &_S_deleter<_Service>), _M_active(true) { } 507 508 std::unique_ptr<service, void(*)(service*)> _M_ptr; 509 bool _M_active; 510 }; 511 512 #if defined(_GLIBCXX_HAS_GTHREADS) 513 using mutex_type = std::mutex; 514 #else 515 struct mutex_type 516 { 517 void lock() const { } 518 void unlock() const { } 519 }; 520 #endif 521 mutable mutex_type _M_mutex; 522 523 // Sorted in order of beginning of service object lifetime. 524 std::list<_ServicePtr> _M_services; 525 526 template<typename _Service, typename... _Args> 527 service* 528 _M_add_svc(_Args&&... __args) 529 { 530 _M_services.push_back( 531 _ServicePtr{new _Service{*this, std::forward<_Args>(__args)...}} ); 532 return _M_services.back()._M_ptr.get(); 533 } 534 535 using __key_type = void(*)(); 536 537 template<typename _Key> 538 static __key_type 539 _S_key() { return reinterpret_cast<__key_type>(&_S_key<_Key>); } 540 541 std::unordered_map<__key_type, service*> _M_keys; 542 543 template<typename _Service> 544 friend typename _Service::key_type& 545 use_service(execution_context&); 546 547 template<typename _Service, typename... _Args> 548 friend _Service& 549 make_service(execution_context&, _Args&&...); 550 551 template<typename _Service> 552 friend bool 553 has_service(const execution_context&) noexcept; 554 }; 555 556 // service access: 557 558 template<typename _Service> 559 typename _Service::key_type& 560 use_service(execution_context& __ctx) 561 { 562 using _Key = typename _Service::key_type; 563 static_assert(is_base_of<execution_context::service, _Key>::value, 564 "a service type must derive from execution_context::service"); 565 static_assert(is_base_of<_Key, _Service>::value, 566 "a service type must match or derive from its key_type"); 567 auto __key = execution_context::_S_key<_Key>(); 568 lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex); 569 auto& __svc = __ctx._M_keys[__key]; 570 if (__svc == nullptr) 571 { 572 __try { 573 __svc = __ctx._M_add_svc<_Service>(); 574 } __catch(...) { 575 __ctx._M_keys.erase(__key); 576 __throw_exception_again; 577 } 578 } 579 return static_cast<_Key&>(*__svc); 580 } 581 582 template<typename _Service, typename... _Args> 583 _Service& 584 make_service(execution_context& __ctx, _Args&&... __args) 585 { 586 using _Key = typename _Service::key_type; 587 static_assert(is_base_of<execution_context::service, _Key>::value, 588 "a service type must derive from execution_context::service"); 589 static_assert(is_base_of<_Key, _Service>::value, 590 "a service type must match or derive from its key_type"); 591 auto __key = execution_context::_S_key<_Key>(); 592 lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex); 593 auto& __svc = __ctx._M_keys[__key]; 594 if (__svc != nullptr) 595 throw service_already_exists(); 596 __try { 597 __svc = __ctx._M_add_svc<_Service>(std::forward<_Args>(__args)...); 598 } __catch(...) { 599 __ctx._M_keys.erase(__key); 600 __throw_exception_again; 601 } 602 return static_cast<_Service&>(*__svc); 603 } 604 605 template<typename _Service> 606 inline bool 607 has_service(const execution_context& __ctx) noexcept 608 { 609 using _Key = typename _Service::key_type; 610 static_assert(is_base_of<execution_context::service, _Key>::value, 611 "a service type must derive from execution_context::service"); 612 static_assert(is_base_of<_Key, _Service>::value, 613 "a service type must match or derive from its key_type"); 614 lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex); 615 return __ctx._M_keys.count(execution_context::_S_key<_Key>()); 616 } 617 618 template<typename _Tp, typename = __void_t<>> 619 struct __is_executor_impl : false_type 620 { }; 621 622 // Check Executor requirements. 623 template<typename _Tp, typename _Up = remove_const_t<_Tp>> 624 auto 625 __executor_reqs(_Up* __x = 0, const _Up* __cx = 0, void(*__f)() = 0, 626 const allocator<int>& __a = {}) 627 -> enable_if_t<__is_value_constructible<_Tp>::value, __void_t< 628 decltype(*__cx == *__cx), 629 decltype(*__cx != *__cx), 630 decltype(__x->context()), 631 decltype(__x->on_work_started()), 632 decltype(__x->on_work_finished()), 633 decltype(__x->dispatch(std::move(__f), __a)), 634 decltype(__x->post(std::move(__f), __a)), 635 decltype(__x->defer(std::move(__f), __a)) 636 >>; 637 638 template<typename _Tp> 639 struct __is_executor_impl<_Tp, decltype(__executor_reqs<_Tp>())> 640 : true_type 641 { }; 642 643 template<typename _Tp> 644 struct is_executor : __is_executor_impl<_Tp> 645 { }; 646 647 template<typename _Tp> 648 constexpr bool is_executor_v = is_executor<_Tp>::value; 649 650 template<typename _Tp, typename _Executor, typename = __void_t<>> 651 struct __uses_executor_impl : false_type 652 { }; 653 654 template<typename _Tp, typename _Executor> 655 struct __uses_executor_impl<_Tp, _Executor, 656 __void_t<typename _Tp::executor_type>> 657 : is_convertible<_Executor, typename _Tp::executor_type> 658 { }; 659 660 template<typename _Tp, typename _Executor> 661 struct uses_executor : __uses_executor_impl<_Tp, _Executor>::type 662 { }; 663 664 template<typename _Tp, typename _Executor> 665 constexpr bool uses_executor_v = uses_executor<_Tp, _Executor>::value; 666 667 template<typename _Tp, typename _Executor> 668 class executor_binder 669 { 670 struct __use_exec { }; 671 672 public: 673 // types: 674 675 using target_type = _Tp; 676 using executor_type = _Executor; 677 678 // construct / copy / destroy: 679 680 executor_binder(_Tp __t, const _Executor& __ex) 681 : executor_binder(__use_exec{}, std::move(__t), __ex) 682 { } 683 684 executor_binder(const executor_binder&) = default; 685 executor_binder(executor_binder&&) = default; 686 687 template<typename _Up, typename _OtherExecutor> 688 executor_binder(const executor_binder<_Up, _OtherExecutor>& __other) 689 : executor_binder(__use_exec{}, __other.get(), __other.get_executor()) 690 { } 691 692 template<typename _Up, typename _OtherExecutor> 693 executor_binder(executor_binder<_Up, _OtherExecutor>&& __other) 694 : executor_binder(__use_exec{}, std::move(__other.get()), 695 __other.get_executor()) 696 { } 697 698 template<typename _Up, typename _OtherExecutor> 699 executor_binder(executor_arg_t, const _Executor& __ex, 700 const executor_binder<_Up, _OtherExecutor>& __other) 701 : executor_binder(__use_exec{}, __other.get(), __ex) 702 { } 703 704 template<typename _Up, typename _OtherExecutor> 705 executor_binder(executor_arg_t, const _Executor& __ex, 706 executor_binder<_Up, _OtherExecutor>&& __other) 707 : executor_binder(__use_exec{}, std::move(__other.get()), __ex) 708 { } 709 710 ~executor_binder(); 711 712 // executor binder access: 713 714 _Tp& get() noexcept { return _M_target; } 715 const _Tp& get() const noexcept { return _M_target; } 716 executor_type get_executor() const noexcept { return _M_ex; } 717 718 // executor binder invocation: 719 720 template<class... _Args> 721 result_of_t<_Tp&(_Args&&...)> 722 operator()(_Args&&... __args) 723 { return std::__invoke(get(), std::forward<_Args>(__args)...); } 724 725 template<class... _Args> 726 result_of_t<const _Tp&(_Args&&...)> 727 operator()(_Args&&... __args) const 728 { return std::__invoke(get(), std::forward<_Args>(__args)...); } 729 730 private: 731 template<typename _Up> 732 using __use_exec_cond 733 = __and_<uses_executor<_Tp, _Executor>, 734 is_constructible<_Tp, executor_arg_t, _Executor, _Up>>; 735 736 template<typename _Up, typename _Exec, typename = 737 enable_if_t<__use_exec_cond<_Up>::value>> 738 executor_binder(__use_exec, _Up&& __u, _Exec&& __ex) 739 : _M_ex(std::forward<_Exec>(__ex)), 740 _M_target(executor_arg, _M_ex, std::forward<_Up>(__u)) 741 { } 742 743 template<typename _Up, typename _Exec, typename = 744 enable_if_t<!__use_exec_cond<_Up>::value>> 745 executor_binder(__use_exec, _Up&& __u, const _Exec& __ex) 746 : _M_ex(std::forward<_Exec>(__ex)), 747 _M_target(std::forward<_Up>(__u)) 748 { } 749 750 _Executor _M_ex; 751 _Tp _M_target; 752 }; 753 754 template<typename _Tp, typename _Executor, typename _Signature> 755 class async_result<executor_binder<_Tp, _Executor>, _Signature> 756 { 757 using __inner = async_result<_Tp, _Signature>; 758 759 public: 760 using completion_handler_type = 761 executor_binder<typename __inner::completion_handler_type, _Executor>; 762 763 using return_type = typename __inner::return_type; 764 765 explicit 766 async_result(completion_handler_type& __h) 767 : _M_target(__h.get()) { } 768 769 async_result(const async_result&) = delete; 770 async_result& operator=(const async_result&) = delete; 771 772 return_type get() { return _M_target.get(); } 773 774 private: 775 __inner _M_target; 776 }; 777 778 template<typename _Tp, typename _Executor, typename _ProtoAlloc> 779 struct associated_allocator<executor_binder<_Tp, _Executor>, _ProtoAlloc> 780 { 781 using type = associated_allocator_t<_Tp, _ProtoAlloc>; 782 783 static type 784 get(const executor_binder<_Tp, _Executor>& __b, 785 const _ProtoAlloc& __a = _ProtoAlloc()) noexcept 786 { return associated_allocator<_Tp, _ProtoAlloc>::get(__b.get(), __a); } 787 }; 788 789 template<typename _Tp, typename _Executor, typename _Executor1> 790 struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1> 791 { 792 using type = _Executor; 793 794 static type 795 get(const executor_binder<_Tp, _Executor>& __b, 796 const _Executor1& = _Executor1()) noexcept 797 { return __b.get_executor(); } 798 }; 799 800 template<typename _Executor> 801 class executor_work_guard 802 { 803 public: 804 // types: 805 806 using executor_type = _Executor; 807 808 // construct / copy / destroy: 809 810 explicit 811 executor_work_guard(const executor_type& __ex) noexcept 812 : _M_ex(__ex), _M_owns(true) 813 { _M_ex.on_work_started(); } 814 815 executor_work_guard(const executor_work_guard& __other) noexcept 816 : _M_ex(__other._M_ex), _M_owns(__other._M_owns) 817 { 818 if (_M_owns) 819 _M_ex.on_work_started(); 820 } 821 822 executor_work_guard(executor_work_guard&& __other) noexcept 823 : _M_ex(__other._M_ex), _M_owns(__other._M_owns) 824 { __other._M_owns = false; } 825 826 executor_work_guard& operator=(const executor_work_guard&) = delete; 827 828 ~executor_work_guard() 829 { 830 if (_M_owns) 831 _M_ex.on_work_finished(); 832 } 833 834 // executor work guard observers: 835 836 executor_type get_executor() const noexcept { return _M_ex; } 837 838 bool owns_work() const noexcept { return _M_owns; } 839 840 // executor work guard modifiers: 841 842 void reset() noexcept 843 { 844 if (_M_owns) 845 _M_ex.on_work_finished(); 846 _M_owns = false; 847 } 848 849 private: 850 _Executor _M_ex; 851 bool _M_owns; 852 }; 853 854 855 class system_context : public execution_context 856 { 857 public: 858 // types: 859 860 using executor_type = system_executor; 861 862 // construct / copy / destroy: 863 864 system_context() = delete; 865 system_context(const system_context&) = delete; 866 system_context& operator=(const system_context&) = delete; 867 868 ~system_context() 869 { 870 stop(); 871 join(); 872 } 873 874 // system_context operations: 875 876 executor_type get_executor() noexcept; 877 878 void stop() 879 { 880 lock_guard<mutex_type> __lock(_M_mtx); 881 _M_stopped = true; 882 _M_cv.notify_all(); 883 } 884 885 bool stopped() const noexcept 886 { 887 lock_guard<mutex_type> __lock(_M_mtx); 888 return _M_stopped; 889 } 890 891 void join() 892 { 893 if (_M_thread.joinable()) 894 _M_thread.join(); 895 } 896 897 private: 898 friend system_executor; 899 900 struct __tag { explicit __tag() = default; }; 901 system_context(__tag) { } 902 903 #ifndef _GLIBCXX_HAS_GTHREADS 904 struct thread 905 { 906 bool joinable() const { return false; } 907 void join() { } 908 }; 909 struct condition_variable 910 { 911 void notify_all() { } 912 }; 913 #endif 914 915 thread _M_thread; 916 mutable mutex_type _M_mtx; // XXX can we reuse base's _M_mutex? 917 condition_variable _M_cv; 918 queue<function<void()>> _M_tasks; 919 bool _M_stopped = false; 920 921 #ifdef _GLIBCXX_HAS_GTHREADS 922 void 923 _M_run() 924 { 925 while (true) 926 { 927 function<void()> __f; 928 { 929 unique_lock<mutex_type> __lock(_M_mtx); 930 _M_cv.wait(__lock, 931 [this]{ return _M_stopped || !_M_tasks.empty(); }); 932 if (_M_stopped) 933 return; 934 __f = std::move(_M_tasks.front()); 935 _M_tasks.pop(); 936 } 937 __f(); 938 } 939 } 940 #endif 941 942 void 943 _M_post(std::function<void()> __f __attribute__((__unused__))) 944 { 945 lock_guard<mutex_type> __lock(_M_mtx); 946 if (_M_stopped) 947 return; 948 #ifdef _GLIBCXX_HAS_GTHREADS 949 if (!_M_thread.joinable()) 950 _M_thread = std::thread(&system_context::_M_run, this); 951 _M_tasks.push(std::move(__f)); // XXX allocator not used 952 _M_cv.notify_one(); 953 #else 954 __throw_system_error(EOPNOTSUPP); 955 #endif 956 } 957 958 static system_context& 959 _S_get() noexcept 960 { 961 static system_context __sc(__tag{}); 962 return __sc; 963 } 964 }; 965 966 class system_executor 967 { 968 public: 969 // executor operations: 970 971 system_executor() { } 972 973 system_context& 974 context() const noexcept { return system_context::_S_get(); } 975 976 void on_work_started() const noexcept { } 977 void on_work_finished() const noexcept { } 978 979 template<typename _Func, typename _ProtoAlloc> 980 void 981 dispatch(_Func&& __f, const _ProtoAlloc& __a) const 982 { decay_t<_Func>{std::forward<_Func>(__f)}(); } 983 984 template<typename _Func, typename _ProtoAlloc> 985 void 986 post(_Func&& __f, const _ProtoAlloc&) const // XXX allocator not used 987 { 988 system_context::_S_get()._M_post(std::forward<_Func>(__f)); 989 } 990 991 template<typename _Func, typename _ProtoAlloc> 992 void 993 defer(_Func&& __f, const _ProtoAlloc& __a) const 994 { post(std::forward<_Func>(__f), __a); } 995 }; 996 997 inline system_executor 998 system_context::get_executor() noexcept 999 { return {}; } 1000 1001 class bad_executor : public std::exception 1002 { 1003 virtual const char* what() const noexcept { return "bad executor"; } 1004 }; 1005 1006 inline void __throw_bad_executor() // TODO make non-inline 1007 { 1008 #if __cpp_exceptions 1009 throw bad_executor(); 1010 #else 1011 __builtin_abort(); 1012 #endif 1013 } 1014 1015 class executor 1016 { 1017 template<typename _Executor> 1018 using _Context_t = decltype(std::declval<_Executor&>().context()); 1019 1020 public: 1021 // construct / copy / destroy: 1022 1023 executor() noexcept = default; 1024 1025 executor(nullptr_t) noexcept { } 1026 executor(const executor&) noexcept = default; 1027 executor(executor&&) noexcept = default; 1028 1029 template<typename _Executor, 1030 typename = _Require<is_lvalue_reference<_Context_t<_Executor>>>> 1031 executor(_Executor __e) 1032 : _M_target(make_shared<_Tgt1<_Executor>>(std::move(__e))) 1033 { } 1034 1035 template<typename _Executor, typename _ProtoAlloc, 1036 typename = _Require<is_lvalue_reference<_Context_t<_Executor>>>> 1037 executor(allocator_arg_t, const _ProtoAlloc& __a, _Executor __e) 1038 : _M_target(allocate_shared<_Tgt2<_Executor, _ProtoAlloc>>(__a, 1039 std::move(__e), __a)) 1040 { } 1041 1042 executor& operator=(const executor&) noexcept = default; 1043 executor& operator=(executor&&) noexcept = default; 1044 1045 executor& 1046 operator=(nullptr_t) noexcept 1047 { 1048 _M_target = nullptr; 1049 return *this; 1050 } 1051 1052 template<typename _Executor> 1053 executor& 1054 operator=(_Executor __e) 1055 { 1056 executor(std::move(__e)).swap(*this); 1057 return *this; 1058 } 1059 1060 ~executor() = default; 1061 1062 // executor modifiers: 1063 1064 void 1065 swap(executor& __other) noexcept 1066 { _M_target.swap(__other._M_target); } 1067 1068 template<typename _Executor, typename _Alloc> 1069 void 1070 assign(_Executor __e, const _Alloc& __a) 1071 { executor(allocator_arg, __a, std::move(__e)).swap(*this); } 1072 1073 // executor operations: 1074 1075 execution_context& 1076 context() const noexcept 1077 { 1078 __glibcxx_assert( _M_target ); 1079 return _M_target->context(); 1080 } 1081 1082 void 1083 on_work_started() const noexcept 1084 { 1085 __glibcxx_assert( _M_target ); 1086 return _M_target->on_work_started(); 1087 } 1088 1089 void 1090 on_work_finished() const noexcept 1091 { 1092 __glibcxx_assert( _M_target ); 1093 return _M_target->on_work_finished(); 1094 } 1095 1096 template<typename _Func, typename _Alloc> 1097 void 1098 dispatch(_Func&& __f, const _Alloc& __a) const 1099 { 1100 if (!_M_target) 1101 __throw_bad_executor(); 1102 // _M_target->dispatch({allocator_arg, __a, std::forward<_Func>(__f)}); 1103 _M_target->dispatch(std::forward<_Func>(__f)); 1104 } 1105 1106 template<typename _Func, typename _Alloc> 1107 void 1108 post(_Func&& __f, const _Alloc& __a) const 1109 { 1110 if (!_M_target) 1111 __throw_bad_executor(); 1112 // _M_target->post({allocator_arg, __a, std::forward<_Func>(__f)}); 1113 _M_target->post(std::forward<_Func>(__f)); 1114 } 1115 1116 template<typename _Func, typename _Alloc> 1117 void 1118 defer(_Func&& __f, const _Alloc& __a) const 1119 { 1120 if (!_M_target) 1121 __throw_bad_executor(); 1122 // _M_target->defer({allocator_arg, __a, std::forward<_Func>(__f)}); 1123 _M_target->defer(std::forward<_Func>(__f)); 1124 } 1125 1126 // executor capacity: 1127 1128 explicit operator bool() const noexcept 1129 { return static_cast<bool>(_M_target); } 1130 1131 // executor target access: 1132 1133 #if __cpp_rtti 1134 const type_info& 1135 target_type() const noexcept 1136 { 1137 if (_M_target) 1138 return *static_cast<const type_info*>(_M_target->target_type()); 1139 return typeid(void); 1140 } 1141 #endif 1142 1143 template<typename _Executor> 1144 _Executor* 1145 target() noexcept 1146 { 1147 void* __p = nullptr; 1148 if (_M_target) 1149 { 1150 if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func) 1151 __p = _M_target->_M_func(_M_target.get(), nullptr); 1152 #if __cpp_rtti 1153 else 1154 __p = _M_target->target(&typeid(_Executor)); 1155 #endif 1156 } 1157 return static_cast<_Executor*>(__p); 1158 } 1159 1160 template<typename _Executor> 1161 const _Executor* 1162 target() const noexcept 1163 { 1164 const void* __p = nullptr; 1165 if (_M_target) 1166 { 1167 if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func) 1168 return (_Executor*)_M_target->_M_func(_M_target.get(), nullptr); 1169 #if __cpp_rtti 1170 else 1171 __p = _M_target->target(&typeid(_Executor)); 1172 #endif 1173 } 1174 return static_cast<const _Executor*>(__p); 1175 } 1176 1177 private: 1178 struct _Tgt 1179 { 1180 virtual void on_work_started() const noexcept = 0; 1181 virtual void on_work_finished() const noexcept = 0; 1182 virtual execution_context& context() const noexcept = 0; 1183 virtual void dispatch(std::function<void()>) const = 0; 1184 virtual void post(std::function<void()>) const = 0; 1185 virtual void defer(std::function<void()>) const = 0; 1186 virtual const void* target_type() const noexcept = 0; 1187 virtual void* target(const void*) noexcept = 0; 1188 virtual bool _M_equals(_Tgt*) const noexcept = 0; 1189 1190 using _Func = void* (_Tgt*, const _Tgt*); 1191 _Func* _M_func; // Provides access to target without RTTI 1192 }; 1193 1194 template<typename _Ex> 1195 struct _Tgt1 : _Tgt 1196 { 1197 explicit 1198 _Tgt1(_Ex&& __ex) 1199 : _M_ex(std::move(__ex)) 1200 { this->_M_func = &_S_func; } 1201 1202 void 1203 on_work_started() const noexcept override 1204 { _M_ex.on_work_started(); } 1205 1206 void 1207 on_work_finished() const noexcept override 1208 { _M_ex.on_work_finished(); } 1209 1210 execution_context& 1211 context() const noexcept override 1212 { return _M_ex.context(); } 1213 1214 void 1215 dispatch(std::function<void()> __f) const override 1216 { _M_ex.dispatch(std::move(__f), allocator<void>()); } 1217 1218 void 1219 post(std::function<void()> __f) const override 1220 { _M_ex.post(std::move(__f), allocator<void>()); } 1221 1222 void 1223 defer(std::function<void()> __f) const override 1224 { _M_ex.defer(std::move(__f), allocator<void>()); } 1225 1226 const void* 1227 target_type() const noexcept override 1228 { 1229 #if __cpp_rtti 1230 return &typeid(_Ex); 1231 #else 1232 return nullptr; 1233 #endif 1234 } 1235 1236 void* 1237 target(const void* __ti) noexcept override 1238 { 1239 #if __cpp_rtti 1240 if (*static_cast<const type_info*>(__ti) == typeid(_Ex)) 1241 return std::__addressof(_M_ex); 1242 #endif 1243 return nullptr; 1244 } 1245 1246 bool 1247 _M_equals(_Tgt* __tgt) const noexcept override 1248 { 1249 #if __cpp_rtti 1250 if (const void* __p = __tgt->target(&typeid(_Ex))) 1251 return *static_cast<const _Ex*>(__p) == _M_ex; 1252 #endif 1253 return false; 1254 } 1255 1256 _Ex _M_ex [[__no_unique_address__]]; 1257 1258 static void* 1259 _S_func(_Tgt* __p, const _Tgt* __q) noexcept 1260 { 1261 auto& __ex = static_cast<_Tgt1*>(__p)->_M_ex; 1262 if (__q) 1263 { 1264 if (__ex == static_cast<const _Tgt1*>(__q)->_M_ex) 1265 return __p; 1266 else 1267 return nullptr; 1268 } 1269 else 1270 return std::__addressof(__ex); 1271 } 1272 }; 1273 1274 template<typename _Ex, typename _Alloc> 1275 struct _Tgt2 : _Tgt1<_Ex> 1276 { 1277 explicit 1278 _Tgt2(_Ex&& __ex, const _Alloc& __a) 1279 : _Tgt1<_Ex>(std::move(__ex)), _M_alloc(__a) { } 1280 1281 void 1282 dispatch(std::function<void()> __f) const override 1283 { this->_M_ex.dispatch(std::move(__f), _M_alloc); } 1284 1285 void 1286 post(std::function<void()> __f) const override 1287 { this->_M_ex.post(std::move(__f), _M_alloc); } 1288 1289 void 1290 defer(std::function<void()> __f) const override 1291 { this->_M_ex.defer(std::move(__f), _M_alloc); } 1292 1293 _Alloc _M_alloc [[__no_unique_address__]]; 1294 }; 1295 1296 // Partial specialization for std::allocator<T>. 1297 // Don't store the allocator. 1298 template<typename _Ex, typename _Tp> 1299 struct _Tgt2<_Ex, std::allocator<_Tp>> : _Tgt1<_Ex> 1300 { }; 1301 1302 friend bool 1303 operator==(const executor& __a, const executor& __b) noexcept 1304 { 1305 _Tgt* __ta = __a._M_target.get(); 1306 _Tgt* __tb = __b._M_target.get(); 1307 if (__ta == __tb) 1308 return true; 1309 if (!__ta || !__tb) 1310 return false; 1311 if (__ta->_M_func == __tb->_M_func) 1312 return __ta->_M_func(__ta, __tb); 1313 return __ta->_M_equals(__tb); 1314 } 1315 1316 shared_ptr<_Tgt> _M_target; 1317 }; 1318 1319 template<> struct is_executor<executor> : true_type { }; 1320 1321 /// executor comparisons 1322 inline bool 1323 operator==(const executor& __e, nullptr_t) noexcept 1324 { return !__e; } 1325 1326 inline bool 1327 operator==(nullptr_t, const executor& __e) noexcept 1328 { return !__e; } 1329 1330 inline bool 1331 operator!=(const executor& __a, const executor& __b) noexcept 1332 { return !(__a == __b); } 1333 1334 inline bool 1335 operator!=(const executor& __e, nullptr_t) noexcept 1336 { return (bool)__e; } 1337 1338 inline bool 1339 operator!=(nullptr_t, const executor& __e) noexcept 1340 { return (bool)__e; } 1341 1342 /// Swap two executor objects. 1343 inline void swap(executor& __a, executor& __b) noexcept { __a.swap(__b); } 1344 1345 1346 template<typename _CompletionHandler> 1347 struct __dispatcher 1348 { 1349 explicit 1350 __dispatcher(_CompletionHandler& __h) 1351 : _M_h(std::move(__h)), _M_w(net::make_work_guard(_M_h)) 1352 { } 1353 1354 void operator()() 1355 { 1356 auto __alloc = net::get_associated_allocator(_M_h); 1357 _M_w.get_executor().dispatch(std::move(_M_h), __alloc); 1358 _M_w.reset(); 1359 } 1360 1361 _CompletionHandler _M_h; 1362 decltype(net::make_work_guard(_M_h)) _M_w; 1363 }; 1364 1365 template<typename _CompletionHandler> 1366 inline __dispatcher<_CompletionHandler> 1367 __make_dispatcher(_CompletionHandler& __h) 1368 { return __dispatcher<_CompletionHandler>{__h}; } 1369 1370 1371 1372 // dispatch: 1373 1374 template<typename _CompletionToken> 1375 inline __deduced_t<_CompletionToken, void()> 1376 dispatch(_CompletionToken&& __token) 1377 { 1378 async_completion<_CompletionToken, void()> __cmpl{__token}; 1379 auto __ex = net::get_associated_executor(__cmpl.completion_handler); 1380 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1381 __ex.dispatch(std::move(__cmpl.completion_handler), __alloc); 1382 return __cmpl.result.get(); 1383 } 1384 1385 template<typename _Executor, typename _CompletionToken> 1386 inline 1387 enable_if_t<is_executor<_Executor>::value, 1388 __deduced_t<_CompletionToken, void()>> 1389 dispatch(const _Executor& __ex, _CompletionToken&& __token) 1390 { 1391 async_completion<_CompletionToken, void()> __cmpl{__token}; 1392 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1393 __ex.dispatch(net::__make_dispatcher(__cmpl.completion_handler), 1394 __alloc); 1395 return __cmpl.result.get(); 1396 } 1397 1398 template<typename _ExecutionContext, typename _CompletionToken> 1399 inline 1400 enable_if_t<__is_exec_context<_ExecutionContext>::value, 1401 __deduced_t<_CompletionToken, void()>> 1402 dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token) 1403 { 1404 return net::dispatch(__ctx.get_executor(), 1405 forward<_CompletionToken>(__token)); 1406 } 1407 1408 // post: 1409 1410 template<typename _CompletionToken> 1411 inline __deduced_t<_CompletionToken, void()> 1412 post(_CompletionToken&& __token) 1413 { 1414 async_completion<_CompletionToken, void()> __cmpl{__token}; 1415 auto __ex = net::get_associated_executor(__cmpl.completion_handler); 1416 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1417 __ex.post(std::move(__cmpl.completion_handler), __alloc); 1418 return __cmpl.result.get(); 1419 } 1420 1421 template<typename _Executor, typename _CompletionToken> 1422 inline 1423 enable_if_t<is_executor<_Executor>::value, 1424 __deduced_t<_CompletionToken, void()>> 1425 post(const _Executor& __ex, _CompletionToken&& __token) 1426 { 1427 async_completion<_CompletionToken, void()> __cmpl{__token}; 1428 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1429 __ex.post(net::__make_dispatcher(__cmpl.completion_handler), __alloc); 1430 return __cmpl.result.get(); 1431 } 1432 1433 template<typename _ExecutionContext, typename _CompletionToken> 1434 inline 1435 enable_if_t<__is_exec_context<_ExecutionContext>::value, 1436 __deduced_t<_CompletionToken, void()>> 1437 post(_ExecutionContext& __ctx, _CompletionToken&& __token) 1438 { 1439 return net::post(__ctx.get_executor(), 1440 forward<_CompletionToken>(__token)); 1441 } 1442 1443 // defer: 1444 1445 template<typename _CompletionToken> 1446 inline __deduced_t<_CompletionToken, void()> 1447 defer(_CompletionToken&& __token) 1448 { 1449 async_completion<_CompletionToken, void()> __cmpl{__token}; 1450 auto __ex = net::get_associated_executor(__cmpl.completion_handler); 1451 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1452 __ex.defer(std::move(__cmpl.completion_handler), __alloc); 1453 return __cmpl.result.get(); 1454 } 1455 1456 template<typename _Executor, typename _CompletionToken> 1457 inline 1458 enable_if_t<is_executor<_Executor>::value, 1459 __deduced_t<_CompletionToken, void()>> 1460 defer(const _Executor& __ex, _CompletionToken&& __token) 1461 { 1462 async_completion<_CompletionToken, void()> __cmpl{__token}; 1463 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1464 __ex.defer(net::__make_dispatcher(__cmpl.completion_handler), __alloc); 1465 return __cmpl.result.get(); 1466 } 1467 1468 template<typename _ExecutionContext, typename _CompletionToken> 1469 inline 1470 enable_if_t<__is_exec_context<_ExecutionContext>::value, 1471 __deduced_t<_CompletionToken, void()>> 1472 defer(_ExecutionContext& __ctx, _CompletionToken&& __token) 1473 { 1474 return net::defer(__ctx.get_executor(), 1475 forward<_CompletionToken>(__token)); 1476 } 1477 1478 1479 template<typename _Executor> 1480 class strand 1481 { 1482 public: 1483 // types: 1484 1485 using inner_executor_type = _Executor; 1486 1487 // construct / copy / destroy: 1488 1489 strand(); // TODO make state 1490 1491 explicit strand(_Executor __ex) : _M_inner_ex(__ex) { } // TODO make state 1492 1493 template<typename _Alloc> 1494 strand(allocator_arg_t, const _Alloc& __a, _Executor __ex) 1495 : _M_inner_ex(__ex) { } // TODO make state 1496 1497 strand(const strand& __other) noexcept 1498 : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { } 1499 1500 strand(strand&& __other) noexcept 1501 : _M_state(std::move(__other._M_state)), 1502 _M_inner_ex(std::move(__other._M_inner_ex)) { } 1503 1504 template<typename _OtherExecutor> 1505 strand(const strand<_OtherExecutor>& __other) noexcept 1506 : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { } 1507 1508 template<typename _OtherExecutor> 1509 strand(strand<_OtherExecutor>&& __other) noexcept 1510 : _M_state(std::move(__other._M_state)), 1511 _M_inner_ex(std::move(__other._M_inner_ex)) { } 1512 1513 strand& 1514 operator=(const strand& __other) noexcept 1515 { 1516 static_assert(is_copy_assignable<_Executor>::value, 1517 "inner executor type must be CopyAssignable"); 1518 1519 // TODO lock __other 1520 // TODO copy state 1521 _M_inner_ex = __other._M_inner_ex; 1522 return *this; 1523 } 1524 1525 strand& 1526 operator=(strand&& __other) noexcept 1527 { 1528 static_assert(is_move_assignable<_Executor>::value, 1529 "inner executor type must be MoveAssignable"); 1530 1531 // TODO move state 1532 _M_inner_ex = std::move(__other._M_inner_ex); 1533 return *this; 1534 } 1535 1536 template<typename _OtherExecutor> 1537 strand& 1538 operator=(const strand<_OtherExecutor>& __other) noexcept 1539 { 1540 static_assert(is_convertible<_OtherExecutor, _Executor>::value, 1541 "inner executor type must be compatible"); 1542 1543 // TODO lock __other 1544 // TODO copy state 1545 _M_inner_ex = __other._M_inner_ex; 1546 return *this; 1547 } 1548 1549 template<typename _OtherExecutor> 1550 strand& 1551 operator=(strand<_OtherExecutor>&& __other) noexcept 1552 { 1553 static_assert(is_convertible<_OtherExecutor, _Executor>::value, 1554 "inner executor type must be compatible"); 1555 1556 // TODO move state 1557 _M_inner_ex = std::move(__other._M_inner_ex); 1558 return *this; 1559 } 1560 1561 ~strand() 1562 { 1563 // the task queue outlives this object if non-empty 1564 // TODO create circular ref in queue? 1565 } 1566 1567 // strand operations: 1568 1569 inner_executor_type 1570 get_inner_executor() const noexcept 1571 { return _M_inner_ex; } 1572 1573 bool 1574 running_in_this_thread() const noexcept 1575 { return _M_state->running_in_this_thread(); } 1576 1577 execution_context& 1578 context() const noexcept 1579 { return _M_inner_ex.context(); } 1580 1581 void on_work_started() const noexcept { _M_inner_ex.on_work_started(); } 1582 void on_work_finished() const noexcept { _M_inner_ex.on_work_finished(); } 1583 1584 template<typename _Func, typename _Alloc> 1585 void 1586 dispatch(_Func&& __f, const _Alloc& __a) const 1587 { 1588 if (running_in_this_thread()) 1589 decay_t<_Func>{std::forward<_Func>(__f)}(); 1590 else 1591 post(std::forward<_Func>(__f), __a); 1592 } 1593 1594 template<typename _Func, typename _Alloc> 1595 void 1596 post(_Func&& __f, const _Alloc& __a) const; // TODO 1597 1598 template<typename _Func, typename _Alloc> 1599 void 1600 defer(_Func&& __f, const _Alloc& __a) const 1601 { post(std::forward<_Func>(__f), __a); } 1602 1603 private: 1604 friend bool 1605 operator==(const strand& __a, const strand& __b) 1606 { return __a._M_state == __b._M_state; } 1607 1608 // TODO add synchronised queue 1609 struct _State 1610 { 1611 #if defined(_GLIBCXX_HAS_GTHREADS) 1612 bool 1613 running_in_this_thread() const noexcept 1614 { return std::this_thread::get_id() == _M_running_on; } 1615 1616 std::thread::id _M_running_on; 1617 #else 1618 bool running_in_this_thread() const { return true; } 1619 #endif 1620 }; 1621 shared_ptr<_State> _M_state; 1622 _Executor _M_inner_ex; 1623 }; 1624 1625 #if defined(_GLIBCXX_HAS_GTHREADS) 1626 1627 // Completion token for asynchronous operations initiated with use_future. 1628 template<typename _Func, typename _Alloc> 1629 struct __use_future_ct 1630 { 1631 std::tuple<_Func, _Alloc> _M_t; 1632 }; 1633 1634 template<typename _Func, typename _Tp> 1635 struct __use_future_ct<_Func, std::allocator<_Tp>> 1636 { 1637 _Func _M_f; 1638 }; 1639 1640 template<typename _ProtoAllocator = allocator<void>> 1641 class use_future_t 1642 { 1643 public: 1644 // use_future_t types: 1645 using allocator_type = _ProtoAllocator; 1646 1647 // use_future_t members: 1648 constexpr 1649 use_future_t() 1650 noexcept(is_nothrow_default_constructible<_ProtoAllocator>::value) 1651 : _M_alloc() { } 1652 1653 explicit 1654 use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { } 1655 1656 template<typename _OtherAllocator> 1657 use_future_t<_OtherAllocator> 1658 rebind(const _OtherAllocator& __a) const noexcept 1659 { return use_future_t<_OtherAllocator>(__a); } 1660 1661 allocator_type get_allocator() const noexcept { return _M_alloc; } 1662 1663 template<typename _Func> 1664 auto 1665 operator()(_Func&& __f) const 1666 { 1667 using _Token = __use_future_ct<decay_t<_Func>, _ProtoAllocator>; 1668 return _Token{ {std::forward<_Func>(__f), _M_alloc} }; 1669 } 1670 1671 private: 1672 _ProtoAllocator _M_alloc; 1673 }; 1674 1675 template<typename _Tp> 1676 class use_future_t<std::allocator<_Tp>> 1677 { 1678 public: 1679 // use_future_t types: 1680 using allocator_type = std::allocator<_Tp>; 1681 1682 // use_future_t members: 1683 constexpr use_future_t() noexcept = default; 1684 1685 explicit 1686 use_future_t(const allocator_type& __a) noexcept { } 1687 1688 template<class _Up> 1689 use_future_t<std::allocator<_Up>> 1690 rebind(const std::allocator<_Up>& __a) const noexcept 1691 { return use_future_t<std::allocator<_Up>>(__a); } 1692 1693 allocator_type get_allocator() const noexcept { return {}; } 1694 1695 template<typename _Func> 1696 auto 1697 operator()(_Func&& __f) const 1698 { 1699 using _Token = __use_future_ct<decay_t<_Func>, allocator_type>; 1700 return _Token{std::forward<_Func>(__f)}; 1701 } 1702 }; 1703 1704 constexpr use_future_t<> use_future = use_future_t<>(); 1705 1706 template<typename _Func, typename _Alloc, typename _Res, typename... _Args> 1707 class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>; 1708 1709 template<typename _Result, typename _Executor> 1710 struct __use_future_ex; 1711 1712 // Completion handler for asynchronous operations initiated with use_future. 1713 template<typename _Func, typename... _Args> 1714 struct __use_future_ch 1715 { 1716 template<typename _Alloc> 1717 explicit 1718 __use_future_ch(__use_future_ct<_Func, _Alloc>&& __token) 1719 : _M_f{ std::move(std::get<0>(__token._M_t)) }, 1720 _M_promise{ std::get<1>(__token._M_t) } 1721 { } 1722 1723 template<typename _Tp> 1724 explicit 1725 __use_future_ch(__use_future_ct<_Func, std::allocator<_Tp>>&& __token) 1726 : _M_f{ std::move(__token._M_f) } 1727 { } 1728 1729 void 1730 operator()(_Args&&... __args) 1731 { 1732 __try 1733 { 1734 _M_promise.set_value(_M_f(std::forward<_Args>(__args)...)); 1735 } 1736 __catch(__cxxabiv1::__forced_unwind&) 1737 { 1738 __throw_exception_again; 1739 } 1740 __catch(...) 1741 { 1742 _M_promise.set_exception(std::current_exception()); 1743 } 1744 } 1745 1746 using __result = result_of_t<_Func(decay_t<_Args>...)>; 1747 1748 future<__result> get_future() { return _M_promise.get_future(); } 1749 1750 private: 1751 template<typename _Result, typename _Executor> 1752 friend struct __use_future_ex; 1753 1754 _Func _M_f; 1755 mutable promise<__result> _M_promise; 1756 }; 1757 1758 // Specialization of async_result for operations initiated with use_future. 1759 template<typename _Func, typename _Alloc, typename _Res, typename... _Args> 1760 class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)> 1761 { 1762 public: 1763 using completion_handler_type = __use_future_ch<_Func, _Args...>; 1764 using return_type = future<typename completion_handler_type::__result>; 1765 1766 explicit 1767 async_result(completion_handler_type& __h) 1768 : _M_future(__h.get_future()) 1769 { } 1770 1771 async_result(const async_result&) = delete; 1772 async_result& operator=(const async_result&) = delete; 1773 1774 return_type get() { return std::move(_M_future); } 1775 1776 private: 1777 return_type _M_future; 1778 }; 1779 1780 template<typename _Result, typename _Executor> 1781 struct __use_future_ex 1782 { 1783 template<typename _Handler> 1784 __use_future_ex(const _Handler& __h, _Executor __ex) 1785 : _M_t(__h._M_promise, __ex) 1786 { } 1787 1788 template<typename _Fn, typename _Alloc> 1789 void 1790 dispatch(_Fn&& __fn) 1791 { 1792 __try 1793 { 1794 std::get<1>(_M_t).dispatch(std::forward<_Fn>(__fn)); 1795 } 1796 __catch(__cxxabiv1::__forced_unwind&) 1797 { 1798 __throw_exception_again; 1799 } 1800 __catch(...) 1801 { 1802 std::get<0>(_M_t).set_exception(std::current_exception()); 1803 } 1804 } 1805 1806 template<typename _Fn, typename _Alloc> 1807 void 1808 post(_Fn&& __fn) 1809 { 1810 __try 1811 { 1812 std::get<1>(_M_t).post(std::forward<_Fn>(__fn)); 1813 } 1814 __catch(__cxxabiv1::__forced_unwind&) 1815 { 1816 __throw_exception_again; 1817 } 1818 __catch(...) 1819 { 1820 std::get<0>(_M_t).set_exception(std::current_exception()); 1821 } 1822 } 1823 1824 template<typename _Fn, typename _Alloc> 1825 void 1826 defer(_Fn&& __fn) 1827 { 1828 __try 1829 { 1830 std::get<1>(_M_t).defer(std::forward<_Fn>(__fn)); 1831 } 1832 __catch(__cxxabiv1::__forced_unwind&) 1833 { 1834 __throw_exception_again; 1835 } 1836 __catch(...) 1837 { 1838 std::get<0>(_M_t).set_exception(std::current_exception()); 1839 } 1840 } 1841 1842 private: 1843 tuple<promise<_Result>&, _Executor> _M_t; 1844 }; 1845 1846 template<typename _Func, typename... _Args, typename _Executor> 1847 struct associated_executor<__use_future_ch<_Func, _Args...>, _Executor> 1848 { 1849 private: 1850 using __handler = __use_future_ch<_Func, _Args...>; 1851 1852 using type = __use_future_ex<typename __handler::__result, _Executor>; 1853 1854 static type 1855 get(const __handler& __h, const _Executor& __ex) 1856 { return { __h, __ex }; } 1857 }; 1858 1859 #if 0 1860 1861 // [async.use.future.traits] 1862 template<typename _Allocator, typename _Ret, typename... _Args> 1863 class handler_type<use_future_t<_Allocator>, _Ret(_Args...)> // TODO uglify name 1864 { 1865 template<typename... _Args> 1866 struct __is_error_result : false_type { }; 1867 1868 template<typename... _Args> 1869 struct __is_error_result<error_code, _Args...> : true_type { }; 1870 1871 template<typename... _Args> 1872 struct __is_error_result<exception_ptr, _Args...> : true_type { }; 1873 1874 static exception_ptr 1875 _S_exptr(exception_ptr& __ex) 1876 { return std::move(__ex); } 1877 1878 static exception_ptr 1879 _S_exptr(const error_code& __ec) 1880 { return make_exception_ptr(system_error(__ec)); } 1881 1882 template<bool _IsError, typename... _UArgs> 1883 struct _Type; 1884 1885 // N == 0 1886 template<bool _IsError> 1887 struct _Type<_IsError> 1888 { 1889 std::promise<void> _M_promise; 1890 1891 void 1892 operator()() 1893 { 1894 _M_promise.set_value(); 1895 } 1896 }; 1897 1898 // N == 1, U0 is error_code or exception_ptr 1899 template<typename _UArg0> 1900 struct _Type<true, _UArg0> 1901 { 1902 std::promise<void> _M_promise; 1903 1904 template<typename _Arg0> 1905 void 1906 operator()(_Arg0&& __a0) 1907 { 1908 if (__a0) 1909 _M_promise.set_exception(_S_exptr(__a0)); 1910 else 1911 _M_promise.set_value(); 1912 } 1913 }; 1914 1915 // N == 1, U0 is not error_code or exception_ptr 1916 template<typename _UArg0> 1917 struct _Type<false, _UArg0> 1918 { 1919 std::promise<_UArg0> _M_promise; 1920 1921 template<typename _Arg0> 1922 void 1923 operator()(_Arg0&& __a0) 1924 { 1925 _M_promise.set_value(std::forward<_Arg0>(__a0)); 1926 } 1927 }; 1928 1929 // N == 2, U0 is error_code or exception_ptr 1930 template<typename _UArg0, typename _UArg1> 1931 struct _Type<true, _UArg0, _UArg1> 1932 { 1933 std::promise<_UArg1> _M_promise; 1934 1935 template<typename _Arg0, typename _Arg1> 1936 void 1937 operator()(_Arg0&& __a0, _Arg1&& __a1) 1938 { 1939 if (__a0) 1940 _M_promise.set_exception(_S_exptr(__a0)); 1941 else 1942 _M_promise.set_value(std::forward<_Arg1>(__a1)); 1943 } 1944 }; 1945 1946 // N >= 2, U0 is not error_code or exception_ptr 1947 template<typename... _UArgs> 1948 struct _Type<false, _UArgs...> 1949 { 1950 static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization"); 1951 1952 std::promise<tuple<_UArgs...>> _M_promise; 1953 1954 template<typename... _Args> 1955 void 1956 operator()(_Args&&... __args) 1957 { 1958 _M_promise.set_value( 1959 std::forward_as_tuple(std::forward<_Args>(__args)...)); 1960 } 1961 }; 1962 1963 // N > 2, U0 is error_code or exception_ptr 1964 template<typename _UArg0, typename... _UArgs> 1965 struct _Type<true, _UArg0, _UArgs...> 1966 { 1967 static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization"); 1968 1969 std::promise<tuple<_UArgs...>> _M_promise; 1970 1971 template<typename _Arg0, typename... _Args> 1972 void 1973 operator()(_Arg0&& __a0, _Args&&... __args) 1974 { 1975 if (__a0) 1976 _M_promise.set_exception(_S_exptr(__a0)); 1977 else 1978 _M_promise.set_value( 1979 std::forward_as_tuple(std::forward<_Args>(__args)...)); 1980 } 1981 }; 1982 1983 public: 1984 using type = 1985 _Type<__is_error_result<_Args...>::value, decay_t<_Args>...>; 1986 }; 1987 1988 1989 template<typename _Alloc, typename _Ret, typename... _Args> 1990 struct async_result<use_future_t<_Alloc>, _Ret(_Args...)> 1991 { 1992 using completion_handler_type 1993 = typename handler_type<use_future_t<_Alloc>, _Ret(_Args...)>::type; 1994 1995 using return_type = void; // XXX TODO ???; 1996 1997 explicit 1998 async_result(completion_handler_type& __h) : _M_handler(__h) { } 1999 2000 auto get() { return _M_handler._M_provider.get_future(); } 2001 2002 async_result(const async_result&) = delete; 2003 async_result& operator=(const async_result&) = delete; 2004 2005 return_type get() { return _M_handler._M_promise.get_future(); } 2006 2007 private: 2008 completion_handler_type& _M_handler; 2009 }; 2010 2011 // TODO specialize associated_executor for 2012 // async_result<use_future_t<A>, Sig>::completion_handler_type 2013 // to use a __use_future_ex 2014 // (probably need to move _Type outside of handler_type so we don't have 2015 // a non-deduced context) 2016 2017 #endif 2018 2019 // [async.packaged.task.specializations] 2020 template<typename _Ret, typename... _Args, typename _Signature> 2021 class async_result<packaged_task<_Ret(_Args...)>, _Signature> 2022 { 2023 public: 2024 using completion_handler_type = packaged_task<_Ret(_Args...)>; 2025 using return_type = future<_Ret>; 2026 2027 explicit 2028 async_result(completion_handler_type& __h) 2029 : _M_future(__h.get_future()) { } 2030 2031 async_result(const async_result&) = delete; 2032 async_result& operator=(const async_result&) = delete; 2033 2034 return_type get() { return std::move(_M_future); } 2035 2036 private: 2037 return_type _M_future; 2038 }; 2039 2040 #endif // _GLIBCXX_HAS_GTHREADS 2041 2042 /// @} 2043 2044 } // namespace v1 2045 } // namespace net 2046 } // namespace experimental 2047 2048 template<typename _Alloc> 2049 struct uses_allocator<experimental::net::executor, _Alloc> 2050 : true_type {}; 2051 2052 _GLIBCXX_END_NAMESPACE_VERSION 2053 } // namespace std 2054 2055 #endif // C++14 2056 2057 #endif // _GLIBCXX_EXPERIMENTAL_EXECUTOR