Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:24

0001 
0002 //          Copyright Oliver Kowalke 2017.
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //    (See accompanying file LICENSE_1_0.txt or copy at
0005 //          http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_CONTEXT_CONTINUATION_H
0008 #define BOOST_CONTEXT_CONTINUATION_H
0009 
0010 #include <windows.h>
0011 
0012 #include <boost/context/detail/config.hpp>
0013 
0014 #include <algorithm>
0015 #include <cstddef>
0016 #include <cstdint>
0017 #include <cstdlib>
0018 #include <cstring>
0019 #include <functional>
0020 #include <memory>
0021 #include <ostream>
0022 #include <system_error>
0023 #include <tuple>
0024 #include <utility>
0025 
0026 #include <boost/assert.hpp>
0027 #include <boost/config.hpp>
0028 
0029 #include <boost/context/detail/disable_overload.hpp>
0030 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0031 #include <boost/context/detail/exchange.hpp>
0032 #endif
0033 #if defined(BOOST_NO_CXX17_STD_INVOKE)
0034 #include <boost/context/detail/invoke.hpp>
0035 #endif
0036 #include <boost/context/fixedsize_stack.hpp>
0037 #include <boost/context/flags.hpp>
0038 #include <boost/context/preallocated.hpp>
0039 #include <boost/context/stack_context.hpp>
0040 
0041 #ifdef BOOST_HAS_ABI_HEADERS
0042 # include BOOST_ABI_PREFIX
0043 #endif
0044 
0045 #if defined(BOOST_MSVC)
0046 # pragma warning(push)
0047 # pragma warning(disable: 4702)
0048 #endif
0049 
0050 namespace boost {
0051 namespace context {
0052 namespace detail {
0053 
0054 // tampoline function
0055 // entered if the execution context
0056 // is resumed for the first time
0057 template< typename Record >
0058 static VOID WINAPI entry_func( LPVOID data) noexcept {
0059     Record * record = static_cast< Record * >( data);
0060     BOOST_ASSERT( nullptr != record);
0061     // start execution of toplevel context-function
0062     record->run();
0063 }
0064 
0065 struct BOOST_CONTEXT_DECL activation_record {
0066     LPVOID                                                      fiber{ nullptr };
0067     stack_context                                               sctx{};
0068     bool                                                        main_ctx{ true };
0069     activation_record                                       *   from{ nullptr };
0070     std::function< activation_record*(activation_record*&) >    ontop{};
0071     bool                                                        terminated{ false };
0072     bool                                                        force_unwind{ false };
0073 
0074     static activation_record *& current() noexcept;
0075 
0076     // used for toplevel-context
0077     // (e.g. main context, thread-entry context)
0078     activation_record() noexcept {
0079 #if ( _WIN32_WINNT > 0x0600)
0080         if ( ::IsThreadAFiber() ) {
0081             fiber = ::GetCurrentFiber();
0082         } else {
0083             fiber = ::ConvertThreadToFiber( nullptr);
0084         }
0085 #else
0086         fiber = ::ConvertThreadToFiber( nullptr);
0087         if ( BOOST_UNLIKELY( nullptr == fiber) ) {
0088             DWORD err = ::GetLastError();
0089             BOOST_ASSERT( ERROR_ALREADY_FIBER == err);
0090             fiber = ::GetCurrentFiber(); 
0091             BOOST_ASSERT( nullptr != fiber);
0092             BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber);
0093         }
0094 #endif
0095     }
0096 
0097     activation_record( stack_context sctx_) noexcept :
0098         sctx{ sctx_ },
0099         main_ctx{ false } {
0100     } 
0101 
0102     virtual ~activation_record() {
0103         if ( BOOST_UNLIKELY( main_ctx) ) {
0104             ::ConvertFiberToThread();
0105         } else {
0106             ::DeleteFiber( fiber);
0107         }
0108     }
0109 
0110     activation_record( activation_record const&) = delete;
0111     activation_record & operator=( activation_record const&) = delete;
0112 
0113     bool is_main_context() const noexcept {
0114         return main_ctx;
0115     }
0116 
0117     activation_record * resume() {
0118         from = current();
0119         // store `this` in static, thread local pointer
0120         // `this` will become the active (running) context
0121         current() = this;
0122         // context switch from parent context to `this`-context
0123         // context switch
0124         ::SwitchToFiber( fiber);
0125 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0126         return detail::exchange( current()->from, nullptr);
0127 #else
0128         return std::exchange( current()->from, nullptr);
0129 #endif
0130     }
0131 
0132     template< typename Ctx, typename Fn >
0133     activation_record * resume_with( Fn && fn) {
0134         from = current();
0135         // store `this` in static, thread local pointer
0136         // `this` will become the active (running) context
0137         // returned by continuation::current()
0138         current() = this;
0139 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
0140         current()->ontop = std::bind(
0141                 [](typename std::decay< Fn >::type & fn, activation_record *& ptr){
0142                     Ctx c{ ptr };
0143                     c = fn( std::move( c) );
0144                     if ( ! c) {
0145                         ptr = nullptr;
0146                     }
0147 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0148                     return exchange( c.ptr_, nullptr);
0149 #else
0150                     return std::exchange( c.ptr_, nullptr);
0151 #endif
0152                 },
0153                 std::forward< Fn >( fn),
0154                 std::placeholders::_1);
0155 #else
0156         current()->ontop = [fn=std::forward<Fn>(fn)](activation_record *& ptr){
0157             Ctx c{ ptr };
0158             c = fn( std::move( c) );
0159             if ( ! c) {
0160                 ptr = nullptr;
0161             }
0162 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0163             return exchange( c.ptr_, nullptr);
0164 #else
0165             return std::exchange( c.ptr_, nullptr);
0166 #endif
0167         };
0168 #endif
0169         // context switch
0170         ::SwitchToFiber( fiber);
0171 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0172         return detail::exchange( current()->from, nullptr);
0173 #else
0174         return std::exchange( current()->from, nullptr);
0175 #endif
0176     }
0177 
0178     virtual void deallocate() noexcept {
0179     }
0180 };
0181 
0182 struct BOOST_CONTEXT_DECL activation_record_initializer {
0183     activation_record_initializer() noexcept;
0184     ~activation_record_initializer();
0185 };
0186 
0187 struct forced_unwind {
0188     activation_record   *   from{ nullptr };
0189 
0190     explicit forced_unwind( activation_record * from_) :
0191         from{ from_ } {
0192     }
0193 };
0194 
0195 template< typename Ctx, typename StackAlloc, typename Fn >
0196 class capture_record : public activation_record {
0197 private:
0198     typename std::decay< StackAlloc >::type             salloc_;
0199     typename std::decay< Fn >::type                     fn_;
0200 
0201     static void destroy( capture_record * p) noexcept {
0202         typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
0203         stack_context sctx = p->sctx;
0204         // deallocate activation record
0205         p->~capture_record();
0206         // destroy stack with stack allocator
0207         salloc.deallocate( sctx);
0208     }
0209 
0210 public:
0211     capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept :
0212         activation_record( sctx),
0213         salloc_( std::forward< StackAlloc >( salloc)),
0214         fn_( std::forward< Fn >( fn) ) {
0215     }
0216 
0217     void deallocate() noexcept override final {
0218         BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) );
0219         destroy( this);
0220     }
0221 
0222     void run() {
0223         Ctx c{ from };
0224         try {
0225             // invoke context-function
0226 #if defined(BOOST_NO_CXX17_STD_INVOKE)
0227             c = boost::context::detail::invoke( fn_, std::move( c) );
0228 #else
0229             c = std::invoke( fn_, std::move( c) );
0230 #endif  
0231         } catch ( forced_unwind const& ex) {
0232             c = Ctx{ ex.from };
0233         }
0234         // this context has finished its task
0235         from = nullptr;
0236         ontop = nullptr;
0237         terminated = true;
0238         force_unwind = false;
0239         c.resume();
0240         BOOST_ASSERT_MSG( false, "continuation already terminated");
0241     }
0242 };
0243 
0244 template< typename Ctx, typename StackAlloc, typename Fn >
0245 static activation_record * create_context1( StackAlloc && salloc, Fn && fn) {
0246     typedef capture_record< Ctx, StackAlloc, Fn >  capture_t;
0247 
0248     auto sctx = salloc.allocate();
0249     BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size);
0250     // reserve space for control structure
0251     void * storage = reinterpret_cast< void * >(
0252             ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
0253             & ~ static_cast< uintptr_t >( 0xff) );
0254     // placment new for control structure on context stack
0255     capture_t * record = new ( storage) capture_t{
0256             sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
0257     // create user-context
0258     record->fiber = ::CreateFiber( sctx.size, & detail::entry_func< capture_t >, record);
0259     return record;
0260 }
0261 
0262 template< typename Ctx, typename StackAlloc, typename Fn >
0263 static activation_record * create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
0264     typedef capture_record< Ctx, StackAlloc, Fn >  capture_t; 
0265 
0266     BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size);
0267     // reserve space for control structure
0268     void * storage = reinterpret_cast< void * >(
0269             ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
0270             & ~ static_cast< uintptr_t >( 0xff) );
0271     // placment new for control structure on context stack
0272     capture_t * record = new ( storage) capture_t{
0273             palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
0274     // create user-context
0275     record->fiber = ::CreateFiber( palloc.sctx.size, & detail::entry_func< capture_t >, record);
0276     return record;
0277 }
0278 
0279 }
0280 
0281 class BOOST_CONTEXT_DECL continuation {
0282 private:
0283     friend struct detail::activation_record;
0284 
0285     template< typename Ctx, typename StackAlloc, typename Fn >
0286     friend class detail::capture_record;
0287 
0288     template< typename Ctx, typename StackAlloc, typename Fn >
0289     friend detail::activation_record * detail::create_context1( StackAlloc &&, Fn &&);
0290 
0291     template< typename Ctx, typename StackAlloc, typename Fn >
0292     friend detail::activation_record * detail::create_context2( preallocated, StackAlloc &&, Fn &&);
0293 
0294     template< typename StackAlloc, typename Fn >
0295     friend continuation
0296     callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
0297 
0298     template< typename StackAlloc, typename Fn >
0299     friend continuation
0300     callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
0301 
0302     detail::activation_record   *   ptr_{ nullptr };
0303 
0304     continuation( detail::activation_record * ptr) noexcept :
0305         ptr_{ ptr } {
0306     }
0307 
0308 public:
0309     continuation() = default;
0310 
0311     ~continuation() {
0312         if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) {
0313             if ( BOOST_LIKELY( ! ptr_->terminated) ) {
0314                 ptr_->force_unwind = true;
0315                 ptr_->resume();
0316                 BOOST_ASSERT( ptr_->terminated);
0317             }
0318             ptr_->deallocate();
0319         }
0320     }
0321 
0322     continuation( continuation const&) = delete;
0323     continuation & operator=( continuation const&) = delete;
0324 
0325     continuation( continuation && other) noexcept {
0326         swap( other);
0327     }
0328 
0329     continuation & operator=( continuation && other) noexcept {
0330         if ( BOOST_LIKELY( this != & other) ) {
0331             continuation tmp = std::move( other);
0332             swap( tmp);
0333         }
0334         return * this;
0335     }
0336 
0337     continuation resume() & {
0338         return std::move( * this).resume();
0339     }
0340 
0341     continuation resume() && {
0342 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0343         detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
0344 #else
0345         detail::activation_record * ptr = std::exchange( ptr_, nullptr)->resume();
0346 #endif
0347         if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) {
0348             throw detail::forced_unwind{ ptr};
0349         } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) {
0350             ptr = detail::activation_record::current()->ontop( ptr);
0351             detail::activation_record::current()->ontop = nullptr;
0352         }
0353         return { ptr };
0354     }
0355 
0356     template< typename Fn >
0357     continuation resume_with( Fn && fn) & {
0358         return std::move( * this).resume_with( std::forward< Fn >( fn) );
0359     }
0360 
0361     template< typename Fn >
0362     continuation resume_with( Fn && fn) && {
0363 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0364         detail::activation_record * ptr =
0365             detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) );
0366 #else
0367         detail::activation_record * ptr =
0368             std::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) );
0369 #endif
0370         if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) {
0371             throw detail::forced_unwind{ ptr};
0372         } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) {
0373             ptr = detail::activation_record::current()->ontop( ptr);
0374             detail::activation_record::current()->ontop = nullptr;
0375         }
0376         return { ptr };
0377     }
0378 
0379     explicit operator bool() const noexcept {
0380         return nullptr != ptr_ && ! ptr_->terminated;
0381     }
0382 
0383     bool operator!() const noexcept {
0384         return nullptr == ptr_ || ptr_->terminated;
0385     }
0386 
0387     bool operator<( continuation const& other) const noexcept {
0388         return ptr_ < other.ptr_;
0389     }
0390     
0391     #if !defined(BOOST_EMBTC)
0392     
0393     template< typename charT, class traitsT >
0394     friend std::basic_ostream< charT, traitsT > &
0395     operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
0396         if ( nullptr != other.ptr_) {
0397             return os << other.ptr_;
0398         } else {
0399             return os << "{not-a-context}";
0400         }
0401     }
0402 
0403     #else
0404     
0405     template< typename charT, class traitsT >
0406     friend std::basic_ostream< charT, traitsT > &
0407     operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other);
0408 
0409     #endif
0410 
0411     void swap( continuation & other) noexcept {
0412         std::swap( ptr_, other.ptr_);
0413     }
0414 };
0415 
0416 #if defined(BOOST_EMBTC)
0417 
0418     template< typename charT, class traitsT >
0419     inline std::basic_ostream< charT, traitsT > &
0420     operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
0421         if ( nullptr != other.ptr_) {
0422             return os << other.ptr_;
0423         } else {
0424             return os << "{not-a-context}";
0425         }
0426     }
0427 
0428 #endif
0429     
0430 template<
0431     typename Fn,
0432     typename = detail::disable_overload< continuation, Fn >
0433 >
0434 continuation
0435 callcc( Fn && fn) {
0436     return callcc(
0437             std::allocator_arg,
0438             fixedsize_stack(),
0439             std::forward< Fn >( fn) );
0440 }
0441 
0442 template< typename StackAlloc, typename Fn >
0443 continuation
0444 callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) {
0445     return continuation{
0446         detail::create_context1< continuation >(
0447                 std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume();
0448 }
0449 
0450 template< typename StackAlloc, typename Fn >
0451 continuation
0452 callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) {
0453     return continuation{
0454         detail::create_context2< continuation >(
0455                 palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume();
0456 }
0457 
0458 inline
0459 void swap( continuation & l, continuation & r) noexcept {
0460     l.swap( r);
0461 }
0462 
0463 }}
0464 
0465 #if defined(BOOST_MSVC)
0466 # pragma warning(pop)
0467 #endif
0468 
0469 #ifdef BOOST_HAS_ABI_HEADERS
0470 # include BOOST_ABI_SUFFIX
0471 #endif
0472 
0473 #endif // BOOST_CONTEXT_CONTINUATION_H