Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:35:09

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_FIBER_H
0008 #define BOOST_CONTEXT_FIBER_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 fiber_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 fiber_activation_record {
0066     LPVOID                                                      fiber{ nullptr };
0067     stack_context                                               sctx{};
0068     bool                                                        main_ctx{ true };
0069     fiber_activation_record                                       *   from{ nullptr };
0070     std::function< fiber_activation_record*(fiber_activation_record*&) >    ontop{};
0071     bool                                                        terminated{ false };
0072     bool                                                        force_unwind{ false };
0073 
0074     static fiber_activation_record *& current() noexcept;
0075 
0076     // used for toplevel-context
0077     // (e.g. main context, thread-entry context)
0078     fiber_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             BOOST_ASSERT( ERROR_ALREADY_FIBER == ::GetLastError());
0089             fiber = ::GetCurrentFiber(); 
0090             BOOST_ASSERT( nullptr != fiber);
0091             BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber);
0092         }
0093 #endif
0094     }
0095 
0096     fiber_activation_record( stack_context sctx_) noexcept :
0097         sctx{ sctx_ },
0098         main_ctx{ false } {
0099     } 
0100 
0101     virtual ~fiber_activation_record() {
0102         if ( BOOST_UNLIKELY( main_ctx) ) {
0103             ::ConvertFiberToThread();
0104         } else {
0105             ::DeleteFiber( fiber);
0106         }
0107     }
0108 
0109     fiber_activation_record( fiber_activation_record const&) = delete;
0110     fiber_activation_record & operator=( fiber_activation_record const&) = delete;
0111 
0112     bool is_main_context() const noexcept {
0113         return main_ctx;
0114     }
0115 
0116     fiber_activation_record * resume() {
0117         from = current();
0118         // store `this` in static, thread local pointer
0119         // `this` will become the active (running) context
0120         current() = this;
0121         // context switch from parent context to `this`-context
0122         // context switch
0123         ::SwitchToFiber( fiber);
0124 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0125         return detail::exchange( current()->from, nullptr);
0126 #else
0127         return std::exchange( current()->from, nullptr);
0128 #endif
0129     }
0130 
0131     template< typename Ctx, typename Fn >
0132     fiber_activation_record * resume_with( Fn && fn) {
0133         from = current();
0134         // store `this` in static, thread local pointer
0135         // `this` will become the active (running) context
0136         // returned by fiber::current()
0137         current() = this;
0138 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
0139         current()->ontop = std::bind(
0140                 [](typename std::decay< Fn >::type & fn, fiber_activation_record *& ptr){
0141                     Ctx c{ ptr };
0142                     c = fn( std::move( c) );
0143                     if ( ! c) {
0144                         ptr = nullptr;
0145                     }
0146 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0147                     return exchange( c.ptr_, nullptr);
0148 #else
0149                     return std::exchange( c.ptr_, nullptr);
0150 #endif
0151                 },
0152                 std::forward< Fn >( fn),
0153                 std::placeholders::_1);
0154 #else
0155         current()->ontop = [fn=std::forward<Fn>(fn)](fiber_activation_record *& ptr){
0156             Ctx c{ ptr };
0157             c = fn( std::move( c) );
0158             if ( ! c) {
0159                 ptr = nullptr;
0160             }
0161 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0162             return exchange( c.ptr_, nullptr);
0163 #else
0164             return std::exchange( c.ptr_, nullptr);
0165 #endif
0166         };
0167 #endif
0168         // context switch
0169         ::SwitchToFiber( fiber);
0170 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0171         return detail::exchange( current()->from, nullptr);
0172 #else
0173         return std::exchange( current()->from, nullptr);
0174 #endif
0175     }
0176 
0177     virtual void deallocate() noexcept {
0178     }
0179 };
0180 
0181 struct BOOST_CONTEXT_DECL fiber_activation_record_initializer {
0182     fiber_activation_record_initializer() noexcept;
0183     ~fiber_activation_record_initializer();
0184 };
0185 
0186 struct forced_unwind {
0187     fiber_activation_record  *  from{ nullptr };
0188 
0189     explicit forced_unwind( fiber_activation_record * from_) :
0190         from{ from_ } {
0191     }
0192 };
0193 
0194 template< typename Ctx, typename StackAlloc, typename Fn >
0195 class fiber_capture_record : public fiber_activation_record {
0196 private:
0197     typename std::decay< StackAlloc >::type             salloc_;
0198     typename std::decay< Fn >::type                     fn_;
0199 
0200     static void destroy( fiber_capture_record * p) noexcept {
0201         typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
0202         stack_context sctx = p->sctx;
0203         // deallocate activation record
0204         p->~fiber_capture_record();
0205         // destroy stack with stack allocator
0206         salloc.deallocate( sctx);
0207     }
0208 
0209 public:
0210     fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept :
0211         fiber_activation_record( sctx),
0212         salloc_( std::forward< StackAlloc >( salloc)),
0213         fn_( std::forward< Fn >( fn) ) {
0214     }
0215 
0216     void deallocate() noexcept override final {
0217         BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) );
0218         destroy( this);
0219     }
0220 
0221     void run() {
0222         Ctx c{ from };
0223         try {
0224             // invoke context-function
0225 #if defined(BOOST_NO_CXX17_STD_INVOKE)
0226             c = boost::context::detail::invoke( fn_, std::move( c) );
0227 #else
0228             c = std::invoke( fn_, std::move( c) );
0229 #endif  
0230         } catch ( forced_unwind const& ex) {
0231             c = Ctx{ ex.from };
0232         }
0233         // this context has finished its task
0234         from = nullptr;
0235         ontop = nullptr;
0236         terminated = true;
0237         force_unwind = false;
0238         std::move( c).resume();
0239         BOOST_ASSERT_MSG( false, "fiber already terminated");
0240     }
0241 };
0242 
0243 template< typename Ctx, typename StackAlloc, typename Fn >
0244 static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) {
0245     typedef fiber_capture_record< Ctx, StackAlloc, Fn >  capture_t;
0246 
0247     auto sctx = salloc.allocate();
0248     BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size);
0249     // reserve space for control structure
0250     void * storage = reinterpret_cast< void * >(
0251             ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
0252             & ~ static_cast< uintptr_t >( 0xff) );
0253     // placment new for control structure on context stack
0254     capture_t * record = new ( storage) capture_t{
0255             sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
0256     // create user-context
0257     record->fiber = ::CreateFiber( sctx.size, & detail::fiber_entry_func< capture_t >, record);
0258     return record;
0259 }
0260 
0261 template< typename Ctx, typename StackAlloc, typename Fn >
0262 static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
0263     typedef fiber_capture_record< Ctx, StackAlloc, Fn >  capture_t; 
0264 
0265     BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size);
0266     // reserve space for control structure
0267     void * storage = reinterpret_cast< void * >(
0268             ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) )
0269             & ~ static_cast< uintptr_t >( 0xff) );
0270     // placment new for control structure on context stack
0271     capture_t * record = new ( storage) capture_t{
0272             palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
0273     // create user-context
0274     record->fiber = ::CreateFiber( palloc.sctx.size, & detail::fiber_entry_func< capture_t >, record);
0275     return record;
0276 }
0277 
0278 }
0279 
0280 class BOOST_CONTEXT_DECL fiber {
0281 private:
0282     friend struct detail::fiber_activation_record;
0283 
0284     template< typename Ctx, typename StackAlloc, typename Fn >
0285     friend class detail::fiber_capture_record;
0286 
0287     template< typename Ctx, typename StackAlloc, typename Fn >
0288     friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&);
0289 
0290     template< typename Ctx, typename StackAlloc, typename Fn >
0291     friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&);
0292 
0293     detail::fiber_activation_record   *   ptr_{ nullptr };
0294 
0295     fiber( detail::fiber_activation_record * ptr) noexcept :
0296         ptr_{ ptr } {
0297     }
0298 
0299 public:
0300     fiber() = default;
0301 
0302     template< typename Fn, typename = detail::disable_overload< fiber, Fn > >
0303     fiber( Fn && fn) :
0304         fiber{ std::allocator_arg,
0305                fixedsize_stack(),
0306                std::forward< Fn >( fn) } {
0307     }
0308 
0309     template< typename StackAlloc, typename Fn >
0310     fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) :
0311         ptr_{ detail::create_fiber1< fiber >(
0312                 std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {;
0313     }
0314 
0315     template< typename StackAlloc, typename Fn >
0316     fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) :
0317         ptr_{ detail::create_fiber2< fiber >(
0318                 palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {
0319     }
0320 
0321     ~fiber() {
0322         if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) {
0323             if ( BOOST_LIKELY( ! ptr_->terminated) ) {
0324                 ptr_->force_unwind = true;
0325                 ptr_->resume();
0326                 BOOST_ASSERT( ptr_->terminated);
0327             }
0328             ptr_->deallocate();
0329         }
0330     }
0331 
0332     fiber( fiber const&) = delete;
0333     fiber & operator=( fiber const&) = delete;
0334 
0335     fiber( fiber && other) noexcept {
0336         swap( other);
0337     }
0338 
0339     fiber & operator=( fiber && other) noexcept {
0340         if ( BOOST_LIKELY( this != & other) ) {
0341             fiber tmp = std::move( other);
0342             swap( tmp);
0343         }
0344         return * this;
0345     }
0346 
0347     fiber resume() && {
0348         BOOST_ASSERT( nullptr != ptr_);
0349 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0350         detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume();
0351 #else
0352         detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume();
0353 #endif
0354         if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
0355             throw detail::forced_unwind{ ptr};
0356         } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
0357             ptr = detail::fiber_activation_record::current()->ontop( ptr);
0358             detail::fiber_activation_record::current()->ontop = nullptr;
0359         }
0360         return { ptr };
0361     }
0362 
0363     template< typename Fn >
0364     fiber resume_with( Fn && fn) && {
0365         BOOST_ASSERT( nullptr != ptr_);
0366 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0367         detail::fiber_activation_record * ptr =
0368             detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
0369 #else
0370         detail::fiber_activation_record * ptr =
0371             std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) );
0372 #endif
0373         if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) {
0374             throw detail::forced_unwind{ ptr};
0375         } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) {
0376             ptr = detail::fiber_activation_record::current()->ontop( ptr);
0377             detail::fiber_activation_record::current()->ontop = nullptr;
0378         }
0379         return { ptr };
0380     }
0381 
0382     explicit operator bool() const noexcept {
0383         return nullptr != ptr_ && ! ptr_->terminated;
0384     }
0385 
0386     bool operator!() const noexcept {
0387         return nullptr == ptr_ || ptr_->terminated;
0388     }
0389 
0390     bool operator<( fiber const& other) const noexcept {
0391         return ptr_ < other.ptr_;
0392     }
0393     
0394     #if !defined(BOOST_EMBTC)
0395     
0396     template< typename charT, class traitsT >
0397     friend std::basic_ostream< charT, traitsT > &
0398     operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
0399         if ( nullptr != other.ptr_) {
0400             return os << other.ptr_;
0401         } else {
0402             return os << "{not-a-context}";
0403         }
0404     }
0405 
0406     #else
0407     
0408     template< typename charT, class traitsT >
0409     friend std::basic_ostream< charT, traitsT > &
0410     operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other);
0411 
0412     #endif
0413 
0414     void swap( fiber & other) noexcept {
0415         std::swap( ptr_, other.ptr_);
0416     }
0417 };
0418 
0419 #if defined(BOOST_EMBTC)
0420 
0421     template< typename charT, class traitsT >
0422     inline std::basic_ostream< charT, traitsT > &
0423     operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) {
0424         if ( nullptr != other.ptr_) {
0425             return os << other.ptr_;
0426         } else {
0427             return os << "{not-a-context}";
0428         }
0429     }
0430 
0431 #endif
0432 
0433 inline
0434 void swap( fiber & l, fiber & r) noexcept {
0435     l.swap( r);
0436 }
0437 
0438 typedef fiber fiber_context;
0439 
0440 }}
0441 
0442 #if defined(BOOST_MSVC)
0443 # pragma warning(pop)
0444 #endif
0445 
0446 #ifdef BOOST_HAS_ABI_HEADERS
0447 # include BOOST_ABI_SUFFIX
0448 #endif
0449 
0450 #endif // BOOST_CONTEXT_FIBER_H