xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/include/experimental/executor (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
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