1//
2// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7
8#ifndef BOOST_COBALT_DETAIL_SPAWN_HPP
9#define BOOST_COBALT_DETAIL_SPAWN_HPP
10
11#include <boost/cobalt/task.hpp>
12#include <boost/asio/dispatch.hpp>
13
14#include <boost/smart_ptr/allocate_unique.hpp>
15
16namespace boost::cobalt
17{
18template<typename T>
19struct task;
20}
21
22namespace boost::cobalt::detail
23{
24
25struct async_initiate_spawn
26{
27 template<typename Handler, typename T>
28 void operator()(Handler && h, task<T> a, executor exec)
29 {
30 auto & rec = a.receiver_;
31 if (rec.done)
32 return asio::dispatch(
33 asio::get_associated_immediate_executor(h, exec),
34 asio::append(std::forward<Handler>(h), rec.exception, rec.exception ? T() : *rec.get_result()));
35
36#if !defined(BOOST_COBALT_NO_PMR)
37 auto dalloc = pmr::polymorphic_allocator<void>{boost::cobalt::this_thread::get_default_resource()};
38 auto alloc = asio::get_associated_allocator(h, dalloc);
39#else
40 auto alloc = asio::get_associated_allocator(h);
41#endif
42 auto recs = std::allocate_shared<detail::task_receiver<T>>(alloc, std::move(rec));
43
44 auto sl = asio::get_associated_cancellation_slot(h);
45 if (sl.is_connected())
46 sl.assign(
47 [exec, recs](asio::cancellation_type ct)
48 {
49 asio::dispatch(exec, [recs, ct] {recs->cancel(ct);});
50 });
51
52 auto p = recs.get();
53
54 p->promise->exec.emplace(exec);
55 p->promise->exec_ = exec;
56
57 struct completion_handler
58 {
59 using allocator_type = std::decay_t<decltype(alloc)>;
60
61 allocator_type get_allocator() const { return alloc_; }
62 allocator_type alloc_;
63
64 using executor_type = std::decay_t<decltype(asio::get_associated_executor(h, exec))>;
65 const executor_type &get_executor() const { return exec_; }
66 executor_type exec_;
67
68 decltype(recs) r;
69 Handler handler;
70
71 void operator()()
72 {
73 auto ex = r->exception;
74 T rr{};
75 if (r->result)
76 rr = std::move(*r->result);
77 r.reset();
78 std::move(handler)(ex, std::move(rr));
79 }
80 };
81
82 p->awaited_from.reset(detail::post_coroutine(
83 completion_handler{
84 alloc, asio::get_associated_executor(h, exec), std::move(recs), std::move(h)
85 }).address());
86
87 asio::dispatch(exec, std::coroutine_handle<detail::task_promise<T>>::from_promise(*p->promise));
88 }
89
90 template<typename Handler>
91 void operator()(Handler && h, task<void> a, executor exec)
92 {
93 if (a.receiver_.done)
94 return asio::dispatch(
95 asio::get_associated_immediate_executor(h, exec),
96 asio::append(std::forward<Handler>(h), a.receiver_.exception));
97
98
99#if !defined(BOOST_COBALT_NO_PMR)
100 auto alloc = asio::get_associated_allocator(h, pmr::polymorphic_allocator<void>{boost::cobalt::this_thread::get_default_resource()});
101#else
102 auto alloc = asio::get_associated_allocator(h);
103#endif
104 auto recs = std::allocate_shared<detail::task_receiver<void>>(alloc, std::move(a.receiver_));
105
106 if (recs->done)
107 return asio::dispatch(asio::get_associated_immediate_executor(h, exec),
108 asio::append(std::forward<Handler>(h), recs->exception));
109
110 auto sl = asio::get_associated_cancellation_slot(h);
111 if (sl.is_connected())
112 sl.assign(
113 [exec, recs](asio::cancellation_type ct)
114 {
115 asio::dispatch(exec, [recs, ct] {recs->cancel(ct);});
116 });
117
118 auto p = recs.get();
119
120 p->promise->exec.emplace(exec);
121 p->promise->exec_ = exec;
122
123 struct completion_handler
124 {
125 using allocator_type = std::decay_t<decltype(alloc)>;
126
127 const allocator_type &get_allocator() const { return alloc_; }
128
129 allocator_type alloc_;
130
131 using executor_type = std::decay_t<decltype(asio::get_associated_executor(h, exec))>;
132 const executor_type &get_executor() const { return exec_; }
133
134 executor_type exec_;
135 decltype(recs) r;
136 Handler handler;
137
138 void operator()()
139 {
140 auto ex = r->exception;
141 r.reset();
142 std::move(handler)(ex);
143 }
144 };
145
146 p->awaited_from.reset(detail::post_coroutine(completion_handler{
147 alloc, asio::get_associated_executor(h, exec), std::move(recs), std::forward<Handler>(h)
148 }).address());
149
150 asio::dispatch(exec, std::coroutine_handle<detail::task_promise<void>>::from_promise(p&: *p->promise));
151 }
152};
153
154}
155
156#endif //BOOST_COBALT_DETAIL_SPAWN_HPP
157

source code of boost/libs/cobalt/include/boost/cobalt/detail/spawn.hpp