source: Daodan/MSYS2/mingw32/include/c++/11.2.0/experimental/executor@ 1177

Last change on this file since 1177 was 1166, checked in by rossy, 3 years ago

Daodan: Replace MinGW build env with an up-to-date MSYS2 env

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