1627f7eb2Smrg// <experimental/executor> -*- C++ -*- 2627f7eb2Smrg 3*4c3eb207Smrg// Copyright (C) 2015-2020 Free Software Foundation, Inc. 4627f7eb2Smrg// 5627f7eb2Smrg// This file is part of the GNU ISO C++ Library. This library is free 6627f7eb2Smrg// software; you can redistribute it and/or modify it under the 7627f7eb2Smrg// terms of the GNU General Public License as published by the 8627f7eb2Smrg// Free Software Foundation; either version 3, or (at your option) 9627f7eb2Smrg// any later version. 10627f7eb2Smrg 11627f7eb2Smrg// This library is distributed in the hope that it will be useful, 12627f7eb2Smrg// but WITHOUT ANY WARRANTY; without even the implied warranty of 13627f7eb2Smrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14627f7eb2Smrg// GNU General Public License for more details. 15627f7eb2Smrg 16627f7eb2Smrg// Under Section 7 of GPL version 3, you are granted additional 17627f7eb2Smrg// permissions described in the GCC Runtime Library Exception, version 18627f7eb2Smrg// 3.1, as published by the Free Software Foundation. 19627f7eb2Smrg 20627f7eb2Smrg// You should have received a copy of the GNU General Public License and 21627f7eb2Smrg// a copy of the GCC Runtime Library Exception along with this program; 22627f7eb2Smrg// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23627f7eb2Smrg// <http://www.gnu.org/licenses/>. 24627f7eb2Smrg 25627f7eb2Smrg/** @file experimental/executor 26627f7eb2Smrg * This is a TS C++ Library header. 27*4c3eb207Smrg * @ingroup networking-ts 28627f7eb2Smrg */ 29627f7eb2Smrg 30627f7eb2Smrg#ifndef _GLIBCXX_EXPERIMENTAL_EXECUTOR 31627f7eb2Smrg#define _GLIBCXX_EXPERIMENTAL_EXECUTOR 1 32627f7eb2Smrg 33627f7eb2Smrg#pragma GCC system_header 34627f7eb2Smrg 35627f7eb2Smrg#if __cplusplus >= 201402L 36627f7eb2Smrg 37627f7eb2Smrg#include <algorithm> 38627f7eb2Smrg#include <condition_variable> 39627f7eb2Smrg#include <functional> 40627f7eb2Smrg#include <future> 41627f7eb2Smrg#include <list> 42627f7eb2Smrg#include <queue> 43627f7eb2Smrg#include <thread> 44627f7eb2Smrg#include <tuple> 45627f7eb2Smrg#include <unordered_map> 46627f7eb2Smrg#include <utility> 47627f7eb2Smrg#include <experimental/netfwd> 48627f7eb2Smrg#include <bits/unique_ptr.h> 49627f7eb2Smrg#include <experimental/bits/net.h> 50627f7eb2Smrg 51627f7eb2Smrgnamespace std _GLIBCXX_VISIBILITY(default) 52627f7eb2Smrg{ 53627f7eb2Smrg_GLIBCXX_BEGIN_NAMESPACE_VERSION 54627f7eb2Smrgnamespace experimental 55627f7eb2Smrg{ 56627f7eb2Smrgnamespace net 57627f7eb2Smrg{ 58627f7eb2Smrginline namespace v1 59627f7eb2Smrg{ 60627f7eb2Smrg 61*4c3eb207Smrg /** @addtogroup networking-ts 62627f7eb2Smrg * @{ 63627f7eb2Smrg */ 64627f7eb2Smrg 65627f7eb2Smrg /// Customization point for asynchronous operations. 66627f7eb2Smrg template<typename _CompletionToken, typename _Signature, typename = void> 67627f7eb2Smrg class async_result; 68627f7eb2Smrg 69627f7eb2Smrg /// Convenience utility to help implement asynchronous operations. 70627f7eb2Smrg template<typename _CompletionToken, typename _Signature> 71627f7eb2Smrg class async_completion; 72627f7eb2Smrg 73627f7eb2Smrg template<typename _Tp, typename _ProtoAlloc, typename = __void_t<>> 74627f7eb2Smrg struct __associated_allocator_impl 75627f7eb2Smrg { 76627f7eb2Smrg using type = _ProtoAlloc; 77627f7eb2Smrg 78627f7eb2Smrg static type 79627f7eb2Smrg _S_get(const _Tp&, const _ProtoAlloc& __a) noexcept { return __a; } 80627f7eb2Smrg }; 81627f7eb2Smrg 82627f7eb2Smrg template<typename _Tp, typename _ProtoAlloc> 83627f7eb2Smrg struct __associated_allocator_impl<_Tp, _ProtoAlloc, 84627f7eb2Smrg __void_t<typename _Tp::allocator_type>> 85627f7eb2Smrg { 86627f7eb2Smrg using type = typename _Tp::allocator_type; 87627f7eb2Smrg 88627f7eb2Smrg static type 89627f7eb2Smrg _S_get(const _Tp& __t, const _ProtoAlloc&) noexcept 90627f7eb2Smrg { return __t.get_allocator(); } 91627f7eb2Smrg }; 92627f7eb2Smrg 93627f7eb2Smrg /// Helper to associate an allocator with a type. 94627f7eb2Smrg template<typename _Tp, typename _ProtoAllocator = allocator<void>> 95627f7eb2Smrg struct associated_allocator 96627f7eb2Smrg : __associated_allocator_impl<_Tp, _ProtoAllocator> 97627f7eb2Smrg { 98627f7eb2Smrg static auto 99627f7eb2Smrg get(const _Tp& __t, 100627f7eb2Smrg const _ProtoAllocator& __a = _ProtoAllocator()) noexcept 101627f7eb2Smrg { 102627f7eb2Smrg using _Impl = __associated_allocator_impl<_Tp, _ProtoAllocator>; 103627f7eb2Smrg return _Impl::_S_get(__t, __a); 104627f7eb2Smrg } 105627f7eb2Smrg }; 106627f7eb2Smrg 107627f7eb2Smrg /// Alias template for associated_allocator. 108627f7eb2Smrg template<typename _Tp, typename _ProtoAllocator = allocator<void>> 109627f7eb2Smrg using associated_allocator_t 110627f7eb2Smrg = typename associated_allocator<_Tp, _ProtoAllocator>::type; 111627f7eb2Smrg 112627f7eb2Smrg // get_associated_allocator: 113627f7eb2Smrg 114627f7eb2Smrg template<typename _Tp> 115627f7eb2Smrg inline associated_allocator_t<_Tp> 116627f7eb2Smrg get_associated_allocator(const _Tp& __t) noexcept 117627f7eb2Smrg { return associated_allocator<_Tp>::get(__t); } 118627f7eb2Smrg 119627f7eb2Smrg template<typename _Tp, typename _ProtoAllocator> 120627f7eb2Smrg inline associated_allocator_t<_Tp, _ProtoAllocator> 121627f7eb2Smrg get_associated_allocator(const _Tp& __t, 122627f7eb2Smrg const _ProtoAllocator& __a) noexcept 123627f7eb2Smrg { return associated_allocator<_Tp, _ProtoAllocator>::get(__t, __a); } 124627f7eb2Smrg 125627f7eb2Smrg enum class fork_event { prepare, parent, child }; 126627f7eb2Smrg 127627f7eb2Smrg /// An extensible, type-safe, polymorphic set of services. 128627f7eb2Smrg class execution_context; 129627f7eb2Smrg 130*4c3eb207Smrg class service_already_exists : public logic_error 131*4c3eb207Smrg { 132*4c3eb207Smrg public: 133*4c3eb207Smrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 134*4c3eb207Smrg // 3414. service_already_exists has no usable constructors 135*4c3eb207Smrg service_already_exists() : logic_error("service already exists") { } 136*4c3eb207Smrg }; 137627f7eb2Smrg 138627f7eb2Smrg template<typename _Tp> struct is_executor; 139627f7eb2Smrg 140627f7eb2Smrg struct executor_arg_t { }; 141627f7eb2Smrg 142627f7eb2Smrg constexpr executor_arg_t executor_arg = executor_arg_t(); 143627f7eb2Smrg 144627f7eb2Smrg /// Trait for determining whether to construct an object with an executor. 145627f7eb2Smrg template<typename _Tp, typename _Executor> struct uses_executor; 146627f7eb2Smrg 147627f7eb2Smrg template<typename _Tp, typename _Executor, typename = __void_t<>> 148627f7eb2Smrg struct __associated_executor_impl 149627f7eb2Smrg { 150627f7eb2Smrg using type = _Executor; 151627f7eb2Smrg 152627f7eb2Smrg static type 153627f7eb2Smrg _S_get(const _Tp&, const _Executor& __e) noexcept { return __e; } 154627f7eb2Smrg }; 155627f7eb2Smrg 156627f7eb2Smrg template<typename _Tp, typename _Executor> 157627f7eb2Smrg struct __associated_executor_impl<_Tp, _Executor, 158627f7eb2Smrg __void_t<typename _Tp::executor_type>> 159627f7eb2Smrg { 160627f7eb2Smrg using type = typename _Tp::executor_type; 161627f7eb2Smrg 162627f7eb2Smrg static type 163627f7eb2Smrg _S_get(const _Tp& __t, const _Executor&) noexcept 164627f7eb2Smrg { return __t.get_executor(); } 165627f7eb2Smrg }; 166627f7eb2Smrg 167627f7eb2Smrg /// Helper to associate an executor with a type. 168627f7eb2Smrg template<typename _Tp, typename _Executor = system_executor> 169627f7eb2Smrg struct associated_executor 170627f7eb2Smrg : __associated_executor_impl<_Tp, _Executor> 171627f7eb2Smrg { 172627f7eb2Smrg static auto 173627f7eb2Smrg get(const _Tp& __t, const _Executor& __e = _Executor()) noexcept 174627f7eb2Smrg { return __associated_executor_impl<_Tp, _Executor>::_S_get(__t, __e); } 175627f7eb2Smrg }; 176627f7eb2Smrg 177627f7eb2Smrg 178627f7eb2Smrg template<typename _Tp, typename _Executor = system_executor> 179627f7eb2Smrg using associated_executor_t 180627f7eb2Smrg = typename associated_executor<_Tp, _Executor>::type; 181627f7eb2Smrg 182627f7eb2Smrg template<typename _ExecutionContext> 183627f7eb2Smrg using __is_exec_context 184627f7eb2Smrg = is_convertible<_ExecutionContext&, execution_context&>; 185627f7eb2Smrg 186627f7eb2Smrg template<typename _Tp> 187627f7eb2Smrg using __executor_t = typename _Tp::executor_type; 188627f7eb2Smrg 189627f7eb2Smrg // get_associated_executor: 190627f7eb2Smrg 191627f7eb2Smrg template<typename _Tp> 192627f7eb2Smrg inline associated_executor_t<_Tp> 193627f7eb2Smrg get_associated_executor(const _Tp& __t) noexcept 194627f7eb2Smrg { return associated_executor<_Tp>::get(__t); } 195627f7eb2Smrg 196627f7eb2Smrg template<typename _Tp, typename _Executor> 197627f7eb2Smrg inline 198627f7eb2Smrg enable_if_t<is_executor<_Executor>::value, 199627f7eb2Smrg associated_executor_t<_Tp, _Executor>> 200627f7eb2Smrg get_associated_executor(const _Tp& __t, const _Executor& __ex) 201627f7eb2Smrg { return associated_executor<_Tp, _Executor>::get(__t, __ex); } 202627f7eb2Smrg 203627f7eb2Smrg template<typename _Tp, typename _ExecutionContext> 204627f7eb2Smrg inline 205627f7eb2Smrg enable_if_t<__is_exec_context<_ExecutionContext>::value, 206627f7eb2Smrg associated_executor_t<_Tp, __executor_t<_ExecutionContext>>> 207627f7eb2Smrg get_associated_executor(const _Tp& __t, _ExecutionContext& __ctx) noexcept 208627f7eb2Smrg { return net::get_associated_executor(__t, __ctx.get_executor()); } 209627f7eb2Smrg 210627f7eb2Smrg 211627f7eb2Smrg /// Helper to bind an executor to an object or function. 212627f7eb2Smrg template<typename _Tp, typename _Executor> 213627f7eb2Smrg class executor_binder; 214627f7eb2Smrg 215627f7eb2Smrg template<typename _Tp, typename _Executor, typename _Signature> 216627f7eb2Smrg class async_result<executor_binder<_Tp, _Executor>, _Signature>; 217627f7eb2Smrg 218627f7eb2Smrg template<typename _Tp, typename _Executor, typename _ProtoAllocator> 219627f7eb2Smrg struct associated_allocator<executor_binder<_Tp, _Executor>, 220627f7eb2Smrg _ProtoAllocator>; 221627f7eb2Smrg 222627f7eb2Smrg template<typename _Tp, typename _Executor, typename _Executor1> 223627f7eb2Smrg struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>; 224627f7eb2Smrg 225627f7eb2Smrg // bind_executor: 226627f7eb2Smrg 227627f7eb2Smrg template<typename _Executor, typename _Tp> 228627f7eb2Smrg inline 229627f7eb2Smrg enable_if_t<is_executor<_Executor>::value, 230627f7eb2Smrg executor_binder<decay_t<_Tp>, _Executor>> 231627f7eb2Smrg bind_executor(const _Executor& __ex, _Tp&& __t) 232627f7eb2Smrg { return { std::forward<_Tp>(__t), __ex }; } 233627f7eb2Smrg 234627f7eb2Smrg template<typename _ExecutionContext, typename _Tp> 235627f7eb2Smrg inline 236627f7eb2Smrg enable_if_t<__is_exec_context<_ExecutionContext>::value, 237627f7eb2Smrg executor_binder<decay_t<_Tp>, __executor_t<_ExecutionContext>>> 238627f7eb2Smrg bind_executor(_ExecutionContext& __ctx, _Tp&& __t) 239627f7eb2Smrg { return { __ctx.get_executor(), forward<_Tp>(__t) }; } 240627f7eb2Smrg 241627f7eb2Smrg 242627f7eb2Smrg /// A scope-guard type to record when work is started and finished. 243627f7eb2Smrg template<typename _Executor> 244627f7eb2Smrg class executor_work_guard; 245627f7eb2Smrg 246627f7eb2Smrg // make_work_guard: 247627f7eb2Smrg 248627f7eb2Smrg template<typename _Executor> 249627f7eb2Smrg inline 250627f7eb2Smrg enable_if_t<is_executor<_Executor>::value, executor_work_guard<_Executor>> 251627f7eb2Smrg make_work_guard(const _Executor& __ex) 252627f7eb2Smrg { return executor_work_guard<_Executor>(__ex); } 253627f7eb2Smrg 254627f7eb2Smrg template<typename _ExecutionContext> 255627f7eb2Smrg inline 256627f7eb2Smrg enable_if_t<__is_exec_context<_ExecutionContext>::value, 257627f7eb2Smrg executor_work_guard<__executor_t<_ExecutionContext>>> 258627f7eb2Smrg make_work_guard(_ExecutionContext& __ctx) 259627f7eb2Smrg { return net::make_work_guard(__ctx.get_executor()); } 260627f7eb2Smrg 261627f7eb2Smrg template<typename _Tp> 262627f7eb2Smrg inline 263627f7eb2Smrg enable_if_t<__not_<__or_<is_executor<_Tp>, __is_exec_context<_Tp>>>::value, 264627f7eb2Smrg executor_work_guard<associated_executor_t<_Tp>>> 265627f7eb2Smrg make_work_guard(const _Tp& __t) 266627f7eb2Smrg { return net::get_associated_executor(__t); } 267627f7eb2Smrg 268627f7eb2Smrg template<typename _Tp, typename _Up> 269627f7eb2Smrg auto 270627f7eb2Smrg make_work_guard(const _Tp& __t, _Up&& __u) 271627f7eb2Smrg -> decltype(net::make_work_guard( 272627f7eb2Smrg net::get_associated_executor(__t, forward<_Up>(__u)))) 273627f7eb2Smrg { 274627f7eb2Smrg return net::make_work_guard( 275627f7eb2Smrg net::get_associated_executor(__t, forward<_Up>(__u))); 276627f7eb2Smrg } 277627f7eb2Smrg 278627f7eb2Smrg /// Allows function objects to execute on any thread. 279627f7eb2Smrg class system_executor; 280627f7eb2Smrg 281627f7eb2Smrg /// The execution context associated with system_executor objects. 282627f7eb2Smrg class system_context; 283627f7eb2Smrg 284627f7eb2Smrg inline bool 285627f7eb2Smrg operator==(const system_executor&, const system_executor&) { return true; } 286627f7eb2Smrg 287627f7eb2Smrg inline bool 288627f7eb2Smrg operator!=(const system_executor&, const system_executor&) { return false; } 289627f7eb2Smrg 290627f7eb2Smrg /// Exception thrown by empty executors. 291627f7eb2Smrg class bad_executor; 292627f7eb2Smrg 293627f7eb2Smrg /// Polymorphic wrapper for types satisfying the Executor requirements. 294627f7eb2Smrg class executor; 295627f7eb2Smrg 296627f7eb2Smrg bool 297*4c3eb207Smrg operator==(const executor&, const executor&) noexcept; 298627f7eb2Smrg 299627f7eb2Smrg bool 300*4c3eb207Smrg operator==(const executor&, nullptr_t) noexcept; 301627f7eb2Smrg 302*4c3eb207Smrg bool 303*4c3eb207Smrg operator==(nullptr_t, const executor&) noexcept; 304627f7eb2Smrg 305*4c3eb207Smrg bool 306*4c3eb207Smrg operator!=(const executor&, const executor&) noexcept; 307627f7eb2Smrg 308*4c3eb207Smrg bool 309*4c3eb207Smrg operator!=(const executor&, nullptr_t) noexcept; 310627f7eb2Smrg 311*4c3eb207Smrg bool 312*4c3eb207Smrg operator!=(nullptr_t, const executor&) noexcept; 313627f7eb2Smrg 314627f7eb2Smrg void swap(executor&, executor&) noexcept; 315627f7eb2Smrg 316627f7eb2Smrg // dispatch: 317627f7eb2Smrg 318627f7eb2Smrg template<typename _CompletionToken> 319627f7eb2Smrg __deduced_t<_CompletionToken, void()> 320627f7eb2Smrg dispatch(_CompletionToken&& __token); 321627f7eb2Smrg 322627f7eb2Smrg template<typename _Executor, typename _CompletionToken> 323627f7eb2Smrg __deduced_t<_CompletionToken, void()> 324627f7eb2Smrg dispatch(const _Executor& __ex, _CompletionToken&& __token); 325627f7eb2Smrg 326627f7eb2Smrg template<typename _ExecutionContext, typename _CompletionToken> 327627f7eb2Smrg __deduced_t<_CompletionToken, void()> 328627f7eb2Smrg dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token); 329627f7eb2Smrg 330627f7eb2Smrg // post: 331627f7eb2Smrg 332627f7eb2Smrg template<typename _CompletionToken> 333627f7eb2Smrg __deduced_t<_CompletionToken, void()> 334627f7eb2Smrg post(_CompletionToken&& __token); 335627f7eb2Smrg template<typename _Executor, typename _CompletionToken> 336627f7eb2Smrg enable_if_t<is_executor<_Executor>::value, 337627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 338627f7eb2Smrg post(const _Executor& __ex, _CompletionToken&& __token); 339627f7eb2Smrg template<typename _ExecutionContext, typename _CompletionToken> 340627f7eb2Smrg enable_if_t<__is_exec_context<_ExecutionContext>::value, 341627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 342627f7eb2Smrg post(_ExecutionContext& __ctx, _CompletionToken&& __token); 343627f7eb2Smrg 344627f7eb2Smrg // defer: 345627f7eb2Smrg 346627f7eb2Smrg template<typename _CompletionToken> 347627f7eb2Smrg __deduced_t<_CompletionToken, void()> 348627f7eb2Smrg defer(_CompletionToken&& __token); 349627f7eb2Smrg template<typename _Executor, typename _CompletionToken> 350627f7eb2Smrg __deduced_t<_CompletionToken, void()> 351627f7eb2Smrg defer(const _Executor& __ex, _CompletionToken&& __token); 352627f7eb2Smrg template<typename _ExecutionContext, typename _CompletionToken> 353627f7eb2Smrg __deduced_t<_CompletionToken, void()> 354627f7eb2Smrg defer(_ExecutionContext& __ctx, _CompletionToken&& __token); 355627f7eb2Smrg 356627f7eb2Smrg template<typename _Executor> 357627f7eb2Smrg class strand; 358627f7eb2Smrg 359627f7eb2Smrg template<typename _Executor> 360627f7eb2Smrg bool 361627f7eb2Smrg operator==(const strand<_Executor>& __a, const strand<_Executor>& __b); 362627f7eb2Smrg 363627f7eb2Smrg template<typename _Executor> 364627f7eb2Smrg bool 365627f7eb2Smrg operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b) 366627f7eb2Smrg { return !(__a == __b); } 367627f7eb2Smrg 368627f7eb2Smrg template<typename _CompletionToken, typename _Signature, typename> 369627f7eb2Smrg class async_result 370627f7eb2Smrg { 371627f7eb2Smrg public: 372627f7eb2Smrg typedef _CompletionToken completion_handler_type; 373627f7eb2Smrg typedef void return_type; 374627f7eb2Smrg 375627f7eb2Smrg explicit async_result(completion_handler_type&) {} 376627f7eb2Smrg async_result(const async_result&) = delete; 377627f7eb2Smrg async_result& operator=(const async_result&) = delete; 378627f7eb2Smrg 379627f7eb2Smrg return_type get() {} 380627f7eb2Smrg }; 381627f7eb2Smrg 382627f7eb2Smrg template<typename _CompletionToken, typename _Signature> 383627f7eb2Smrg class async_completion 384627f7eb2Smrg { 385627f7eb2Smrg using __result_type 386627f7eb2Smrg = async_result<decay_t<_CompletionToken>, _Signature>; 387627f7eb2Smrg 388627f7eb2Smrg public: 389627f7eb2Smrg using completion_handler_type 390627f7eb2Smrg = typename __result_type::completion_handler_type; 391627f7eb2Smrg 392627f7eb2Smrg private: 393627f7eb2Smrg using __handler_type = conditional_t< 394627f7eb2Smrg is_same<_CompletionToken, completion_handler_type>::value, 395627f7eb2Smrg completion_handler_type&, 396627f7eb2Smrg completion_handler_type>; 397627f7eb2Smrg 398627f7eb2Smrg public: 399627f7eb2Smrg explicit 400627f7eb2Smrg async_completion(_CompletionToken& __t) 401627f7eb2Smrg : completion_handler(std::forward<__handler_type>(__t)), 402627f7eb2Smrg result(completion_handler) 403627f7eb2Smrg { } 404627f7eb2Smrg 405627f7eb2Smrg async_completion(const async_completion&) = delete; 406627f7eb2Smrg async_completion& operator=(const async_completion&) = delete; 407627f7eb2Smrg 408627f7eb2Smrg __handler_type completion_handler; 409627f7eb2Smrg __result_type result; 410627f7eb2Smrg }; 411627f7eb2Smrg 412627f7eb2Smrg 413627f7eb2Smrg class execution_context 414627f7eb2Smrg { 415627f7eb2Smrg public: 416627f7eb2Smrg class service 417627f7eb2Smrg { 418627f7eb2Smrg protected: 419627f7eb2Smrg // construct / copy / destroy: 420627f7eb2Smrg 421627f7eb2Smrg explicit 422627f7eb2Smrg service(execution_context& __owner) : _M_context(__owner) { } 423627f7eb2Smrg 424627f7eb2Smrg service(const service&) = delete; 425627f7eb2Smrg service& operator=(const service&) = delete; 426627f7eb2Smrg 427627f7eb2Smrg virtual ~service() { } // TODO should not be inline 428627f7eb2Smrg 429627f7eb2Smrg // service observers: 430627f7eb2Smrg 431627f7eb2Smrg execution_context& context() const noexcept { return _M_context; } 432627f7eb2Smrg 433627f7eb2Smrg private: 434627f7eb2Smrg // service operations: 435627f7eb2Smrg 436627f7eb2Smrg virtual void shutdown() noexcept = 0; 437627f7eb2Smrg virtual void notify_fork(fork_event) { } 438627f7eb2Smrg 439627f7eb2Smrg friend class execution_context; 440627f7eb2Smrg execution_context& _M_context; 441627f7eb2Smrg }; 442627f7eb2Smrg 443627f7eb2Smrg // construct / copy / destroy: 444627f7eb2Smrg 445627f7eb2Smrg execution_context() { } 446627f7eb2Smrg 447627f7eb2Smrg execution_context(const execution_context&) = delete; 448627f7eb2Smrg execution_context& operator=(const execution_context&) = delete; 449627f7eb2Smrg 450627f7eb2Smrg virtual ~execution_context() 451627f7eb2Smrg { 452627f7eb2Smrg shutdown(); 453627f7eb2Smrg destroy(); 454627f7eb2Smrg } 455627f7eb2Smrg 456627f7eb2Smrg // execution context operations: 457627f7eb2Smrg 458627f7eb2Smrg void 459627f7eb2Smrg notify_fork(fork_event __e) 460627f7eb2Smrg { 461627f7eb2Smrg auto __l = [=](auto& __svc) { __svc._M_ptr->notify_fork(__e); }; 462627f7eb2Smrg if (__e == fork_event::prepare) 463627f7eb2Smrg std::for_each(_M_services.rbegin(), _M_services.rend(), __l); 464627f7eb2Smrg else 465627f7eb2Smrg std::for_each(_M_services.begin(), _M_services.end(), __l); 466627f7eb2Smrg } 467627f7eb2Smrg 468627f7eb2Smrg protected: 469627f7eb2Smrg // execution context protected operations: 470627f7eb2Smrg 471627f7eb2Smrg void 472627f7eb2Smrg shutdown() 473627f7eb2Smrg { 474627f7eb2Smrg std::for_each(_M_services.rbegin(), _M_services.rend(), 475627f7eb2Smrg [=](auto& __svc) { 476627f7eb2Smrg if (__svc._M_active) 477627f7eb2Smrg { 478627f7eb2Smrg __svc._M_ptr->shutdown(); 479627f7eb2Smrg __svc._M_active = false; 480627f7eb2Smrg } 481627f7eb2Smrg }); 482627f7eb2Smrg } 483627f7eb2Smrg 484627f7eb2Smrg void 485627f7eb2Smrg destroy() 486627f7eb2Smrg { 487627f7eb2Smrg while (_M_services.size()) 488627f7eb2Smrg _M_services.pop_back(); 489627f7eb2Smrg _M_keys.clear(); 490627f7eb2Smrg } 491627f7eb2Smrg 492627f7eb2Smrg protected: 493627f7eb2Smrg 494627f7eb2Smrg template<typename _Service> 495627f7eb2Smrg static void 496627f7eb2Smrg _S_deleter(service* __svc) { delete static_cast<_Service*>(__svc); } 497627f7eb2Smrg 498627f7eb2Smrg struct _ServicePtr 499627f7eb2Smrg { 500627f7eb2Smrg template<typename _Service> 501627f7eb2Smrg explicit 502627f7eb2Smrg _ServicePtr(_Service* __svc) 503627f7eb2Smrg : _M_ptr(__svc, &_S_deleter<_Service>), _M_active(true) { } 504627f7eb2Smrg 505627f7eb2Smrg std::unique_ptr<service, void(*)(service*)> _M_ptr; 506627f7eb2Smrg bool _M_active; 507627f7eb2Smrg }; 508627f7eb2Smrg 509627f7eb2Smrg mutable std::mutex _M_mutex; 510627f7eb2Smrg 511627f7eb2Smrg // Sorted in order of beginning of service object lifetime. 512627f7eb2Smrg std::list<_ServicePtr> _M_services; 513627f7eb2Smrg 514627f7eb2Smrg template<typename _Service, typename... _Args> 515627f7eb2Smrg service* 516627f7eb2Smrg _M_add_svc(_Args&&... __args) 517627f7eb2Smrg { 518627f7eb2Smrg _M_services.push_back( 519627f7eb2Smrg _ServicePtr{new _Service{*this, std::forward<_Args>(__args)...}} ); 520627f7eb2Smrg return _M_services.back()._M_ptr.get(); 521627f7eb2Smrg } 522627f7eb2Smrg 523627f7eb2Smrg using __key_type = void(*)(); 524627f7eb2Smrg 525627f7eb2Smrg template<typename _Key> 526627f7eb2Smrg static __key_type 527627f7eb2Smrg _S_key() { return reinterpret_cast<__key_type>(&_S_key<_Key>); } 528627f7eb2Smrg 529627f7eb2Smrg std::unordered_map<__key_type, service*> _M_keys; 530627f7eb2Smrg 531627f7eb2Smrg template<typename _Service> 532627f7eb2Smrg friend typename _Service::key_type& 533627f7eb2Smrg use_service(execution_context&); 534627f7eb2Smrg 535627f7eb2Smrg template<typename _Service, typename... _Args> 536627f7eb2Smrg friend _Service& 537627f7eb2Smrg make_service(execution_context&, _Args&&...); 538627f7eb2Smrg 539627f7eb2Smrg template<typename _Service> 540627f7eb2Smrg friend bool 541627f7eb2Smrg has_service(const execution_context&) noexcept; 542627f7eb2Smrg }; 543627f7eb2Smrg 544627f7eb2Smrg // service access: 545627f7eb2Smrg 546627f7eb2Smrg template<typename _Service> 547627f7eb2Smrg typename _Service::key_type& 548627f7eb2Smrg use_service(execution_context& __ctx) 549627f7eb2Smrg { 550627f7eb2Smrg using _Key = typename _Service::key_type; 551627f7eb2Smrg static_assert(is_base_of<execution_context::service, _Key>::value, 552627f7eb2Smrg "a service type must derive from execution_context::service"); 553627f7eb2Smrg static_assert(is_base_of<_Key, _Service>::value, 554627f7eb2Smrg "a service type must match or derive from its key_type"); 555627f7eb2Smrg auto __key = execution_context::_S_key<_Key>(); 556627f7eb2Smrg std::lock_guard<std::mutex> __lock(__ctx._M_mutex); 557627f7eb2Smrg auto& __svc = __ctx._M_keys[__key]; 558627f7eb2Smrg if (__svc == nullptr) 559627f7eb2Smrg { 560627f7eb2Smrg __try { 561627f7eb2Smrg __svc = __ctx._M_add_svc<_Service>(); 562627f7eb2Smrg } __catch(...) { 563627f7eb2Smrg __ctx._M_keys.erase(__key); 564627f7eb2Smrg __throw_exception_again; 565627f7eb2Smrg } 566627f7eb2Smrg } 567627f7eb2Smrg return static_cast<_Key&>(*__svc); 568627f7eb2Smrg } 569627f7eb2Smrg 570627f7eb2Smrg template<typename _Service, typename... _Args> 571627f7eb2Smrg _Service& 572627f7eb2Smrg make_service(execution_context& __ctx, _Args&&... __args) 573627f7eb2Smrg { 574627f7eb2Smrg using _Key = typename _Service::key_type; 575627f7eb2Smrg static_assert(is_base_of<execution_context::service, _Key>::value, 576627f7eb2Smrg "a service type must derive from execution_context::service"); 577627f7eb2Smrg static_assert(is_base_of<_Key, _Service>::value, 578627f7eb2Smrg "a service type must match or derive from its key_type"); 579627f7eb2Smrg auto __key = execution_context::_S_key<_Key>(); 580627f7eb2Smrg std::lock_guard<std::mutex> __lock(__ctx._M_mutex); 581627f7eb2Smrg auto& __svc = __ctx._M_keys[__key]; 582627f7eb2Smrg if (__svc != nullptr) 583627f7eb2Smrg throw service_already_exists(); 584627f7eb2Smrg __try { 585627f7eb2Smrg __svc = __ctx._M_add_svc<_Service>(std::forward<_Args>(__args)...); 586627f7eb2Smrg } __catch(...) { 587627f7eb2Smrg __ctx._M_keys.erase(__key); 588627f7eb2Smrg __throw_exception_again; 589627f7eb2Smrg } 590627f7eb2Smrg return static_cast<_Service&>(*__svc); 591627f7eb2Smrg } 592627f7eb2Smrg 593627f7eb2Smrg template<typename _Service> 594627f7eb2Smrg inline bool 595627f7eb2Smrg has_service(const execution_context& __ctx) noexcept 596627f7eb2Smrg { 597627f7eb2Smrg using _Key = typename _Service::key_type; 598627f7eb2Smrg static_assert(is_base_of<execution_context::service, _Key>::value, 599627f7eb2Smrg "a service type must derive from execution_context::service"); 600627f7eb2Smrg static_assert(is_base_of<_Key, _Service>::value, 601627f7eb2Smrg "a service type must match or derive from its key_type"); 602627f7eb2Smrg std::lock_guard<std::mutex> __lock(__ctx._M_mutex); 603627f7eb2Smrg return __ctx._M_keys.count(execution_context::_S_key<_Key>()); 604627f7eb2Smrg } 605627f7eb2Smrg 606627f7eb2Smrg template<typename _Tp, typename = __void_t<>> 607627f7eb2Smrg struct __is_executor_impl : false_type 608627f7eb2Smrg { }; 609627f7eb2Smrg 610627f7eb2Smrg // Check Executor requirements. 611627f7eb2Smrg template<typename _Tp, typename _Up = remove_const_t<_Tp>> 612627f7eb2Smrg auto 613627f7eb2Smrg __executor_reqs(_Up* __x = 0, const _Up* __cx = 0, void(*__f)() = 0, 614627f7eb2Smrg const allocator<int>& __a = {}) 615627f7eb2Smrg -> enable_if_t<__is_value_constructible<_Tp>::value, __void_t< 616627f7eb2Smrg decltype(*__cx == *__cx), 617627f7eb2Smrg decltype(*__cx != *__cx), 618627f7eb2Smrg decltype(__x->context()), 619627f7eb2Smrg decltype(__x->on_work_started()), 620627f7eb2Smrg decltype(__x->on_work_finished()), 621627f7eb2Smrg decltype(__x->dispatch(std::move(__f), __a)), 622627f7eb2Smrg decltype(__x->post(std::move(__f), __a)), 623627f7eb2Smrg decltype(__x->defer(std::move(__f), __a)) 624627f7eb2Smrg >>; 625627f7eb2Smrg 626627f7eb2Smrg template<typename _Tp> 627627f7eb2Smrg struct __is_executor_impl<_Tp, decltype(__executor_reqs<_Tp>())> 628627f7eb2Smrg : true_type 629627f7eb2Smrg { }; 630627f7eb2Smrg 631627f7eb2Smrg template<typename _Tp> 632627f7eb2Smrg struct is_executor : __is_executor_impl<_Tp> 633627f7eb2Smrg { }; 634627f7eb2Smrg 635627f7eb2Smrg template<typename _Tp> 636627f7eb2Smrg constexpr bool is_executor_v = is_executor<_Tp>::value; 637627f7eb2Smrg 638627f7eb2Smrg template<typename _Tp, typename _Executor, typename = __void_t<>> 639627f7eb2Smrg struct __uses_executor_impl : false_type 640627f7eb2Smrg { }; 641627f7eb2Smrg 642627f7eb2Smrg template<typename _Tp, typename _Executor> 643627f7eb2Smrg struct __uses_executor_impl<_Tp, _Executor, 644627f7eb2Smrg __void_t<typename _Tp::executor_type>> 645627f7eb2Smrg : is_convertible<_Executor, typename _Tp::executor_type> 646627f7eb2Smrg { }; 647627f7eb2Smrg 648627f7eb2Smrg template<typename _Tp, typename _Executor> 649627f7eb2Smrg struct uses_executor : __uses_executor_impl<_Tp, _Executor>::type 650627f7eb2Smrg { }; 651627f7eb2Smrg 652627f7eb2Smrg template<typename _Tp, typename _Executor> 653627f7eb2Smrg constexpr bool uses_executor_v = uses_executor<_Tp, _Executor>::value; 654627f7eb2Smrg 655627f7eb2Smrg template<typename _Tp, typename _Executor> 656627f7eb2Smrg class executor_binder 657627f7eb2Smrg { 658627f7eb2Smrg struct __use_exec { }; 659627f7eb2Smrg 660627f7eb2Smrg public: 661627f7eb2Smrg // types: 662627f7eb2Smrg 663627f7eb2Smrg typedef _Tp target_type; 664627f7eb2Smrg typedef _Executor executor_type; 665627f7eb2Smrg 666627f7eb2Smrg // construct / copy / destroy: 667627f7eb2Smrg 668627f7eb2Smrg executor_binder(_Tp __t, const _Executor& __ex) 669627f7eb2Smrg : executor_binder(__use_exec{}, std::move(__t), __ex) 670627f7eb2Smrg { } 671627f7eb2Smrg 672627f7eb2Smrg executor_binder(const executor_binder&) = default; 673627f7eb2Smrg executor_binder(executor_binder&&) = default; 674627f7eb2Smrg 675627f7eb2Smrg template<typename _Up, typename _OtherExecutor> 676627f7eb2Smrg executor_binder(const executor_binder<_Up, _OtherExecutor>& __other) 677627f7eb2Smrg : executor_binder(__use_exec{}, __other.get(), __other.get_executor()) 678627f7eb2Smrg { } 679627f7eb2Smrg 680627f7eb2Smrg template<typename _Up, typename _OtherExecutor> 681627f7eb2Smrg executor_binder(executor_binder<_Up, _OtherExecutor>&& __other) 682627f7eb2Smrg : executor_binder(__use_exec{}, std::move(__other.get()), 683627f7eb2Smrg __other.get_executor()) 684627f7eb2Smrg { } 685627f7eb2Smrg 686627f7eb2Smrg template<typename _Up, typename _OtherExecutor> 687627f7eb2Smrg executor_binder(executor_arg_t, const _Executor& __ex, 688627f7eb2Smrg const executor_binder<_Up, _OtherExecutor>& __other) 689627f7eb2Smrg : executor_binder(__use_exec{}, __other.get(), __ex) 690627f7eb2Smrg { } 691627f7eb2Smrg 692627f7eb2Smrg template<typename _Up, typename _OtherExecutor> 693627f7eb2Smrg executor_binder(executor_arg_t, const _Executor& __ex, 694627f7eb2Smrg executor_binder<_Up, _OtherExecutor>&& __other) 695627f7eb2Smrg : executor_binder(__use_exec{}, std::move(__other.get()), __ex) 696627f7eb2Smrg { } 697627f7eb2Smrg 698627f7eb2Smrg ~executor_binder(); 699627f7eb2Smrg 700627f7eb2Smrg // executor binder access: 701627f7eb2Smrg 702627f7eb2Smrg _Tp& get() noexcept { return _M_target; } 703627f7eb2Smrg const _Tp& get() const noexcept { return _M_target; } 704627f7eb2Smrg executor_type get_executor() const noexcept { return _M_ex; } 705627f7eb2Smrg 706627f7eb2Smrg // executor binder invocation: 707627f7eb2Smrg 708627f7eb2Smrg template<class... _Args> 709627f7eb2Smrg result_of_t<_Tp&(_Args&&...)> 710627f7eb2Smrg operator()(_Args&&... __args) 711627f7eb2Smrg { return std::__invoke(get(), std::forward<_Args>(__args)...); } 712627f7eb2Smrg 713627f7eb2Smrg template<class... _Args> 714627f7eb2Smrg result_of_t<const _Tp&(_Args&&...)> 715627f7eb2Smrg operator()(_Args&&... __args) const 716627f7eb2Smrg { return std::__invoke(get(), std::forward<_Args>(__args)...); } 717627f7eb2Smrg 718627f7eb2Smrg private: 719627f7eb2Smrg template<typename _Up> 720627f7eb2Smrg using __use_exec_cond 721627f7eb2Smrg = __and_<uses_executor<_Tp, _Executor>, 722627f7eb2Smrg is_constructible<_Tp, executor_arg_t, _Executor, _Up>>; 723627f7eb2Smrg 724627f7eb2Smrg template<typename _Up, typename _Exec, typename = 725627f7eb2Smrg enable_if_t<__use_exec_cond<_Up>::value>> 726627f7eb2Smrg executor_binder(__use_exec, _Up&& __u, _Exec&& __ex) 727627f7eb2Smrg : _M_ex(std::forward<_Exec>(__ex)), 728627f7eb2Smrg _M_target(executor_arg, _M_ex, std::forward<_Up>(__u)) 729627f7eb2Smrg { } 730627f7eb2Smrg 731627f7eb2Smrg template<typename _Up, typename _Exec, typename = 732627f7eb2Smrg enable_if_t<!__use_exec_cond<_Up>::value>> 733627f7eb2Smrg executor_binder(__use_exec, _Up&& __u, const _Exec& __ex) 734627f7eb2Smrg : _M_ex(std::forward<_Exec>(__ex)), 735627f7eb2Smrg _M_target(std::forward<_Up>(__u)) 736627f7eb2Smrg { } 737627f7eb2Smrg 738627f7eb2Smrg _Executor _M_ex; 739627f7eb2Smrg _Tp _M_target; 740627f7eb2Smrg }; 741627f7eb2Smrg 742627f7eb2Smrg template<typename _Tp, typename _Executor, typename _Signature> 743627f7eb2Smrg class async_result<executor_binder<_Tp, _Executor>, _Signature> 744627f7eb2Smrg { 745627f7eb2Smrg using __inner = async_result<_Tp, _Signature>; 746627f7eb2Smrg 747627f7eb2Smrg public: 748627f7eb2Smrg using completion_handler_type = 749627f7eb2Smrg executor_binder<typename __inner::completion_handler_type, _Executor>; 750627f7eb2Smrg 751627f7eb2Smrg using return_type = typename __inner::return_type; 752627f7eb2Smrg 753627f7eb2Smrg explicit 754627f7eb2Smrg async_result(completion_handler_type& __h) 755627f7eb2Smrg : _M_target(__h.get()) { } 756627f7eb2Smrg 757627f7eb2Smrg async_result(const async_result&) = delete; 758627f7eb2Smrg async_result& operator=(const async_result&) = delete; 759627f7eb2Smrg 760627f7eb2Smrg return_type get() { return _M_target.get(); } 761627f7eb2Smrg 762627f7eb2Smrg private: 763627f7eb2Smrg __inner _M_target; 764627f7eb2Smrg }; 765627f7eb2Smrg 766627f7eb2Smrg template<typename _Tp, typename _Executor, typename _ProtoAlloc> 767627f7eb2Smrg struct associated_allocator<executor_binder<_Tp, _Executor>, _ProtoAlloc> 768627f7eb2Smrg { 769627f7eb2Smrg typedef associated_allocator_t<_Tp, _ProtoAlloc> type; 770627f7eb2Smrg 771627f7eb2Smrg static type 772627f7eb2Smrg get(const executor_binder<_Tp, _Executor>& __b, 773627f7eb2Smrg const _ProtoAlloc& __a = _ProtoAlloc()) noexcept 774627f7eb2Smrg { return associated_allocator<_Tp, _ProtoAlloc>::get(__b.get(), __a); } 775627f7eb2Smrg }; 776627f7eb2Smrg 777627f7eb2Smrg template<typename _Tp, typename _Executor, typename _Executor1> 778627f7eb2Smrg struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1> 779627f7eb2Smrg { 780627f7eb2Smrg typedef _Executor type; 781627f7eb2Smrg 782627f7eb2Smrg static type 783627f7eb2Smrg get(const executor_binder<_Tp, _Executor>& __b, 784627f7eb2Smrg const _Executor1& = _Executor1()) noexcept 785627f7eb2Smrg { return __b.get_executor(); } 786627f7eb2Smrg }; 787627f7eb2Smrg 788627f7eb2Smrg template<typename _Executor> 789627f7eb2Smrg class executor_work_guard 790627f7eb2Smrg { 791627f7eb2Smrg public: 792627f7eb2Smrg // types: 793627f7eb2Smrg 794627f7eb2Smrg typedef _Executor executor_type; 795627f7eb2Smrg 796627f7eb2Smrg // construct / copy / destroy: 797627f7eb2Smrg 798627f7eb2Smrg explicit 799627f7eb2Smrg executor_work_guard(const executor_type& __ex) noexcept 800627f7eb2Smrg : _M_ex(__ex), _M_owns(true) 801627f7eb2Smrg { _M_ex.on_work_started(); } 802627f7eb2Smrg 803627f7eb2Smrg executor_work_guard(const executor_work_guard& __other) noexcept 804627f7eb2Smrg : _M_ex(__other._M_ex), _M_owns(__other._M_owns) 805627f7eb2Smrg { 806627f7eb2Smrg if (_M_owns) 807627f7eb2Smrg _M_ex.on_work_started(); 808627f7eb2Smrg } 809627f7eb2Smrg 810627f7eb2Smrg executor_work_guard(executor_work_guard&& __other) noexcept 811627f7eb2Smrg : _M_ex(__other._M_ex), _M_owns(__other._M_owns) 812627f7eb2Smrg { __other._M_owns = false; } 813627f7eb2Smrg 814627f7eb2Smrg executor_work_guard& operator=(const executor_work_guard&) = delete; 815627f7eb2Smrg 816627f7eb2Smrg ~executor_work_guard() 817627f7eb2Smrg { 818627f7eb2Smrg if (_M_owns) 819627f7eb2Smrg _M_ex.on_work_finished(); 820627f7eb2Smrg } 821627f7eb2Smrg 822627f7eb2Smrg // executor work guard observers: 823627f7eb2Smrg 824627f7eb2Smrg executor_type get_executor() const noexcept { return _M_ex; } 825627f7eb2Smrg 826627f7eb2Smrg bool owns_work() const noexcept { return _M_owns; } 827627f7eb2Smrg 828627f7eb2Smrg // executor work guard modifiers: 829627f7eb2Smrg 830627f7eb2Smrg void reset() noexcept 831627f7eb2Smrg { 832627f7eb2Smrg if (_M_owns) 833627f7eb2Smrg _M_ex.on_work_finished(); 834627f7eb2Smrg _M_owns = false; 835627f7eb2Smrg } 836627f7eb2Smrg 837627f7eb2Smrg private: 838627f7eb2Smrg _Executor _M_ex; 839627f7eb2Smrg bool _M_owns; 840627f7eb2Smrg }; 841627f7eb2Smrg 842627f7eb2Smrg 843627f7eb2Smrg class system_context : public execution_context 844627f7eb2Smrg { 845627f7eb2Smrg public: 846627f7eb2Smrg // types: 847627f7eb2Smrg 848627f7eb2Smrg typedef system_executor executor_type; 849627f7eb2Smrg 850627f7eb2Smrg // construct / copy / destroy: 851627f7eb2Smrg 852*4c3eb207Smrg system_context() = delete; 853627f7eb2Smrg system_context(const system_context&) = delete; 854627f7eb2Smrg system_context& operator=(const system_context&) = delete; 855627f7eb2Smrg 856627f7eb2Smrg ~system_context() 857627f7eb2Smrg { 858627f7eb2Smrg stop(); 859627f7eb2Smrg join(); 860627f7eb2Smrg } 861627f7eb2Smrg 862627f7eb2Smrg // system_context operations: 863627f7eb2Smrg 864627f7eb2Smrg executor_type get_executor() noexcept; 865627f7eb2Smrg 866627f7eb2Smrg void stop() 867627f7eb2Smrg { 868627f7eb2Smrg lock_guard<mutex> __lock(_M_mtx); 869627f7eb2Smrg _M_stopped = true; 870627f7eb2Smrg _M_cv.notify_all(); 871627f7eb2Smrg } 872627f7eb2Smrg 873627f7eb2Smrg bool stopped() const noexcept 874627f7eb2Smrg { 875627f7eb2Smrg lock_guard<mutex> __lock(_M_mtx); 876627f7eb2Smrg return _M_stopped; 877627f7eb2Smrg } 878627f7eb2Smrg 879627f7eb2Smrg void join() 880627f7eb2Smrg { 881*4c3eb207Smrg if (_M_thread.joinable()) 882627f7eb2Smrg _M_thread.join(); 883627f7eb2Smrg } 884627f7eb2Smrg 885627f7eb2Smrg private: 886627f7eb2Smrg friend system_executor; 887627f7eb2Smrg 888627f7eb2Smrg struct __tag { }; 889627f7eb2Smrg system_context(__tag) { } 890627f7eb2Smrg 891627f7eb2Smrg thread _M_thread; 892627f7eb2Smrg mutable mutex _M_mtx; 893627f7eb2Smrg condition_variable _M_cv; 894627f7eb2Smrg queue<function<void()>> _M_tasks; 895627f7eb2Smrg bool _M_stopped = false; 896627f7eb2Smrg 897627f7eb2Smrg void 898627f7eb2Smrg _M_run() 899627f7eb2Smrg { 900627f7eb2Smrg while (true) 901627f7eb2Smrg { 902627f7eb2Smrg function<void()> __f; 903627f7eb2Smrg { 904627f7eb2Smrg unique_lock<mutex> __lock(_M_mtx); 905627f7eb2Smrg _M_cv.wait(__lock, 906*4c3eb207Smrg [this]{ return _M_stopped || !_M_tasks.empty(); }); 907627f7eb2Smrg if (_M_stopped) 908627f7eb2Smrg return; 909627f7eb2Smrg __f = std::move(_M_tasks.front()); 910627f7eb2Smrg _M_tasks.pop(); 911627f7eb2Smrg } 912627f7eb2Smrg __f(); 913627f7eb2Smrg } 914627f7eb2Smrg } 915627f7eb2Smrg 916627f7eb2Smrg void 917627f7eb2Smrg _M_post(std::function<void()> __f) 918627f7eb2Smrg { 919627f7eb2Smrg lock_guard<mutex> __lock(_M_mtx); 920627f7eb2Smrg if (_M_stopped) 921627f7eb2Smrg return; 922627f7eb2Smrg if (!_M_thread.joinable()) 923627f7eb2Smrg _M_thread = std::thread(&system_context::_M_run, this); 924627f7eb2Smrg _M_tasks.push(std::move(__f)); // XXX allocator not used 925627f7eb2Smrg _M_cv.notify_one(); 926627f7eb2Smrg } 927627f7eb2Smrg 928627f7eb2Smrg static system_context& 929627f7eb2Smrg _S_get() noexcept 930627f7eb2Smrg { 931627f7eb2Smrg static system_context __sc(__tag{}); 932627f7eb2Smrg return __sc; 933627f7eb2Smrg } 934627f7eb2Smrg }; 935627f7eb2Smrg 936627f7eb2Smrg class system_executor 937627f7eb2Smrg { 938627f7eb2Smrg public: 939627f7eb2Smrg // executor operations: 940627f7eb2Smrg 941627f7eb2Smrg system_executor() { } 942627f7eb2Smrg 943627f7eb2Smrg system_context& 944627f7eb2Smrg context() const noexcept { return system_context::_S_get(); } 945627f7eb2Smrg 946627f7eb2Smrg void on_work_started() const noexcept { } 947627f7eb2Smrg void on_work_finished() const noexcept { } 948627f7eb2Smrg 949627f7eb2Smrg template<typename _Func, typename _ProtoAlloc> 950627f7eb2Smrg void 951627f7eb2Smrg dispatch(_Func&& __f, const _ProtoAlloc& __a) const 952627f7eb2Smrg { decay_t<_Func>{std::forward<_Func>(__f)}(); } 953627f7eb2Smrg 954627f7eb2Smrg template<typename _Func, typename _ProtoAlloc> 955627f7eb2Smrg void 956627f7eb2Smrg post(_Func&& __f, const _ProtoAlloc&) const // XXX allocator not used 957627f7eb2Smrg { 958627f7eb2Smrg system_context::_S_get()._M_post(std::forward<_Func>(__f)); 959627f7eb2Smrg } 960627f7eb2Smrg 961627f7eb2Smrg template<typename _Func, typename _ProtoAlloc> 962627f7eb2Smrg void 963627f7eb2Smrg defer(_Func&& __f, const _ProtoAlloc& __a) const 964627f7eb2Smrg { post(std::forward<_Func>(__f), __a); } 965627f7eb2Smrg }; 966627f7eb2Smrg 967627f7eb2Smrg inline system_executor 968627f7eb2Smrg system_context::get_executor() noexcept 969627f7eb2Smrg { return {}; } 970627f7eb2Smrg 971627f7eb2Smrg class bad_executor : public std::exception 972627f7eb2Smrg { 973627f7eb2Smrg virtual const char* what() const noexcept { return "bad executor"; } 974627f7eb2Smrg }; 975627f7eb2Smrg 976627f7eb2Smrg inline void __throw_bad_executor() // TODO make non-inline 977627f7eb2Smrg { 978627f7eb2Smrg#if __cpp_exceptions 979627f7eb2Smrg throw bad_executor(); 980627f7eb2Smrg#else 981627f7eb2Smrg __builtin_abort(); 982627f7eb2Smrg#endif 983627f7eb2Smrg } 984627f7eb2Smrg 985627f7eb2Smrg class executor 986627f7eb2Smrg { 987627f7eb2Smrg public: 988627f7eb2Smrg // construct / copy / destroy: 989627f7eb2Smrg 990627f7eb2Smrg executor() noexcept = default; 991627f7eb2Smrg 992627f7eb2Smrg executor(nullptr_t) noexcept { } 993627f7eb2Smrg executor(const executor&) noexcept = default; 994627f7eb2Smrg executor(executor&&) noexcept = default; 995627f7eb2Smrg 996627f7eb2Smrg template<typename _Executor> 997627f7eb2Smrg executor(_Executor __e) 998*4c3eb207Smrg : _M_target(make_shared<_Tgt1<_Executor>>(std::move(__e))) 999627f7eb2Smrg { } 1000627f7eb2Smrg 1001627f7eb2Smrg template<typename _Executor, typename _ProtoAlloc> 1002627f7eb2Smrg executor(allocator_arg_t, const _ProtoAlloc& __a, _Executor __e) 1003*4c3eb207Smrg : _M_target(allocate_shared<_Tgt2<_Executor, _ProtoAlloc>>(__a, 1004*4c3eb207Smrg std::move(__e), __a)) 1005627f7eb2Smrg { } 1006627f7eb2Smrg 1007627f7eb2Smrg executor& operator=(const executor&) noexcept = default; 1008627f7eb2Smrg executor& operator=(executor&&) noexcept = default; 1009627f7eb2Smrg 1010627f7eb2Smrg executor& 1011627f7eb2Smrg operator=(nullptr_t) noexcept 1012627f7eb2Smrg { 1013627f7eb2Smrg _M_target = nullptr; 1014627f7eb2Smrg return *this; 1015627f7eb2Smrg } 1016627f7eb2Smrg 1017627f7eb2Smrg template<typename _Executor> 1018627f7eb2Smrg executor& 1019627f7eb2Smrg operator=(_Executor __e) 1020627f7eb2Smrg { 1021627f7eb2Smrg executor(std::move(__e)).swap(*this); 1022627f7eb2Smrg return *this; 1023627f7eb2Smrg } 1024627f7eb2Smrg 1025627f7eb2Smrg ~executor() = default; 1026627f7eb2Smrg 1027627f7eb2Smrg // executor modifiers: 1028627f7eb2Smrg 1029627f7eb2Smrg void 1030627f7eb2Smrg swap(executor& __other) noexcept 1031627f7eb2Smrg { _M_target.swap(__other._M_target); } 1032627f7eb2Smrg 1033627f7eb2Smrg template<typename _Executor, typename _Alloc> 1034627f7eb2Smrg void 1035627f7eb2Smrg assign(_Executor __e, const _Alloc& __a) 1036627f7eb2Smrg { executor(allocator_arg, __a, std::move(__e)).swap(*this); } 1037627f7eb2Smrg 1038627f7eb2Smrg // executor operations: 1039627f7eb2Smrg 1040627f7eb2Smrg execution_context& 1041627f7eb2Smrg context() const noexcept 1042627f7eb2Smrg { 1043627f7eb2Smrg __glibcxx_assert( _M_target ); 1044627f7eb2Smrg return _M_target->context(); 1045627f7eb2Smrg } 1046627f7eb2Smrg 1047627f7eb2Smrg void 1048627f7eb2Smrg on_work_started() const noexcept 1049627f7eb2Smrg { 1050627f7eb2Smrg __glibcxx_assert( _M_target ); 1051627f7eb2Smrg return _M_target->on_work_started(); 1052627f7eb2Smrg } 1053627f7eb2Smrg 1054627f7eb2Smrg void 1055627f7eb2Smrg on_work_finished() const noexcept 1056627f7eb2Smrg { 1057627f7eb2Smrg __glibcxx_assert( _M_target ); 1058627f7eb2Smrg return _M_target->on_work_finished(); 1059627f7eb2Smrg } 1060627f7eb2Smrg 1061627f7eb2Smrg template<typename _Func, typename _Alloc> 1062627f7eb2Smrg void 1063627f7eb2Smrg dispatch(_Func&& __f, const _Alloc& __a) const 1064627f7eb2Smrg { 1065627f7eb2Smrg if (!_M_target) 1066627f7eb2Smrg __throw_bad_executor(); 1067627f7eb2Smrg // _M_target->dispatch({allocator_arg, __a, std::forward<_Func>(__f)}); 1068627f7eb2Smrg _M_target->dispatch(std::forward<_Func>(__f)); 1069627f7eb2Smrg } 1070627f7eb2Smrg 1071627f7eb2Smrg template<typename _Func, typename _Alloc> 1072627f7eb2Smrg void 1073627f7eb2Smrg post(_Func&& __f, const _Alloc& __a) const 1074627f7eb2Smrg { 1075627f7eb2Smrg if (!_M_target) 1076627f7eb2Smrg __throw_bad_executor(); 1077627f7eb2Smrg // _M_target->post({allocator_arg, __a, std::forward<_Func>(__f)}); 1078627f7eb2Smrg _M_target->post(std::forward<_Func>(__f)); 1079627f7eb2Smrg } 1080627f7eb2Smrg 1081627f7eb2Smrg template<typename _Func, typename _Alloc> 1082627f7eb2Smrg void 1083627f7eb2Smrg defer(_Func&& __f, const _Alloc& __a) const 1084627f7eb2Smrg { 1085627f7eb2Smrg if (!_M_target) 1086627f7eb2Smrg __throw_bad_executor(); 1087627f7eb2Smrg // _M_target->defer({allocator_arg, __a, std::forward<_Func>(__f)}); 1088627f7eb2Smrg _M_target->defer(std::forward<_Func>(__f)); 1089627f7eb2Smrg } 1090627f7eb2Smrg 1091627f7eb2Smrg // executor capacity: 1092627f7eb2Smrg 1093627f7eb2Smrg explicit operator bool() const noexcept 1094627f7eb2Smrg { return static_cast<bool>(_M_target); } 1095627f7eb2Smrg 1096627f7eb2Smrg // executor target access: 1097627f7eb2Smrg 1098627f7eb2Smrg#if __cpp_rtti 1099627f7eb2Smrg const type_info& 1100627f7eb2Smrg target_type() const noexcept 1101*4c3eb207Smrg { 1102*4c3eb207Smrg if (_M_target) 1103*4c3eb207Smrg return *static_cast<const type_info*>(_M_target->target_type()); 1104*4c3eb207Smrg return typeid(void); 1105*4c3eb207Smrg } 1106*4c3eb207Smrg#endif 1107627f7eb2Smrg 1108627f7eb2Smrg template<typename _Executor> 1109627f7eb2Smrg _Executor* 1110627f7eb2Smrg target() noexcept 1111627f7eb2Smrg { 1112*4c3eb207Smrg void* __p = nullptr; 1113627f7eb2Smrg if (_M_target) 1114*4c3eb207Smrg { 1115*4c3eb207Smrg if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func) 1116*4c3eb207Smrg __p = _M_target->_M_func(_M_target.get(), nullptr); 1117*4c3eb207Smrg#if __cpp_rtti 1118*4c3eb207Smrg else 1119*4c3eb207Smrg __p = _M_target->target(&typeid(_Executor)); 1120*4c3eb207Smrg#endif 1121*4c3eb207Smrg } 1122*4c3eb207Smrg return static_cast<_Executor*>(__p); 1123627f7eb2Smrg } 1124627f7eb2Smrg 1125627f7eb2Smrg template<typename _Executor> 1126627f7eb2Smrg const _Executor* 1127627f7eb2Smrg target() const noexcept 1128627f7eb2Smrg { 1129*4c3eb207Smrg const void* __p = nullptr; 1130627f7eb2Smrg if (_M_target) 1131*4c3eb207Smrg { 1132*4c3eb207Smrg if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func) 1133*4c3eb207Smrg return (_Executor*)_M_target->_M_func(_M_target.get(), nullptr); 1134*4c3eb207Smrg#if __cpp_rtti 1135*4c3eb207Smrg else 1136*4c3eb207Smrg __p = _M_target->target(&typeid(_Executor)); 1137627f7eb2Smrg#endif 1138*4c3eb207Smrg } 1139*4c3eb207Smrg return static_cast<const _Executor*>(__p); 1140*4c3eb207Smrg } 1141627f7eb2Smrg 1142627f7eb2Smrg private: 1143627f7eb2Smrg struct _Tgt 1144627f7eb2Smrg { 1145627f7eb2Smrg virtual void on_work_started() const noexcept = 0; 1146627f7eb2Smrg virtual void on_work_finished() const noexcept = 0; 1147627f7eb2Smrg virtual execution_context& context() const noexcept = 0; 1148627f7eb2Smrg virtual void dispatch(std::function<void()>) const = 0; 1149627f7eb2Smrg virtual void post(std::function<void()>) const = 0; 1150627f7eb2Smrg virtual void defer(std::function<void()>) const = 0; 1151*4c3eb207Smrg virtual const void* target_type() const noexcept = 0; 1152*4c3eb207Smrg virtual void* target(const void*) noexcept = 0; 1153627f7eb2Smrg virtual bool _M_equals(_Tgt*) const noexcept = 0; 1154*4c3eb207Smrg 1155*4c3eb207Smrg using _Func = void* (_Tgt*, const _Tgt*); 1156*4c3eb207Smrg _Func* _M_func; // Provides access to target without RTTI 1157627f7eb2Smrg }; 1158627f7eb2Smrg 1159*4c3eb207Smrg template<typename _Ex> 1160*4c3eb207Smrg struct _Tgt1 : _Tgt 1161627f7eb2Smrg { 1162627f7eb2Smrg explicit 1163*4c3eb207Smrg _Tgt1(_Ex&& __ex) 1164*4c3eb207Smrg : _M_ex(std::move(__ex)) 1165*4c3eb207Smrg { this->_M_func = &_S_func; } 1166627f7eb2Smrg 1167627f7eb2Smrg void 1168*4c3eb207Smrg on_work_started() const noexcept override 1169*4c3eb207Smrg { _M_ex.on_work_started(); } 1170627f7eb2Smrg 1171*4c3eb207Smrg void 1172*4c3eb207Smrg on_work_finished() const noexcept override 1173*4c3eb207Smrg { _M_ex.on_work_finished(); } 1174627f7eb2Smrg 1175*4c3eb207Smrg execution_context& 1176*4c3eb207Smrg context() const noexcept override 1177*4c3eb207Smrg { return _M_ex.context(); } 1178*4c3eb207Smrg 1179*4c3eb207Smrg void 1180*4c3eb207Smrg dispatch(std::function<void()> __f) const override 1181*4c3eb207Smrg { _M_ex.dispatch(std::move(__f), allocator<void>()); } 1182*4c3eb207Smrg 1183*4c3eb207Smrg void 1184*4c3eb207Smrg post(std::function<void()> __f) const override 1185*4c3eb207Smrg { _M_ex.post(std::move(__f), allocator<void>()); } 1186*4c3eb207Smrg 1187*4c3eb207Smrg void 1188*4c3eb207Smrg defer(std::function<void()> __f) const override 1189*4c3eb207Smrg { _M_ex.defer(std::move(__f), allocator<void>()); } 1190*4c3eb207Smrg 1191*4c3eb207Smrg const void* 1192*4c3eb207Smrg target_type() const noexcept override 1193627f7eb2Smrg { 1194*4c3eb207Smrg#if __cpp_rtti 1195*4c3eb207Smrg return &typeid(_Ex); 1196*4c3eb207Smrg#else 1197*4c3eb207Smrg return nullptr; 1198*4c3eb207Smrg#endif 1199*4c3eb207Smrg } 1200*4c3eb207Smrg 1201*4c3eb207Smrg void* 1202*4c3eb207Smrg target(const void* __ti) noexcept override 1203*4c3eb207Smrg { 1204*4c3eb207Smrg#if __cpp_rtti 1205*4c3eb207Smrg if (*static_cast<const type_info*>(__ti) == typeid(_Ex)) 1206*4c3eb207Smrg return std::__addressof(_M_ex); 1207*4c3eb207Smrg#endif 1208627f7eb2Smrg return nullptr; 1209627f7eb2Smrg } 1210627f7eb2Smrg 1211*4c3eb207Smrg bool 1212*4c3eb207Smrg _M_equals(_Tgt* __tgt) const noexcept override 1213627f7eb2Smrg { 1214*4c3eb207Smrg#if __cpp_rtti 1215*4c3eb207Smrg if (const void* __p = __tgt->target(&typeid(_Ex))) 1216*4c3eb207Smrg return *static_cast<const _Ex*>(__p) == _M_ex; 1217*4c3eb207Smrg#endif 1218627f7eb2Smrg return false; 1219627f7eb2Smrg } 1220627f7eb2Smrg 1221*4c3eb207Smrg _Ex _M_ex [[__no_unique_address__]]; 1222627f7eb2Smrg 1223*4c3eb207Smrg static void* 1224*4c3eb207Smrg _S_func(_Tgt* __p, const _Tgt* __q) noexcept 1225*4c3eb207Smrg { 1226*4c3eb207Smrg auto& __ex = static_cast<_Tgt1*>(__p)->_M_ex; 1227*4c3eb207Smrg if (__q) 1228*4c3eb207Smrg { 1229*4c3eb207Smrg if (__ex == static_cast<const _Tgt1*>(__q)->_M_ex) 1230*4c3eb207Smrg return __p; 1231*4c3eb207Smrg else 1232*4c3eb207Smrg return nullptr; 1233*4c3eb207Smrg } 1234*4c3eb207Smrg else 1235*4c3eb207Smrg return std::__addressof(__ex); 1236*4c3eb207Smrg } 1237627f7eb2Smrg }; 1238627f7eb2Smrg 1239*4c3eb207Smrg template<typename _Ex, typename _Alloc> 1240*4c3eb207Smrg struct _Tgt2 : _Tgt1<_Ex> 1241627f7eb2Smrg { 1242*4c3eb207Smrg explicit 1243*4c3eb207Smrg _Tgt2(_Ex&& __ex, const _Alloc& __a) 1244*4c3eb207Smrg : _Tgt1<_Ex>(std::move(__ex)), _M_alloc(__a) { } 1245*4c3eb207Smrg 1246*4c3eb207Smrg void 1247*4c3eb207Smrg dispatch(std::function<void()> __f) const override 1248*4c3eb207Smrg { this->_M_ex.dispatch(std::move(__f), _M_alloc); } 1249*4c3eb207Smrg 1250*4c3eb207Smrg void 1251*4c3eb207Smrg post(std::function<void()> __f) const override 1252*4c3eb207Smrg { this->_M_ex.post(std::move(__f), _M_alloc); } 1253*4c3eb207Smrg 1254*4c3eb207Smrg void 1255*4c3eb207Smrg defer(std::function<void()> __f) const override 1256*4c3eb207Smrg { this->_M_ex.defer(std::move(__f), _M_alloc); } 1257*4c3eb207Smrg 1258*4c3eb207Smrg _Alloc _M_alloc [[__no_unique_address__]]; 1259*4c3eb207Smrg }; 1260*4c3eb207Smrg 1261*4c3eb207Smrg // Partial specialization for std::allocator<T>. 1262*4c3eb207Smrg // Don't store the allocator. 1263*4c3eb207Smrg template<typename _Ex, typename _Tp> 1264*4c3eb207Smrg struct _Tgt2<_Ex, std::allocator<_Tp>> : _Tgt1<_Ex> 1265*4c3eb207Smrg { }; 1266627f7eb2Smrg 1267627f7eb2Smrg friend bool 1268627f7eb2Smrg operator==(const executor& __a, const executor& __b) noexcept 1269627f7eb2Smrg { 1270*4c3eb207Smrg _Tgt* __ta = __a._M_target.get(); 1271*4c3eb207Smrg _Tgt* __tb = __b._M_target.get(); 1272*4c3eb207Smrg if (__ta == __tb) 1273627f7eb2Smrg return true; 1274*4c3eb207Smrg if (!__ta || !__tb) 1275627f7eb2Smrg return false; 1276*4c3eb207Smrg if (__ta->_M_func == __tb->_M_func) 1277*4c3eb207Smrg return __ta->_M_func(__ta, __tb); 1278*4c3eb207Smrg return __ta->_M_equals(__tb); 1279627f7eb2Smrg } 1280627f7eb2Smrg 1281627f7eb2Smrg shared_ptr<_Tgt> _M_target; 1282627f7eb2Smrg }; 1283627f7eb2Smrg 1284627f7eb2Smrg template<> struct is_executor<executor> : true_type { }; 1285627f7eb2Smrg 1286627f7eb2Smrg /// executor comparisons 1287627f7eb2Smrg inline bool 1288627f7eb2Smrg operator==(const executor& __e, nullptr_t) noexcept 1289627f7eb2Smrg { return !__e; } 1290627f7eb2Smrg 1291*4c3eb207Smrg inline bool 1292*4c3eb207Smrg operator==(nullptr_t, const executor& __e) noexcept 1293*4c3eb207Smrg { return !__e; } 1294*4c3eb207Smrg 1295*4c3eb207Smrg inline bool 1296*4c3eb207Smrg operator!=(const executor& __a, const executor& __b) noexcept 1297*4c3eb207Smrg { return !(__a == __b); } 1298*4c3eb207Smrg 1299*4c3eb207Smrg inline bool 1300*4c3eb207Smrg operator!=(const executor& __e, nullptr_t) noexcept 1301*4c3eb207Smrg { return (bool)__e; } 1302*4c3eb207Smrg 1303*4c3eb207Smrg inline bool 1304*4c3eb207Smrg operator!=(nullptr_t, const executor& __e) noexcept 1305*4c3eb207Smrg { return (bool)__e; } 1306*4c3eb207Smrg 1307627f7eb2Smrg /// Swap two executor objects. 1308627f7eb2Smrg inline void swap(executor& __a, executor& __b) noexcept { __a.swap(__b); } 1309627f7eb2Smrg 1310627f7eb2Smrg 1311627f7eb2Smrg template<typename _CompletionHandler> 1312627f7eb2Smrg struct __dispatcher 1313627f7eb2Smrg { 1314627f7eb2Smrg explicit 1315627f7eb2Smrg __dispatcher(_CompletionHandler& __h) 1316627f7eb2Smrg : _M_h(std::move(__h)), _M_w(net::make_work_guard(_M_h)) 1317627f7eb2Smrg { } 1318627f7eb2Smrg 1319627f7eb2Smrg void operator()() 1320627f7eb2Smrg { 1321627f7eb2Smrg auto __alloc = net::get_associated_allocator(_M_h); 1322627f7eb2Smrg _M_w.get_executor().dispatch(std::move(_M_h), __alloc); 1323627f7eb2Smrg _M_w.reset(); 1324627f7eb2Smrg } 1325627f7eb2Smrg 1326627f7eb2Smrg _CompletionHandler _M_h; 1327627f7eb2Smrg decltype(net::make_work_guard(_M_h)) _M_w; 1328627f7eb2Smrg }; 1329627f7eb2Smrg 1330627f7eb2Smrg template<typename _CompletionHandler> 1331627f7eb2Smrg inline __dispatcher<_CompletionHandler> 1332627f7eb2Smrg __make_dispatcher(_CompletionHandler& __h) 1333627f7eb2Smrg { return __dispatcher<_CompletionHandler>{__h}; } 1334627f7eb2Smrg 1335627f7eb2Smrg 1336627f7eb2Smrg 1337627f7eb2Smrg // dispatch: 1338627f7eb2Smrg 1339627f7eb2Smrg template<typename _CompletionToken> 1340627f7eb2Smrg inline __deduced_t<_CompletionToken, void()> 1341627f7eb2Smrg dispatch(_CompletionToken&& __token) 1342627f7eb2Smrg { 1343627f7eb2Smrg async_completion<_CompletionToken, void()> __cmpl{__token}; 1344627f7eb2Smrg auto __ex = net::get_associated_executor(__cmpl.completion_handler); 1345627f7eb2Smrg auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1346627f7eb2Smrg __ex.dispatch(std::move(__cmpl.completion_handler), __alloc); 1347627f7eb2Smrg return __cmpl.result.get(); 1348627f7eb2Smrg } 1349627f7eb2Smrg 1350627f7eb2Smrg template<typename _Executor, typename _CompletionToken> 1351627f7eb2Smrg inline 1352627f7eb2Smrg enable_if_t<is_executor<_Executor>::value, 1353627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 1354627f7eb2Smrg dispatch(const _Executor& __ex, _CompletionToken&& __token) 1355627f7eb2Smrg { 1356627f7eb2Smrg async_completion<_CompletionToken, void()> __cmpl{__token}; 1357627f7eb2Smrg auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1358627f7eb2Smrg __ex.dispatch(net::__make_dispatcher(__cmpl.completion_handler), 1359627f7eb2Smrg __alloc); 1360627f7eb2Smrg return __cmpl.result.get(); 1361627f7eb2Smrg } 1362627f7eb2Smrg 1363627f7eb2Smrg template<typename _ExecutionContext, typename _CompletionToken> 1364627f7eb2Smrg inline 1365627f7eb2Smrg enable_if_t<__is_exec_context<_ExecutionContext>::value, 1366627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 1367627f7eb2Smrg dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token) 1368627f7eb2Smrg { 1369627f7eb2Smrg return net::dispatch(__ctx.get_executor(), 1370627f7eb2Smrg forward<_CompletionToken>(__token)); 1371627f7eb2Smrg } 1372627f7eb2Smrg 1373627f7eb2Smrg // post: 1374627f7eb2Smrg 1375627f7eb2Smrg template<typename _CompletionToken> 1376627f7eb2Smrg inline __deduced_t<_CompletionToken, void()> 1377627f7eb2Smrg post(_CompletionToken&& __token) 1378627f7eb2Smrg { 1379627f7eb2Smrg async_completion<_CompletionToken, void()> __cmpl{__token}; 1380627f7eb2Smrg auto __ex = net::get_associated_executor(__cmpl.completion_handler); 1381627f7eb2Smrg auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1382627f7eb2Smrg __ex.post(std::move(__cmpl.completion_handler), __alloc); 1383627f7eb2Smrg return __cmpl.result.get(); 1384627f7eb2Smrg } 1385627f7eb2Smrg 1386627f7eb2Smrg template<typename _Executor, typename _CompletionToken> 1387627f7eb2Smrg inline 1388627f7eb2Smrg enable_if_t<is_executor<_Executor>::value, 1389627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 1390627f7eb2Smrg post(const _Executor& __ex, _CompletionToken&& __token) 1391627f7eb2Smrg { 1392627f7eb2Smrg async_completion<_CompletionToken, void()> __cmpl{__token}; 1393627f7eb2Smrg auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1394627f7eb2Smrg __ex.post(net::__make_dispatcher(__cmpl.completion_handler), __alloc); 1395627f7eb2Smrg return __cmpl.result.get(); 1396627f7eb2Smrg } 1397627f7eb2Smrg 1398627f7eb2Smrg template<typename _ExecutionContext, typename _CompletionToken> 1399627f7eb2Smrg inline 1400627f7eb2Smrg enable_if_t<__is_exec_context<_ExecutionContext>::value, 1401627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 1402627f7eb2Smrg post(_ExecutionContext& __ctx, _CompletionToken&& __token) 1403627f7eb2Smrg { 1404627f7eb2Smrg return net::post(__ctx.get_executor(), 1405627f7eb2Smrg forward<_CompletionToken>(__token)); 1406627f7eb2Smrg } 1407627f7eb2Smrg 1408627f7eb2Smrg // defer: 1409627f7eb2Smrg 1410627f7eb2Smrg template<typename _CompletionToken> 1411627f7eb2Smrg inline __deduced_t<_CompletionToken, void()> 1412627f7eb2Smrg defer(_CompletionToken&& __token) 1413627f7eb2Smrg { 1414627f7eb2Smrg async_completion<_CompletionToken, void()> __cmpl{__token}; 1415627f7eb2Smrg auto __ex = net::get_associated_executor(__cmpl.completion_handler); 1416627f7eb2Smrg auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1417627f7eb2Smrg __ex.defer(std::move(__cmpl.completion_handler), __alloc); 1418627f7eb2Smrg return __cmpl.result.get(); 1419627f7eb2Smrg } 1420627f7eb2Smrg 1421627f7eb2Smrg template<typename _Executor, typename _CompletionToken> 1422627f7eb2Smrg inline 1423627f7eb2Smrg enable_if_t<is_executor<_Executor>::value, 1424627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 1425627f7eb2Smrg defer(const _Executor& __ex, _CompletionToken&& __token) 1426627f7eb2Smrg { 1427627f7eb2Smrg async_completion<_CompletionToken, void()> __cmpl{__token}; 1428627f7eb2Smrg auto __alloc = net::get_associated_allocator(__cmpl.completion_handler); 1429627f7eb2Smrg __ex.defer(net::__make_dispatcher(__cmpl.completion_handler), __alloc); 1430627f7eb2Smrg return __cmpl.result.get(); 1431627f7eb2Smrg } 1432627f7eb2Smrg 1433627f7eb2Smrg template<typename _ExecutionContext, typename _CompletionToken> 1434627f7eb2Smrg inline 1435627f7eb2Smrg enable_if_t<__is_exec_context<_ExecutionContext>::value, 1436627f7eb2Smrg __deduced_t<_CompletionToken, void()>> 1437627f7eb2Smrg defer(_ExecutionContext& __ctx, _CompletionToken&& __token) 1438627f7eb2Smrg { 1439627f7eb2Smrg return net::defer(__ctx.get_executor(), 1440627f7eb2Smrg forward<_CompletionToken>(__token)); 1441627f7eb2Smrg } 1442627f7eb2Smrg 1443627f7eb2Smrg 1444627f7eb2Smrg template<typename _Executor> 1445627f7eb2Smrg class strand 1446627f7eb2Smrg { 1447627f7eb2Smrg public: 1448627f7eb2Smrg // types: 1449627f7eb2Smrg 1450627f7eb2Smrg typedef _Executor inner_executor_type; 1451627f7eb2Smrg 1452627f7eb2Smrg // construct / copy / destroy: 1453627f7eb2Smrg 1454627f7eb2Smrg strand(); // TODO make state 1455627f7eb2Smrg 1456627f7eb2Smrg explicit strand(_Executor __ex) : _M_inner_ex(__ex) { } // TODO make state 1457627f7eb2Smrg 1458627f7eb2Smrg template<typename _Alloc> 1459627f7eb2Smrg strand(allocator_arg_t, const _Alloc& __a, _Executor __ex) 1460627f7eb2Smrg : _M_inner_ex(__ex) { } // TODO make state 1461627f7eb2Smrg 1462627f7eb2Smrg strand(const strand& __other) noexcept 1463627f7eb2Smrg : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { } 1464627f7eb2Smrg 1465627f7eb2Smrg strand(strand&& __other) noexcept 1466627f7eb2Smrg : _M_state(std::move(__other._M_state)), 1467627f7eb2Smrg _M_inner_ex(std::move(__other._M_inner_ex)) { } 1468627f7eb2Smrg 1469627f7eb2Smrg template<typename _OtherExecutor> 1470627f7eb2Smrg strand(const strand<_OtherExecutor>& __other) noexcept 1471627f7eb2Smrg : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { } 1472627f7eb2Smrg 1473627f7eb2Smrg template<typename _OtherExecutor> 1474627f7eb2Smrg strand(strand<_OtherExecutor>&& __other) noexcept 1475627f7eb2Smrg : _M_state(std::move(__other._M_state)), 1476627f7eb2Smrg _M_inner_ex(std::move(__other._M_inner_ex)) { } 1477627f7eb2Smrg 1478627f7eb2Smrg strand& 1479627f7eb2Smrg operator=(const strand& __other) noexcept 1480627f7eb2Smrg { 1481627f7eb2Smrg static_assert(is_copy_assignable<_Executor>::value, 1482627f7eb2Smrg "inner executor type must be CopyAssignable"); 1483627f7eb2Smrg 1484627f7eb2Smrg // TODO lock __other 1485627f7eb2Smrg // TODO copy state 1486627f7eb2Smrg _M_inner_ex = __other._M_inner_ex; 1487627f7eb2Smrg return *this; 1488627f7eb2Smrg } 1489627f7eb2Smrg 1490627f7eb2Smrg strand& 1491627f7eb2Smrg operator=(strand&& __other) noexcept 1492627f7eb2Smrg { 1493627f7eb2Smrg static_assert(is_move_assignable<_Executor>::value, 1494627f7eb2Smrg "inner executor type must be MoveAssignable"); 1495627f7eb2Smrg 1496627f7eb2Smrg // TODO move state 1497627f7eb2Smrg _M_inner_ex = std::move(__other._M_inner_ex); 1498627f7eb2Smrg return *this; 1499627f7eb2Smrg } 1500627f7eb2Smrg 1501627f7eb2Smrg template<typename _OtherExecutor> 1502627f7eb2Smrg strand& 1503627f7eb2Smrg operator=(const strand<_OtherExecutor>& __other) noexcept 1504627f7eb2Smrg { 1505627f7eb2Smrg static_assert(is_convertible<_OtherExecutor, _Executor>::value, 1506627f7eb2Smrg "inner executor type must be compatible"); 1507627f7eb2Smrg 1508627f7eb2Smrg // TODO lock __other 1509627f7eb2Smrg // TODO copy state 1510627f7eb2Smrg _M_inner_ex = __other._M_inner_ex; 1511627f7eb2Smrg return *this; 1512627f7eb2Smrg } 1513627f7eb2Smrg 1514627f7eb2Smrg template<typename _OtherExecutor> 1515627f7eb2Smrg strand& 1516627f7eb2Smrg operator=(strand<_OtherExecutor>&& __other) noexcept 1517627f7eb2Smrg { 1518627f7eb2Smrg static_assert(is_convertible<_OtherExecutor, _Executor>::value, 1519627f7eb2Smrg "inner executor type must be compatible"); 1520627f7eb2Smrg 1521627f7eb2Smrg // TODO move state 1522627f7eb2Smrg _M_inner_ex = std::move(__other._M_inner_ex); 1523627f7eb2Smrg return *this; 1524627f7eb2Smrg } 1525627f7eb2Smrg 1526627f7eb2Smrg ~strand() 1527627f7eb2Smrg { 1528627f7eb2Smrg // the task queue outlives this object if non-empty 1529627f7eb2Smrg // TODO create circular ref in queue? 1530627f7eb2Smrg } 1531627f7eb2Smrg 1532627f7eb2Smrg // strand operations: 1533627f7eb2Smrg 1534627f7eb2Smrg inner_executor_type 1535627f7eb2Smrg get_inner_executor() const noexcept 1536627f7eb2Smrg { return _M_inner_ex; } 1537627f7eb2Smrg 1538627f7eb2Smrg bool 1539627f7eb2Smrg running_in_this_thread() const noexcept 1540627f7eb2Smrg { return std::this_thread::get_id() == _M_state->_M_running_on; } 1541627f7eb2Smrg 1542627f7eb2Smrg execution_context& 1543627f7eb2Smrg context() const noexcept 1544627f7eb2Smrg { return _M_inner_ex.context(); } 1545627f7eb2Smrg 1546627f7eb2Smrg void on_work_started() const noexcept { _M_inner_ex.on_work_started(); } 1547627f7eb2Smrg void on_work_finished() const noexcept { _M_inner_ex.on_work_finished(); } 1548627f7eb2Smrg 1549627f7eb2Smrg template<typename _Func, typename _Alloc> 1550627f7eb2Smrg void 1551627f7eb2Smrg dispatch(_Func&& __f, const _Alloc& __a) const 1552627f7eb2Smrg { 1553627f7eb2Smrg if (running_in_this_thread()) 1554627f7eb2Smrg decay_t<_Func>{std::forward<_Func>(__f)}(); 1555627f7eb2Smrg else 1556627f7eb2Smrg post(std::forward<_Func>(__f), __a); 1557627f7eb2Smrg } 1558627f7eb2Smrg 1559627f7eb2Smrg template<typename _Func, typename _Alloc> 1560627f7eb2Smrg void 1561627f7eb2Smrg post(_Func&& __f, const _Alloc& __a) const; // TODO 1562627f7eb2Smrg 1563627f7eb2Smrg template<typename _Func, typename _Alloc> 1564627f7eb2Smrg void 1565627f7eb2Smrg defer(_Func&& __f, const _Alloc& __a) const 1566627f7eb2Smrg { post(std::forward<_Func>(__f), __a); } 1567627f7eb2Smrg 1568627f7eb2Smrg private: 1569627f7eb2Smrg friend bool 1570627f7eb2Smrg operator==(const strand& __a, const strand& __b) 1571627f7eb2Smrg { return __a._M_state == __b._M_state; } 1572627f7eb2Smrg 1573627f7eb2Smrg // TODO add synchronised queue 1574627f7eb2Smrg struct _State 1575627f7eb2Smrg { 1576627f7eb2Smrg std::thread::id _M_running_on; 1577627f7eb2Smrg }; 1578627f7eb2Smrg shared_ptr<_State> _M_state; 1579627f7eb2Smrg _Executor _M_inner_ex; 1580627f7eb2Smrg }; 1581627f7eb2Smrg 1582627f7eb2Smrg#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) 1583627f7eb2Smrg 1584627f7eb2Smrg // Completion token for asynchronous operations initiated with use_future. 1585627f7eb2Smrg template<typename _Func, typename _Alloc> 1586627f7eb2Smrg struct __use_future_ct 1587627f7eb2Smrg { 1588627f7eb2Smrg std::tuple<_Func, _Alloc> _M_t; 1589627f7eb2Smrg }; 1590627f7eb2Smrg 1591*4c3eb207Smrg template<typename _Func, typename _Tp> 1592*4c3eb207Smrg struct __use_future_ct<_Func, std::allocator<_Tp>> 1593*4c3eb207Smrg { 1594*4c3eb207Smrg _Func _M_f; 1595*4c3eb207Smrg }; 1596*4c3eb207Smrg 1597627f7eb2Smrg template<typename _ProtoAllocator = allocator<void>> 1598627f7eb2Smrg class use_future_t 1599627f7eb2Smrg { 1600627f7eb2Smrg public: 1601627f7eb2Smrg // use_future_t types: 1602*4c3eb207Smrg using allocator_type = _ProtoAllocator; 1603627f7eb2Smrg 1604627f7eb2Smrg // use_future_t members: 1605*4c3eb207Smrg constexpr 1606*4c3eb207Smrg use_future_t() 1607*4c3eb207Smrg noexcept(is_nothrow_default_constructible<_ProtoAllocator>::value) 1608*4c3eb207Smrg : _M_alloc() { } 1609627f7eb2Smrg 1610627f7eb2Smrg explicit 1611627f7eb2Smrg use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { } 1612627f7eb2Smrg 1613*4c3eb207Smrg template<typename _OtherAllocator> 1614627f7eb2Smrg use_future_t<_OtherAllocator> 1615627f7eb2Smrg rebind(const _OtherAllocator& __a) const noexcept 1616627f7eb2Smrg { return use_future_t<_OtherAllocator>(__a); } 1617627f7eb2Smrg 1618627f7eb2Smrg allocator_type get_allocator() const noexcept { return _M_alloc; } 1619627f7eb2Smrg 1620627f7eb2Smrg template<typename _Func> 1621627f7eb2Smrg auto 1622627f7eb2Smrg operator()(_Func&& __f) const 1623627f7eb2Smrg { 1624627f7eb2Smrg using _Token = __use_future_ct<decay_t<_Func>, _ProtoAllocator>; 1625627f7eb2Smrg return _Token{ {std::forward<_Func>(__f), _M_alloc} }; 1626627f7eb2Smrg } 1627627f7eb2Smrg 1628627f7eb2Smrg private: 1629627f7eb2Smrg _ProtoAllocator _M_alloc; 1630627f7eb2Smrg }; 1631627f7eb2Smrg 1632*4c3eb207Smrg template<typename _Tp> 1633*4c3eb207Smrg class use_future_t<std::allocator<_Tp>> 1634*4c3eb207Smrg { 1635*4c3eb207Smrg public: 1636*4c3eb207Smrg // use_future_t types: 1637*4c3eb207Smrg using allocator_type = std::allocator<_Tp>; 1638*4c3eb207Smrg 1639*4c3eb207Smrg // use_future_t members: 1640*4c3eb207Smrg constexpr use_future_t() noexcept = default; 1641*4c3eb207Smrg 1642*4c3eb207Smrg explicit 1643*4c3eb207Smrg use_future_t(const allocator_type& __a) noexcept { } 1644*4c3eb207Smrg 1645*4c3eb207Smrg template<class _Up> 1646*4c3eb207Smrg use_future_t<std::allocator<_Up>> 1647*4c3eb207Smrg rebind(const std::allocator<_Up>& __a) const noexcept 1648*4c3eb207Smrg { return use_future_t<std::allocator<_Up>>(__a); } 1649*4c3eb207Smrg 1650*4c3eb207Smrg allocator_type get_allocator() const noexcept { return {}; } 1651*4c3eb207Smrg 1652*4c3eb207Smrg template<typename _Func> 1653*4c3eb207Smrg auto 1654*4c3eb207Smrg operator()(_Func&& __f) const 1655*4c3eb207Smrg { 1656*4c3eb207Smrg using _Token = __use_future_ct<decay_t<_Func>, allocator_type>; 1657*4c3eb207Smrg return _Token{std::forward<_Func>(__f)}; 1658*4c3eb207Smrg } 1659*4c3eb207Smrg }; 1660*4c3eb207Smrg 1661627f7eb2Smrg constexpr use_future_t<> use_future = use_future_t<>(); 1662627f7eb2Smrg 1663627f7eb2Smrg template<typename _Func, typename _Alloc, typename _Res, typename... _Args> 1664627f7eb2Smrg class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>; 1665627f7eb2Smrg 1666627f7eb2Smrg template<typename _Result, typename _Executor> 1667627f7eb2Smrg struct __use_future_ex; 1668627f7eb2Smrg 1669627f7eb2Smrg // Completion handler for asynchronous operations initiated with use_future. 1670627f7eb2Smrg template<typename _Func, typename... _Args> 1671627f7eb2Smrg struct __use_future_ch 1672627f7eb2Smrg { 1673627f7eb2Smrg template<typename _Alloc> 1674627f7eb2Smrg explicit 1675627f7eb2Smrg __use_future_ch(__use_future_ct<_Func, _Alloc>&& __token) 1676627f7eb2Smrg : _M_f{ std::move(std::get<0>(__token._M_t)) }, 1677627f7eb2Smrg _M_promise{ std::get<1>(__token._M_t) } 1678627f7eb2Smrg { } 1679627f7eb2Smrg 1680*4c3eb207Smrg template<typename _Tp> 1681*4c3eb207Smrg explicit 1682*4c3eb207Smrg __use_future_ch(__use_future_ct<_Func, std::allocator<_Tp>>&& __token) 1683*4c3eb207Smrg : _M_f{ std::move(__token._M_f) } 1684*4c3eb207Smrg { } 1685*4c3eb207Smrg 1686627f7eb2Smrg void 1687627f7eb2Smrg operator()(_Args&&... __args) 1688627f7eb2Smrg { 1689627f7eb2Smrg __try 1690627f7eb2Smrg { 1691627f7eb2Smrg _M_promise.set_value(_M_f(std::forward<_Args>(__args)...)); 1692627f7eb2Smrg } 1693627f7eb2Smrg __catch(__cxxabiv1::__forced_unwind&) 1694627f7eb2Smrg { 1695627f7eb2Smrg __throw_exception_again; 1696627f7eb2Smrg } 1697627f7eb2Smrg __catch(...) 1698627f7eb2Smrg { 1699627f7eb2Smrg _M_promise.set_exception(std::current_exception()); 1700627f7eb2Smrg } 1701627f7eb2Smrg } 1702627f7eb2Smrg 1703627f7eb2Smrg using __result = result_of_t<_Func(decay_t<_Args>...)>; 1704627f7eb2Smrg 1705627f7eb2Smrg future<__result> get_future() { return _M_promise.get_future(); } 1706627f7eb2Smrg 1707627f7eb2Smrg private: 1708627f7eb2Smrg template<typename _Result, typename _Executor> 1709627f7eb2Smrg friend struct __use_future_ex; 1710627f7eb2Smrg 1711627f7eb2Smrg _Func _M_f; 1712627f7eb2Smrg mutable promise<__result> _M_promise; 1713627f7eb2Smrg }; 1714627f7eb2Smrg 1715627f7eb2Smrg // Specialization of async_result for operations initiated with use_future. 1716627f7eb2Smrg template<typename _Func, typename _Alloc, typename _Res, typename... _Args> 1717627f7eb2Smrg class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)> 1718627f7eb2Smrg { 1719627f7eb2Smrg public: 1720627f7eb2Smrg using completion_handler_type = __use_future_ch<_Func, _Args...>; 1721627f7eb2Smrg using return_type = future<typename completion_handler_type::__result>; 1722627f7eb2Smrg 1723627f7eb2Smrg explicit 1724627f7eb2Smrg async_result(completion_handler_type& __h) 1725627f7eb2Smrg : _M_future(__h.get_future()) 1726627f7eb2Smrg { } 1727627f7eb2Smrg 1728627f7eb2Smrg async_result(const async_result&) = delete; 1729627f7eb2Smrg async_result& operator=(const async_result&) = delete; 1730627f7eb2Smrg 1731627f7eb2Smrg return_type get() { return std::move(_M_future); } 1732627f7eb2Smrg 1733627f7eb2Smrg private: 1734627f7eb2Smrg return_type _M_future; 1735627f7eb2Smrg }; 1736627f7eb2Smrg 1737627f7eb2Smrg template<typename _Result, typename _Executor> 1738627f7eb2Smrg struct __use_future_ex 1739627f7eb2Smrg { 1740627f7eb2Smrg template<typename _Handler> 1741627f7eb2Smrg __use_future_ex(const _Handler& __h, _Executor __ex) 1742627f7eb2Smrg : _M_t(__h._M_promise, __ex) 1743627f7eb2Smrg { } 1744627f7eb2Smrg 1745627f7eb2Smrg template<typename _Fn, typename _Alloc> 1746627f7eb2Smrg void 1747627f7eb2Smrg dispatch(_Fn&& __fn) 1748627f7eb2Smrg { 1749627f7eb2Smrg __try 1750627f7eb2Smrg { 1751627f7eb2Smrg std::get<1>(_M_t).dispatch(std::forward<_Fn>(__fn)); 1752627f7eb2Smrg } 1753627f7eb2Smrg __catch(__cxxabiv1::__forced_unwind&) 1754627f7eb2Smrg { 1755627f7eb2Smrg __throw_exception_again; 1756627f7eb2Smrg } 1757627f7eb2Smrg __catch(...) 1758627f7eb2Smrg { 1759627f7eb2Smrg std::get<0>(_M_t).set_exception(std::current_exception()); 1760627f7eb2Smrg } 1761627f7eb2Smrg } 1762627f7eb2Smrg 1763627f7eb2Smrg template<typename _Fn, typename _Alloc> 1764627f7eb2Smrg void 1765627f7eb2Smrg post(_Fn&& __fn) 1766627f7eb2Smrg { 1767627f7eb2Smrg __try 1768627f7eb2Smrg { 1769627f7eb2Smrg std::get<1>(_M_t).post(std::forward<_Fn>(__fn)); 1770627f7eb2Smrg } 1771627f7eb2Smrg __catch(__cxxabiv1::__forced_unwind&) 1772627f7eb2Smrg { 1773627f7eb2Smrg __throw_exception_again; 1774627f7eb2Smrg } 1775627f7eb2Smrg __catch(...) 1776627f7eb2Smrg { 1777627f7eb2Smrg std::get<0>(_M_t).set_exception(std::current_exception()); 1778627f7eb2Smrg } 1779627f7eb2Smrg } 1780627f7eb2Smrg 1781627f7eb2Smrg template<typename _Fn, typename _Alloc> 1782627f7eb2Smrg void 1783627f7eb2Smrg defer(_Fn&& __fn) 1784627f7eb2Smrg { 1785627f7eb2Smrg __try 1786627f7eb2Smrg { 1787627f7eb2Smrg std::get<1>(_M_t).defer(std::forward<_Fn>(__fn)); 1788627f7eb2Smrg } 1789627f7eb2Smrg __catch(__cxxabiv1::__forced_unwind&) 1790627f7eb2Smrg { 1791627f7eb2Smrg __throw_exception_again; 1792627f7eb2Smrg } 1793627f7eb2Smrg __catch(...) 1794627f7eb2Smrg { 1795627f7eb2Smrg std::get<0>(_M_t).set_exception(std::current_exception()); 1796627f7eb2Smrg } 1797627f7eb2Smrg } 1798627f7eb2Smrg 1799627f7eb2Smrg private: 1800627f7eb2Smrg tuple<promise<_Result>&, _Executor> _M_t; 1801627f7eb2Smrg }; 1802627f7eb2Smrg 1803627f7eb2Smrg template<typename _Func, typename... _Args, typename _Executor> 1804627f7eb2Smrg struct associated_executor<__use_future_ch<_Func, _Args...>, _Executor> 1805627f7eb2Smrg { 1806627f7eb2Smrg private: 1807627f7eb2Smrg using __handler = __use_future_ch<_Func, _Args...>; 1808627f7eb2Smrg 1809627f7eb2Smrg using type = __use_future_ex<typename __handler::__result, _Executor>; 1810627f7eb2Smrg 1811627f7eb2Smrg static type 1812627f7eb2Smrg get(const __handler& __h, const _Executor& __ex) 1813627f7eb2Smrg { return { __h, __ex }; } 1814627f7eb2Smrg }; 1815627f7eb2Smrg 1816627f7eb2Smrg#if 0 1817627f7eb2Smrg 1818627f7eb2Smrg // [async.use.future.traits] 1819627f7eb2Smrg template<typename _Allocator, typename _Ret, typename... _Args> 1820627f7eb2Smrg class handler_type<use_future_t<_Allocator>, _Ret(_Args...)> // TODO uglify name 1821627f7eb2Smrg { 1822627f7eb2Smrg template<typename... _Args> 1823627f7eb2Smrg struct __is_error_result : false_type { }; 1824627f7eb2Smrg 1825627f7eb2Smrg template<typename... _Args> 1826627f7eb2Smrg struct __is_error_result<error_code, _Args...> : true_type { }; 1827627f7eb2Smrg 1828627f7eb2Smrg template<typename... _Args> 1829627f7eb2Smrg struct __is_error_result<exception_ptr, _Args...> : true_type { }; 1830627f7eb2Smrg 1831627f7eb2Smrg static exception_ptr 1832627f7eb2Smrg _S_exptr(exception_ptr& __ex) 1833627f7eb2Smrg { return std::move(__ex); } 1834627f7eb2Smrg 1835627f7eb2Smrg static exception_ptr 1836627f7eb2Smrg _S_exptr(const error_code& __ec) 1837627f7eb2Smrg { return make_exception_ptr(system_error(__ec)); } 1838627f7eb2Smrg 1839627f7eb2Smrg template<bool _IsError, typename... _UArgs> 1840627f7eb2Smrg struct _Type; 1841627f7eb2Smrg 1842627f7eb2Smrg // N == 0 1843627f7eb2Smrg template<bool _IsError> 1844627f7eb2Smrg struct _Type<_IsError> 1845627f7eb2Smrg { 1846627f7eb2Smrg std::promise<void> _M_promise; 1847627f7eb2Smrg 1848627f7eb2Smrg void 1849627f7eb2Smrg operator()() 1850627f7eb2Smrg { 1851627f7eb2Smrg _M_promise.set_value(); 1852627f7eb2Smrg } 1853627f7eb2Smrg }; 1854627f7eb2Smrg 1855627f7eb2Smrg // N == 1, U0 is error_code or exception_ptr 1856627f7eb2Smrg template<typename _UArg0> 1857627f7eb2Smrg struct _Type<true, _UArg0> 1858627f7eb2Smrg { 1859627f7eb2Smrg std::promise<void> _M_promise; 1860627f7eb2Smrg 1861627f7eb2Smrg template<typename _Arg0> 1862627f7eb2Smrg void 1863627f7eb2Smrg operator()(_Arg0&& __a0) 1864627f7eb2Smrg { 1865627f7eb2Smrg if (__a0) 1866627f7eb2Smrg _M_promise.set_exception(_S_exptr(__a0)); 1867627f7eb2Smrg else 1868627f7eb2Smrg _M_promise.set_value(); 1869627f7eb2Smrg } 1870627f7eb2Smrg }; 1871627f7eb2Smrg 1872627f7eb2Smrg // N == 1, U0 is not error_code or exception_ptr 1873627f7eb2Smrg template<typename _UArg0> 1874627f7eb2Smrg struct _Type<false, _UArg0> 1875627f7eb2Smrg { 1876627f7eb2Smrg std::promise<_UArg0> _M_promise; 1877627f7eb2Smrg 1878627f7eb2Smrg template<typename _Arg0> 1879627f7eb2Smrg void 1880627f7eb2Smrg operator()(_Arg0&& __a0) 1881627f7eb2Smrg { 1882627f7eb2Smrg _M_promise.set_value(std::forward<_Arg0>(__a0)); 1883627f7eb2Smrg } 1884627f7eb2Smrg }; 1885627f7eb2Smrg 1886627f7eb2Smrg // N == 2, U0 is error_code or exception_ptr 1887627f7eb2Smrg template<typename _UArg0, typename _UArg1> 1888627f7eb2Smrg struct _Type<true, _UArg0, _UArg1> 1889627f7eb2Smrg { 1890627f7eb2Smrg std::promise<_UArg1> _M_promise; 1891627f7eb2Smrg 1892627f7eb2Smrg template<typename _Arg0, typename _Arg1> 1893627f7eb2Smrg void 1894627f7eb2Smrg operator()(_Arg0&& __a0, _Arg1&& __a1) 1895627f7eb2Smrg { 1896627f7eb2Smrg if (__a0) 1897627f7eb2Smrg _M_promise.set_exception(_S_exptr(__a0)); 1898627f7eb2Smrg else 1899627f7eb2Smrg _M_promise.set_value(std::forward<_Arg1>(__a1)); 1900627f7eb2Smrg } 1901627f7eb2Smrg }; 1902627f7eb2Smrg 1903627f7eb2Smrg // N >= 2, U0 is not error_code or exception_ptr 1904627f7eb2Smrg template<typename... _UArgs> 1905627f7eb2Smrg struct _Type<false, _UArgs...> 1906627f7eb2Smrg { 1907627f7eb2Smrg static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization"); 1908627f7eb2Smrg 1909627f7eb2Smrg std::promise<tuple<_UArgs...>> _M_promise; 1910627f7eb2Smrg 1911627f7eb2Smrg template<typename... _Args> 1912627f7eb2Smrg void 1913627f7eb2Smrg operator()(_Args&&... __args) 1914627f7eb2Smrg { 1915627f7eb2Smrg _M_promise.set_value( 1916627f7eb2Smrg std::forward_as_tuple(std::forward<_Args>(__args)...)); 1917627f7eb2Smrg } 1918627f7eb2Smrg }; 1919627f7eb2Smrg 1920627f7eb2Smrg // N > 2, U0 is error_code or exception_ptr 1921627f7eb2Smrg template<typename _UArg0, typename... _UArgs> 1922627f7eb2Smrg struct _Type<true, _UArg0, _UArgs...> 1923627f7eb2Smrg { 1924627f7eb2Smrg static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization"); 1925627f7eb2Smrg 1926627f7eb2Smrg std::promise<tuple<_UArgs...>> _M_promise; 1927627f7eb2Smrg 1928627f7eb2Smrg template<typename _Arg0, typename... _Args> 1929627f7eb2Smrg void 1930627f7eb2Smrg operator()(_Arg0&& __a0, _Args&&... __args) 1931627f7eb2Smrg { 1932627f7eb2Smrg if (__a0) 1933627f7eb2Smrg _M_promise.set_exception(_S_exptr(__a0)); 1934627f7eb2Smrg else 1935627f7eb2Smrg _M_promise.set_value( 1936627f7eb2Smrg std::forward_as_tuple(std::forward<_Args>(__args)...)); 1937627f7eb2Smrg } 1938627f7eb2Smrg }; 1939627f7eb2Smrg 1940627f7eb2Smrg public: 1941627f7eb2Smrg using type = 1942627f7eb2Smrg _Type<__is_error_result<_Args...>::value, decay_t<_Args>...>; 1943627f7eb2Smrg }; 1944627f7eb2Smrg 1945627f7eb2Smrg 1946627f7eb2Smrg template<typename _Alloc, typename _Ret, typename... _Args> 1947627f7eb2Smrg struct async_result<use_future_t<_Alloc>, _Ret(_Args...)> 1948627f7eb2Smrg { 1949627f7eb2Smrg using completion_handler_type 1950627f7eb2Smrg = typename handler_type<use_future_t<_Alloc>, _Ret(_Args...)>::type; 1951627f7eb2Smrg 1952627f7eb2Smrg using return_type = void; // XXX TODO ???; 1953627f7eb2Smrg 1954627f7eb2Smrg explicit 1955627f7eb2Smrg async_result(completion_handler_type& __h) : _M_handler(__h) { } 1956627f7eb2Smrg 1957627f7eb2Smrg auto get() { return _M_handler._M_provider.get_future(); } 1958627f7eb2Smrg 1959627f7eb2Smrg async_result(const async_result&) = delete; 1960627f7eb2Smrg async_result& operator=(const async_result&) = delete; 1961627f7eb2Smrg 1962627f7eb2Smrg return_type get() { return _M_handler._M_promise.get_future(); } 1963627f7eb2Smrg 1964627f7eb2Smrg private: 1965627f7eb2Smrg completion_handler_type& _M_handler; 1966627f7eb2Smrg }; 1967627f7eb2Smrg 1968627f7eb2Smrg // TODO specialize associated_executor for 1969627f7eb2Smrg // async_result<use_future_t<A>, Sig>::completion_handler_type 1970627f7eb2Smrg // to use a __use_future_ex 1971627f7eb2Smrg // (probably need to move _Type outside of handler_type so we don't have 1972627f7eb2Smrg // a non-deduced context) 1973627f7eb2Smrg 1974627f7eb2Smrg 1975627f7eb2Smrg#endif 1976627f7eb2Smrg 1977627f7eb2Smrg // [async.packaged.task.specializations] 1978627f7eb2Smrg template<typename _Ret, typename... _Args, typename _Signature> 1979627f7eb2Smrg class async_result<packaged_task<_Ret(_Args...)>, _Signature> 1980627f7eb2Smrg { 1981627f7eb2Smrg public: 1982627f7eb2Smrg using completion_handler_type = packaged_task<_Ret(_Args...)>; 1983627f7eb2Smrg using return_type = future<_Ret>; 1984627f7eb2Smrg 1985627f7eb2Smrg explicit 1986627f7eb2Smrg async_result(completion_handler_type& __h) 1987627f7eb2Smrg : _M_future(__h.get_future()) { } 1988627f7eb2Smrg 1989627f7eb2Smrg async_result(const async_result&) = delete; 1990627f7eb2Smrg async_result& operator=(const async_result&) = delete; 1991627f7eb2Smrg 1992627f7eb2Smrg return_type get() { return std::move(_M_future); } 1993627f7eb2Smrg 1994627f7eb2Smrg private: 1995627f7eb2Smrg return_type _M_future; 1996627f7eb2Smrg }; 1997627f7eb2Smrg 1998627f7eb2Smrg#endif 1999627f7eb2Smrg 2000627f7eb2Smrg /// @} 2001627f7eb2Smrg 2002627f7eb2Smrg} // namespace v1 2003627f7eb2Smrg} // namespace net 2004627f7eb2Smrg} // namespace experimental 2005627f7eb2Smrg 2006627f7eb2Smrg template<typename _Alloc> 2007627f7eb2Smrg struct uses_allocator<experimental::net::executor, _Alloc> 2008627f7eb2Smrg : true_type {}; 2009627f7eb2Smrg 2010627f7eb2Smrg_GLIBCXX_END_NAMESPACE_VERSION 2011627f7eb2Smrg} // namespace std 2012627f7eb2Smrg 2013627f7eb2Smrg#endif // C++14 2014627f7eb2Smrg 2015627f7eb2Smrg#endif // _GLIBCXX_EXPERIMENTAL_EXECUTOR 2016