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