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