| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049 |
- // <experimental/executor> -*- C++ -*-
- // Copyright (C) 2015-2021 Free Software Foundation, Inc.
- //
- // This file is part of the GNU ISO C++ Library. This library is free
- // software; you can redistribute it and/or modify it under the
- // terms of the GNU General Public License as published by the
- // Free Software Foundation; either version 3, or (at your option)
- // any later version.
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // Under Section 7 of GPL version 3, you are granted additional
- // permissions described in the GCC Runtime Library Exception, version
- // 3.1, as published by the Free Software Foundation.
- // You should have received a copy of the GNU General Public License and
- // a copy of the GCC Runtime Library Exception along with this program;
- // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- // <http://www.gnu.org/licenses/>.
- /** @file experimental/executor
- * This is a TS C++ Library header.
- * @ingroup networking-ts
- */
- #ifndef _GLIBCXX_EXPERIMENTAL_EXECUTOR
- #define _GLIBCXX_EXPERIMENTAL_EXECUTOR 1
- #pragma GCC system_header
- #if __cplusplus >= 201402L
- #include <algorithm>
- #include <condition_variable>
- #include <functional>
- #include <future>
- #include <list>
- #include <queue>
- #include <thread>
- #include <tuple>
- #include <unordered_map>
- #include <utility>
- #include <experimental/netfwd>
- #include <bits/unique_ptr.h>
- #include <experimental/bits/net.h>
- namespace std _GLIBCXX_VISIBILITY(default)
- {
- _GLIBCXX_BEGIN_NAMESPACE_VERSION
- namespace experimental
- {
- namespace net
- {
- inline namespace v1
- {
- /** @addtogroup networking-ts
- * @{
- */
- /// Customization point for asynchronous operations.
- template<typename _CompletionToken, typename _Signature, typename = void>
- class async_result;
- /// Convenience utility to help implement asynchronous operations.
- template<typename _CompletionToken, typename _Signature>
- class async_completion;
- template<typename _Tp, typename _ProtoAlloc, typename = __void_t<>>
- struct __associated_allocator_impl
- {
- using type = _ProtoAlloc;
- static type
- _S_get(const _Tp&, const _ProtoAlloc& __a) noexcept { return __a; }
- };
- template<typename _Tp, typename _ProtoAlloc>
- struct __associated_allocator_impl<_Tp, _ProtoAlloc,
- __void_t<typename _Tp::allocator_type>>
- {
- using type = typename _Tp::allocator_type;
- static type
- _S_get(const _Tp& __t, const _ProtoAlloc&) noexcept
- { return __t.get_allocator(); }
- };
- /// Helper to associate an allocator with a type.
- template<typename _Tp, typename _ProtoAllocator = allocator<void>>
- struct associated_allocator
- : __associated_allocator_impl<_Tp, _ProtoAllocator>
- {
- static auto
- get(const _Tp& __t,
- const _ProtoAllocator& __a = _ProtoAllocator()) noexcept
- {
- using _Impl = __associated_allocator_impl<_Tp, _ProtoAllocator>;
- return _Impl::_S_get(__t, __a);
- }
- };
- /// Alias template for associated_allocator.
- template<typename _Tp, typename _ProtoAllocator = allocator<void>>
- using associated_allocator_t
- = typename associated_allocator<_Tp, _ProtoAllocator>::type;
- // get_associated_allocator:
- template<typename _Tp>
- inline associated_allocator_t<_Tp>
- get_associated_allocator(const _Tp& __t) noexcept
- { return associated_allocator<_Tp>::get(__t); }
- template<typename _Tp, typename _ProtoAllocator>
- inline associated_allocator_t<_Tp, _ProtoAllocator>
- get_associated_allocator(const _Tp& __t,
- const _ProtoAllocator& __a) noexcept
- { return associated_allocator<_Tp, _ProtoAllocator>::get(__t, __a); }
- enum class fork_event { prepare, parent, child };
- /// An extensible, type-safe, polymorphic set of services.
- class execution_context;
- class service_already_exists : public logic_error
- {
- public:
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3414. service_already_exists has no usable constructors
- service_already_exists() : logic_error("service already exists") { }
- };
- template<typename _Tp> struct is_executor;
- struct executor_arg_t { };
- constexpr executor_arg_t executor_arg = executor_arg_t();
- /// Trait for determining whether to construct an object with an executor.
- template<typename _Tp, typename _Executor> struct uses_executor;
- template<typename _Tp, typename _Executor, typename = __void_t<>>
- struct __associated_executor_impl
- {
- using type = _Executor;
- static type
- _S_get(const _Tp&, const _Executor& __e) noexcept { return __e; }
- };
- template<typename _Tp, typename _Executor>
- struct __associated_executor_impl<_Tp, _Executor,
- __void_t<typename _Tp::executor_type>>
- {
- using type = typename _Tp::executor_type;
- static type
- _S_get(const _Tp& __t, const _Executor&) noexcept
- { return __t.get_executor(); }
- };
- /// Helper to associate an executor with a type.
- template<typename _Tp, typename _Executor = system_executor>
- struct associated_executor
- : __associated_executor_impl<_Tp, _Executor>
- {
- static auto
- get(const _Tp& __t, const _Executor& __e = _Executor()) noexcept
- { return __associated_executor_impl<_Tp, _Executor>::_S_get(__t, __e); }
- };
- template<typename _Tp, typename _Executor = system_executor>
- using associated_executor_t
- = typename associated_executor<_Tp, _Executor>::type;
- template<typename _ExecutionContext>
- using __is_exec_context
- = is_convertible<_ExecutionContext&, execution_context&>;
- template<typename _Tp>
- using __executor_t = typename _Tp::executor_type;
- // get_associated_executor:
- template<typename _Tp>
- inline associated_executor_t<_Tp>
- get_associated_executor(const _Tp& __t) noexcept
- { return associated_executor<_Tp>::get(__t); }
- template<typename _Tp, typename _Executor>
- inline
- enable_if_t<is_executor<_Executor>::value,
- associated_executor_t<_Tp, _Executor>>
- get_associated_executor(const _Tp& __t, const _Executor& __ex)
- { return associated_executor<_Tp, _Executor>::get(__t, __ex); }
- template<typename _Tp, typename _ExecutionContext>
- inline
- enable_if_t<__is_exec_context<_ExecutionContext>::value,
- associated_executor_t<_Tp, __executor_t<_ExecutionContext>>>
- get_associated_executor(const _Tp& __t, _ExecutionContext& __ctx) noexcept
- { return net::get_associated_executor(__t, __ctx.get_executor()); }
- /// Helper to bind an executor to an object or function.
- template<typename _Tp, typename _Executor>
- class executor_binder;
- template<typename _Tp, typename _Executor, typename _Signature>
- class async_result<executor_binder<_Tp, _Executor>, _Signature>;
- template<typename _Tp, typename _Executor, typename _ProtoAllocator>
- struct associated_allocator<executor_binder<_Tp, _Executor>,
- _ProtoAllocator>;
- template<typename _Tp, typename _Executor, typename _Executor1>
- struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>;
- // bind_executor:
- template<typename _Executor, typename _Tp>
- inline
- enable_if_t<is_executor<_Executor>::value,
- executor_binder<decay_t<_Tp>, _Executor>>
- bind_executor(const _Executor& __ex, _Tp&& __t)
- { return { std::forward<_Tp>(__t), __ex }; }
- template<typename _ExecutionContext, typename _Tp>
- inline
- enable_if_t<__is_exec_context<_ExecutionContext>::value,
- executor_binder<decay_t<_Tp>, __executor_t<_ExecutionContext>>>
- bind_executor(_ExecutionContext& __ctx, _Tp&& __t)
- { return { __ctx.get_executor(), forward<_Tp>(__t) }; }
- /// A scope-guard type to record when work is started and finished.
- template<typename _Executor>
- class executor_work_guard;
- // make_work_guard:
- template<typename _Executor>
- inline
- enable_if_t<is_executor<_Executor>::value, executor_work_guard<_Executor>>
- make_work_guard(const _Executor& __ex)
- { return executor_work_guard<_Executor>(__ex); }
- template<typename _ExecutionContext>
- inline
- enable_if_t<__is_exec_context<_ExecutionContext>::value,
- executor_work_guard<__executor_t<_ExecutionContext>>>
- make_work_guard(_ExecutionContext& __ctx)
- { return net::make_work_guard(__ctx.get_executor()); }
- template<typename _Tp>
- inline
- enable_if_t<__not_<__or_<is_executor<_Tp>, __is_exec_context<_Tp>>>::value,
- executor_work_guard<associated_executor_t<_Tp>>>
- make_work_guard(const _Tp& __t)
- { return net::get_associated_executor(__t); }
- template<typename _Tp, typename _Up>
- auto
- make_work_guard(const _Tp& __t, _Up&& __u)
- -> decltype(net::make_work_guard(
- net::get_associated_executor(__t, forward<_Up>(__u))))
- {
- return net::make_work_guard(
- net::get_associated_executor(__t, forward<_Up>(__u)));
- }
- /// Allows function objects to execute on any thread.
- class system_executor;
- /// The execution context associated with system_executor objects.
- class system_context;
- inline bool
- operator==(const system_executor&, const system_executor&) { return true; }
- inline bool
- operator!=(const system_executor&, const system_executor&) { return false; }
- /// Exception thrown by empty executors.
- class bad_executor;
- /// Polymorphic wrapper for types satisfying the Executor requirements.
- class executor;
- bool
- operator==(const executor&, const executor&) noexcept;
- bool
- operator==(const executor&, nullptr_t) noexcept;
- bool
- operator==(nullptr_t, const executor&) noexcept;
- bool
- operator!=(const executor&, const executor&) noexcept;
- bool
- operator!=(const executor&, nullptr_t) noexcept;
- bool
- operator!=(nullptr_t, const executor&) noexcept;
- void swap(executor&, executor&) noexcept;
- // dispatch:
- template<typename _CompletionToken>
- __deduced_t<_CompletionToken, void()>
- dispatch(_CompletionToken&& __token);
- template<typename _Executor, typename _CompletionToken>
- __deduced_t<_CompletionToken, void()>
- dispatch(const _Executor& __ex, _CompletionToken&& __token);
- template<typename _ExecutionContext, typename _CompletionToken>
- __deduced_t<_CompletionToken, void()>
- dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token);
- // post:
- template<typename _CompletionToken>
- __deduced_t<_CompletionToken, void()>
- post(_CompletionToken&& __token);
- template<typename _Executor, typename _CompletionToken>
- enable_if_t<is_executor<_Executor>::value,
- __deduced_t<_CompletionToken, void()>>
- post(const _Executor& __ex, _CompletionToken&& __token);
- template<typename _ExecutionContext, typename _CompletionToken>
- enable_if_t<__is_exec_context<_ExecutionContext>::value,
- __deduced_t<_CompletionToken, void()>>
- post(_ExecutionContext& __ctx, _CompletionToken&& __token);
- // defer:
- template<typename _CompletionToken>
- __deduced_t<_CompletionToken, void()>
- defer(_CompletionToken&& __token);
- template<typename _Executor, typename _CompletionToken>
- __deduced_t<_CompletionToken, void()>
- defer(const _Executor& __ex, _CompletionToken&& __token);
- template<typename _ExecutionContext, typename _CompletionToken>
- __deduced_t<_CompletionToken, void()>
- defer(_ExecutionContext& __ctx, _CompletionToken&& __token);
- template<typename _Executor>
- class strand;
- template<typename _Executor>
- bool
- operator==(const strand<_Executor>& __a, const strand<_Executor>& __b);
- template<typename _Executor>
- bool
- operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b)
- { return !(__a == __b); }
- template<typename _CompletionToken, typename _Signature, typename>
- class async_result
- {
- public:
- using completion_handler_type = _CompletionToken;
- using return_type = void;
- explicit async_result(completion_handler_type&) {}
- async_result(const async_result&) = delete;
- async_result& operator=(const async_result&) = delete;
- return_type get() {}
- };
- template<typename _CompletionToken, typename _Signature>
- class async_completion
- {
- using __result_type
- = async_result<decay_t<_CompletionToken>, _Signature>;
- public:
- using completion_handler_type
- = typename __result_type::completion_handler_type;
- private:
- using __handler_type = conditional_t<
- is_same<_CompletionToken, completion_handler_type>::value,
- completion_handler_type&,
- completion_handler_type>;
- public:
- explicit
- async_completion(_CompletionToken& __t)
- : completion_handler(std::forward<__handler_type>(__t)),
- result(completion_handler)
- { }
- async_completion(const async_completion&) = delete;
- async_completion& operator=(const async_completion&) = delete;
- __handler_type completion_handler;
- __result_type result;
- };
- class execution_context
- {
- public:
- class service
- {
- protected:
- // construct / copy / destroy:
- explicit
- service(execution_context& __owner) : _M_context(__owner) { }
- service(const service&) = delete;
- service& operator=(const service&) = delete;
- virtual ~service() { } // TODO should not be inline
- // service observers:
- execution_context& context() const noexcept { return _M_context; }
- private:
- // service operations:
- virtual void shutdown() noexcept = 0;
- virtual void notify_fork(fork_event) { }
- friend class execution_context;
- execution_context& _M_context;
- };
- // construct / copy / destroy:
- execution_context() { }
- execution_context(const execution_context&) = delete;
- execution_context& operator=(const execution_context&) = delete;
- virtual ~execution_context()
- {
- shutdown();
- destroy();
- }
- // execution context operations:
- void
- notify_fork(fork_event __e)
- {
- auto __l = [=](auto& __svc) { __svc._M_ptr->notify_fork(__e); };
- if (__e == fork_event::prepare)
- std::for_each(_M_services.rbegin(), _M_services.rend(), __l);
- else
- std::for_each(_M_services.begin(), _M_services.end(), __l);
- }
- protected:
- // execution context protected operations:
- void
- shutdown()
- {
- std::for_each(_M_services.rbegin(), _M_services.rend(),
- [=](auto& __svc) {
- if (__svc._M_active)
- {
- __svc._M_ptr->shutdown();
- __svc._M_active = false;
- }
- });
- }
- void
- destroy()
- {
- while (_M_services.size())
- _M_services.pop_back();
- _M_keys.clear();
- }
- protected:
- template<typename _Service>
- static void
- _S_deleter(service* __svc) { delete static_cast<_Service*>(__svc); }
- struct _ServicePtr
- {
- template<typename _Service>
- explicit
- _ServicePtr(_Service* __svc)
- : _M_ptr(__svc, &_S_deleter<_Service>), _M_active(true) { }
- std::unique_ptr<service, void(*)(service*)> _M_ptr;
- bool _M_active;
- };
- #if defined(_GLIBCXX_HAS_GTHREADS)
- using mutex_type = std::mutex;
- #else
- struct mutex_type
- {
- void lock() const { }
- void unlock() const { }
- };
- #endif
- mutable mutex_type _M_mutex;
- // Sorted in order of beginning of service object lifetime.
- std::list<_ServicePtr> _M_services;
- template<typename _Service, typename... _Args>
- service*
- _M_add_svc(_Args&&... __args)
- {
- _M_services.push_back(
- _ServicePtr{new _Service{*this, std::forward<_Args>(__args)...}} );
- return _M_services.back()._M_ptr.get();
- }
- using __key_type = void(*)();
- template<typename _Key>
- static __key_type
- _S_key() { return reinterpret_cast<__key_type>(&_S_key<_Key>); }
- std::unordered_map<__key_type, service*> _M_keys;
- template<typename _Service>
- friend typename _Service::key_type&
- use_service(execution_context&);
- template<typename _Service, typename... _Args>
- friend _Service&
- make_service(execution_context&, _Args&&...);
- template<typename _Service>
- friend bool
- has_service(const execution_context&) noexcept;
- };
- // service access:
- template<typename _Service>
- typename _Service::key_type&
- use_service(execution_context& __ctx)
- {
- using _Key = typename _Service::key_type;
- static_assert(is_base_of<execution_context::service, _Key>::value,
- "a service type must derive from execution_context::service");
- static_assert(is_base_of<_Key, _Service>::value,
- "a service type must match or derive from its key_type");
- auto __key = execution_context::_S_key<_Key>();
- lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
- auto& __svc = __ctx._M_keys[__key];
- if (__svc == nullptr)
- {
- __try {
- __svc = __ctx._M_add_svc<_Service>();
- } __catch(...) {
- __ctx._M_keys.erase(__key);
- __throw_exception_again;
- }
- }
- return static_cast<_Key&>(*__svc);
- }
- template<typename _Service, typename... _Args>
- _Service&
- make_service(execution_context& __ctx, _Args&&... __args)
- {
- using _Key = typename _Service::key_type;
- static_assert(is_base_of<execution_context::service, _Key>::value,
- "a service type must derive from execution_context::service");
- static_assert(is_base_of<_Key, _Service>::value,
- "a service type must match or derive from its key_type");
- auto __key = execution_context::_S_key<_Key>();
- lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
- auto& __svc = __ctx._M_keys[__key];
- if (__svc != nullptr)
- throw service_already_exists();
- __try {
- __svc = __ctx._M_add_svc<_Service>(std::forward<_Args>(__args)...);
- } __catch(...) {
- __ctx._M_keys.erase(__key);
- __throw_exception_again;
- }
- return static_cast<_Service&>(*__svc);
- }
- template<typename _Service>
- inline bool
- has_service(const execution_context& __ctx) noexcept
- {
- using _Key = typename _Service::key_type;
- static_assert(is_base_of<execution_context::service, _Key>::value,
- "a service type must derive from execution_context::service");
- static_assert(is_base_of<_Key, _Service>::value,
- "a service type must match or derive from its key_type");
- lock_guard<execution_context::mutex_type> __lock(__ctx._M_mutex);
- return __ctx._M_keys.count(execution_context::_S_key<_Key>());
- }
- template<typename _Tp, typename = __void_t<>>
- struct __is_executor_impl : false_type
- { };
- // Check Executor requirements.
- template<typename _Tp, typename _Up = remove_const_t<_Tp>>
- auto
- __executor_reqs(_Up* __x = 0, const _Up* __cx = 0, void(*__f)() = 0,
- const allocator<int>& __a = {})
- -> enable_if_t<__is_value_constructible<_Tp>::value, __void_t<
- decltype(*__cx == *__cx),
- decltype(*__cx != *__cx),
- decltype(__x->context()),
- decltype(__x->on_work_started()),
- decltype(__x->on_work_finished()),
- decltype(__x->dispatch(std::move(__f), __a)),
- decltype(__x->post(std::move(__f), __a)),
- decltype(__x->defer(std::move(__f), __a))
- >>;
- template<typename _Tp>
- struct __is_executor_impl<_Tp, decltype(__executor_reqs<_Tp>())>
- : true_type
- { };
- template<typename _Tp>
- struct is_executor : __is_executor_impl<_Tp>
- { };
- template<typename _Tp>
- constexpr bool is_executor_v = is_executor<_Tp>::value;
- template<typename _Tp, typename _Executor, typename = __void_t<>>
- struct __uses_executor_impl : false_type
- { };
- template<typename _Tp, typename _Executor>
- struct __uses_executor_impl<_Tp, _Executor,
- __void_t<typename _Tp::executor_type>>
- : is_convertible<_Executor, typename _Tp::executor_type>
- { };
- template<typename _Tp, typename _Executor>
- struct uses_executor : __uses_executor_impl<_Tp, _Executor>::type
- { };
- template<typename _Tp, typename _Executor>
- constexpr bool uses_executor_v = uses_executor<_Tp, _Executor>::value;
- template<typename _Tp, typename _Executor>
- class executor_binder
- {
- struct __use_exec { };
- public:
- // types:
- using target_type = _Tp;
- using executor_type = _Executor;
- // construct / copy / destroy:
- executor_binder(_Tp __t, const _Executor& __ex)
- : executor_binder(__use_exec{}, std::move(__t), __ex)
- { }
- executor_binder(const executor_binder&) = default;
- executor_binder(executor_binder&&) = default;
- template<typename _Up, typename _OtherExecutor>
- executor_binder(const executor_binder<_Up, _OtherExecutor>& __other)
- : executor_binder(__use_exec{}, __other.get(), __other.get_executor())
- { }
- template<typename _Up, typename _OtherExecutor>
- executor_binder(executor_binder<_Up, _OtherExecutor>&& __other)
- : executor_binder(__use_exec{}, std::move(__other.get()),
- __other.get_executor())
- { }
- template<typename _Up, typename _OtherExecutor>
- executor_binder(executor_arg_t, const _Executor& __ex,
- const executor_binder<_Up, _OtherExecutor>& __other)
- : executor_binder(__use_exec{}, __other.get(), __ex)
- { }
- template<typename _Up, typename _OtherExecutor>
- executor_binder(executor_arg_t, const _Executor& __ex,
- executor_binder<_Up, _OtherExecutor>&& __other)
- : executor_binder(__use_exec{}, std::move(__other.get()), __ex)
- { }
- ~executor_binder();
- // executor binder access:
- _Tp& get() noexcept { return _M_target; }
- const _Tp& get() const noexcept { return _M_target; }
- executor_type get_executor() const noexcept { return _M_ex; }
- // executor binder invocation:
- template<class... _Args>
- result_of_t<_Tp&(_Args&&...)>
- operator()(_Args&&... __args)
- { return std::__invoke(get(), std::forward<_Args>(__args)...); }
- template<class... _Args>
- result_of_t<const _Tp&(_Args&&...)>
- operator()(_Args&&... __args) const
- { return std::__invoke(get(), std::forward<_Args>(__args)...); }
- private:
- template<typename _Up>
- using __use_exec_cond
- = __and_<uses_executor<_Tp, _Executor>,
- is_constructible<_Tp, executor_arg_t, _Executor, _Up>>;
- template<typename _Up, typename _Exec, typename =
- enable_if_t<__use_exec_cond<_Up>::value>>
- executor_binder(__use_exec, _Up&& __u, _Exec&& __ex)
- : _M_ex(std::forward<_Exec>(__ex)),
- _M_target(executor_arg, _M_ex, std::forward<_Up>(__u))
- { }
- template<typename _Up, typename _Exec, typename =
- enable_if_t<!__use_exec_cond<_Up>::value>>
- executor_binder(__use_exec, _Up&& __u, const _Exec& __ex)
- : _M_ex(std::forward<_Exec>(__ex)),
- _M_target(std::forward<_Up>(__u))
- { }
- _Executor _M_ex;
- _Tp _M_target;
- };
- template<typename _Tp, typename _Executor, typename _Signature>
- class async_result<executor_binder<_Tp, _Executor>, _Signature>
- {
- using __inner = async_result<_Tp, _Signature>;
- public:
- using completion_handler_type =
- executor_binder<typename __inner::completion_handler_type, _Executor>;
- using return_type = typename __inner::return_type;
- explicit
- async_result(completion_handler_type& __h)
- : _M_target(__h.get()) { }
- async_result(const async_result&) = delete;
- async_result& operator=(const async_result&) = delete;
- return_type get() { return _M_target.get(); }
- private:
- __inner _M_target;
- };
- template<typename _Tp, typename _Executor, typename _ProtoAlloc>
- struct associated_allocator<executor_binder<_Tp, _Executor>, _ProtoAlloc>
- {
- using type = associated_allocator_t<_Tp, _ProtoAlloc>;
- static type
- get(const executor_binder<_Tp, _Executor>& __b,
- const _ProtoAlloc& __a = _ProtoAlloc()) noexcept
- { return associated_allocator<_Tp, _ProtoAlloc>::get(__b.get(), __a); }
- };
- template<typename _Tp, typename _Executor, typename _Executor1>
- struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>
- {
- using type = _Executor;
- static type
- get(const executor_binder<_Tp, _Executor>& __b,
- const _Executor1& = _Executor1()) noexcept
- { return __b.get_executor(); }
- };
- template<typename _Executor>
- class executor_work_guard
- {
- public:
- // types:
- using executor_type = _Executor;
- // construct / copy / destroy:
- explicit
- executor_work_guard(const executor_type& __ex) noexcept
- : _M_ex(__ex), _M_owns(true)
- { _M_ex.on_work_started(); }
- executor_work_guard(const executor_work_guard& __other) noexcept
- : _M_ex(__other._M_ex), _M_owns(__other._M_owns)
- {
- if (_M_owns)
- _M_ex.on_work_started();
- }
- executor_work_guard(executor_work_guard&& __other) noexcept
- : _M_ex(__other._M_ex), _M_owns(__other._M_owns)
- { __other._M_owns = false; }
- executor_work_guard& operator=(const executor_work_guard&) = delete;
- ~executor_work_guard()
- {
- if (_M_owns)
- _M_ex.on_work_finished();
- }
- // executor work guard observers:
- executor_type get_executor() const noexcept { return _M_ex; }
- bool owns_work() const noexcept { return _M_owns; }
- // executor work guard modifiers:
- void reset() noexcept
- {
- if (_M_owns)
- _M_ex.on_work_finished();
- _M_owns = false;
- }
- private:
- _Executor _M_ex;
- bool _M_owns;
- };
- class system_context : public execution_context
- {
- public:
- // types:
- using executor_type = system_executor;
- // construct / copy / destroy:
- system_context() = delete;
- system_context(const system_context&) = delete;
- system_context& operator=(const system_context&) = delete;
- ~system_context()
- {
- stop();
- join();
- }
- // system_context operations:
- executor_type get_executor() noexcept;
- void stop()
- {
- lock_guard<mutex_type> __lock(_M_mtx);
- _M_stopped = true;
- _M_cv.notify_all();
- }
- bool stopped() const noexcept
- {
- lock_guard<mutex_type> __lock(_M_mtx);
- return _M_stopped;
- }
- void join()
- {
- if (_M_thread.joinable())
- _M_thread.join();
- }
- private:
- friend system_executor;
- struct __tag { explicit __tag() = default; };
- system_context(__tag) { }
- #ifndef _GLIBCXX_HAS_GTHREADS
- struct thread
- {
- bool joinable() const { return false; }
- void join() { }
- };
- struct condition_variable
- {
- void notify_all() { }
- };
- #endif
- thread _M_thread;
- mutable mutex_type _M_mtx; // XXX can we reuse base's _M_mutex?
- condition_variable _M_cv;
- queue<function<void()>> _M_tasks;
- bool _M_stopped = false;
- #ifdef _GLIBCXX_HAS_GTHREADS
- void
- _M_run()
- {
- while (true)
- {
- function<void()> __f;
- {
- unique_lock<mutex_type> __lock(_M_mtx);
- _M_cv.wait(__lock,
- [this]{ return _M_stopped || !_M_tasks.empty(); });
- if (_M_stopped)
- return;
- __f = std::move(_M_tasks.front());
- _M_tasks.pop();
- }
- __f();
- }
- }
- #endif
- void
- _M_post(std::function<void()> __f __attribute__((__unused__)))
- {
- lock_guard<mutex_type> __lock(_M_mtx);
- if (_M_stopped)
- return;
- #ifdef _GLIBCXX_HAS_GTHREADS
- if (!_M_thread.joinable())
- _M_thread = std::thread(&system_context::_M_run, this);
- _M_tasks.push(std::move(__f)); // XXX allocator not used
- _M_cv.notify_one();
- #else
- __throw_system_error(EOPNOTSUPP);
- #endif
- }
- static system_context&
- _S_get() noexcept
- {
- static system_context __sc(__tag{});
- return __sc;
- }
- };
- class system_executor
- {
- public:
- // executor operations:
- system_executor() { }
- system_context&
- context() const noexcept { return system_context::_S_get(); }
- void on_work_started() const noexcept { }
- void on_work_finished() const noexcept { }
- template<typename _Func, typename _ProtoAlloc>
- void
- dispatch(_Func&& __f, const _ProtoAlloc& __a) const
- { decay_t<_Func>{std::forward<_Func>(__f)}(); }
- template<typename _Func, typename _ProtoAlloc>
- void
- post(_Func&& __f, const _ProtoAlloc&) const // XXX allocator not used
- {
- system_context::_S_get()._M_post(std::forward<_Func>(__f));
- }
- template<typename _Func, typename _ProtoAlloc>
- void
- defer(_Func&& __f, const _ProtoAlloc& __a) const
- { post(std::forward<_Func>(__f), __a); }
- };
- inline system_executor
- system_context::get_executor() noexcept
- { return {}; }
- class bad_executor : public std::exception
- {
- virtual const char* what() const noexcept { return "bad executor"; }
- };
- inline void __throw_bad_executor() // TODO make non-inline
- {
- #if __cpp_exceptions
- throw bad_executor();
- #else
- __builtin_abort();
- #endif
- }
- class executor
- {
- public:
- // construct / copy / destroy:
- executor() noexcept = default;
- executor(nullptr_t) noexcept { }
- executor(const executor&) noexcept = default;
- executor(executor&&) noexcept = default;
- template<typename _Executor>
- executor(_Executor __e)
- : _M_target(make_shared<_Tgt1<_Executor>>(std::move(__e)))
- { }
- template<typename _Executor, typename _ProtoAlloc>
- executor(allocator_arg_t, const _ProtoAlloc& __a, _Executor __e)
- : _M_target(allocate_shared<_Tgt2<_Executor, _ProtoAlloc>>(__a,
- std::move(__e), __a))
- { }
- executor& operator=(const executor&) noexcept = default;
- executor& operator=(executor&&) noexcept = default;
- executor&
- operator=(nullptr_t) noexcept
- {
- _M_target = nullptr;
- return *this;
- }
- template<typename _Executor>
- executor&
- operator=(_Executor __e)
- {
- executor(std::move(__e)).swap(*this);
- return *this;
- }
- ~executor() = default;
- // executor modifiers:
- void
- swap(executor& __other) noexcept
- { _M_target.swap(__other._M_target); }
- template<typename _Executor, typename _Alloc>
- void
- assign(_Executor __e, const _Alloc& __a)
- { executor(allocator_arg, __a, std::move(__e)).swap(*this); }
- // executor operations:
- execution_context&
- context() const noexcept
- {
- __glibcxx_assert( _M_target );
- return _M_target->context();
- }
- void
- on_work_started() const noexcept
- {
- __glibcxx_assert( _M_target );
- return _M_target->on_work_started();
- }
- void
- on_work_finished() const noexcept
- {
- __glibcxx_assert( _M_target );
- return _M_target->on_work_finished();
- }
- template<typename _Func, typename _Alloc>
- void
- dispatch(_Func&& __f, const _Alloc& __a) const
- {
- if (!_M_target)
- __throw_bad_executor();
- // _M_target->dispatch({allocator_arg, __a, std::forward<_Func>(__f)});
- _M_target->dispatch(std::forward<_Func>(__f));
- }
- template<typename _Func, typename _Alloc>
- void
- post(_Func&& __f, const _Alloc& __a) const
- {
- if (!_M_target)
- __throw_bad_executor();
- // _M_target->post({allocator_arg, __a, std::forward<_Func>(__f)});
- _M_target->post(std::forward<_Func>(__f));
- }
- template<typename _Func, typename _Alloc>
- void
- defer(_Func&& __f, const _Alloc& __a) const
- {
- if (!_M_target)
- __throw_bad_executor();
- // _M_target->defer({allocator_arg, __a, std::forward<_Func>(__f)});
- _M_target->defer(std::forward<_Func>(__f));
- }
- // executor capacity:
- explicit operator bool() const noexcept
- { return static_cast<bool>(_M_target); }
- // executor target access:
- #if __cpp_rtti
- const type_info&
- target_type() const noexcept
- {
- if (_M_target)
- return *static_cast<const type_info*>(_M_target->target_type());
- return typeid(void);
- }
- #endif
- template<typename _Executor>
- _Executor*
- target() noexcept
- {
- void* __p = nullptr;
- if (_M_target)
- {
- if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func)
- __p = _M_target->_M_func(_M_target.get(), nullptr);
- #if __cpp_rtti
- else
- __p = _M_target->target(&typeid(_Executor));
- #endif
- }
- return static_cast<_Executor*>(__p);
- }
- template<typename _Executor>
- const _Executor*
- target() const noexcept
- {
- const void* __p = nullptr;
- if (_M_target)
- {
- if (_M_target->_M_func == &_Tgt1<remove_cv_t<_Executor>>::_S_func)
- return (_Executor*)_M_target->_M_func(_M_target.get(), nullptr);
- #if __cpp_rtti
- else
- __p = _M_target->target(&typeid(_Executor));
- #endif
- }
- return static_cast<const _Executor*>(__p);
- }
- private:
- struct _Tgt
- {
- virtual void on_work_started() const noexcept = 0;
- virtual void on_work_finished() const noexcept = 0;
- virtual execution_context& context() const noexcept = 0;
- virtual void dispatch(std::function<void()>) const = 0;
- virtual void post(std::function<void()>) const = 0;
- virtual void defer(std::function<void()>) const = 0;
- virtual const void* target_type() const noexcept = 0;
- virtual void* target(const void*) noexcept = 0;
- virtual bool _M_equals(_Tgt*) const noexcept = 0;
- using _Func = void* (_Tgt*, const _Tgt*);
- _Func* _M_func; // Provides access to target without RTTI
- };
- template<typename _Ex>
- struct _Tgt1 : _Tgt
- {
- explicit
- _Tgt1(_Ex&& __ex)
- : _M_ex(std::move(__ex))
- { this->_M_func = &_S_func; }
- void
- on_work_started() const noexcept override
- { _M_ex.on_work_started(); }
- void
- on_work_finished() const noexcept override
- { _M_ex.on_work_finished(); }
- execution_context&
- context() const noexcept override
- { return _M_ex.context(); }
- void
- dispatch(std::function<void()> __f) const override
- { _M_ex.dispatch(std::move(__f), allocator<void>()); }
- void
- post(std::function<void()> __f) const override
- { _M_ex.post(std::move(__f), allocator<void>()); }
- void
- defer(std::function<void()> __f) const override
- { _M_ex.defer(std::move(__f), allocator<void>()); }
- const void*
- target_type() const noexcept override
- {
- #if __cpp_rtti
- return &typeid(_Ex);
- #else
- return nullptr;
- #endif
- }
- void*
- target(const void* __ti) noexcept override
- {
- #if __cpp_rtti
- if (*static_cast<const type_info*>(__ti) == typeid(_Ex))
- return std::__addressof(_M_ex);
- #endif
- return nullptr;
- }
- bool
- _M_equals(_Tgt* __tgt) const noexcept override
- {
- #if __cpp_rtti
- if (const void* __p = __tgt->target(&typeid(_Ex)))
- return *static_cast<const _Ex*>(__p) == _M_ex;
- #endif
- return false;
- }
- _Ex _M_ex [[__no_unique_address__]];
- static void*
- _S_func(_Tgt* __p, const _Tgt* __q) noexcept
- {
- auto& __ex = static_cast<_Tgt1*>(__p)->_M_ex;
- if (__q)
- {
- if (__ex == static_cast<const _Tgt1*>(__q)->_M_ex)
- return __p;
- else
- return nullptr;
- }
- else
- return std::__addressof(__ex);
- }
- };
- template<typename _Ex, typename _Alloc>
- struct _Tgt2 : _Tgt1<_Ex>
- {
- explicit
- _Tgt2(_Ex&& __ex, const _Alloc& __a)
- : _Tgt1<_Ex>(std::move(__ex)), _M_alloc(__a) { }
- void
- dispatch(std::function<void()> __f) const override
- { this->_M_ex.dispatch(std::move(__f), _M_alloc); }
- void
- post(std::function<void()> __f) const override
- { this->_M_ex.post(std::move(__f), _M_alloc); }
- void
- defer(std::function<void()> __f) const override
- { this->_M_ex.defer(std::move(__f), _M_alloc); }
- _Alloc _M_alloc [[__no_unique_address__]];
- };
- // Partial specialization for std::allocator<T>.
- // Don't store the allocator.
- template<typename _Ex, typename _Tp>
- struct _Tgt2<_Ex, std::allocator<_Tp>> : _Tgt1<_Ex>
- { };
- friend bool
- operator==(const executor& __a, const executor& __b) noexcept
- {
- _Tgt* __ta = __a._M_target.get();
- _Tgt* __tb = __b._M_target.get();
- if (__ta == __tb)
- return true;
- if (!__ta || !__tb)
- return false;
- if (__ta->_M_func == __tb->_M_func)
- return __ta->_M_func(__ta, __tb);
- return __ta->_M_equals(__tb);
- }
- shared_ptr<_Tgt> _M_target;
- };
- template<> struct is_executor<executor> : true_type { };
- /// executor comparisons
- inline bool
- operator==(const executor& __e, nullptr_t) noexcept
- { return !__e; }
- inline bool
- operator==(nullptr_t, const executor& __e) noexcept
- { return !__e; }
- inline bool
- operator!=(const executor& __a, const executor& __b) noexcept
- { return !(__a == __b); }
- inline bool
- operator!=(const executor& __e, nullptr_t) noexcept
- { return (bool)__e; }
- inline bool
- operator!=(nullptr_t, const executor& __e) noexcept
- { return (bool)__e; }
- /// Swap two executor objects.
- inline void swap(executor& __a, executor& __b) noexcept { __a.swap(__b); }
- template<typename _CompletionHandler>
- struct __dispatcher
- {
- explicit
- __dispatcher(_CompletionHandler& __h)
- : _M_h(std::move(__h)), _M_w(net::make_work_guard(_M_h))
- { }
- void operator()()
- {
- auto __alloc = net::get_associated_allocator(_M_h);
- _M_w.get_executor().dispatch(std::move(_M_h), __alloc);
- _M_w.reset();
- }
- _CompletionHandler _M_h;
- decltype(net::make_work_guard(_M_h)) _M_w;
- };
- template<typename _CompletionHandler>
- inline __dispatcher<_CompletionHandler>
- __make_dispatcher(_CompletionHandler& __h)
- { return __dispatcher<_CompletionHandler>{__h}; }
- // dispatch:
- template<typename _CompletionToken>
- inline __deduced_t<_CompletionToken, void()>
- dispatch(_CompletionToken&& __token)
- {
- async_completion<_CompletionToken, void()> __cmpl{__token};
- auto __ex = net::get_associated_executor(__cmpl.completion_handler);
- auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
- __ex.dispatch(std::move(__cmpl.completion_handler), __alloc);
- return __cmpl.result.get();
- }
- template<typename _Executor, typename _CompletionToken>
- inline
- enable_if_t<is_executor<_Executor>::value,
- __deduced_t<_CompletionToken, void()>>
- dispatch(const _Executor& __ex, _CompletionToken&& __token)
- {
- async_completion<_CompletionToken, void()> __cmpl{__token};
- auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
- __ex.dispatch(net::__make_dispatcher(__cmpl.completion_handler),
- __alloc);
- return __cmpl.result.get();
- }
- template<typename _ExecutionContext, typename _CompletionToken>
- inline
- enable_if_t<__is_exec_context<_ExecutionContext>::value,
- __deduced_t<_CompletionToken, void()>>
- dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token)
- {
- return net::dispatch(__ctx.get_executor(),
- forward<_CompletionToken>(__token));
- }
- // post:
- template<typename _CompletionToken>
- inline __deduced_t<_CompletionToken, void()>
- post(_CompletionToken&& __token)
- {
- async_completion<_CompletionToken, void()> __cmpl{__token};
- auto __ex = net::get_associated_executor(__cmpl.completion_handler);
- auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
- __ex.post(std::move(__cmpl.completion_handler), __alloc);
- return __cmpl.result.get();
- }
- template<typename _Executor, typename _CompletionToken>
- inline
- enable_if_t<is_executor<_Executor>::value,
- __deduced_t<_CompletionToken, void()>>
- post(const _Executor& __ex, _CompletionToken&& __token)
- {
- async_completion<_CompletionToken, void()> __cmpl{__token};
- auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
- __ex.post(net::__make_dispatcher(__cmpl.completion_handler), __alloc);
- return __cmpl.result.get();
- }
- template<typename _ExecutionContext, typename _CompletionToken>
- inline
- enable_if_t<__is_exec_context<_ExecutionContext>::value,
- __deduced_t<_CompletionToken, void()>>
- post(_ExecutionContext& __ctx, _CompletionToken&& __token)
- {
- return net::post(__ctx.get_executor(),
- forward<_CompletionToken>(__token));
- }
- // defer:
- template<typename _CompletionToken>
- inline __deduced_t<_CompletionToken, void()>
- defer(_CompletionToken&& __token)
- {
- async_completion<_CompletionToken, void()> __cmpl{__token};
- auto __ex = net::get_associated_executor(__cmpl.completion_handler);
- auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
- __ex.defer(std::move(__cmpl.completion_handler), __alloc);
- return __cmpl.result.get();
- }
- template<typename _Executor, typename _CompletionToken>
- inline
- enable_if_t<is_executor<_Executor>::value,
- __deduced_t<_CompletionToken, void()>>
- defer(const _Executor& __ex, _CompletionToken&& __token)
- {
- async_completion<_CompletionToken, void()> __cmpl{__token};
- auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
- __ex.defer(net::__make_dispatcher(__cmpl.completion_handler), __alloc);
- return __cmpl.result.get();
- }
- template<typename _ExecutionContext, typename _CompletionToken>
- inline
- enable_if_t<__is_exec_context<_ExecutionContext>::value,
- __deduced_t<_CompletionToken, void()>>
- defer(_ExecutionContext& __ctx, _CompletionToken&& __token)
- {
- return net::defer(__ctx.get_executor(),
- forward<_CompletionToken>(__token));
- }
- template<typename _Executor>
- class strand
- {
- public:
- // types:
- using inner_executor_type = _Executor;
- // construct / copy / destroy:
- strand(); // TODO make state
- explicit strand(_Executor __ex) : _M_inner_ex(__ex) { } // TODO make state
- template<typename _Alloc>
- strand(allocator_arg_t, const _Alloc& __a, _Executor __ex)
- : _M_inner_ex(__ex) { } // TODO make state
- strand(const strand& __other) noexcept
- : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }
- strand(strand&& __other) noexcept
- : _M_state(std::move(__other._M_state)),
- _M_inner_ex(std::move(__other._M_inner_ex)) { }
- template<typename _OtherExecutor>
- strand(const strand<_OtherExecutor>& __other) noexcept
- : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }
- template<typename _OtherExecutor>
- strand(strand<_OtherExecutor>&& __other) noexcept
- : _M_state(std::move(__other._M_state)),
- _M_inner_ex(std::move(__other._M_inner_ex)) { }
- strand&
- operator=(const strand& __other) noexcept
- {
- static_assert(is_copy_assignable<_Executor>::value,
- "inner executor type must be CopyAssignable");
- // TODO lock __other
- // TODO copy state
- _M_inner_ex = __other._M_inner_ex;
- return *this;
- }
- strand&
- operator=(strand&& __other) noexcept
- {
- static_assert(is_move_assignable<_Executor>::value,
- "inner executor type must be MoveAssignable");
- // TODO move state
- _M_inner_ex = std::move(__other._M_inner_ex);
- return *this;
- }
- template<typename _OtherExecutor>
- strand&
- operator=(const strand<_OtherExecutor>& __other) noexcept
- {
- static_assert(is_convertible<_OtherExecutor, _Executor>::value,
- "inner executor type must be compatible");
- // TODO lock __other
- // TODO copy state
- _M_inner_ex = __other._M_inner_ex;
- return *this;
- }
- template<typename _OtherExecutor>
- strand&
- operator=(strand<_OtherExecutor>&& __other) noexcept
- {
- static_assert(is_convertible<_OtherExecutor, _Executor>::value,
- "inner executor type must be compatible");
- // TODO move state
- _M_inner_ex = std::move(__other._M_inner_ex);
- return *this;
- }
- ~strand()
- {
- // the task queue outlives this object if non-empty
- // TODO create circular ref in queue?
- }
- // strand operations:
- inner_executor_type
- get_inner_executor() const noexcept
- { return _M_inner_ex; }
- bool
- running_in_this_thread() const noexcept
- { return _M_state->running_in_this_thread(); }
- execution_context&
- context() const noexcept
- { return _M_inner_ex.context(); }
- void on_work_started() const noexcept { _M_inner_ex.on_work_started(); }
- void on_work_finished() const noexcept { _M_inner_ex.on_work_finished(); }
- template<typename _Func, typename _Alloc>
- void
- dispatch(_Func&& __f, const _Alloc& __a) const
- {
- if (running_in_this_thread())
- decay_t<_Func>{std::forward<_Func>(__f)}();
- else
- post(std::forward<_Func>(__f), __a);
- }
- template<typename _Func, typename _Alloc>
- void
- post(_Func&& __f, const _Alloc& __a) const; // TODO
- template<typename _Func, typename _Alloc>
- void
- defer(_Func&& __f, const _Alloc& __a) const
- { post(std::forward<_Func>(__f), __a); }
- private:
- friend bool
- operator==(const strand& __a, const strand& __b)
- { return __a._M_state == __b._M_state; }
- // TODO add synchronised queue
- struct _State
- {
- #if defined(_GLIBCXX_HAS_GTHREADS)
- bool
- running_in_this_thread() const noexcept
- { return std::this_thread::get_id() == _M_running_on; }
- std::thread::id _M_running_on;
- #else
- bool running_in_this_thread() const { return true; }
- #endif
- };
- shared_ptr<_State> _M_state;
- _Executor _M_inner_ex;
- };
- #if defined(_GLIBCXX_HAS_GTHREADS)
- // Completion token for asynchronous operations initiated with use_future.
- template<typename _Func, typename _Alloc>
- struct __use_future_ct
- {
- std::tuple<_Func, _Alloc> _M_t;
- };
- template<typename _Func, typename _Tp>
- struct __use_future_ct<_Func, std::allocator<_Tp>>
- {
- _Func _M_f;
- };
- template<typename _ProtoAllocator = allocator<void>>
- class use_future_t
- {
- public:
- // use_future_t types:
- using allocator_type = _ProtoAllocator;
- // use_future_t members:
- constexpr
- use_future_t()
- noexcept(is_nothrow_default_constructible<_ProtoAllocator>::value)
- : _M_alloc() { }
- explicit
- use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { }
- template<typename _OtherAllocator>
- use_future_t<_OtherAllocator>
- rebind(const _OtherAllocator& __a) const noexcept
- { return use_future_t<_OtherAllocator>(__a); }
- allocator_type get_allocator() const noexcept { return _M_alloc; }
- template<typename _Func>
- auto
- operator()(_Func&& __f) const
- {
- using _Token = __use_future_ct<decay_t<_Func>, _ProtoAllocator>;
- return _Token{ {std::forward<_Func>(__f), _M_alloc} };
- }
- private:
- _ProtoAllocator _M_alloc;
- };
- template<typename _Tp>
- class use_future_t<std::allocator<_Tp>>
- {
- public:
- // use_future_t types:
- using allocator_type = std::allocator<_Tp>;
- // use_future_t members:
- constexpr use_future_t() noexcept = default;
- explicit
- use_future_t(const allocator_type& __a) noexcept { }
- template<class _Up>
- use_future_t<std::allocator<_Up>>
- rebind(const std::allocator<_Up>& __a) const noexcept
- { return use_future_t<std::allocator<_Up>>(__a); }
- allocator_type get_allocator() const noexcept { return {}; }
- template<typename _Func>
- auto
- operator()(_Func&& __f) const
- {
- using _Token = __use_future_ct<decay_t<_Func>, allocator_type>;
- return _Token{std::forward<_Func>(__f)};
- }
- };
- constexpr use_future_t<> use_future = use_future_t<>();
- template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
- class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>;
- template<typename _Result, typename _Executor>
- struct __use_future_ex;
- // Completion handler for asynchronous operations initiated with use_future.
- template<typename _Func, typename... _Args>
- struct __use_future_ch
- {
- template<typename _Alloc>
- explicit
- __use_future_ch(__use_future_ct<_Func, _Alloc>&& __token)
- : _M_f{ std::move(std::get<0>(__token._M_t)) },
- _M_promise{ std::get<1>(__token._M_t) }
- { }
- template<typename _Tp>
- explicit
- __use_future_ch(__use_future_ct<_Func, std::allocator<_Tp>>&& __token)
- : _M_f{ std::move(__token._M_f) }
- { }
- void
- operator()(_Args&&... __args)
- {
- __try
- {
- _M_promise.set_value(_M_f(std::forward<_Args>(__args)...));
- }
- __catch(__cxxabiv1::__forced_unwind&)
- {
- __throw_exception_again;
- }
- __catch(...)
- {
- _M_promise.set_exception(std::current_exception());
- }
- }
- using __result = result_of_t<_Func(decay_t<_Args>...)>;
- future<__result> get_future() { return _M_promise.get_future(); }
- private:
- template<typename _Result, typename _Executor>
- friend struct __use_future_ex;
- _Func _M_f;
- mutable promise<__result> _M_promise;
- };
- // Specialization of async_result for operations initiated with use_future.
- template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
- class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>
- {
- public:
- using completion_handler_type = __use_future_ch<_Func, _Args...>;
- using return_type = future<typename completion_handler_type::__result>;
- explicit
- async_result(completion_handler_type& __h)
- : _M_future(__h.get_future())
- { }
- async_result(const async_result&) = delete;
- async_result& operator=(const async_result&) = delete;
- return_type get() { return std::move(_M_future); }
- private:
- return_type _M_future;
- };
- template<typename _Result, typename _Executor>
- struct __use_future_ex
- {
- template<typename _Handler>
- __use_future_ex(const _Handler& __h, _Executor __ex)
- : _M_t(__h._M_promise, __ex)
- { }
- template<typename _Fn, typename _Alloc>
- void
- dispatch(_Fn&& __fn)
- {
- __try
- {
- std::get<1>(_M_t).dispatch(std::forward<_Fn>(__fn));
- }
- __catch(__cxxabiv1::__forced_unwind&)
- {
- __throw_exception_again;
- }
- __catch(...)
- {
- std::get<0>(_M_t).set_exception(std::current_exception());
- }
- }
- template<typename _Fn, typename _Alloc>
- void
- post(_Fn&& __fn)
- {
- __try
- {
- std::get<1>(_M_t).post(std::forward<_Fn>(__fn));
- }
- __catch(__cxxabiv1::__forced_unwind&)
- {
- __throw_exception_again;
- }
- __catch(...)
- {
- std::get<0>(_M_t).set_exception(std::current_exception());
- }
- }
- template<typename _Fn, typename _Alloc>
- void
- defer(_Fn&& __fn)
- {
- __try
- {
- std::get<1>(_M_t).defer(std::forward<_Fn>(__fn));
- }
- __catch(__cxxabiv1::__forced_unwind&)
- {
- __throw_exception_again;
- }
- __catch(...)
- {
- std::get<0>(_M_t).set_exception(std::current_exception());
- }
- }
- private:
- tuple<promise<_Result>&, _Executor> _M_t;
- };
- template<typename _Func, typename... _Args, typename _Executor>
- struct associated_executor<__use_future_ch<_Func, _Args...>, _Executor>
- {
- private:
- using __handler = __use_future_ch<_Func, _Args...>;
- using type = __use_future_ex<typename __handler::__result, _Executor>;
- static type
- get(const __handler& __h, const _Executor& __ex)
- { return { __h, __ex }; }
- };
- #if 0
- // [async.use.future.traits]
- template<typename _Allocator, typename _Ret, typename... _Args>
- class handler_type<use_future_t<_Allocator>, _Ret(_Args...)> // TODO uglify name
- {
- template<typename... _Args>
- struct __is_error_result : false_type { };
- template<typename... _Args>
- struct __is_error_result<error_code, _Args...> : true_type { };
- template<typename... _Args>
- struct __is_error_result<exception_ptr, _Args...> : true_type { };
- static exception_ptr
- _S_exptr(exception_ptr& __ex)
- { return std::move(__ex); }
- static exception_ptr
- _S_exptr(const error_code& __ec)
- { return make_exception_ptr(system_error(__ec)); }
- template<bool _IsError, typename... _UArgs>
- struct _Type;
- // N == 0
- template<bool _IsError>
- struct _Type<_IsError>
- {
- std::promise<void> _M_promise;
- void
- operator()()
- {
- _M_promise.set_value();
- }
- };
- // N == 1, U0 is error_code or exception_ptr
- template<typename _UArg0>
- struct _Type<true, _UArg0>
- {
- std::promise<void> _M_promise;
- template<typename _Arg0>
- void
- operator()(_Arg0&& __a0)
- {
- if (__a0)
- _M_promise.set_exception(_S_exptr(__a0));
- else
- _M_promise.set_value();
- }
- };
- // N == 1, U0 is not error_code or exception_ptr
- template<typename _UArg0>
- struct _Type<false, _UArg0>
- {
- std::promise<_UArg0> _M_promise;
- template<typename _Arg0>
- void
- operator()(_Arg0&& __a0)
- {
- _M_promise.set_value(std::forward<_Arg0>(__a0));
- }
- };
- // N == 2, U0 is error_code or exception_ptr
- template<typename _UArg0, typename _UArg1>
- struct _Type<true, _UArg0, _UArg1>
- {
- std::promise<_UArg1> _M_promise;
- template<typename _Arg0, typename _Arg1>
- void
- operator()(_Arg0&& __a0, _Arg1&& __a1)
- {
- if (__a0)
- _M_promise.set_exception(_S_exptr(__a0));
- else
- _M_promise.set_value(std::forward<_Arg1>(__a1));
- }
- };
- // N >= 2, U0 is not error_code or exception_ptr
- template<typename... _UArgs>
- struct _Type<false, _UArgs...>
- {
- static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");
- std::promise<tuple<_UArgs...>> _M_promise;
- template<typename... _Args>
- void
- operator()(_Args&&... __args)
- {
- _M_promise.set_value(
- std::forward_as_tuple(std::forward<_Args>(__args)...));
- }
- };
- // N > 2, U0 is error_code or exception_ptr
- template<typename _UArg0, typename... _UArgs>
- struct _Type<true, _UArg0, _UArgs...>
- {
- static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");
- std::promise<tuple<_UArgs...>> _M_promise;
- template<typename _Arg0, typename... _Args>
- void
- operator()(_Arg0&& __a0, _Args&&... __args)
- {
- if (__a0)
- _M_promise.set_exception(_S_exptr(__a0));
- else
- _M_promise.set_value(
- std::forward_as_tuple(std::forward<_Args>(__args)...));
- }
- };
- public:
- using type =
- _Type<__is_error_result<_Args...>::value, decay_t<_Args>...>;
- };
- template<typename _Alloc, typename _Ret, typename... _Args>
- struct async_result<use_future_t<_Alloc>, _Ret(_Args...)>
- {
- using completion_handler_type
- = typename handler_type<use_future_t<_Alloc>, _Ret(_Args...)>::type;
- using return_type = void; // XXX TODO ???;
- explicit
- async_result(completion_handler_type& __h) : _M_handler(__h) { }
- auto get() { return _M_handler._M_provider.get_future(); }
- async_result(const async_result&) = delete;
- async_result& operator=(const async_result&) = delete;
- return_type get() { return _M_handler._M_promise.get_future(); }
- private:
- completion_handler_type& _M_handler;
- };
- // TODO specialize associated_executor for
- // async_result<use_future_t<A>, Sig>::completion_handler_type
- // to use a __use_future_ex
- // (probably need to move _Type outside of handler_type so we don't have
- // a non-deduced context)
- #endif
- // [async.packaged.task.specializations]
- template<typename _Ret, typename... _Args, typename _Signature>
- class async_result<packaged_task<_Ret(_Args...)>, _Signature>
- {
- public:
- using completion_handler_type = packaged_task<_Ret(_Args...)>;
- using return_type = future<_Ret>;
- explicit
- async_result(completion_handler_type& __h)
- : _M_future(__h.get_future()) { }
- async_result(const async_result&) = delete;
- async_result& operator=(const async_result&) = delete;
- return_type get() { return std::move(_M_future); }
- private:
- return_type _M_future;
- };
- #endif // _GLIBCXX_HAS_GTHREADS
- /// @}
- } // namespace v1
- } // namespace net
- } // namespace experimental
- template<typename _Alloc>
- struct uses_allocator<experimental::net::executor, _Alloc>
- : true_type {};
- _GLIBCXX_END_NAMESPACE_VERSION
- } // namespace std
- #endif // C++14
- #endif // _GLIBCXX_EXPERIMENTAL_EXECUTOR
|