Mercurial > hg > vamp-build-and-test
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 |