]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/context/include/boost/context/execution_context_v2.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / context / include / boost / context / execution_context_v2.hpp
CommitLineData
7c673cae
FG
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#include <algorithm>
13#include <cstddef>
14#include <cstdint>
15#include <cstdlib>
16#include <functional>
17#include <memory>
18#include <ostream>
19#include <tuple>
20#include <utility>
21
22#include <boost/assert.hpp>
23#include <boost/config.hpp>
24#include <boost/intrusive_ptr.hpp>
25
26#include <boost/context/detail/apply.hpp>
27#include <boost/context/detail/disable_overload.hpp>
28#include <boost/context/detail/exception.hpp>
29#include <boost/context/detail/exchange.hpp>
30#include <boost/context/detail/fcontext.hpp>
31#include <boost/context/detail/tuple.hpp>
32#include <boost/context/fixedsize_stack.hpp>
33#include <boost/context/flags.hpp>
34#include <boost/context/preallocated.hpp>
35#include <boost/context/segmented_stack.hpp>
36#include <boost/context/stack_context.hpp>
37
38#ifdef BOOST_HAS_ABI_HEADERS
39# include BOOST_ABI_PREFIX
40#endif
41
42namespace boost {
43namespace context {
44namespace detail {
45
46inline
47transfer_t context_unwind( transfer_t t) {
48 throw forced_unwind( t.fctx);
49 return { nullptr, nullptr };
50}
51
52template< typename Rec >
53transfer_t context_exit( transfer_t t) noexcept {
54 Rec * rec = static_cast< Rec * >( t.data);
55 // destroy context stack
56 rec->deallocate();
57 return { nullptr, nullptr };
58}
59
60template< typename Rec >
61void context_entry( transfer_t t_) noexcept {
62 // transfer control structure to the context-stack
63 Rec * rec = static_cast< Rec * >( t_.data);
64 BOOST_ASSERT( nullptr != rec);
65 transfer_t t = { nullptr, nullptr };
66 try {
67 // jump back to `context_create()`
68 t = jump_fcontext( t_.fctx, nullptr);
69 // start executing
70 t = rec->run( t);
71 } catch ( forced_unwind const& e) {
72 t = { e.fctx, nullptr };
73 }
74 BOOST_ASSERT( nullptr != t.fctx);
75 // destroy context-stack of `this`context on next context
76 ontop_fcontext( t.fctx, rec, context_exit< Rec >);
77 BOOST_ASSERT_MSG( false, "context already terminated");
78}
79
80template< typename Ctx, typename Fn, typename ... Args >
81transfer_t context_ontop( transfer_t t) {
82 auto tpl = static_cast< std::tuple< Fn, std::tuple< Args ... > > * >( t.data);
83 BOOST_ASSERT( nullptr != tpl);
84 typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * tpl) );
85 auto args = std::move( std::get< 1 >( * tpl) );
86 Ctx ctx{ t.fctx };
87 // execute function
88 auto result = apply(
89 fn,
90 std::tuple_cat(
91 std::forward_as_tuple( std::move( ctx) ),
92 std::move( args) ) );
93 ctx = std::move( std::get< 0 >( result) );
94 // apply returned data
95 detail::tail( args) = std::move( result);
96 std::get< 1 >( * tpl) = std::move( args);
97 return { exchange( ctx.fctx_, nullptr), & std::get< 1 >( * tpl) };
98}
99
100template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
101class record {
102private:
103 StackAlloc salloc_;
104 stack_context sctx_;
105 typename std::decay< Fn >::type fn_;
106 std::tuple< typename std::decay< Params >::type ... > params_;
107
108 static void destroy( record * p) noexcept {
109 StackAlloc salloc = p->salloc_;
110 stack_context sctx = p->sctx_;
111 // deallocate record
112 p->~record();
113 // destroy stack with stack allocator
114 salloc.deallocate( sctx);
115 }
116
117public:
118 record( stack_context sctx, StackAlloc const& salloc,
119 Fn && fn, Params && ... params) noexcept :
120 salloc_( salloc),
121 sctx_( sctx),
122 fn_( std::forward< Fn >( fn) ),
123 params_( std::forward< Params >( params) ... ) {
124 }
125
126 record( record const&) = delete;
127 record & operator=( record const&) = delete;
128
129 void deallocate() noexcept {
130 destroy( this);
131 }
132
133 transfer_t run( transfer_t t) {
134 Ctx from{ t.fctx };
135 typename Ctx::args_tpl_t args = std::move( * static_cast< typename Ctx::args_tpl_t * >( t.data) );
136 auto tpl = std::tuple_cat(
137 params_,
138 std::forward_as_tuple( std::move( from) ),
139 std::move( args) );
140 // invoke context-function
141 Ctx cc = apply( std::move( fn_), std::move( tpl) );
142 return { exchange( cc.fctx_, nullptr), nullptr };
143 }
144};
145
146template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
147fcontext_t context_create( StackAlloc salloc, Fn && fn, Params && ... params) {
148 typedef record< Ctx, StackAlloc, Fn, Params ... > record_t;
149
150 auto sctx = salloc.allocate();
151 // reserve space for control structure
152#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
153 const std::size_t size = sctx.size - sizeof( record_t);
154 void * sp = static_cast< char * >( sctx.sp) - sizeof( record_t);
155#else
156 constexpr std::size_t func_alignment = 64; // alignof( record_t);
157 constexpr std::size_t func_size = sizeof( record_t);
158 // reserve space on stack
159 void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
160 // align sp pointer
161 std::size_t space = func_size + func_alignment;
162 sp = std::align( func_alignment, func_size, sp, space);
163 BOOST_ASSERT( nullptr != sp);
164 // calculate remaining size
165 const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
166#endif
167 // create fast-context
168 const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
169 BOOST_ASSERT( nullptr != fctx);
170 // placment new for control structure on context-stack
171 auto rec = ::new ( sp) record_t{
172 sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... };
173 // transfer control structure to context-stack
174 return jump_fcontext( fctx, rec).fctx;
175}
176
177template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
178fcontext_t context_create( preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) {
179 typedef record< Ctx, StackAlloc, Fn, Params ... > record_t;
180
181 // reserve space for control structure
182#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
183 const std::size_t size = palloc.size - sizeof( record_t);
184 void * sp = static_cast< char * >( palloc.sp) - sizeof( record_t);
185#else
186 constexpr std::size_t func_alignment = 64; // alignof( record_t);
187 constexpr std::size_t func_size = sizeof( record_t);
188 // reserve space on stack
189 void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
190 // align sp pointer
191 std::size_t space = func_size + func_alignment;
192 sp = std::align( func_alignment, func_size, sp, space);
193 BOOST_ASSERT( nullptr != sp);
194 // calculate remaining size
195 const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
196#endif
197 // create fast-context
198 const fcontext_t fctx = make_fcontext( sp, size, & context_entry< record_t >);
199 BOOST_ASSERT( nullptr != fctx);
200 // placment new for control structure on context-stack
201 auto rec = ::new ( sp) record_t{
202 palloc.sctx, salloc, std::forward< Fn >( fn), std::forward< Params >( params) ... };
203 // transfer control structure to context-stack
204 return jump_fcontext( fctx, rec).fctx;
205}
206
207}
208
209template< typename ... Args >
210class execution_context {
211private:
212 typedef std::tuple< Args ... > args_tpl_t;
213 typedef std::tuple< execution_context, typename std::decay< Args >::type ... > ret_tpl_t;
214
215 template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
216 friend class detail::record;
217
218 template< typename Ctx, typename Fn, typename ... ArgsT >
219 friend detail::transfer_t detail::context_ontop( detail::transfer_t);
220
221 detail::fcontext_t fctx_{ nullptr };
222
223 execution_context( detail::fcontext_t fctx) noexcept :
224 fctx_( fctx) {
225 }
226
227public:
228 constexpr execution_context() noexcept = default;
229
230#if defined(BOOST_USE_SEGMENTED_STACKS)
231 // segmented-stack requires to preserve the segments of the `current` context
232 // which is not possible (no global pointer to current context)
233 template< typename Fn, typename ... Params >
234 execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete;
235
236 template< typename Fn, typename ... Params >
237 execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete;
238#else
239 template< typename Fn,
240 typename ... Params,
241 typename = detail::disable_overload< execution_context, Fn >
242 >
243 execution_context( Fn && fn, Params && ... params) :
244 // deferred execution of fn and its arguments
245 // arguments are stored in std::tuple<>
246 // non-type template parameter pack via std::index_sequence_for<>
247 // preserves the number of arguments
248 // used to extract the function arguments from std::tuple<>
249 fctx_( detail::context_create< execution_context >(
250 fixedsize_stack(),
251 std::forward< Fn >( fn),
252 std::forward< Params >( params) ... ) ) {
253 }
254
255 template< typename StackAlloc,
256 typename Fn,
257 typename ... Params
258 >
259 execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Params && ... params) :
260 // deferred execution of fn and its arguments
261 // arguments are stored in std::tuple<>
262 // non-type template parameter pack via std::index_sequence_for<>
263 // preserves the number of arguments
264 // used to extract the function arguments from std::tuple<>
265 fctx_( detail::context_create< execution_context >(
266 salloc,
267 std::forward< Fn >( fn),
268 std::forward< Params >( params) ... ) ) {
269 }
270
271 template< typename StackAlloc,
272 typename Fn,
273 typename ... Params
274 >
275 execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Params && ... params) :
276 // deferred execution of fn and its arguments
277 // arguments are stored in std::tuple<>
278 // non-type template parameter pack via std::index_sequence_for<>
279 // preserves the number of arguments
280 // used to extract the function arguments from std::tuple<>
281 fctx_( detail::context_create< execution_context >(
282 palloc, salloc,
283 std::forward< Fn >( fn),
284 std::forward< Params >( params) ... ) ) {
285 }
286#endif
287
288 ~execution_context() {
289 if ( nullptr != fctx_) {
290 detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::context_unwind);
291 }
292 }
293
294 execution_context( execution_context && other) noexcept :
295 fctx_( other.fctx_) {
296 other.fctx_ = nullptr;
297 }
298
299 execution_context & operator=( execution_context && other) noexcept {
300 if ( this != & other) {
301 execution_context tmp = std::move( other);
302 swap( tmp);
303 }
304 return * this;
305 }
306
307 execution_context( execution_context const& other) noexcept = delete;
308 execution_context & operator=( execution_context const& other) noexcept = delete;
309
310 ret_tpl_t operator()( Args ... args) {
311 BOOST_ASSERT( nullptr != fctx_);
312 args_tpl_t data( std::forward< Args >( args) ... );
313 detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), & data);
314 if ( nullptr != t.data) {
315 data = std::move( * static_cast< args_tpl_t * >( t.data) );
316 }
317 return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
318 }
319
320 template< typename Fn >
321 ret_tpl_t operator()( exec_ontop_arg_t, Fn && fn, Args ... args) {
322 BOOST_ASSERT( nullptr != fctx_);
323 args_tpl_t data{ std::forward< Args >( args) ... };
324 auto p = std::make_tuple( fn, std::move( data) );
325 detail::transfer_t t = detail::ontop_fcontext(
326 detail::exchange( fctx_, nullptr),
327 & p,
328 detail::context_ontop< execution_context, Fn, Args ... >);
329 if ( nullptr != t.data) {
330 data = std::move( * static_cast< args_tpl_t * >( t.data) );
331 }
332 return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
333 }
334
335 explicit operator bool() const noexcept {
336 return nullptr != fctx_;
337 }
338
339 bool operator!() const noexcept {
340 return nullptr == fctx_;
341 }
342
343 bool operator==( execution_context const& other) const noexcept {
344 return fctx_ == other.fctx_;
345 }
346
347 bool operator!=( execution_context const& other) const noexcept {
348 return fctx_ != other.fctx_;
349 }
350
351 bool operator<( execution_context const& other) const noexcept {
352 return fctx_ < other.fctx_;
353 }
354
355 bool operator>( execution_context const& other) const noexcept {
356 return other.fctx_ < fctx_;
357 }
358
359 bool operator<=( execution_context const& other) const noexcept {
360 return ! ( * this > other);
361 }
362
363 bool operator>=( execution_context const& other) const noexcept {
364 return ! ( * this < other);
365 }
366
367 template< typename charT, class traitsT >
368 friend std::basic_ostream< charT, traitsT > &
369 operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other) {
370 if ( nullptr != other.fctx_) {
371 return os << other.fctx_;
372 } else {
373 return os << "{not-a-context}";
374 }
375 }
376
377 void swap( execution_context & other) noexcept {
378 std::swap( fctx_, other.fctx_);
379 }
380};
381
382#include <boost/context/execution_context_v2_void.ipp>
383
384template< typename ... Args >
385void swap( execution_context< Args ... > & l, execution_context< Args ... > & r) noexcept {
386 l.swap( r);
387}
388
389}}
390
391#ifdef BOOST_HAS_ABI_HEADERS
392# include BOOST_ABI_SUFFIX
393#endif
394
395#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H