]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/context/execution_context_v2.hpp
Add patch for failing prerm scripts
[ceph.git] / ceph / src / boost / boost / context / execution_context_v2.hpp
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_V2_H
8 #define BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H
9
10 #include <boost/context/detail/config.hpp>
11
12 #include <algorithm>
13 #include <cstddef>
14 #include <cstdint>
15 #include <cstdlib>
16 #include <exception>
17 #include <functional>
18 #include <memory>
19 #include <ostream>
20 #include <tuple>
21 #include <utility>
22
23 #include <boost/assert.hpp>
24 #include <boost/config.hpp>
25 #include <boost/intrusive_ptr.hpp>
26
27 #if defined(BOOST_NO_CXX17_STD_APPLY)
28 #include <boost/context/detail/apply.hpp>
29 #endif
30 #include <boost/context/detail/disable_overload.hpp>
31 #include <boost/context/detail/exception.hpp>
32 #include <boost/context/detail/exchange.hpp>
33 #include <boost/context/detail/fcontext.hpp>
34 #include <boost/context/detail/tuple.hpp>
35 #include <boost/context/fixedsize_stack.hpp>
36 #include <boost/context/flags.hpp>
37 #include <boost/context/preallocated.hpp>
38 #include <boost/context/segmented_stack.hpp>
39 #include <boost/context/stack_context.hpp>
40
41 #ifdef BOOST_HAS_ABI_HEADERS
42 # include BOOST_ABI_PREFIX
43 #endif
44
45 #if defined(BOOST_MSVC)
46 # pragma warning(push)
47 # pragma warning(disable: 4702)
48 #endif
49
50 namespace boost {
51 namespace context {
52 namespace detail {
53
54 transfer_t ecv2_context_unwind( transfer_t);
55
56 template< typename Rec >
57 transfer_t ecv2_context_exit( transfer_t) noexcept;
58
59 template< typename Rec >
60 void ecv2_context_etry( transfer_t) noexcept;
61
62 template< typename Ctx, typename Fn, typename ... Args >
63 transfer_t ecv2_context_ontop( transfer_t);
64
65 template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
66 fcontext_t ecv2_context_create( StackAlloc &&, Fn &&, Params && ...);
67
68 template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
69 fcontext_t ecv2_context_create( preallocated, StackAlloc &&, Fn &&, Params && ...);
70
71 template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
72 class ecv2_record {
73 private:
74 typename std::decay< StackAlloc >::type salloc_;
75 stack_context sctx_;
76 typename std::decay< Fn >::type fn_;
77 std::tuple< typename std::decay< Params >::type ... > params_;
78
79 static void destroy( ecv2_record * p) noexcept {
80 typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
81 stack_context sctx = p->sctx_;
82 // deallocate ecv2_record
83 p->~ecv2_record();
84 // destroy stack with stack allocator
85 salloc.deallocate( sctx);
86 }
87
88 public:
89 ecv2_record( stack_context sctx, StackAlloc && salloc,
90 Fn && fn, Params && ... params) noexcept :
91 salloc_( std::forward< StackAlloc >( salloc)),
92 sctx_( sctx),
93 fn_( std::forward< Fn >( fn) ),
94 params_( std::forward< Params >( params) ... ) {
95 }
96
97 ecv2_record( ecv2_record const&) = delete;
98 ecv2_record & operator=( ecv2_record const&) = delete;
99
100 void deallocate() noexcept {
101 destroy( this);
102 }
103
104 transfer_t run( transfer_t t) {
105 Ctx from{ t.fctx };
106 typename Ctx::args_tpl_t args = std::move( std::get<1>( * static_cast< std::tuple< std::exception_ptr, typename Ctx::args_tpl_t > * >( t.data) ) );
107 auto tpl = std::tuple_cat(
108 params_,
109 std::forward_as_tuple( std::move( from) ),
110 std::move( args) );
111 // invoke context-function
112 #if defined(BOOST_NO_CXX17_STD_APPLY)
113 Ctx cc = boost::context::detail::apply( std::move( fn_), std::move( tpl) );
114 #else
115 Ctx cc = std::apply( std::move( fn_), std::move( tpl) );
116 #endif
117 return { exchange( cc.fctx_, nullptr), nullptr };
118 }
119 };
120
121 }
122
123 inline namespace v2 {
124
125 template< typename ... Args >
126 class execution_context {
127 private:
128 friend class ontop_error;
129
130 typedef std::tuple< Args ... > args_tpl_t;
131 typedef std::tuple< execution_context, typename std::decay< Args >::type ... > ret_tpl_t;
132
133 template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
134 friend class detail::ecv2_record;
135
136 template< typename Ctx, typename Fn, typename ... ArgsT >
137 friend detail::transfer_t detail::ecv2_context_ontop( detail::transfer_t);
138
139 detail::fcontext_t fctx_{ nullptr };
140
141 execution_context( detail::fcontext_t fctx) noexcept :
142 fctx_( fctx) {
143 }
144
145 public:
146 execution_context() noexcept = default;
147
148 #if defined(BOOST_USE_SEGMENTED_STACKS)
149 // segmented-stack requires to preserve the segments of the `current` context
150 // which is not possible (no global pointer to current context)
151 template< typename Fn, typename ... Params >
152 execution_context( std::allocator_arg_t, segmented_stack, Fn &&, Params && ...) = delete;
153
154 template< typename Fn, typename ... Params >
155 execution_context( std::allocator_arg_t, preallocated, segmented_stack, Fn &&, Params && ...) = delete;
156 #else
157 template< typename Fn,
158 typename ... Params,
159 typename = detail::disable_overload< execution_context, Fn >
160 >
161 execution_context( Fn && fn, Params && ... params) :
162 // deferred execution of fn and its arguments
163 // arguments are stored in std::tuple<>
164 // non-type template parameter pack via std::index_sequence_for<>
165 // preserves the number of arguments
166 // used to extract the function arguments from std::tuple<>
167 fctx_( detail::ecv2_context_create< execution_context >(
168 fixedsize_stack(),
169 std::forward< Fn >( fn),
170 std::forward< Params >( params) ... ) ) {
171 }
172
173 template< typename StackAlloc,
174 typename Fn,
175 typename ... Params
176 >
177 execution_context( std::allocator_arg_t, StackAlloc && salloc, Fn && fn, Params && ... params) :
178 // deferred execution of fn and its arguments
179 // arguments are stored in std::tuple<>
180 // non-type template parameter pack via std::index_sequence_for<>
181 // preserves the number of arguments
182 // used to extract the function arguments from std::tuple<>
183 fctx_( detail::ecv2_context_create< execution_context >(
184 std::forward< StackAlloc >( salloc),
185 std::forward< Fn >( fn),
186 std::forward< Params >( params) ... ) ) {
187 }
188
189 template< typename StackAlloc,
190 typename Fn,
191 typename ... Params
192 >
193 execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) :
194 // deferred execution of fn and its arguments
195 // arguments are stored in std::tuple<>
196 // non-type template parameter pack via std::index_sequence_for<>
197 // preserves the number of arguments
198 // used to extract the function arguments from std::tuple<>
199 fctx_( detail::ecv2_context_create< execution_context >(
200 palloc, std::forward< StackAlloc >( salloc),
201 std::forward< Fn >( fn),
202 std::forward< Params >( params) ... ) ) {
203 }
204 #endif
205
206 ~execution_context() {
207 if ( nullptr != fctx_) {
208 detail::ontop_fcontext( detail::exchange( fctx_, nullptr), nullptr, detail::ecv2_context_unwind);
209 }
210 }
211
212 execution_context( execution_context && other) noexcept :
213 fctx_( other.fctx_) {
214 other.fctx_ = nullptr;
215 }
216
217 execution_context & operator=( execution_context && other) noexcept {
218 if ( this != & other) {
219 execution_context tmp = std::move( other);
220 swap( tmp);
221 }
222 return * this;
223 }
224
225 execution_context( execution_context const& other) noexcept = delete;
226 execution_context & operator=( execution_context const& other) noexcept = delete;
227
228 ret_tpl_t operator()( Args ... args);
229
230 template< typename Fn >
231 ret_tpl_t operator()( exec_ontop_arg_t, Fn && fn, Args ... args);
232
233 explicit operator bool() const noexcept {
234 return nullptr != fctx_;
235 }
236
237 bool operator!() const noexcept {
238 return nullptr == fctx_;
239 }
240
241 bool operator==( execution_context const& other) const noexcept {
242 return fctx_ == other.fctx_;
243 }
244
245 bool operator!=( execution_context const& other) const noexcept {
246 return fctx_ != other.fctx_;
247 }
248
249 bool operator<( execution_context const& other) const noexcept {
250 return fctx_ < other.fctx_;
251 }
252
253 bool operator>( execution_context const& other) const noexcept {
254 return other.fctx_ < fctx_;
255 }
256
257 bool operator<=( execution_context const& other) const noexcept {
258 return ! ( * this > other);
259 }
260
261 bool operator>=( execution_context const& other) const noexcept {
262 return ! ( * this < other);
263 }
264
265 template< typename charT, class traitsT >
266 friend std::basic_ostream< charT, traitsT > &
267 operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other) {
268 if ( nullptr != other.fctx_) {
269 return os << other.fctx_;
270 } else {
271 return os << "{not-a-context}";
272 }
273 }
274
275 void swap( execution_context & other) noexcept {
276 std::swap( fctx_, other.fctx_);
277 }
278 };
279
280 class ontop_error : public std::exception {
281 private:
282 detail::fcontext_t fctx_;
283
284 public:
285 ontop_error( detail::fcontext_t fctx) noexcept :
286 fctx_{ fctx } {
287 }
288
289 template< typename ... Args >
290 execution_context< Args ... > get_context() const noexcept {
291 return execution_context< Args ... >{ fctx_ };
292 }
293 };
294
295 template< typename ... Args >
296 typename execution_context< Args ... >::ret_tpl_t
297 execution_context< Args ... >::operator()( Args ... args) {
298 BOOST_ASSERT( nullptr != fctx_);
299 args_tpl_t data( std::forward< Args >( args) ... );
300 auto p = std::make_tuple( std::exception_ptr{}, std::move( data) );
301 detail::transfer_t t = detail::jump_fcontext( detail::exchange( fctx_, nullptr), & p);
302 if ( nullptr != t.data) {
303 auto p = static_cast< std::tuple< std::exception_ptr, args_tpl_t > * >( t.data);
304 std::exception_ptr eptr = std::get< 0 >( * p);
305 if ( eptr) {
306 try {
307 std::rethrow_exception( eptr);
308 } catch (...) {
309 std::throw_with_nested( ontop_error{ t.fctx } );
310 }
311 }
312 data = std::move( std::get< 1 >( * p) );
313 }
314 return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
315 }
316
317 template< typename ... Args >
318 template< typename Fn >
319 typename execution_context< Args ... >::ret_tpl_t
320 execution_context< Args ... >::operator()( exec_ontop_arg_t, Fn && fn, Args ... args) {
321 BOOST_ASSERT( nullptr != fctx_);
322 args_tpl_t data{ std::forward< Args >( args) ... };
323 auto p = std::make_tuple( fn, std::make_tuple( std::exception_ptr{}, std::move( data) ) );
324 detail::transfer_t t = detail::ontop_fcontext(
325 detail::exchange( fctx_, nullptr),
326 & p,
327 detail::ecv2_context_ontop< execution_context, Fn, Args ... >);
328 if ( nullptr != t.data) {
329 auto p = static_cast< std::tuple< std::exception_ptr, args_tpl_t > * >( t.data);
330 std::exception_ptr eptr = std::get< 0 >( * p);
331 if ( eptr) {
332 try {
333 std::rethrow_exception( eptr);
334 } catch (...) {
335 std::throw_with_nested( ontop_error{ t.fctx } );
336 }
337 }
338 data = std::move( std::get< 1 >( * p) );
339 }
340 return std::tuple_cat( std::forward_as_tuple( execution_context( t.fctx) ), std::move( data) );
341 }
342
343 }
344
345 namespace detail {
346
347 template< int N >
348 struct helper {
349 template< typename T >
350 static T convert( T && t) noexcept {
351 return std::forward< T >( t);
352 }
353 };
354
355 template<>
356 struct helper< 1 > {
357 template< typename T >
358 static std::tuple< T > convert( T && t) noexcept {
359 return std::make_tuple( std::forward< T >( t) );
360 }
361 };
362
363 inline
364 transfer_t ecv2_context_unwind( transfer_t t) {
365 throw forced_unwind( t.fctx);
366 return { nullptr, nullptr };
367 }
368
369 template< typename Rec >
370 transfer_t ecv2_context_exit( transfer_t t) noexcept {
371 Rec * rec = static_cast< Rec * >( t.data);
372 // destroy context stack
373 rec->deallocate();
374 return { nullptr, nullptr };
375 }
376
377 template< typename Rec >
378 void ecv2_context_etry( transfer_t t_) noexcept {
379 // transfer control structure to the context-stack
380 Rec * rec = static_cast< Rec * >( t_.data);
381 BOOST_ASSERT( nullptr != rec);
382 transfer_t t = { nullptr, nullptr };
383 try {
384 // jump back to `ecv2_context_create()`
385 t = jump_fcontext( t_.fctx, nullptr);
386 // start executing
387 t = rec->run( t);
388 } catch ( forced_unwind const& e) {
389 t = { e.fctx, nullptr };
390 }
391 BOOST_ASSERT( nullptr != t.fctx);
392 // destroy context-stack of `this`context on next context
393 ontop_fcontext( t.fctx, rec, ecv2_context_exit< Rec >);
394 BOOST_ASSERT_MSG( false, "context already terminated");
395 }
396
397 template< typename Ctx, typename Fn, typename ... Args >
398 transfer_t ecv2_context_ontop( transfer_t t) {
399 auto p = static_cast< std::tuple< Fn, std::tuple< std::exception_ptr, std::tuple< Args ... > > > * >( t.data);
400 BOOST_ASSERT( nullptr != p);
401 typename std::decay< Fn >::type fn = std::forward< Fn >( std::get< 0 >( * p) );
402 auto args = std::move( std::get< 1 >( std::get< 1 >( * p) ) );
403 try {
404 // execute function
405 #if defined(BOOST_NO_CXX17_STD_APPLY)
406 std::get< 1 >( std::get< 1 >( * p) ) = helper< sizeof ... (Args) >::convert( boost::context::detail::apply( fn, std::move( args) ) );
407 #else
408 std::get< 1 >( std::get< 1 >( * p) ) = helper< sizeof ... (Args) >::convert( std::apply( fn, std::move( args) ) );
409 #endif
410 } catch (...) {
411 std::get< 0 >( std::get< 1 >( * p) ) = std::current_exception();
412 }
413 // apply returned data
414 return { t.fctx, & std::get< 1 >( * p) };
415 }
416
417 template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
418 fcontext_t ecv2_context_create( StackAlloc && salloc, Fn && fn, Params && ... params) {
419 typedef ecv2_record< Ctx, StackAlloc, Fn, Params ... > ecv2_record_t;
420
421 auto sctx = salloc.allocate();
422 // reserve space for control structure
423 #if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
424 const std::size_t size = sctx.size - sizeof( ecv2_record_t);
425 void * sp = static_cast< char * >( sctx.sp) - sizeof( ecv2_record_t);
426 #else
427 constexpr std::size_t func_alignment = 64; // alignof( ecv2_record_t);
428 constexpr std::size_t func_size = sizeof( ecv2_record_t);
429 // reserve space on stack
430 void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
431 // align sp pointer
432 std::size_t space = func_size + func_alignment;
433 sp = std::align( func_alignment, func_size, sp, space);
434 BOOST_ASSERT( nullptr != sp);
435 // calculate remaining size
436 const std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
437 #endif
438 // create fast-context
439 const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< ecv2_record_t >);
440 BOOST_ASSERT( nullptr != fctx);
441 // placment new for control structure on context-stack
442 auto rec = ::new ( sp) ecv2_record_t{
443 sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
444 // transfer control structure to context-stack
445 return jump_fcontext( fctx, rec).fctx;
446 }
447
448 template< typename Ctx, typename StackAlloc, typename Fn, typename ... Params >
449 fcontext_t ecv2_context_create( preallocated palloc, StackAlloc && salloc, Fn && fn, Params && ... params) {
450 typedef ecv2_record< Ctx, StackAlloc, Fn, Params ... > ecv2_record_t;
451
452 // reserve space for control structure
453 #if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_STD_ALIGN)
454 const std::size_t size = palloc.size - sizeof( ecv2_record_t);
455 void * sp = static_cast< char * >( palloc.sp) - sizeof( ecv2_record_t);
456 #else
457 constexpr std::size_t func_alignment = 64; // alignof( ecv2_record_t);
458 constexpr std::size_t func_size = sizeof( ecv2_record_t);
459 // reserve space on stack
460 void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
461 // align sp pointer
462 std::size_t space = func_size + func_alignment;
463 sp = std::align( func_alignment, func_size, sp, space);
464 BOOST_ASSERT( nullptr != sp);
465 // calculate remaining size
466 const std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
467 #endif
468 // create fast-context
469 const fcontext_t fctx = make_fcontext( sp, size, & ecv2_context_etry< ecv2_record_t >);
470 BOOST_ASSERT( nullptr != fctx);
471 // placment new for control structure on context-stack
472 auto rec = ::new ( sp) ecv2_record_t{
473 palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn), std::forward< Params >( params) ... };
474 // transfer control structure to context-stack
475 return jump_fcontext( fctx, rec).fctx;
476 }
477
478 }
479
480 #include <boost/context/execution_context_v2_void.ipp>
481
482 inline namespace v2 {
483
484 template< typename ... Args >
485 void swap( execution_context< Args ... > & l, execution_context< Args ... > & r) noexcept {
486 l.swap( r);
487 }
488
489 }}}
490
491 #if defined(BOOST_MSVC)
492 # pragma warning(pop)
493 #endif
494
495 #ifdef BOOST_HAS_ABI_HEADERS
496 # include BOOST_ABI_SUFFIX
497 #endif
498
499 #endif // BOOST_CONTEXT_EXECUTION_CONTEXT_V2_H