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