comparison DEPENDENCIES/generic/include/boost/context/execution_context.hpp @ 102:f46d142149f5

Whoops, finish that update
author Chris Cannam
date Mon, 07 Sep 2015 11:13:41 +0100
parents
children
comparison
equal deleted inserted replaced
101:c530137014c0 102:f46d142149f5
1
2 // Copyright Oliver Kowalke 2014.
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_CONTEXT_EXECUTION_CONTEXT_H
8 #define BOOST_CONTEXT_EXECUTION_CONTEXT_H
9
10 #include <boost/context/detail/config.hpp>
11
12 #if ! defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT)
13
14 # include <cstddef>
15 # include <cstdint>
16 # include <cstdlib>
17 # include <exception>
18 # include <memory>
19 # include <tuple>
20 # include <utility>
21
22 # include <boost/assert.hpp>
23 # include <boost/config.hpp>
24 # include <boost/context/fcontext.hpp>
25 # include <boost/intrusive_ptr.hpp>
26
27 # include <boost/context/stack_context.hpp>
28 # include <boost/context/segmented_stack.hpp>
29
30 # ifdef BOOST_HAS_ABI_HEADERS
31 # include BOOST_ABI_PREFIX
32 # endif
33
34 # if defined(BOOST_USE_SEGMENTED_STACKS)
35 extern "C" {
36
37 void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
38
39 void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
40
41 }
42 # endif
43
44 namespace boost {
45 namespace context {
46
47 struct preallocated {
48 void * sp;
49 std::size_t size;
50 stack_context sctx;
51
52 preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept :
53 sp( sp_), size( size_), sctx( sctx_) {
54 }
55 };
56
57 class BOOST_CONTEXT_DECL execution_context {
58 private:
59 struct fcontext {
60 std::size_t use_count;
61 fcontext_t fctx;
62 stack_context sctx;
63
64 // main-context
65 fcontext() noexcept :
66 use_count( 1),
67 fctx( nullptr),
68 sctx() {
69 }
70
71 // worker-context
72 fcontext( fcontext_t fctx_, stack_context const& sctx_) noexcept :
73 use_count( 0),
74 fctx( fctx_),
75 sctx( sctx_) {
76 }
77
78 virtual ~fcontext() noexcept {
79 }
80
81 virtual void deallocate() {
82 }
83
84 virtual void run() noexcept {
85 }
86
87 friend void intrusive_ptr_add_ref( fcontext * ctx) {
88 ++ctx->use_count;
89 }
90
91 friend void intrusive_ptr_release( fcontext * ctx) {
92 BOOST_ASSERT( nullptr != ctx);
93
94 if ( 0 == --ctx->use_count) {
95 ctx->~fcontext();
96 }
97 }
98 };
99
100 template< typename Fn, typename StackAlloc >
101 class worker_fcontext : public fcontext {
102 private:
103 StackAlloc salloc_;
104 Fn fn_;
105
106 static void destroy( worker_fcontext * p) {
107 StackAlloc salloc( p->salloc_);
108 stack_context sctx( p->sctx);
109 p->~worker_fcontext();
110 salloc.deallocate( sctx);
111 }
112
113 public:
114 explicit worker_fcontext( stack_context sctx, StackAlloc const& salloc, fcontext_t fctx, Fn && fn) noexcept :
115 fcontext( fctx, sctx),
116 salloc_( salloc),
117 fn_( std::forward< Fn >( fn) ) {
118 }
119
120 void deallocate() override final {
121 destroy( this);
122 }
123
124 void run() noexcept override final {
125 fn_();
126 }
127 };
128
129 static void entry_func( intptr_t p) noexcept {
130 BOOST_ASSERT( 0 != p);
131
132 fcontext * bp( reinterpret_cast< fcontext * >( p) );
133 BOOST_ASSERT( nullptr != bp);
134
135 bp->run();
136 }
137
138 typedef boost::intrusive_ptr< fcontext > ptr_t;
139
140 thread_local static fcontext main_ctx_;
141 thread_local static ptr_t current_ctx_;
142
143 boost::intrusive_ptr< fcontext > ptr_;
144 # if defined(BOOST_USE_SEGMENTED_STACKS)
145 bool use_segmented_stack_ = false;
146 # endif
147
148 template< typename StackAlloc, typename Fn >
149 static fcontext * create_context( StackAlloc salloc, Fn && fn) {
150 typedef worker_fcontext< Fn, StackAlloc > func_t;
151
152 stack_context sctx( salloc.allocate() );
153 // reserve space for control structure
154 std::size_t size = sctx.size - sizeof( func_t);
155 void * sp = static_cast< char * >( sctx.sp) - sizeof( func_t);
156 #if 0
157 constexpr std::size_t func_alignment = 64; // alignof( func_t);
158 constexpr std::size_t func_size = sizeof( func_t);
159 // reserve space on stack
160 void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
161 // align sp pointer
162 sp = std::align( func_alignment, func_size, sp, func_size + func_alignment);
163 BOOST_ASSERT( nullptr != sp);
164 // calculate remaining size
165 std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
166 #endif
167 // create fast-context
168 fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func);
169 BOOST_ASSERT( nullptr != fctx);
170 // placment new for control structure on fast-context stack
171 return new ( sp) func_t( sctx, salloc, fctx, std::forward< Fn >( fn) );
172 }
173
174 template< typename StackAlloc, typename Fn >
175 static fcontext * create_context( preallocated palloc, StackAlloc salloc, Fn && fn) {
176 typedef worker_fcontext< Fn, StackAlloc > func_t;
177
178 // reserve space for control structure
179 std::size_t size = palloc.size - sizeof( func_t);
180 void * sp = static_cast< char * >( palloc.sp) - sizeof( func_t);
181 #if 0
182 constexpr std::size_t func_alignment = 64; // alignof( func_t);
183 constexpr std::size_t func_size = sizeof( func_t);
184 // reserve space on stack
185 void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
186 // align sp pointer
187 sp = std::align( func_alignment, func_size, sp, func_size + func_alignment);
188 BOOST_ASSERT( nullptr != sp);
189 // calculate remaining size
190 std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
191 #endif
192 // create fast-context
193 fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func);
194 BOOST_ASSERT( nullptr != fctx);
195 // placment new for control structure on fast-context stack
196 return new ( sp) func_t( palloc.sctx, salloc, fctx, std::forward< Fn >( fn) );
197 }
198
199 template< typename StackAlloc, typename Fn, typename Tpl, std::size_t ... I >
200 static fcontext * create_worker_fcontext( StackAlloc salloc,
201 Fn && fn_, Tpl && tpl_,
202 std::index_sequence< I ... >) {
203 return create_context( salloc,
204 [fn=std::forward< Fn >( fn_),tpl=std::forward< Tpl >( tpl_)] () mutable {
205 try {
206 fn(
207 // std::tuple_element<> does not perfect forwarding
208 std::forward< decltype( std::get< I >( std::declval< Tpl >() ) ) >(
209 std::get< I >( std::forward< Tpl >( tpl) ) ) ... );
210 } catch (...) {
211 std::terminate();
212 }
213 });
214 }
215
216 template< typename StackAlloc, typename Fn, typename Tpl, std::size_t ... I >
217 static fcontext * create_worker_fcontext( preallocated palloc, StackAlloc salloc,
218 Fn && fn_, Tpl && tpl_,
219 std::index_sequence< I ... >) {
220 return create_context( palloc, salloc,
221 [fn=std::forward< Fn >( fn_),tpl=std::forward< Tpl >( tpl_)] () mutable {
222 try {
223 fn(
224 // std::tuple_element<> does not perfect forwarding
225 std::forward< decltype( std::get< I >( std::declval< Tpl >() ) ) >(
226 std::get< I >( std::forward< Tpl >( tpl) ) ) ... );
227 } catch (...) {
228 std::terminate();
229 }
230 });
231 }
232
233 execution_context() :
234 ptr_( current_ctx_) {
235 }
236
237 public:
238 static execution_context current() noexcept {
239 return execution_context();
240 }
241
242 # if defined(BOOST_USE_SEGMENTED_STACKS)
243 template< typename Fn, typename ... Args >
244 explicit execution_context( segmented_stack salloc, Fn && fn, Args && ... args) :
245 ptr_( create_worker_fcontext( salloc,
246 std::forward< Fn >( fn),
247 std::make_tuple( std::forward< Args >( args) ... ),
248 std::index_sequence_for< Args ... >() ) ),
249 use_segmented_stack_( true) {
250 }
251
252 template< typename Fn, typename ... Args >
253 explicit execution_context( preallocated palloc, segmented_stack salloc, Fn && fn, Args && ... args) :
254 ptr_( create_worker_fcontext( palloc, salloc,
255 std::forward< Fn >( fn),
256 std::make_tuple( std::forward< Args >( args) ... ),
257 std::index_sequence_for< Args ... >() ) ),
258 use_segmented_stack_( true) {
259 }
260 # endif
261
262 template< typename StackAlloc, typename Fn, typename ... Args >
263 explicit execution_context( StackAlloc salloc, Fn && fn, Args && ... args) :
264 ptr_( create_worker_fcontext( salloc,
265 std::forward< Fn >( fn),
266 std::make_tuple( std::forward< Args >( args) ... ),
267 std::index_sequence_for< Args ... >() ) ) {
268 }
269
270 template< typename StackAlloc, typename Fn, typename ... Args >
271 explicit execution_context( preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) :
272 ptr_( create_worker_fcontext( palloc, salloc,
273 std::forward< Fn >( fn),
274 std::make_tuple( std::forward< Args >( args) ... ),
275 std::index_sequence_for< Args ... >() ) ) {
276 }
277
278 void resume( bool preserve_fpu = false) noexcept {
279 fcontext * old_ctx( current_ctx_.get() );
280 fcontext * new_ctx( ptr_.get() );
281 current_ctx_ = ptr_;
282 # if defined(BOOST_USE_SEGMENTED_STACKS)
283 if ( use_segmented_stack_) {
284 __splitstack_getcontext( old_ctx->sctx.segments_ctx);
285 __splitstack_setcontext( new_ctx->sctx.segments_ctx);
286
287 jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu);
288
289 __splitstack_setcontext( old_ctx->sctx.segments_ctx);
290 } else {
291 jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu);
292 }
293 # else
294 jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu);
295 # endif
296 }
297 };
298
299 }}
300
301 # ifdef BOOST_HAS_ABI_HEADERS
302 # include BOOST_ABI_SUFFIX
303 # endif
304
305 #endif
306
307 #endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H