]>
Commit | Line | Data |
---|---|---|
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_PUSH_COROUTINE_IMPL_H | |
8 | #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H | |
9 | ||
10 | #include <boost/assert.hpp> | |
11 | #include <boost/config.hpp> | |
12 | #include <boost/exception_ptr.hpp> | |
13 | #include <boost/throw_exception.hpp> | |
14 | #include <boost/utility.hpp> | |
15 | ||
16 | #include <boost/coroutine/detail/config.hpp> | |
17 | #include <boost/coroutine/detail/coroutine_context.hpp> | |
18 | #include <boost/coroutine/detail/flags.hpp> | |
19 | #include <boost/coroutine/detail/parameters.hpp> | |
20 | #include <boost/coroutine/detail/trampoline_push.hpp> | |
21 | #include <boost/coroutine/exceptions.hpp> | |
22 | ||
23 | #ifdef BOOST_HAS_ABI_HEADERS | |
24 | # include BOOST_ABI_PREFIX | |
25 | #endif | |
26 | ||
27 | namespace boost { | |
28 | namespace coroutines { | |
29 | ||
30 | struct stack_context; | |
31 | ||
32 | namespace detail { | |
33 | ||
34 | template< typename Arg > | |
35 | class push_coroutine_impl : private noncopyable | |
36 | { | |
37 | protected: | |
38 | int flags_; | |
39 | exception_ptr except_; | |
40 | coroutine_context * caller_; | |
41 | coroutine_context * callee_; | |
42 | ||
43 | public: | |
44 | typedef parameters< Arg > param_type; | |
45 | ||
46 | push_coroutine_impl( coroutine_context * caller, | |
47 | coroutine_context * callee, | |
48 | bool unwind) : | |
49 | flags_( 0), | |
50 | except_(), | |
51 | caller_( caller), | |
52 | callee_( callee) | |
53 | { | |
54 | if ( unwind) flags_ |= flag_force_unwind; | |
55 | } | |
56 | ||
57 | bool force_unwind() const BOOST_NOEXCEPT | |
58 | { return 0 != ( flags_ & flag_force_unwind); } | |
59 | ||
60 | bool unwind_requested() const BOOST_NOEXCEPT | |
61 | { return 0 != ( flags_ & flag_unwind_stack); } | |
62 | ||
63 | bool is_started() const BOOST_NOEXCEPT | |
64 | { return 0 != ( flags_ & flag_started); } | |
65 | ||
66 | bool is_running() const BOOST_NOEXCEPT | |
67 | { return 0 != ( flags_ & flag_running); } | |
68 | ||
69 | bool is_complete() const BOOST_NOEXCEPT | |
70 | { return 0 != ( flags_ & flag_complete); } | |
71 | ||
72 | void unwind_stack() BOOST_NOEXCEPT | |
73 | { | |
74 | if ( is_started() && ! is_complete() && force_unwind() ) | |
75 | { | |
76 | flags_ |= flag_unwind_stack; | |
77 | param_type to( unwind_t::force_unwind); | |
78 | caller_->jump( | |
79 | * callee_, | |
80 | & to); | |
81 | flags_ &= ~flag_unwind_stack; | |
82 | ||
83 | BOOST_ASSERT( is_complete() ); | |
84 | } | |
85 | } | |
86 | ||
87 | void push( Arg const& arg) | |
88 | { | |
89 | BOOST_ASSERT( ! is_running() ); | |
90 | BOOST_ASSERT( ! is_complete() ); | |
91 | ||
92 | flags_ |= flag_running; | |
93 | param_type to( const_cast< Arg * >( & arg), this); | |
94 | param_type * from( | |
95 | static_cast< param_type * >( | |
96 | caller_->jump( | |
97 | * callee_, | |
98 | & to) ) ); | |
99 | flags_ &= ~flag_running; | |
100 | if ( from->do_unwind) throw forced_unwind(); | |
101 | if ( except_) rethrow_exception( except_); | |
102 | } | |
103 | ||
104 | void push( BOOST_RV_REF( Arg) arg) | |
105 | { | |
106 | BOOST_ASSERT( ! is_running() ); | |
107 | BOOST_ASSERT( ! is_complete() ); | |
108 | ||
109 | flags_ |= flag_running; | |
110 | param_type to( const_cast< Arg * >( & arg), this); | |
111 | param_type * from( | |
112 | static_cast< param_type * >( | |
113 | caller_->jump( | |
114 | * callee_, | |
115 | & to) ) ); | |
116 | flags_ &= ~flag_running; | |
117 | if ( from->do_unwind) throw forced_unwind(); | |
118 | if ( except_) rethrow_exception( except_); | |
119 | } | |
120 | ||
121 | virtual void destroy() = 0; | |
122 | }; | |
123 | ||
124 | template< typename Arg > | |
125 | class push_coroutine_impl< Arg & > : private noncopyable | |
126 | { | |
127 | protected: | |
128 | int flags_; | |
129 | exception_ptr except_; | |
130 | coroutine_context * caller_; | |
131 | coroutine_context * callee_; | |
132 | ||
133 | public: | |
134 | typedef parameters< Arg & > param_type; | |
135 | ||
136 | push_coroutine_impl( coroutine_context * caller, | |
137 | coroutine_context * callee, | |
138 | bool unwind) : | |
139 | flags_( 0), | |
140 | except_(), | |
141 | caller_( caller), | |
142 | callee_( callee) | |
143 | { | |
144 | if ( unwind) flags_ |= flag_force_unwind; | |
145 | } | |
146 | ||
147 | bool force_unwind() const BOOST_NOEXCEPT | |
148 | { return 0 != ( flags_ & flag_force_unwind); } | |
149 | ||
150 | bool unwind_requested() const BOOST_NOEXCEPT | |
151 | { return 0 != ( flags_ & flag_unwind_stack); } | |
152 | ||
153 | bool is_started() const BOOST_NOEXCEPT | |
154 | { return 0 != ( flags_ & flag_started); } | |
155 | ||
156 | bool is_running() const BOOST_NOEXCEPT | |
157 | { return 0 != ( flags_ & flag_running); } | |
158 | ||
159 | bool is_complete() const BOOST_NOEXCEPT | |
160 | { return 0 != ( flags_ & flag_complete); } | |
161 | ||
162 | void unwind_stack() BOOST_NOEXCEPT | |
163 | { | |
164 | if ( is_started() && ! is_complete() && force_unwind() ) | |
165 | { | |
166 | flags_ |= flag_unwind_stack; | |
167 | param_type to( unwind_t::force_unwind); | |
168 | caller_->jump( | |
169 | * callee_, | |
170 | & to); | |
171 | flags_ &= ~flag_unwind_stack; | |
172 | ||
173 | BOOST_ASSERT( is_complete() ); | |
174 | } | |
175 | } | |
176 | ||
177 | void push( Arg & arg) | |
178 | { | |
179 | BOOST_ASSERT( ! is_running() ); | |
180 | BOOST_ASSERT( ! is_complete() ); | |
181 | ||
182 | flags_ |= flag_running; | |
183 | param_type to( & arg, this); | |
184 | param_type * from( | |
185 | static_cast< param_type * >( | |
186 | caller_->jump( | |
187 | * callee_, | |
188 | & to) ) ); | |
189 | flags_ &= ~flag_running; | |
190 | if ( from->do_unwind) throw forced_unwind(); | |
191 | if ( except_) rethrow_exception( except_); | |
192 | } | |
193 | ||
194 | virtual void destroy() = 0; | |
195 | }; | |
196 | ||
197 | template<> | |
198 | class push_coroutine_impl< void > : private noncopyable | |
199 | { | |
200 | protected: | |
201 | int flags_; | |
202 | exception_ptr except_; | |
203 | coroutine_context * caller_; | |
204 | coroutine_context * callee_; | |
205 | ||
206 | public: | |
207 | typedef parameters< void > param_type; | |
208 | ||
209 | push_coroutine_impl( coroutine_context * caller, | |
210 | coroutine_context * callee, | |
211 | bool unwind) : | |
212 | flags_( 0), | |
213 | except_(), | |
214 | caller_( caller), | |
215 | callee_( callee) | |
216 | { | |
217 | if ( unwind) flags_ |= flag_force_unwind; | |
218 | } | |
219 | ||
220 | inline bool force_unwind() const BOOST_NOEXCEPT | |
221 | { return 0 != ( flags_ & flag_force_unwind); } | |
222 | ||
223 | inline bool unwind_requested() const BOOST_NOEXCEPT | |
224 | { return 0 != ( flags_ & flag_unwind_stack); } | |
225 | ||
226 | inline bool is_started() const BOOST_NOEXCEPT | |
227 | { return 0 != ( flags_ & flag_started); } | |
228 | ||
229 | inline bool is_running() const BOOST_NOEXCEPT | |
230 | { return 0 != ( flags_ & flag_running); } | |
231 | ||
232 | inline bool is_complete() const BOOST_NOEXCEPT | |
233 | { return 0 != ( flags_ & flag_complete); } | |
234 | ||
235 | inline void unwind_stack() BOOST_NOEXCEPT | |
236 | { | |
237 | if ( is_started() && ! is_complete() && force_unwind() ) | |
238 | { | |
239 | flags_ |= flag_unwind_stack; | |
240 | param_type to( unwind_t::force_unwind); | |
241 | caller_->jump( | |
242 | * callee_, | |
243 | & to); | |
244 | flags_ &= ~flag_unwind_stack; | |
245 | ||
246 | BOOST_ASSERT( is_complete() ); | |
247 | } | |
248 | } | |
249 | ||
250 | inline void push() | |
251 | { | |
252 | BOOST_ASSERT( ! is_running() ); | |
253 | BOOST_ASSERT( ! is_complete() ); | |
254 | ||
255 | flags_ |= flag_running; | |
256 | param_type to( this); | |
257 | param_type * from( | |
258 | static_cast< param_type * >( | |
259 | caller_->jump( | |
260 | * callee_, | |
261 | & to) ) ); | |
262 | flags_ &= ~flag_running; | |
263 | if ( from->do_unwind) throw forced_unwind(); | |
264 | if ( except_) rethrow_exception( except_); | |
265 | } | |
266 | ||
267 | virtual void destroy() = 0; | |
268 | }; | |
269 | ||
270 | }}} | |
271 | ||
272 | #ifdef BOOST_HAS_ABI_HEADERS | |
273 | # include BOOST_ABI_SUFFIX | |
274 | #endif | |
275 | ||
276 | #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H |