]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/asio/experimental/impl/co_spawn.hpp
Add patch for failing prerm scripts
[ceph.git] / ceph / src / boost / boost / asio / experimental / impl / co_spawn.hpp
1 //
2 // experimental/impl/co_spawn.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 #ifndef BOOST_ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP
12 #define BOOST_ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP
13
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18 #include <boost/asio/detail/config.hpp>
19 #include <exception>
20 #include <functional>
21 #include <memory>
22 #include <new>
23 #include <tuple>
24 #include <utility>
25 #include <boost/asio/async_result.hpp>
26 #include <boost/asio/detail/thread_context.hpp>
27 #include <boost/asio/detail/thread_info_base.hpp>
28 #include <boost/asio/detail/type_traits.hpp>
29 #include <boost/asio/dispatch.hpp>
30 #include <boost/asio/post.hpp>
31
32 #include <boost/asio/detail/push_options.hpp>
33
34 namespace boost {
35 namespace asio {
36 namespace experimental {
37 namespace detail {
38
39 // Promise object for coroutine at top of thread-of-execution "stack".
40 template <typename Executor>
41 class awaiter
42 {
43 public:
44 struct deleter
45 {
46 void operator()(awaiter* a)
47 {
48 if (a)
49 a->release();
50 }
51 };
52
53 typedef std::unique_ptr<awaiter, deleter> ptr;
54
55 typedef Executor executor_type;
56
57 ~awaiter()
58 {
59 if (has_executor_)
60 static_cast<Executor*>(static_cast<void*>(executor_))->~Executor();
61 }
62
63 void set_executor(const Executor& ex)
64 {
65 new (&executor_) Executor(ex);
66 has_executor_ = true;
67 }
68
69 executor_type get_executor() const noexcept
70 {
71 return *static_cast<const Executor*>(static_cast<const void*>(executor_));
72 }
73
74 awaiter* get_return_object()
75 {
76 return this;
77 }
78
79 auto initial_suspend()
80 {
81 return std::experimental::suspend_always();
82 }
83
84 auto final_suspend()
85 {
86 return std::experimental::suspend_always();
87 }
88
89 void return_void()
90 {
91 }
92
93 awaiter* add_ref()
94 {
95 ++ref_count_;
96 return this;
97 }
98
99 void release()
100 {
101 if (--ref_count_ == 0)
102 coroutine_handle<awaiter>::from_promise(*this).destroy();
103 }
104
105 void unhandled_exception()
106 {
107 pending_exception_ = std::current_exception();
108 }
109
110 void rethrow_unhandled_exception()
111 {
112 if (pending_exception_)
113 {
114 std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
115 std::rethrow_exception(ex);
116 }
117 }
118
119 private:
120 std::size_t ref_count_ = 0;
121 std::exception_ptr pending_exception_ = nullptr;
122 alignas(Executor) unsigned char executor_[sizeof(Executor)];
123 bool has_executor_ = false;
124 };
125
126 // Base promise for coroutines further down the thread-of-execution "stack".
127 template <typename Executor>
128 class awaitee_base
129 {
130 public:
131 #if !defined(BOOST_ASIO_DISABLE_AWAITEE_RECYCLING)
132 void* operator new(std::size_t size)
133 {
134 return boost::asio::detail::thread_info_base::allocate(
135 boost::asio::detail::thread_info_base::awaitee_tag(),
136 boost::asio::detail::thread_context::thread_call_stack::top(),
137 size);
138 }
139
140 void operator delete(void* pointer, std::size_t size)
141 {
142 boost::asio::detail::thread_info_base::deallocate(
143 boost::asio::detail::thread_info_base::awaitee_tag(),
144 boost::asio::detail::thread_context::thread_call_stack::top(),
145 pointer, size);
146 }
147 #endif // !defined(BOOST_ASIO_DISABLE_AWAITEE_RECYCLING)
148
149 auto initial_suspend()
150 {
151 return std::experimental::suspend_never();
152 }
153
154 struct final_suspender
155 {
156 awaitee_base* this_;
157
158 bool await_ready() const noexcept
159 {
160 return false;
161 }
162
163 void await_suspend(coroutine_handle<void>)
164 {
165 this_->wake_caller();
166 }
167
168 void await_resume() const noexcept
169 {
170 }
171 };
172
173 auto final_suspend()
174 {
175 return final_suspender{this};
176 }
177
178 void set_except(std::exception_ptr e)
179 {
180 pending_exception_ = e;
181 }
182
183 void unhandled_exception()
184 {
185 set_except(std::current_exception());
186 }
187
188 void rethrow_exception()
189 {
190 if (pending_exception_)
191 {
192 std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
193 std::rethrow_exception(ex);
194 }
195 }
196
197 awaiter<Executor>* top()
198 {
199 return awaiter_;
200 }
201
202 coroutine_handle<void> caller()
203 {
204 return caller_;
205 }
206
207 bool ready() const
208 {
209 return ready_;
210 }
211
212 void wake_caller()
213 {
214 if (caller_)
215 caller_.resume();
216 else
217 ready_ = true;
218 }
219
220 class awaitable_executor
221 {
222 public:
223 explicit awaitable_executor(awaitee_base* a)
224 : this_(a)
225 {
226 }
227
228 bool await_ready() const noexcept
229 {
230 return this_->awaiter_ != nullptr;
231 }
232
233 template <typename U, typename Ex>
234 void await_suspend(coroutine_handle<detail::awaitee<U, Ex>> h) noexcept
235 {
236 this_->resume_on_attach_ = h;
237 }
238
239 Executor await_resume()
240 {
241 return this_->awaiter_->get_executor();
242 }
243
244 private:
245 awaitee_base* this_;
246 };
247
248 awaitable_executor await_transform(this_coro::executor_t) noexcept
249 {
250 return awaitable_executor(this);
251 }
252
253 class awaitable_token
254 {
255 public:
256 explicit awaitable_token(awaitee_base* a)
257 : this_(a)
258 {
259 }
260
261 bool await_ready() const noexcept
262 {
263 return this_->awaiter_ != nullptr;
264 }
265
266 template <typename U, typename Ex>
267 void await_suspend(coroutine_handle<detail::awaitee<U, Ex>> h) noexcept
268 {
269 this_->resume_on_attach_ = h;
270 }
271
272 await_token<Executor> await_resume()
273 {
274 return await_token<Executor>(this_->awaiter_);
275 }
276
277 private:
278 awaitee_base* this_;
279 };
280
281 awaitable_token await_transform(this_coro::token_t) noexcept
282 {
283 return awaitable_token(this);
284 }
285
286 template <typename T>
287 awaitable<T, Executor> await_transform(awaitable<T, Executor>& t) const
288 {
289 return std::move(t);
290 }
291
292 template <typename T>
293 awaitable<T, Executor> await_transform(awaitable<T, Executor>&& t) const
294 {
295 return std::move(t);
296 }
297
298 std::experimental::suspend_always await_transform(
299 std::experimental::suspend_always) const
300 {
301 return std::experimental::suspend_always();
302 }
303
304 void attach_caller(coroutine_handle<awaiter<Executor>> h)
305 {
306 this->caller_ = h;
307 this->attach_callees(&h.promise());
308 }
309
310 template <typename U>
311 void attach_caller(coroutine_handle<awaitee<U, Executor>> h)
312 {
313 this->caller_ = h;
314 if (h.promise().awaiter_)
315 this->attach_callees(h.promise().awaiter_);
316 else
317 h.promise().unattached_callee_ = this;
318 }
319
320 void attach_callees(awaiter<Executor>* a)
321 {
322 for (awaitee_base* curr = this; curr != nullptr;
323 curr = std::exchange(curr->unattached_callee_, nullptr))
324 {
325 curr->awaiter_ = a;
326 if (curr->resume_on_attach_)
327 return std::exchange(curr->resume_on_attach_, nullptr).resume();
328 }
329 }
330
331 protected:
332 awaiter<Executor>* awaiter_ = nullptr;
333 coroutine_handle<void> caller_ = nullptr;
334 awaitee_base<Executor>* unattached_callee_ = nullptr;
335 std::exception_ptr pending_exception_ = nullptr;
336 coroutine_handle<void> resume_on_attach_ = nullptr;
337 bool ready_ = false;
338 };
339
340 // Promise object for coroutines further down the thread-of-execution "stack".
341 template <typename T, typename Executor>
342 class awaitee
343 : public awaitee_base<Executor>
344 {
345 public:
346 awaitee()
347 {
348 }
349
350 awaitee(awaitee&& other) noexcept
351 : awaitee_base<Executor>(std::move(other))
352 {
353 }
354
355 ~awaitee()
356 {
357 if (has_result_)
358 static_cast<T*>(static_cast<void*>(result_))->~T();
359 }
360
361 awaitable<T, Executor> get_return_object()
362 {
363 return awaitable<T, Executor>(this);
364 };
365
366 template <typename U>
367 void return_value(U&& u)
368 {
369 new (&result_) T(std::forward<U>(u));
370 has_result_ = true;
371 }
372
373 T get()
374 {
375 this->caller_ = nullptr;
376 this->rethrow_exception();
377 return std::move(*static_cast<T*>(static_cast<void*>(result_)));
378 }
379
380 private:
381 alignas(T) unsigned char result_[sizeof(T)];
382 bool has_result_ = false;
383 };
384
385 // Promise object for coroutines further down the thread-of-execution "stack".
386 template <typename Executor>
387 class awaitee<void, Executor>
388 : public awaitee_base<Executor>
389 {
390 public:
391 awaitable<void, Executor> get_return_object()
392 {
393 return awaitable<void, Executor>(this);
394 };
395
396 void return_void()
397 {
398 }
399
400 void get()
401 {
402 this->caller_ = nullptr;
403 this->rethrow_exception();
404 }
405 };
406
407 template <typename Executor>
408 class awaiter_task
409 {
410 public:
411 typedef Executor executor_type;
412
413 awaiter_task(awaiter<Executor>* a)
414 : awaiter_(a->add_ref())
415 {
416 }
417
418 awaiter_task(awaiter_task&& other) noexcept
419 : awaiter_(std::exchange(other.awaiter_, nullptr))
420 {
421 }
422
423 ~awaiter_task()
424 {
425 if (awaiter_)
426 {
427 // Coroutine "stack unwinding" must be performed through the executor.
428 executor_type ex(awaiter_->get_executor());
429 (post)(ex,
430 [a = std::move(awaiter_)]() mutable
431 {
432 typename awaiter<Executor>::ptr(std::move(a));
433 });
434 }
435 }
436
437 executor_type get_executor() const noexcept
438 {
439 return awaiter_->get_executor();
440 }
441
442 protected:
443 typename awaiter<Executor>::ptr awaiter_;
444 };
445
446 template <typename Executor>
447 class co_spawn_handler : public awaiter_task<Executor>
448 {
449 public:
450 using awaiter_task<Executor>::awaiter_task;
451
452 void operator()()
453 {
454 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
455 coroutine_handle<awaiter<Executor>>::from_promise(*ptr.get()).resume();
456 }
457 };
458
459 template <typename Executor, typename T>
460 class await_handler_base : public awaiter_task<Executor>
461 {
462 public:
463 typedef awaitable<T, Executor> awaitable_type;
464
465 await_handler_base(await_token<Executor> token)
466 : awaiter_task<Executor>(token.awaiter_),
467 awaitee_(nullptr)
468 {
469 }
470
471 await_handler_base(await_handler_base&& other) noexcept
472 : awaiter_task<Executor>(std::move(other)),
473 awaitee_(std::exchange(other.awaitee_, nullptr))
474 {
475 }
476
477 void attach_awaitee(const awaitable<T, Executor>& a)
478 {
479 awaitee_ = a.awaitee_;
480 }
481
482 protected:
483 awaitee<T, Executor>* awaitee_;
484 };
485
486 template <typename, typename...> class await_handler;
487
488 template <typename Executor>
489 class await_handler<Executor, void>
490 : public await_handler_base<Executor, void>
491 {
492 public:
493 using await_handler_base<Executor, void>::await_handler_base;
494
495 void operator()()
496 {
497 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
498 this->awaitee_->return_void();
499 this->awaitee_->wake_caller();
500 ptr->rethrow_unhandled_exception();
501 }
502 };
503
504 template <typename Executor>
505 class await_handler<Executor, boost::system::error_code>
506 : public await_handler_base<Executor, void>
507 {
508 public:
509 typedef void return_type;
510
511 using await_handler_base<Executor, void>::await_handler_base;
512
513 void operator()(const boost::system::error_code& ec)
514 {
515 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
516 if (ec)
517 {
518 this->awaitee_->set_except(
519 std::make_exception_ptr(boost::system::system_error(ec)));
520 }
521 else
522 this->awaitee_->return_void();
523 this->awaitee_->wake_caller();
524 ptr->rethrow_unhandled_exception();
525 }
526 };
527
528 template <typename Executor>
529 class await_handler<Executor, std::exception_ptr>
530 : public await_handler_base<Executor, void>
531 {
532 public:
533 using await_handler_base<Executor, void>::await_handler_base;
534
535 void operator()(std::exception_ptr ex)
536 {
537 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
538 if (ex)
539 this->awaitee_->set_except(ex);
540 else
541 this->awaitee_->return_void();
542 this->awaitee_->wake_caller();
543 ptr->rethrow_unhandled_exception();
544 }
545 };
546
547 template <typename Executor, typename T>
548 class await_handler<Executor, T>
549 : public await_handler_base<Executor, T>
550 {
551 public:
552 using await_handler_base<Executor, T>::await_handler_base;
553
554 template <typename Arg>
555 void operator()(Arg&& arg)
556 {
557 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
558 this->awaitee_->return_value(std::forward<Arg>(arg));
559 this->awaitee_->wake_caller();
560 ptr->rethrow_unhandled_exception();
561 }
562 };
563
564 template <typename Executor, typename T>
565 class await_handler<Executor, boost::system::error_code, T>
566 : public await_handler_base<Executor, T>
567 {
568 public:
569 using await_handler_base<Executor, T>::await_handler_base;
570
571 template <typename Arg>
572 void operator()(const boost::system::error_code& ec, Arg&& arg)
573 {
574 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
575 if (ec)
576 {
577 this->awaitee_->set_except(
578 std::make_exception_ptr(boost::system::system_error(ec)));
579 }
580 else
581 this->awaitee_->return_value(std::forward<Arg>(arg));
582 this->awaitee_->wake_caller();
583 ptr->rethrow_unhandled_exception();
584 }
585 };
586
587 template <typename Executor, typename T>
588 class await_handler<Executor, std::exception_ptr, T>
589 : public await_handler_base<Executor, T>
590 {
591 public:
592 using await_handler_base<Executor, T>::await_handler_base;
593
594 template <typename Arg>
595 void operator()(std::exception_ptr ex, Arg&& arg)
596 {
597 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
598 if (ex)
599 this->awaitee_->set_except(ex);
600 else
601 this->awaitee_->return_value(std::forward<Arg>(arg));
602 this->awaitee_->wake_caller();
603 ptr->rethrow_unhandled_exception();
604 }
605 };
606
607 template <typename Executor, typename... Ts>
608 class await_handler
609 : public await_handler_base<Executor, std::tuple<Ts...>>
610 {
611 public:
612 using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base;
613
614 template <typename... Args>
615 void operator()(Args&&... args)
616 {
617 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
618 this->awaitee_->return_value(
619 std::forward_as_tuple(std::forward<Args>(args)...));
620 this->awaitee_->wake_caller();
621 ptr->rethrow_unhandled_exception();
622 }
623 };
624
625 template <typename Executor, typename... Ts>
626 class await_handler<Executor, boost::system::error_code, Ts...>
627 : public await_handler_base<Executor, std::tuple<Ts...>>
628 {
629 public:
630 using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base;
631
632 template <typename... Args>
633 void operator()(const boost::system::error_code& ec, Args&&... args)
634 {
635 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
636 if (ec)
637 {
638 this->awaitee_->set_except(
639 std::make_exception_ptr(boost::system::system_error(ec)));
640 }
641 else
642 {
643 this->awaitee_->return_value(
644 std::forward_as_tuple(std::forward<Args>(args)...));
645 }
646 this->awaitee_->wake_caller();
647 ptr->rethrow_unhandled_exception();
648 }
649 };
650
651 template <typename Executor, typename... Ts>
652 class await_handler<Executor, std::exception_ptr, Ts...>
653 : public await_handler_base<Executor, std::tuple<Ts...>>
654 {
655 public:
656 using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base;
657
658 template <typename... Args>
659 void operator()(std::exception_ptr ex, Args&&... args)
660 {
661 typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
662 if (ex)
663 this->awaitee_->set_except(ex);
664 else
665 {
666 this->awaitee_->return_value(
667 std::forward_as_tuple(std::forward<Args>(args)...));
668 }
669 this->awaitee_->wake_caller();
670 ptr->rethrow_unhandled_exception();
671 }
672 };
673
674 template <typename T>
675 struct awaitable_signature;
676
677 template <typename T, typename Executor>
678 struct awaitable_signature<awaitable<T, Executor>>
679 {
680 typedef void type(std::exception_ptr, T);
681 };
682
683 template <typename Executor>
684 struct awaitable_signature<awaitable<void, Executor>>
685 {
686 typedef void type(std::exception_ptr);
687 };
688
689 template <typename T, typename Executor, typename F, typename Handler>
690 awaiter<Executor>* co_spawn_entry_point(awaitable<T, Executor>*,
691 executor_work_guard<Executor> work_guard, F f, Handler handler)
692 {
693 bool done = false;
694
695 try
696 {
697 T t = co_await f();
698
699 done = true;
700
701 (dispatch)(work_guard.get_executor(),
702 [handler = std::move(handler), t = std::move(t)]() mutable
703 {
704 handler(std::exception_ptr(), std::move(t));
705 });
706 }
707 catch (...)
708 {
709 if (done)
710 throw;
711
712 (dispatch)(work_guard.get_executor(),
713 [handler = std::move(handler), e = std::current_exception()]() mutable
714 {
715 handler(e, T());
716 });
717 }
718 }
719
720 template <typename Executor, typename F, typename Handler>
721 awaiter<Executor>* co_spawn_entry_point(awaitable<void, Executor>*,
722 executor_work_guard<Executor> work_guard, F f, Handler handler)
723 {
724 std::exception_ptr e = nullptr;
725
726 try
727 {
728 co_await f();
729 }
730 catch (...)
731 {
732 e = std::current_exception();
733 }
734
735 (dispatch)(work_guard.get_executor(),
736 [handler = std::move(handler), e]() mutable
737 {
738 handler(e);
739 });
740 }
741
742 template <typename Executor, typename F, typename CompletionToken>
743 auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token)
744 {
745 typedef typename result_of<F()>::type awaitable_type;
746 typedef typename awaitable_type::executor_type executor_type;
747 typedef typename awaitable_signature<awaitable_type>::type signature_type;
748
749 async_completion<CompletionToken, signature_type> completion(token);
750
751 executor_type ex2(ex);
752 auto work_guard = make_work_guard(completion.completion_handler, ex2);
753
754 auto* a = (co_spawn_entry_point)(
755 static_cast<awaitable_type*>(nullptr), std::move(work_guard),
756 std::forward<F>(f), std::move(completion.completion_handler));
757
758 a->set_executor(ex2);
759 (post)(co_spawn_handler<executor_type>(a));
760
761 return completion.result.get();
762 }
763
764 #if defined(_MSC_VER)
765 # pragma warning(push)
766 # pragma warning(disable:4033)
767 #endif // defined(_MSC_VER)
768
769 #if defined(_MSC_VER)
770 template <typename T> T dummy_return()
771 {
772 return std::move(*static_cast<T*>(nullptr));
773 }
774
775 template <>
776 inline void dummy_return()
777 {
778 }
779 #endif // defined(_MSC_VER)
780
781 template <typename Awaitable>
782 inline Awaitable make_dummy_awaitable()
783 {
784 for (;;) co_await std::experimental::suspend_always();
785 #if defined(_MSC_VER)
786 co_return dummy_return<typename Awaitable::value_type>();
787 #endif // defined(_MSC_VER)
788 }
789
790 #if defined(_MSC_VER)
791 # pragma warning(pop)
792 #endif // defined(_MSC_VER)
793
794 } // namespace detail
795 } // namespace experimental
796
797 template <typename Executor, typename R, typename... Args>
798 class async_result<experimental::await_token<Executor>, R(Args...)>
799 {
800 public:
801 typedef experimental::detail::await_handler<
802 Executor, typename decay<Args>::type...> completion_handler_type;
803
804 typedef typename experimental::detail::await_handler<
805 Executor, Args...>::awaitable_type return_type;
806
807 async_result(completion_handler_type& h)
808 : awaitable_(experimental::detail::make_dummy_awaitable<return_type>())
809 {
810 h.attach_awaitee(awaitable_);
811 }
812
813 return_type get()
814 {
815 return std::move(awaitable_);
816 }
817
818 private:
819 return_type awaitable_;
820 };
821
822 #if !defined(BOOST_ASIO_NO_DEPRECATED)
823
824 template <typename Executor, typename R, typename... Args>
825 struct handler_type<experimental::await_token<Executor>, R(Args...)>
826 {
827 typedef experimental::detail::await_handler<
828 Executor, typename decay<Args>::type...> type;
829 };
830
831 template <typename Executor, typename... Args>
832 class async_result<experimental::detail::await_handler<Executor, Args...>>
833 {
834 public:
835 typedef typename experimental::detail::await_handler<
836 Executor, Args...>::awaitable_type type;
837
838 async_result(experimental::detail::await_handler<Executor, Args...>& h)
839 : awaitable_(experimental::detail::make_dummy_awaitable<type>())
840 {
841 h.attach_awaitee(awaitable_);
842 }
843
844 type get()
845 {
846 return std::move(awaitable_);
847 }
848
849 private:
850 type awaitable_;
851 };
852
853 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
854
855 } // namespace asio
856 } // namespace boost
857
858 namespace std { namespace experimental {
859
860 template <typename Executor, typename... Args>
861 struct coroutine_traits<
862 boost::asio::experimental::detail::awaiter<Executor>*, Args...>
863 {
864 typedef boost::asio::experimental::detail::awaiter<Executor> promise_type;
865 };
866
867 template <typename T, typename Executor, typename... Args>
868 struct coroutine_traits<
869 boost::asio::experimental::awaitable<T, Executor>, Args...>
870 {
871 typedef boost::asio::experimental::detail::awaitee<T, Executor> promise_type;
872 };
873
874 }} // namespace std::experimental
875
876 #include <boost/asio/detail/pop_options.hpp>
877
878 #endif // BOOST_ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP