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 
36 namespace boost {
37 namespace coroutines {
38 namespace detail {
39 
40 struct pull_coroutine_context
41 {
42     coroutine_context   caller;
43     coroutine_context   callee;
44 
45     template< typename Coro >
pull_coroutine_contextboost::coroutines::detail::pull_coroutine_context46     pull_coroutine_context( preallocated const& palloc, Coro *) :
47         caller(),
48         callee( trampoline_pull< Coro >, palloc)
49     {}
50 };
51 
52 template< typename PushCoro, typename R, typename Fn, typename StackAllocator >
53 class pull_coroutine_object : private pull_coroutine_context,
54                               public pull_coroutine_impl< R >
55 {
56 private:
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 
deallocate_(obj_t * obj)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 
74 public:
75 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
pull_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)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 
pull_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)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 
run()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 
destroy()135     void destroy()
136     { deallocate_( this); }
137 };
138 
139 template< typename PushCoro, typename R, typename Fn, typename StackAllocator >
140 class pull_coroutine_object< PushCoro, R &, Fn, StackAllocator > : private pull_coroutine_context,
141                                                                    public pull_coroutine_impl< R & >
142 {
143 private:
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 
deallocate_(obj_t * obj)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 
161 public:
162 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
pull_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)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 
pull_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)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 
run()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 
destroy()222     void destroy()
223     { deallocate_( this); }
224 };
225 
226 template< typename PushCoro, typename Fn, typename StackAllocator >
227 class pull_coroutine_object< PushCoro, void, Fn, StackAllocator > : private pull_coroutine_context,
228                                                                     public pull_coroutine_impl< void >
229 {
230 private:
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 
deallocate_(obj_t * obj)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 
248 public:
249 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
pull_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)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 
pull_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)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 
run()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 
destroy()309     void destroy()
310     { deallocate_( 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