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)
7 #ifndef BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H
8 #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H
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>
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/push_coroutine_impl.hpp>
22 #include <boost/coroutine/detail/trampoline_push.hpp>
23 #include <boost/coroutine/exceptions.hpp>
24 #include <boost/coroutine/flags.hpp>
25 #include <boost/coroutine/stack_context.hpp>
27 #ifdef BOOST_HAS_ABI_HEADERS
28 # include BOOST_ABI_PREFIX
31 #if defined(BOOST_MSVC)
32 # pragma warning(push)
33 # pragma warning(disable:4355)
37 namespace coroutines {
40 struct push_coroutine_context
42 coroutine_context caller;
43 coroutine_context callee;
45 template< typename Coro >
46 push_coroutine_context( preallocated const& palloc, Coro *) :
48 callee( trampoline_push< Coro >, palloc)
52 struct push_coroutine_context_void
54 coroutine_context caller;
55 coroutine_context callee;
57 template< typename Coro >
58 push_coroutine_context_void( preallocated const& palloc, Coro *) :
60 callee( trampoline_push_void< Coro >, palloc)
64 template< typename PullCoro, typename R, typename Fn, typename StackAllocator >
65 class push_coroutine_object : private push_coroutine_context,
66 public push_coroutine_impl< R >
69 typedef push_coroutine_context ctx_t;
70 typedef push_coroutine_impl< R > base_t;
71 typedef push_coroutine_object< PullCoro, R, Fn, StackAllocator > obj_t;
74 stack_context stack_ctx_;
75 StackAllocator stack_alloc_;
77 static void deallocate_( obj_t * obj)
79 stack_context stack_ctx( obj->stack_ctx_);
80 StackAllocator stack_alloc( obj->stack_alloc_);
83 stack_alloc.deallocate( stack_ctx);
87 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
88 push_coroutine_object( Fn fn, attributes const& attrs,
89 preallocated const& palloc,
90 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
92 base_t( & this->caller,
94 stack_unwind == attrs.do_unwind),
96 stack_ctx_( palloc.sctx),
97 stack_alloc_( stack_alloc)
101 push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
102 preallocated const& palloc,
103 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
104 ctx_t( palloc, this),
105 base_t( & this->caller,
107 stack_unwind == attrs.do_unwind),
108 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
111 fn_( boost::forward< Fn >( fn) ),
113 stack_ctx_( palloc.sctx),
114 stack_alloc_( stack_alloc)
117 void run( R * result)
119 BOOST_ASSERT( ! base_t::unwind_requested() );
121 base_t::flags_ |= flag_started;
122 base_t::flags_ |= flag_running;
124 // create push_coroutine
125 typename PullCoro::synth_type b( & this->callee, & this->caller, false, result);
126 PullCoro pull_coro( synthesized_t::syntesized, b);
129 catch ( forced_unwind const&)
131 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
132 catch ( abi::__forced_unwind const&)
136 { base_t::except_ = current_exception(); }
138 base_t::flags_ |= flag_complete;
139 base_t::flags_ &= ~flag_running;
140 typename base_t::param_type to;
144 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
148 { deallocate_( this); }
151 template< typename PullCoro, typename R, typename Fn, typename StackAllocator >
152 class push_coroutine_object< PullCoro, R &, Fn, StackAllocator > : private push_coroutine_context,
153 public push_coroutine_impl< R & >
156 typedef push_coroutine_context ctx_t;
157 typedef push_coroutine_impl< R & > base_t;
158 typedef push_coroutine_object< PullCoro, R &, Fn, StackAllocator > obj_t;
161 stack_context stack_ctx_;
162 StackAllocator stack_alloc_;
164 static void deallocate_( obj_t * obj)
166 stack_context stack_ctx( obj->stack_ctx_);
167 StackAllocator stack_alloc( obj->stack_alloc_);
170 stack_alloc.deallocate( stack_ctx);
174 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
175 push_coroutine_object( Fn fn, attributes const& attrs,
176 preallocated const& palloc,
177 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
178 ctx_t( palloc, this),
179 base_t( & this->caller,
181 stack_unwind == attrs.do_unwind),
183 stack_ctx_( palloc.sctx),
184 stack_alloc_( stack_alloc)
188 push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
189 preallocated const& palloc,
190 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
191 ctx_t( palloc, this),
192 base_t( & this->caller,
194 stack_unwind == attrs.do_unwind),
195 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
198 fn_( boost::forward< Fn >( fn) ),
200 stack_ctx_( palloc.sctx),
201 stack_alloc_( stack_alloc)
204 void run( R * result)
206 BOOST_ASSERT( ! base_t::unwind_requested() );
208 base_t::flags_ |= flag_started;
209 base_t::flags_ |= flag_running;
211 // create push_coroutine
212 typename PullCoro::synth_type b( & this->callee, & this->caller, false, result);
213 PullCoro push_coro( synthesized_t::syntesized, b);
216 catch ( forced_unwind const&)
218 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
219 catch ( abi::__forced_unwind const&)
223 { base_t::except_ = current_exception(); }
225 base_t::flags_ |= flag_complete;
226 base_t::flags_ &= ~flag_running;
227 typename base_t::param_type to;
231 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
235 { deallocate_( this); }
238 template< typename PullCoro, typename Fn, typename StackAllocator >
239 class push_coroutine_object< PullCoro, void, Fn, StackAllocator > : private push_coroutine_context_void,
240 public push_coroutine_impl< void >
243 typedef push_coroutine_context_void ctx_t;
244 typedef push_coroutine_impl< void > base_t;
245 typedef push_coroutine_object< PullCoro, void, Fn, StackAllocator > obj_t;
248 stack_context stack_ctx_;
249 StackAllocator stack_alloc_;
251 static void deallocate_( obj_t * obj)
253 stack_context stack_ctx( obj->stack_ctx_);
254 StackAllocator stack_alloc( obj->stack_alloc_);
257 stack_alloc.deallocate( stack_ctx);
261 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
262 push_coroutine_object( Fn fn, attributes const& attrs,
263 preallocated const& palloc,
264 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
265 ctx_t( palloc, this),
266 base_t( & this->caller,
268 stack_unwind == attrs.do_unwind),
270 stack_ctx_( palloc.sctx),
271 stack_alloc_( stack_alloc)
275 push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
276 preallocated const& palloc,
277 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
278 ctx_t( palloc, this),
279 base_t( & this->caller,
281 stack_unwind == attrs.do_unwind),
282 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
285 fn_( boost::forward< Fn >( fn) ),
287 stack_ctx_( palloc.sctx),
288 stack_alloc_( stack_alloc)
293 BOOST_ASSERT( ! base_t::unwind_requested() );
295 base_t::flags_ |= flag_started;
296 base_t::flags_ |= flag_running;
298 // create push_coroutine
299 typename PullCoro::synth_type b( & this->callee, & this->caller, false);
300 PullCoro push_coro( synthesized_t::syntesized, b);
303 catch ( forced_unwind const&)
305 #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
306 catch ( abi::__forced_unwind const&)
310 { base_t::except_ = current_exception(); }
312 base_t::flags_ |= flag_complete;
313 base_t::flags_ &= ~flag_running;
314 typename base_t::param_type to;
318 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
322 { deallocate_( this); }
327 #if defined(BOOST_MSVC)
328 # pragma warning(pop)
331 #ifdef BOOST_HAS_ABI_HEADERS
332 # include BOOST_ABI_SUFFIX
335 #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H