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