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 <boost/context/detail/config.hpp>
0011 
0012 #include <algorithm>
0013 #include <cstddef>
0014 #include <cstdint>
0015 #include <cstdlib>
0016 #include <exception>
0017 #include <functional>
0018 #include <memory>
0019 #include <ostream>
0020 #include <tuple>
0021 #include <utility>
0022 
0023 #include <boost/assert.hpp>
0024 #include <boost/config.hpp>
0025 #include <boost/intrusive_ptr.hpp>
0026 
0027 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0028 #include <boost/context/detail/exchange.hpp>
0029 #endif
0030 #if defined(BOOST_NO_CXX17_STD_INVOKE)
0031 #include <boost/context/detail/invoke.hpp>
0032 #endif
0033 #include <boost/context/detail/disable_overload.hpp>
0034 #include <boost/context/detail/exception.hpp>
0035 #include <boost/context/detail/fcontext.hpp>
0036 #include <boost/context/detail/tuple.hpp>
0037 #include <boost/context/fixedsize_stack.hpp>
0038 #include <boost/context/flags.hpp>
0039 #include <boost/context/preallocated.hpp>
0040 #include <boost/context/segmented_stack.hpp>
0041 #include <boost/context/stack_context.hpp>
0042 
0043 #ifdef BOOST_HAS_ABI_HEADERS
0044 # include BOOST_ABI_PREFIX
0045 #endif
0046 
0047 #if defined(__CET__) && defined(__unix__)
0048 #  include <cet.h>
0049 #  include <sys/mman.h>
0050 #  define SHSTK_ENABLED (__CET__ & 0x2)
0051 #  define BOOST_CONTEXT_SHADOW_STACK (SHSTK_ENABLED && SHADOW_STACK_SYSCALL)
0052 #  define __NR_map_shadow_stack 451
0053 #ifndef SHADOW_STACK_SET_TOKEN
0054 #  define SHADOW_STACK_SET_TOKEN 0x1
0055 #endif
0056 #endif
0057 
0058 #if defined(BOOST_MSVC)
0059 # pragma warning(push)
0060 # pragma warning(disable: 4702)
0061 #endif
0062 
0063 namespace boost {
0064 namespace context {
0065 namespace detail {
0066 
0067 inline
0068 transfer_t context_unwind( transfer_t t) {
0069     throw forced_unwind( t.fctx);
0070     return { nullptr, nullptr };
0071 }
0072 
0073 template< typename Rec >
0074 transfer_t context_exit( transfer_t t) noexcept {
0075     Rec * rec = static_cast< Rec * >( t.data);
0076 #if BOOST_CONTEXT_SHADOW_STACK
0077     // destory shadow stack
0078     std::size_t ss_size = *((unsigned long*)(reinterpret_cast< uintptr_t >( rec)- 16));
0079     long unsigned int ss_base = *((unsigned long*)(reinterpret_cast< uintptr_t >( rec)- 8));
0080     munmap((void *)ss_base, ss_size);
0081 #endif
0082     // destroy context stack
0083     rec->deallocate();
0084     return { nullptr, nullptr };
0085 }
0086 
0087 template< typename Rec >
0088 void context_entry( transfer_t t) noexcept {
0089     // transfer control structure to the context-stack
0090     Rec * rec = static_cast< Rec * >( t.data);
0091     BOOST_ASSERT( nullptr != t.fctx);
0092     BOOST_ASSERT( nullptr != rec);
0093     try {
0094         // jump back to `create_context()`
0095         t = jump_fcontext( t.fctx, nullptr);
0096         // start executing
0097         t.fctx = rec->run( t.fctx);
0098     } catch ( forced_unwind const& ex) {
0099         t = { ex.fctx, nullptr };
0100     }
0101     BOOST_ASSERT( nullptr != t.fctx);
0102     // destroy context-stack of `this`context on next context
0103     ontop_fcontext( t.fctx, rec, context_exit< Rec >);
0104     BOOST_ASSERT_MSG( false, "context already terminated");
0105 }
0106 
0107 template< typename Ctx, typename Fn >
0108 transfer_t context_ontop( transfer_t t) {
0109     auto p = static_cast< std::tuple< Fn > * >( t.data);
0110     BOOST_ASSERT( nullptr != p);
0111     typename std::decay< Fn >::type fn = std::get< 0 >( * p);
0112     t.data = nullptr;
0113     Ctx c{ t.fctx };
0114     // execute function, pass continuation via reference
0115     c = fn( std::move( c) );
0116 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0117     return { exchange( c.fctx_, nullptr), nullptr };
0118 #else
0119     return { std::exchange( c.fctx_, nullptr), nullptr };
0120 #endif
0121 }
0122 
0123 template< typename Ctx, typename StackAlloc, typename Fn >
0124 class record {
0125 private:
0126     stack_context                                       sctx_;
0127     typename std::decay< StackAlloc >::type             salloc_;
0128     typename std::decay< Fn >::type                     fn_;
0129 
0130     static void destroy( record * p) noexcept {
0131         typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_);
0132         stack_context sctx = p->sctx_;
0133         // deallocate record
0134         p->~record();
0135         // destroy stack with stack allocator
0136         salloc.deallocate( sctx);
0137     }
0138 
0139 public:
0140     record( stack_context sctx, StackAlloc && salloc,
0141             Fn && fn) noexcept :
0142         sctx_( sctx),
0143         salloc_( std::forward< StackAlloc >( salloc)),
0144         fn_( std::forward< Fn >( fn) ) {
0145     }
0146 
0147     record( record const&) = delete;
0148     record & operator=( record const&) = delete;
0149 
0150     void deallocate() noexcept {
0151         destroy( this);
0152     }
0153 
0154     fcontext_t run( fcontext_t fctx) {
0155         Ctx c{ fctx };
0156         // invoke context-function
0157 #if defined(BOOST_NO_CXX17_STD_INVOKE)
0158         c = boost::context::detail::invoke( fn_, std::move( c) );
0159 #else
0160         c = std::invoke( fn_, std::move( c) );
0161 #endif
0162 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0163         return exchange( c.fctx_, nullptr);
0164 #else
0165         return std::exchange( c.fctx_, nullptr);
0166 #endif
0167     }
0168 };
0169 
0170 template< typename Record, typename StackAlloc, typename Fn >
0171 fcontext_t create_context1( StackAlloc && salloc, Fn && fn) {
0172     auto sctx = salloc.allocate();
0173     // reserve space for control structure
0174     void * storage = reinterpret_cast< void * >(
0175             ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) )
0176             & ~static_cast< uintptr_t >( 0xff) );
0177     // placment new for control structure on context stack
0178     Record * record = new ( storage) Record{
0179             sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
0180     // 64byte gab between control structure and stack top
0181     // should be 16byte aligned
0182     void * stack_top = reinterpret_cast< void * >(
0183             reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) );
0184     void * stack_bottom = reinterpret_cast< void * >(
0185             reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) );
0186     // create fast-context
0187     const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom);
0188 
0189 #if BOOST_CONTEXT_SHADOW_STACK
0190     std::size_t ss_size = size >> 5;
0191     // align shadow stack to 8 bytes.
0192     ss_size = (ss_size + 7) & ~7;
0193     // Todo: shadow stack occupies at least 4KB
0194     ss_size = (ss_size > 4096) ? size : 4096;
0195     // create shadow stack
0196     void *ss_base = (void *)syscall(__NR_map_shadow_stack, 0, ss_size, SHADOW_STACK_SET_TOKEN);
0197     BOOST_ASSERT(ss_base != -1);
0198     unsigned long ss_sp = (unsigned long)ss_base + ss_size;
0199     /* pass the shadow stack pointer to make_fcontext
0200      i.e., link the new shadow stack with the new fcontext
0201      TODO should be a better way? */
0202     *((unsigned long*)(reinterpret_cast< uintptr_t >( stack_top)- 8)) = ss_sp;
0203     /* Todo: place shadow stack info in 64byte gap */
0204     *((unsigned long*)(reinterpret_cast< uintptr_t >( storage)- 8)) = (unsigned long) ss_base;
0205     *((unsigned long*)(reinterpret_cast< uintptr_t >( storage)- 16)) = ss_size;
0206 #endif
0207     const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >);
0208     BOOST_ASSERT( nullptr != fctx);
0209     // transfer control structure to context-stack
0210     return jump_fcontext( fctx, record).fctx;
0211 }
0212 
0213 template< typename Record, typename StackAlloc, typename Fn >
0214 fcontext_t create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) {
0215     // reserve space for control structure
0216     void * storage = reinterpret_cast< void * >(
0217             ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) )
0218             & ~ static_cast< uintptr_t >( 0xff) );
0219     // placment new for control structure on context-stack
0220     Record * record = new ( storage) Record{
0221             palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) };
0222     // 64byte gab between control structure and stack top
0223     void * stack_top = reinterpret_cast< void * >(
0224             reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) );
0225     void * stack_bottom = reinterpret_cast< void * >(
0226             reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) );
0227     // create fast-context
0228     const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom);
0229 
0230 #if BOOST_CONTEXT_SHADOW_STACK
0231     std::size_t ss_size = size >> 5;
0232     // align shadow stack to 8 bytes.
0233     ss_size = (ss_size + 7) & ~7;
0234     // Todo: shadow stack occupies at least 4KB
0235     ss_size = (ss_size > 4096) ? size : 4096;
0236     // create shadow stack
0237     void *ss_base = (void *)syscall(__NR_map_shadow_stack, 0, ss_size, SHADOW_STACK_SET_TOKEN);
0238     BOOST_ASSERT(ss_base != -1);
0239     unsigned long ss_sp = (unsigned long)ss_base + ss_size;
0240     /* pass the shadow stack pointer to make_fcontext
0241      i.e., link the new shadow stack with the new fcontext
0242      TODO should be a better way? */
0243     *((unsigned long*)(reinterpret_cast< uintptr_t >( stack_top)- 8)) = ss_sp;
0244     /* Todo: place shadow stack info in 64byte gap */
0245     *((unsigned long*)(reinterpret_cast< uintptr_t >( storage)- 8)) = (unsigned long) ss_base;
0246     *((unsigned long*)(reinterpret_cast< uintptr_t >( storage)- 16)) = ss_size;
0247 #endif
0248     const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >);
0249     BOOST_ASSERT( nullptr != fctx);
0250     // transfer control structure to context-stack
0251     return jump_fcontext( fctx, record).fctx;
0252 }
0253 
0254 }
0255 
0256 class continuation {
0257 private:
0258     template< typename Ctx, typename StackAlloc, typename Fn >
0259     friend class detail::record;
0260 
0261     template< typename Ctx, typename Fn >
0262     friend detail::transfer_t
0263     detail::context_ontop( detail::transfer_t);
0264 
0265     template< typename StackAlloc, typename Fn >
0266     friend continuation
0267     callcc( std::allocator_arg_t, StackAlloc &&, Fn &&);
0268 
0269     template< typename StackAlloc, typename Fn >
0270     friend continuation
0271     callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&);
0272 
0273     detail::fcontext_t  fctx_{ nullptr };
0274 
0275     continuation( detail::fcontext_t fctx) noexcept :
0276         fctx_{ fctx } {
0277     }
0278 
0279 public:
0280     continuation() noexcept = default;
0281 
0282     ~continuation() {
0283         if ( BOOST_UNLIKELY( nullptr != fctx_) ) {
0284             detail::ontop_fcontext(
0285 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0286                     detail::exchange( fctx_, nullptr),
0287 #else
0288                     std::exchange( fctx_, nullptr),
0289 #endif
0290                    nullptr,
0291                    detail::context_unwind);
0292         }
0293     }
0294 
0295     continuation( continuation && other) noexcept {
0296         swap( other);
0297     }
0298 
0299     continuation & operator=( continuation && other) noexcept {
0300         if ( BOOST_LIKELY( this != & other) ) {
0301             continuation tmp = std::move( other);
0302             swap( tmp);
0303         }
0304         return * this;
0305     }
0306 
0307     continuation( continuation const& other) noexcept = delete;
0308     continuation & operator=( continuation const& other) noexcept = delete;
0309 
0310     continuation resume() & {
0311         return std::move( * this).resume();
0312     }
0313 
0314     continuation resume() && {
0315         BOOST_ASSERT( nullptr != fctx_);
0316         return { detail::jump_fcontext(
0317 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0318                     detail::exchange( fctx_, nullptr),
0319 #else
0320                     std::exchange( fctx_, nullptr),
0321 #endif
0322                     nullptr).fctx };
0323     }
0324 
0325     template< typename Fn >
0326     continuation resume_with( Fn && fn) & {
0327         return std::move( * this).resume_with( std::forward< Fn >( fn) );
0328     }
0329 
0330     template< typename Fn >
0331     continuation resume_with( Fn && fn) && {
0332         BOOST_ASSERT( nullptr != fctx_);
0333         auto p = std::make_tuple( std::forward< Fn >( fn) );
0334         return { detail::ontop_fcontext(
0335 #if defined(BOOST_NO_CXX14_STD_EXCHANGE)
0336                     detail::exchange( fctx_, nullptr),
0337 #else
0338                     std::exchange( fctx_, nullptr),
0339 #endif
0340                     & p,
0341                     detail::context_ontop< continuation, Fn >).fctx };
0342     }
0343 
0344     explicit operator bool() const noexcept {
0345         return nullptr != fctx_;
0346     }
0347 
0348     bool operator!() const noexcept {
0349         return nullptr == fctx_;
0350     }
0351 
0352     bool operator<( continuation const& other) const noexcept {
0353         return fctx_ < other.fctx_;
0354     }
0355 
0356     template< typename charT, class traitsT >
0357     friend std::basic_ostream< charT, traitsT > &
0358     operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) {
0359         if ( nullptr != other.fctx_) {
0360             return os << other.fctx_;
0361         } else {
0362             return os << "{not-a-context}";
0363         }
0364     }
0365 
0366     void swap( continuation & other) noexcept {
0367         std::swap( fctx_, other.fctx_);
0368     }
0369 };
0370 
0371 template<
0372     typename Fn,
0373     typename = detail::disable_overload< continuation, Fn >
0374 >
0375 continuation
0376 callcc( Fn && fn) {
0377     return callcc(
0378             std::allocator_arg, fixedsize_stack(),
0379             std::forward< Fn >( fn) );
0380 }
0381 
0382 template< typename StackAlloc, typename Fn >
0383 continuation
0384 callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) {
0385     using Record = detail::record< continuation, StackAlloc, Fn >;
0386     return continuation{
0387                 detail::create_context1< Record >(
0388                         std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume();
0389 }
0390 
0391 template< typename StackAlloc, typename Fn >
0392 continuation
0393 callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) {
0394     using Record = detail::record< continuation, StackAlloc, Fn >;
0395     return continuation{
0396                 detail::create_context2< Record >(
0397                         palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume();
0398 }
0399 
0400 #if defined(BOOST_USE_SEGMENTED_STACKS)
0401 template< typename Fn >
0402 continuation
0403 callcc( std::allocator_arg_t, segmented_stack, Fn &&);
0404 
0405 template< typename StackAlloc, typename Fn >
0406 continuation
0407 callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&);
0408 #endif
0409 
0410 inline
0411 void swap( continuation & l, continuation & r) noexcept {
0412     l.swap( r);
0413 }
0414 
0415 }}
0416 
0417 #if defined(BOOST_MSVC)
0418 # pragma warning(pop)
0419 #endif
0420 
0421 #ifdef BOOST_HAS_ABI_HEADERS
0422 # include BOOST_ABI_SUFFIX
0423 #endif
0424 
0425 #endif // BOOST_CONTEXT_CONTINUATION_H