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_SYMMETRIC_COROUTINE_OBJECT_H
8 #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H
9 
10 #include <boost/assert.hpp>
11 #include <boost/config.hpp>
12 #include <boost/move/move.hpp>
13 
14 #include <boost/coroutine/detail/config.hpp>
15 #include <boost/coroutine/detail/flags.hpp>
16 #include <boost/coroutine/detail/preallocated.hpp>
17 #include <boost/coroutine/detail/symmetric_coroutine_impl.hpp>
18 #include <boost/coroutine/detail/symmetric_coroutine_yield.hpp>
19 #include <boost/coroutine/exceptions.hpp>
20 #include <boost/coroutine/stack_context.hpp>
21 
22 #ifdef BOOST_HAS_ABI_HEADERS
23 #  include BOOST_ABI_PREFIX
24 #endif
25 
26 namespace boost {
27 namespace coroutines {
28 
29 struct stack_context;
30 
31 namespace detail {
32 
33 template< typename R, typename Fn, typename StackAllocator >
34 class symmetric_coroutine_object : public symmetric_coroutine_impl< R >
35 {
36 private:
37     typedef symmetric_coroutine_impl< R >                       impl_t;
38     typedef symmetric_coroutine_object< R, Fn, StackAllocator > obj_t;
39 
40     Fn                  fn_;
41     stack_context       stack_ctx_;
42     StackAllocator      stack_alloc_;
43 
deallocate_(obj_t * obj)44     static void deallocate_( obj_t * obj)
45     {
46         stack_context stack_ctx( obj->stack_ctx_);
47         StackAllocator stack_alloc( obj->stack_alloc_);
48         obj->unwind_stack();
49         obj->~obj_t();
50         stack_alloc.deallocate( stack_ctx);
51     }
52 
53 public:
54 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)55     symmetric_coroutine_object( Fn fn, attributes const& attrs,
56                                 preallocated const& palloc,
57                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
58         impl_t( palloc,
59                 stack_unwind == attrs.do_unwind,
60                 fpu_preserved == attrs.preserve_fpu),
61         fn_( fn),
62         stack_ctx_( palloc.sctx),
63         stack_alloc_( stack_alloc)
64     {}
65 #endif
66 
symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)67     symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
68                                 preallocated const& palloc,
69                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
70         impl_t( palloc,
71                 stack_unwind == attrs.do_unwind,
72                 fpu_preserved == attrs.preserve_fpu),
73 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
74         fn_( fn),
75 #else
76         fn_( boost::forward< Fn >( fn) ),
77 #endif
78         stack_ctx_( palloc.sctx),
79         stack_alloc_( stack_alloc)
80     {}
81 
run(R * r)82     void run( R * r) BOOST_NOEXCEPT
83     {
84         BOOST_ASSERT( ! impl_t::unwind_requested() );
85 
86         impl_t::flags_ |= flag_started;
87         impl_t::flags_ |= flag_running;
88         try
89         {
90             symmetric_coroutine_yield< R > yc( this, r);
91             fn_( yc);
92         }
93         catch ( forced_unwind const&)
94         {}
95         catch (...)
96         { std::terminate(); }
97 
98         impl_t::flags_ |= flag_complete;
99         impl_t::flags_ &= ~flag_running;
100         typename impl_t::param_type to;
101         impl_t::callee_.jump(
102             impl_t::caller_,
103             reinterpret_cast< intptr_t >( & to),
104             impl_t::preserve_fpu() );
105         BOOST_ASSERT_MSG( false, "coroutine is complete");
106     }
107 
destroy()108     void destroy()
109     { deallocate_( this); }
110 };
111 
112 template< typename R, typename Fn, typename StackAllocator >
113 class symmetric_coroutine_object< R &, Fn, StackAllocator > : public symmetric_coroutine_impl< R & >
114 {
115 private:
116     typedef symmetric_coroutine_impl< R & >                         impl_t;
117     typedef symmetric_coroutine_object< R &, Fn, StackAllocator >   obj_t;
118 
119     Fn                  fn_;
120     stack_context       stack_ctx_;
121     StackAllocator      stack_alloc_;
122 
deallocate_(obj_t * obj)123     static void deallocate_( obj_t * obj)
124     {
125         stack_context stack_ctx( obj->stack_ctx_);
126         StackAllocator stack_alloc( obj->stack_alloc_);
127         obj->unwind_stack();
128         obj->~obj_t();
129         stack_alloc.deallocate( stack_ctx);
130     }
131 
132 public:
133 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)134     symmetric_coroutine_object( Fn fn, attributes const& attrs,
135                                 preallocated const& palloc,
136                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
137         impl_t( palloc,
138                 stack_unwind == attrs.do_unwind,
139                 fpu_preserved == attrs.preserve_fpu),
140         fn_( fn),
141         stack_ctx_( palloc.sctx),
142         stack_alloc_( stack_alloc)
143     {}
144 #endif
145 
symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)146     symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
147                                 preallocated const& palloc,
148                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
149         impl_t( palloc,
150                 stack_unwind == attrs.do_unwind,
151                 fpu_preserved == attrs.preserve_fpu),
152 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
153         fn_( fn),
154 #else
155         fn_( boost::forward< Fn >( fn) ),
156 #endif
157         stack_ctx_( palloc.sctx),
158         stack_alloc_( stack_alloc)
159     {}
160 
run(R * r)161     void run( R * r) BOOST_NOEXCEPT
162     {
163         BOOST_ASSERT( ! impl_t::unwind_requested() );
164 
165         impl_t::flags_ |= flag_started;
166         impl_t::flags_ |= flag_running;
167         try
168         {
169             symmetric_coroutine_yield< R & > yc( this, r);
170             fn_( yc);
171         }
172         catch ( forced_unwind const&)
173         {}
174         catch (...)
175         { std::terminate(); }
176 
177         impl_t::flags_ |= flag_complete;
178         impl_t::flags_ &= ~flag_running;
179         typename impl_t::param_type to;
180         impl_t::callee_.jump(
181             impl_t::caller_,
182             reinterpret_cast< intptr_t >( & to),
183             impl_t::preserve_fpu() );
184         BOOST_ASSERT_MSG( false, "coroutine is complete");
185     }
186 
destroy()187     void destroy()
188     { deallocate_( this); }
189 };
190 
191 template< typename Fn, typename StackAllocator >
192 class symmetric_coroutine_object< void, Fn, StackAllocator > : public symmetric_coroutine_impl< void >
193 {
194 private:
195     typedef symmetric_coroutine_impl< void >                        impl_t;
196     typedef symmetric_coroutine_object< void, Fn, StackAllocator >  obj_t;
197 
198     Fn                  fn_;
199     stack_context       stack_ctx_;
200     StackAllocator      stack_alloc_;
201 
deallocate_(obj_t * obj)202     static void deallocate_( obj_t * obj)
203     {
204         stack_context stack_ctx( obj->stack_ctx_);
205         StackAllocator stack_alloc( obj->stack_alloc_);
206         obj->unwind_stack();
207         obj->~obj_t();
208         stack_alloc.deallocate( stack_ctx);
209     }
210 
211 public:
212 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)213     symmetric_coroutine_object( Fn fn, attributes const& attrs,
214                                 preallocated const& palloc,
215                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
216         impl_t( palloc,
217                 stack_unwind == attrs.do_unwind,
218                 fpu_preserved == attrs.preserve_fpu),
219         fn_( fn),
220         stack_ctx_( palloc.sctx),
221         stack_alloc_( stack_alloc)
222     {}
223 #endif
224 
symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)225     symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
226                                 preallocated const& palloc,
227                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
228         impl_t( palloc,
229                 stack_unwind == attrs.do_unwind,
230                 fpu_preserved == attrs.preserve_fpu),
231 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
232         fn_( fn),
233 #else
234         fn_( boost::forward< Fn >( fn) ),
235 #endif
236         stack_ctx_( palloc.sctx),
237         stack_alloc_( stack_alloc)
238     {}
239 
run()240     void run() BOOST_NOEXCEPT
241     {
242         BOOST_ASSERT( ! impl_t::unwind_requested() );
243 
244         impl_t::flags_ |= flag_started;
245         impl_t::flags_ |= flag_running;
246         try
247         {
248             symmetric_coroutine_yield< void > yc( this);
249             fn_( yc);
250         }
251         catch ( forced_unwind const&)
252         {}
253         catch (...)
254         { std::terminate(); }
255 
256         impl_t::flags_ |= flag_complete;
257         impl_t::flags_ &= ~flag_running;
258         typename impl_t::param_type to;
259         impl_t::callee_.jump(
260             impl_t::caller_,
261             reinterpret_cast< intptr_t >( & to),
262             impl_t::preserve_fpu() );
263         BOOST_ASSERT_MSG( false, "coroutine is complete");
264     }
265 
destroy()266     void destroy()
267     { deallocate_( this); }
268 };
269 
270 }}}
271 
272 #ifdef BOOST_HAS_ABI_HEADERS
273 #  include BOOST_ABI_SUFFIX
274 #endif
275 
276 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H
277