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_SYMMETRIC_COROUTINE_IMPL_H
8 #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H
10 #include <boost/assert.hpp>
11 #include <boost/config.hpp>
12 #include <boost/cstdint.hpp>
13 #include <boost/utility.hpp>
15 #include <boost/coroutine/detail/config.hpp>
16 #include <boost/coroutine/detail/coroutine_context.hpp>
17 #include <boost/coroutine/detail/flags.hpp>
18 #include <boost/coroutine/detail/parameters.hpp>
19 #include <boost/coroutine/detail/preallocated.hpp>
20 #include <boost/coroutine/detail/trampoline.hpp>
21 #include <boost/coroutine/exceptions.hpp>
22 #include <boost/coroutine/stack_context.hpp>
24 #ifdef BOOST_HAS_ABI_HEADERS
25 # include BOOST_ABI_PREFIX
29 namespace coroutines {
32 template< typename R >
33 class symmetric_coroutine_impl : private noncopyable
36 typedef parameters< R > param_type;
38 symmetric_coroutine_impl( preallocated const& palloc,
39 bool unwind) BOOST_NOEXCEPT :
42 callee_( trampoline< symmetric_coroutine_impl< R > >, palloc)
44 if ( unwind) flags_ |= flag_force_unwind;
47 virtual ~symmetric_coroutine_impl() {}
49 bool force_unwind() const BOOST_NOEXCEPT
50 { return 0 != ( flags_ & flag_force_unwind); }
52 bool unwind_requested() const BOOST_NOEXCEPT
53 { return 0 != ( flags_ & flag_unwind_stack); }
55 bool is_started() const BOOST_NOEXCEPT
56 { return 0 != ( flags_ & flag_started); }
58 bool is_running() const BOOST_NOEXCEPT
59 { return 0 != ( flags_ & flag_running); }
61 bool is_complete() const BOOST_NOEXCEPT
62 { return 0 != ( flags_ & flag_complete); }
64 void unwind_stack() BOOST_NOEXCEPT
66 if ( is_started() && ! is_complete() && force_unwind() )
68 flags_ |= flag_unwind_stack;
69 flags_ |= flag_running;
70 param_type to( unwind_t::force_unwind);
74 flags_ &= ~flag_running;
75 flags_ &= ~flag_unwind_stack;
77 BOOST_ASSERT( is_complete() );
81 void resume( R r) BOOST_NOEXCEPT
83 param_type to( const_cast< R * >( & r), this);
89 BOOST_ASSERT( is_running() );
90 BOOST_ASSERT( ! is_complete() );
92 flags_ &= ~flag_running;
95 static_cast< param_type * >(
99 flags_ |= flag_running;
100 if ( from->do_unwind) throw forced_unwind();
101 BOOST_ASSERT( from->data);
105 template< typename X >
106 R * yield_to( symmetric_coroutine_impl< X > * other, X x)
108 typename symmetric_coroutine_impl< X >::param_type to( & x, other);
109 return yield_to_( other, & to);
112 template< typename X >
113 R * yield_to( symmetric_coroutine_impl< X & > * other, X & x)
115 typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
116 return yield_to_( other, & to);
119 template< typename X >
120 R * yield_to( symmetric_coroutine_impl< X > * other)
122 typename symmetric_coroutine_impl< X >::param_type to( other);
123 return yield_to_( other, & to);
126 virtual void run( R *) BOOST_NOEXCEPT = 0;
128 virtual void destroy() = 0;
131 template< typename X >
132 friend class symmetric_coroutine_impl;
135 coroutine_context caller_;
136 coroutine_context callee_;
138 void resume_( param_type * to) BOOST_NOEXCEPT
140 BOOST_ASSERT( ! is_running() );
141 BOOST_ASSERT( ! is_complete() );
143 flags_ |= flag_running;
147 flags_ &= ~flag_running;
150 template< typename Other >
151 R * yield_to_( Other * other, typename Other::param_type * to)
153 BOOST_ASSERT( is_running() );
154 BOOST_ASSERT( ! is_complete() );
155 BOOST_ASSERT( ! other->is_running() );
156 BOOST_ASSERT( ! other->is_complete() );
158 other->caller_ = caller_;
159 flags_ &= ~flag_running;
161 static_cast< param_type * >(
165 flags_ |= flag_running;
166 if ( from->do_unwind) throw forced_unwind();
167 BOOST_ASSERT( from->data);
172 template< typename R >
173 class symmetric_coroutine_impl< R & > : private noncopyable
176 typedef parameters< R & > param_type;
178 symmetric_coroutine_impl( preallocated const& palloc,
179 bool unwind) BOOST_NOEXCEPT :
182 callee_( trampoline< symmetric_coroutine_impl< R > >, palloc)
184 if ( unwind) flags_ |= flag_force_unwind;
187 virtual ~symmetric_coroutine_impl() {}
189 bool force_unwind() const BOOST_NOEXCEPT
190 { return 0 != ( flags_ & flag_force_unwind); }
192 bool unwind_requested() const BOOST_NOEXCEPT
193 { return 0 != ( flags_ & flag_unwind_stack); }
195 bool is_started() const BOOST_NOEXCEPT
196 { return 0 != ( flags_ & flag_started); }
198 bool is_running() const BOOST_NOEXCEPT
199 { return 0 != ( flags_ & flag_running); }
201 bool is_complete() const BOOST_NOEXCEPT
202 { return 0 != ( flags_ & flag_complete); }
204 void unwind_stack() BOOST_NOEXCEPT
206 if ( is_started() && ! is_complete() && force_unwind() )
208 flags_ |= flag_unwind_stack;
209 flags_ |= flag_running;
210 param_type to( unwind_t::force_unwind);
214 flags_ &= ~flag_running;
215 flags_ &= ~flag_unwind_stack;
217 BOOST_ASSERT( is_complete() );
221 void resume( R & arg) BOOST_NOEXCEPT
223 param_type to( & arg, this);
229 BOOST_ASSERT( is_running() );
230 BOOST_ASSERT( ! is_complete() );
232 flags_ &= ~flag_running;
235 static_cast< param_type * >(
239 flags_ |= flag_running;
240 if ( from->do_unwind) throw forced_unwind();
241 BOOST_ASSERT( from->data);
245 template< typename X >
246 R * yield_to( symmetric_coroutine_impl< X > * other, X x)
248 typename symmetric_coroutine_impl< X >::param_type to( & x, other);
249 return yield_to_( other, & to);
252 template< typename X >
253 R * yield_to( symmetric_coroutine_impl< X & > * other, X & x)
255 typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
256 return yield_to_( other, & to);
259 template< typename X >
260 R * yield_to( symmetric_coroutine_impl< X > * other)
262 typename symmetric_coroutine_impl< X >::param_type to( other);
263 return yield_to_( other, & to);
266 virtual void run( R *) BOOST_NOEXCEPT = 0;
268 virtual void destroy() = 0;
271 template< typename X >
272 friend class symmetric_coroutine_impl;
275 coroutine_context caller_;
276 coroutine_context callee_;
278 void resume_( param_type * to) BOOST_NOEXCEPT
280 BOOST_ASSERT( ! is_running() );
281 BOOST_ASSERT( ! is_complete() );
283 flags_ |= flag_running;
287 flags_ &= ~flag_running;
290 template< typename Other >
291 R * yield_to_( Other * other, typename Other::param_type * to)
293 BOOST_ASSERT( is_running() );
294 BOOST_ASSERT( ! is_complete() );
295 BOOST_ASSERT( ! other->is_running() );
296 BOOST_ASSERT( ! other->is_complete() );
298 other->caller_ = caller_;
299 flags_ &= ~flag_running;
301 static_cast< param_type * >(
305 flags_ |= flag_running;
306 if ( from->do_unwind) throw forced_unwind();
307 BOOST_ASSERT( from->data);
313 class symmetric_coroutine_impl< void > : private noncopyable
316 typedef parameters< void > param_type;
318 symmetric_coroutine_impl( preallocated const& palloc,
319 bool unwind) BOOST_NOEXCEPT :
322 callee_( trampoline_void< symmetric_coroutine_impl< void > >, palloc)
324 if ( unwind) flags_ |= flag_force_unwind;
327 virtual ~symmetric_coroutine_impl() {}
329 inline bool force_unwind() const BOOST_NOEXCEPT
330 { return 0 != ( flags_ & flag_force_unwind); }
332 inline bool unwind_requested() const BOOST_NOEXCEPT
333 { return 0 != ( flags_ & flag_unwind_stack); }
335 inline bool is_started() const BOOST_NOEXCEPT
336 { return 0 != ( flags_ & flag_started); }
338 inline bool is_running() const BOOST_NOEXCEPT
339 { return 0 != ( flags_ & flag_running); }
341 inline bool is_complete() const BOOST_NOEXCEPT
342 { return 0 != ( flags_ & flag_complete); }
344 inline void unwind_stack() BOOST_NOEXCEPT
346 if ( is_started() && ! is_complete() && force_unwind() )
348 flags_ |= flag_unwind_stack;
349 flags_ |= flag_running;
350 param_type to( unwind_t::force_unwind);
354 flags_ &= ~flag_running;
355 flags_ &= ~flag_unwind_stack;
357 BOOST_ASSERT( is_complete() );
361 inline void resume() BOOST_NOEXCEPT
363 BOOST_ASSERT( ! is_running() );
364 BOOST_ASSERT( ! is_complete() );
366 param_type to( this);
367 flags_ |= flag_running;
371 flags_ &= ~flag_running;
376 BOOST_ASSERT( is_running() );
377 BOOST_ASSERT( ! is_complete() );
379 flags_ &= ~flag_running;
382 static_cast< param_type * >(
386 flags_ |= flag_running;
387 if ( from->do_unwind) throw forced_unwind();
390 template< typename X >
391 void yield_to( symmetric_coroutine_impl< X > * other, X x)
393 typename symmetric_coroutine_impl< X >::param_type to( & x, other);
394 yield_to_( other, & to);
397 template< typename X >
398 void yield_to( symmetric_coroutine_impl< X & > * other, X & x)
400 typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
401 yield_to_( other, & to);
404 template< typename X >
405 void yield_to( symmetric_coroutine_impl< X > * other)
407 typename symmetric_coroutine_impl< X >::param_type to( other);
408 yield_to_( other, & to);
411 virtual void run() BOOST_NOEXCEPT = 0;
413 virtual void destroy() = 0;
416 template< typename X >
417 friend class symmetric_coroutine_impl;
420 coroutine_context caller_;
421 coroutine_context callee_;
423 template< typename Other >
424 void yield_to_( Other * other, typename Other::param_type * to)
426 BOOST_ASSERT( is_running() );
427 BOOST_ASSERT( ! is_complete() );
428 BOOST_ASSERT( ! other->is_running() );
429 BOOST_ASSERT( ! other->is_complete() );
431 other->caller_ = caller_;
432 flags_ &= ~flag_running;
434 static_cast< param_type * >(
438 flags_ |= flag_running;
439 if ( from->do_unwind) throw forced_unwind();
445 #ifdef BOOST_HAS_ABI_HEADERS
446 # include BOOST_ABI_SUFFIX
449 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H