1
2// Copyright Oliver Kowalke 2009.
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H
8#define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H
9
10#include <boost/assert.hpp>
11#include <boost/config.hpp>
12#include <boost/context/detail/config.hpp>
13#include <boost/cstdint.hpp>
14#include <boost/exception_ptr.hpp>
15#include <boost/move/move.hpp>
16
17#include <boost/coroutine/detail/config.hpp>
18#include <boost/coroutine/detail/coroutine_context.hpp>
19#include <boost/coroutine/detail/flags.hpp>
20#include <boost/coroutine/detail/preallocated.hpp>
21#include <boost/coroutine/detail/pull_coroutine_impl.hpp>
22#include <boost/coroutine/detail/trampoline_pull.hpp>
23#include <boost/coroutine/exceptions.hpp>
24#include <boost/coroutine/flags.hpp>
25#include <boost/coroutine/stack_context.hpp>
26
27#ifdef BOOST_HAS_ABI_HEADERS
28# include BOOST_ABI_PREFIX
29#endif
30
31#if defined(BOOST_MSVC)
32# pragma warning(push)
33# pragma warning(disable:4355)
34#endif
35
36namespace boost {
37namespace coroutines {
38namespace detail {
39
40struct pull_coroutine_context
41{
42 coroutine_context caller;
43 coroutine_context callee;
44
45 template< typename Coro >
46 pull_coroutine_context( preallocated const& palloc, Coro *) :
47 caller(),
48 callee( trampoline_pull< Coro >, palloc)
49 {}
50};
51
52template< typename PushCoro, typename R, typename Fn, typename StackAllocator >
53class pull_coroutine_object : private pull_coroutine_context,
54 public pull_coroutine_impl< R >
55{
56private:
57 typedef pull_coroutine_context ctx_t;
58 typedef pull_coroutine_impl< R > base_t;
59 typedef pull_coroutine_object< PushCoro, R, Fn, StackAllocator > obj_t;
60
61 Fn fn_;
62 stack_context stack_ctx_;
63 StackAllocator stack_alloc_;
64
65 static void deallocate_( obj_t * obj)
66 {
67 stack_context stack_ctx( obj->stack_ctx_);
68 StackAllocator stack_alloc( obj->stack_alloc_);
69 obj->unwind_stack();
70 obj->~obj_t();
71 stack_alloc.deallocate( stack_ctx);
72 }
73
74public:
75#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
76 pull_coroutine_object( Fn fn, attributes const& attrs,
77 preallocated const& palloc,
78 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
79 ctx_t( palloc, this),
80 base_t( & this->caller,
81 & this->callee,
82 stack_unwind == attrs.do_unwind),
83 fn_( fn),
84 stack_ctx_( palloc.sctx),
85 stack_alloc_( stack_alloc)
86 {}
87#endif
88
89 pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
90 preallocated const& palloc,
91 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
92 ctx_t( palloc, this),
93 base_t( & this->caller,
94 & this->callee,
95 stack_unwind == attrs.do_unwind),
96#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
97 fn_( fn),
98#else
99 fn_( boost::forward< Fn >( fn) ),
100#endif
101 stack_ctx_( palloc.sctx),
102 stack_alloc_( stack_alloc)
103 {}
104
105 void run()
106 {
107 BOOST_ASSERT( ! base_t::unwind_requested() );
108
109 base_t::flags_ |= flag_started;
110 base_t::flags_ |= flag_running;
111
112 // create push_coroutine
113 typename PushCoro::synth_type b( & this->callee, & this->caller, false);
114 PushCoro push_coro( synthesized_t::syntesized, b);
115 try
116 { fn_( push_coro); }
117 catch ( forced_unwind const&)
118 {}
119#if defined( BOOST_CONTEXT_HAS_CXXABI_H )
120 catch ( abi::__forced_unwind const&)
121 { throw; }
122#endif
123 catch (...)
124 { base_t::except_ = current_exception(); }
125
126 base_t::flags_ |= flag_complete;
127 base_t::flags_ &= ~flag_running;
128 typename base_t::param_type to;
129 this->callee.jump(
130 this->caller,
131 & to);
132 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
133 }
134
135 void destroy()
136 { deallocate_( obj: this); }
137};
138
139template< typename PushCoro, typename R, typename Fn, typename StackAllocator >
140class pull_coroutine_object< PushCoro, R &, Fn, StackAllocator > : private pull_coroutine_context,
141 public pull_coroutine_impl< R & >
142{
143private:
144 typedef pull_coroutine_context ctx_t;
145 typedef pull_coroutine_impl< R & > base_t;
146 typedef pull_coroutine_object< PushCoro, R &, Fn, StackAllocator > obj_t;
147
148 Fn fn_;
149 stack_context stack_ctx_;
150 StackAllocator stack_alloc_;
151
152 static void deallocate_( obj_t * obj)
153 {
154 stack_context stack_ctx( obj->stack_ctx_);
155 StackAllocator stack_alloc( obj->stack_alloc_);
156 obj->unwind_stack();
157 obj->~obj_t();
158 stack_alloc.deallocate( stack_ctx);
159 }
160
161public:
162#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
163 pull_coroutine_object( Fn fn, attributes const& attrs,
164 preallocated const& palloc,
165 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
166 ctx_t( palloc, this),
167 base_t( & this->caller,
168 & this->callee,
169 stack_unwind == attrs.do_unwind),
170 fn_( fn),
171 stack_ctx_( palloc.sctx),
172 stack_alloc_( stack_alloc)
173 {}
174#endif
175
176 pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
177 preallocated const& palloc,
178 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
179 ctx_t( palloc, this),
180 base_t( & this->caller,
181 & this->callee,
182 stack_unwind == attrs.do_unwind),
183#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
184 fn_( fn),
185#else
186 fn_( boost::forward< Fn >( fn) ),
187#endif
188 stack_ctx_( palloc.sctx),
189 stack_alloc_( stack_alloc)
190 {}
191
192 void run()
193 {
194 BOOST_ASSERT( ! base_t::unwind_requested() );
195
196 base_t::flags_ |= flag_started;
197 base_t::flags_ |= flag_running;
198
199 // create push_coroutine
200 typename PushCoro::synth_type b( & this->callee, & this->caller, false);
201 PushCoro push_coro( synthesized_t::syntesized, b);
202 try
203 { fn_( push_coro); }
204 catch ( forced_unwind const&)
205 {}
206#if defined( BOOST_CONTEXT_HAS_CXXABI_H )
207 catch ( abi::__forced_unwind const&)
208 { throw; }
209#endif
210 catch (...)
211 { base_t::except_ = current_exception(); }
212
213 base_t::flags_ |= flag_complete;
214 base_t::flags_ &= ~flag_running;
215 typename base_t::param_type to;
216 this->callee.jump(
217 this->caller,
218 & to);
219 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
220 }
221
222 void destroy()
223 { deallocate_( obj: this); }
224};
225
226template< typename PushCoro, typename Fn, typename StackAllocator >
227class pull_coroutine_object< PushCoro, void, Fn, StackAllocator > : private pull_coroutine_context,
228 public pull_coroutine_impl< void >
229{
230private:
231 typedef pull_coroutine_context ctx_t;
232 typedef pull_coroutine_impl< void > base_t;
233 typedef pull_coroutine_object< PushCoro, void, Fn, StackAllocator > obj_t;
234
235 Fn fn_;
236 stack_context stack_ctx_;
237 StackAllocator stack_alloc_;
238
239 static void deallocate_( obj_t * obj)
240 {
241 stack_context stack_ctx( obj->stack_ctx_);
242 StackAllocator stack_alloc( obj->stack_alloc_);
243 obj->unwind_stack();
244 obj->~obj_t();
245 stack_alloc.deallocate( stack_ctx);
246 }
247
248public:
249#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
250 pull_coroutine_object( Fn fn, attributes const& attrs,
251 preallocated const& palloc,
252 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
253 ctx_t( palloc, this),
254 base_t( & this->caller,
255 & this->callee,
256 stack_unwind == attrs.do_unwind),
257 fn_( fn),
258 stack_ctx_( palloc.sctx),
259 stack_alloc_( stack_alloc)
260 {}
261#endif
262
263 pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
264 preallocated const& palloc,
265 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
266 ctx_t( palloc, this),
267 base_t( & this->caller,
268 & this->callee,
269 stack_unwind == attrs.do_unwind),
270#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
271 fn_( fn),
272#else
273 fn_( boost::forward< Fn >( fn) ),
274#endif
275 stack_ctx_( palloc.sctx),
276 stack_alloc_( stack_alloc)
277 {}
278
279 void run()
280 {
281 BOOST_ASSERT( ! base_t::unwind_requested() );
282
283 base_t::flags_ |= flag_started;
284 base_t::flags_ |= flag_running;
285
286 // create push_coroutine
287 typename PushCoro::synth_type b( & this->callee, & this->caller, false);
288 PushCoro push_coro( synthesized_t::syntesized, b);
289 try
290 { fn_( push_coro); }
291 catch ( forced_unwind const&)
292 {}
293#if defined( BOOST_CONTEXT_HAS_CXXABI_H )
294 catch ( abi::__forced_unwind const&)
295 { throw; }
296#endif
297 catch (...)
298 { base_t::except_ = current_exception(); }
299
300 base_t::flags_ |= flag_complete;
301 base_t::flags_ &= ~flag_running;
302 typename base_t::param_type to;
303 this->callee.jump(
304 this->caller,
305 & to);
306 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
307 }
308
309 void destroy()
310 { deallocate_( obj: this); }
311};
312
313}}}
314
315#if defined(BOOST_MSVC)
316# pragma warning(pop)
317#endif
318
319#ifdef BOOST_HAS_ABI_HEADERS
320# include BOOST_ABI_SUFFIX
321#endif
322
323#endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H
324

source code of boost/libs/coroutine/include/boost/coroutine/detail/pull_coroutine_object.hpp