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