• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
push_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)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 
~push_coroutine_impl()57     virtual ~push_coroutine_impl() {}
58 
force_unwind() const59     bool force_unwind() const BOOST_NOEXCEPT
60     { return 0 != ( flags_ & flag_force_unwind); }
61 
unwind_requested() const62     bool unwind_requested() const BOOST_NOEXCEPT
63     { return 0 != ( flags_ & flag_unwind_stack); }
64 
is_started() const65     bool is_started() const BOOST_NOEXCEPT
66     { return 0 != ( flags_ & flag_started); }
67 
is_running() const68     bool is_running() const BOOST_NOEXCEPT
69     { return 0 != ( flags_ & flag_running); }
70 
is_complete() const71     bool is_complete() const BOOST_NOEXCEPT
72     { return 0 != ( flags_ & flag_complete); }
73 
unwind_stack()74     void unwind_stack() BOOST_NOEXCEPT
75     {
76         if ( is_started() && ! is_complete() && force_unwind() )
77         {
78             flags_ |= flag_unwind_stack;
79             param_type to( unwind_t::force_unwind);
80             caller_->jump(
81                 * callee_,
82                 & to);
83             flags_ &= ~flag_unwind_stack;
84 
85             BOOST_ASSERT( is_complete() );
86         }
87     }
88 
push(Arg const & arg)89     void push( Arg const& arg)
90     {
91         BOOST_ASSERT( ! is_running() );
92         BOOST_ASSERT( ! is_complete() );
93 
94         flags_ |= flag_running;
95         param_type to( const_cast< Arg * >( & arg), this);
96         param_type * from(
97             static_cast< param_type * >(
98                 caller_->jump(
99                     * callee_,
100                     & to) ) );
101         flags_ &= ~flag_running;
102         if ( from->do_unwind) throw forced_unwind();
103         if ( except_) rethrow_exception( except_);
104     }
105 
push(BOOST_RV_REF (Arg)arg)106     void push( BOOST_RV_REF( Arg) arg)
107     {
108         BOOST_ASSERT( ! is_running() );
109         BOOST_ASSERT( ! is_complete() );
110 
111         flags_ |= flag_running;
112         param_type to( const_cast< Arg * >( & arg), this);
113         param_type * from(
114             static_cast< param_type * >(
115                 caller_->jump(
116                     * callee_,
117                     & to) ) );
118         flags_ &= ~flag_running;
119         if ( from->do_unwind) throw forced_unwind();
120         if ( except_) rethrow_exception( except_);
121     }
122 
123     virtual void destroy() = 0;
124 };
125 
126 template< typename Arg >
127 class push_coroutine_impl< Arg & > : private noncopyable
128 {
129 protected:
130     int                     flags_;
131     exception_ptr           except_;
132     coroutine_context   *   caller_;
133     coroutine_context   *   callee_;
134 
135 public:
136     typedef parameters< Arg & >                         param_type;
137 
push_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)138     push_coroutine_impl( coroutine_context * caller,
139                          coroutine_context * callee,
140                          bool unwind) :
141         flags_( 0),
142         except_(),
143         caller_( caller),
144         callee_( callee)
145     {
146         if ( unwind) flags_ |= flag_force_unwind;
147     }
148 
~push_coroutine_impl()149     virtual ~push_coroutine_impl() {}
150 
force_unwind() const151     bool force_unwind() const BOOST_NOEXCEPT
152     { return 0 != ( flags_ & flag_force_unwind); }
153 
unwind_requested() const154     bool unwind_requested() const BOOST_NOEXCEPT
155     { return 0 != ( flags_ & flag_unwind_stack); }
156 
is_started() const157     bool is_started() const BOOST_NOEXCEPT
158     { return 0 != ( flags_ & flag_started); }
159 
is_running() const160     bool is_running() const BOOST_NOEXCEPT
161     { return 0 != ( flags_ & flag_running); }
162 
is_complete() const163     bool is_complete() const BOOST_NOEXCEPT
164     { return 0 != ( flags_ & flag_complete); }
165 
unwind_stack()166     void unwind_stack() BOOST_NOEXCEPT
167     {
168         if ( is_started() && ! is_complete() && force_unwind() )
169         {
170             flags_ |= flag_unwind_stack;
171             param_type to( unwind_t::force_unwind);
172             caller_->jump(
173                 * callee_,
174                 & to);
175             flags_ &= ~flag_unwind_stack;
176 
177             BOOST_ASSERT( is_complete() );
178         }
179     }
180 
push(Arg & arg)181     void push( Arg & arg)
182     {
183         BOOST_ASSERT( ! is_running() );
184         BOOST_ASSERT( ! is_complete() );
185 
186         flags_ |= flag_running;
187         param_type to( & arg, this);
188         param_type * from(
189             static_cast< param_type * >(
190                 caller_->jump(
191                     * callee_,
192                     & to) ) );
193         flags_ &= ~flag_running;
194         if ( from->do_unwind) throw forced_unwind();
195         if ( except_) rethrow_exception( except_);
196     }
197 
198     virtual void destroy() = 0;
199 };
200 
201 template<>
202 class push_coroutine_impl< void > : private noncopyable
203 {
204 protected:
205     int                     flags_;
206     exception_ptr           except_;
207     coroutine_context   *   caller_;
208     coroutine_context   *   callee_;
209 
210 public:
211     typedef parameters< void >                          param_type;
212 
push_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)213     push_coroutine_impl( coroutine_context * caller,
214                          coroutine_context * callee,
215                          bool unwind) :
216         flags_( 0),
217         except_(),
218         caller_( caller),
219         callee_( callee)
220     {
221         if ( unwind) flags_ |= flag_force_unwind;
222     }
223 
~push_coroutine_impl()224     virtual ~push_coroutine_impl() {}
225 
force_unwind() const226     inline bool force_unwind() const BOOST_NOEXCEPT
227     { return 0 != ( flags_ & flag_force_unwind); }
228 
unwind_requested() const229     inline bool unwind_requested() const BOOST_NOEXCEPT
230     { return 0 != ( flags_ & flag_unwind_stack); }
231 
is_started() const232     inline bool is_started() const BOOST_NOEXCEPT
233     { return 0 != ( flags_ & flag_started); }
234 
is_running() const235     inline bool is_running() const BOOST_NOEXCEPT
236     { return 0 != ( flags_ & flag_running); }
237 
is_complete() const238     inline bool is_complete() const BOOST_NOEXCEPT
239     { return 0 != ( flags_ & flag_complete); }
240 
unwind_stack()241     inline void unwind_stack() BOOST_NOEXCEPT
242     {
243         if ( is_started() && ! is_complete() && force_unwind() )
244         {
245             flags_ |= flag_unwind_stack;
246             param_type to( unwind_t::force_unwind);
247             caller_->jump(
248                 * callee_,
249                 & to);
250             flags_ &= ~flag_unwind_stack;
251 
252             BOOST_ASSERT( is_complete() );
253         }
254     }
255 
push()256     inline void push()
257     {
258         BOOST_ASSERT( ! is_running() );
259         BOOST_ASSERT( ! is_complete() );
260 
261         flags_ |= flag_running;
262         param_type to( this);
263         param_type * from(
264             static_cast< param_type * >(
265                 caller_->jump(
266                     * callee_,
267                     & to) ) );
268         flags_ &= ~flag_running;
269         if ( from->do_unwind) throw forced_unwind();
270         if ( except_) rethrow_exception( except_);
271     }
272 
273     virtual void destroy() = 0;
274 };
275 
276 }}}
277 
278 #ifdef BOOST_HAS_ABI_HEADERS
279 #  include BOOST_ABI_SUFFIX
280 #endif
281 
282 #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H
283