diff DEPENDENCIES/generic/include/boost/context/execution_context.hpp @ 102:f46d142149f5

Whoops, finish that update
author Chris Cannam
date Mon, 07 Sep 2015 11:13:41 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DEPENDENCIES/generic/include/boost/context/execution_context.hpp	Mon Sep 07 11:13:41 2015 +0100
@@ -0,0 +1,307 @@
+
+//          Copyright Oliver Kowalke 2014.
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_CONTEXT_EXECUTION_CONTEXT_H
+#define BOOST_CONTEXT_EXECUTION_CONTEXT_H
+
+#include <boost/context/detail/config.hpp>
+
+#if ! defined(BOOST_CONTEXT_NO_EXECUTION_CONTEXT)
+
+# include <cstddef>
+# include <cstdint>
+# include <cstdlib>
+# include <exception>
+# include <memory>
+# include <tuple>
+# include <utility>
+
+# include <boost/assert.hpp>
+# include <boost/config.hpp>
+# include <boost/context/fcontext.hpp>
+# include <boost/intrusive_ptr.hpp>
+
+# include <boost/context/stack_context.hpp>
+# include <boost/context/segmented_stack.hpp>
+
+# ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+# endif
+
+# if defined(BOOST_USE_SEGMENTED_STACKS)
+extern "C" {
+
+void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
+
+void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
+
+}
+# endif
+
+namespace boost {
+namespace context {
+
+struct preallocated {
+    void        *   sp;
+    std::size_t     size;
+    stack_context   sctx;
+
+    preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept :
+        sp( sp_), size( size_), sctx( sctx_) {
+    }
+};
+
+class BOOST_CONTEXT_DECL execution_context {
+private:
+    struct fcontext {
+        std::size_t     use_count;
+        fcontext_t      fctx;
+        stack_context   sctx;
+
+        // main-context
+        fcontext() noexcept :
+            use_count( 1),
+            fctx( nullptr),
+            sctx() {
+        } 
+
+        // worker-context
+        fcontext( fcontext_t fctx_, stack_context const& sctx_) noexcept :
+            use_count( 0),
+            fctx( fctx_),
+            sctx( sctx_) {
+        } 
+
+        virtual ~fcontext() noexcept {
+        }
+
+        virtual void deallocate() {
+        }
+
+        virtual void run() noexcept {
+        }
+
+        friend void intrusive_ptr_add_ref( fcontext * ctx) {
+            ++ctx->use_count;
+        }
+
+        friend void intrusive_ptr_release( fcontext * ctx) {
+            BOOST_ASSERT( nullptr != ctx);
+
+            if ( 0 == --ctx->use_count) {
+                ctx->~fcontext();
+            }
+        }
+    };
+
+    template< typename Fn, typename StackAlloc >
+    class worker_fcontext : public fcontext {
+    private:
+        StackAlloc      salloc_;
+        Fn              fn_;
+
+        static void destroy( worker_fcontext * p) {
+            StackAlloc salloc( p->salloc_);
+            stack_context sctx( p->sctx);
+            p->~worker_fcontext();
+            salloc.deallocate( sctx);
+        }
+
+    public:
+        explicit worker_fcontext( stack_context sctx, StackAlloc const& salloc, fcontext_t fctx, Fn && fn) noexcept :
+            fcontext( fctx, sctx),
+            salloc_( salloc),
+            fn_( std::forward< Fn >( fn) ) {
+        }
+
+        void deallocate() override final {
+            destroy( this);
+        }
+
+        void run() noexcept override final {
+            fn_();
+        }
+    };
+
+    static void entry_func( intptr_t p) noexcept {
+        BOOST_ASSERT( 0 != p);
+
+        fcontext * bp( reinterpret_cast< fcontext * >( p) );
+        BOOST_ASSERT( nullptr != bp);
+
+        bp->run();
+    }
+
+    typedef boost::intrusive_ptr< fcontext >    ptr_t;
+
+    thread_local static fcontext                main_ctx_;
+    thread_local static ptr_t                   current_ctx_;
+
+    boost::intrusive_ptr< fcontext >            ptr_;
+# if defined(BOOST_USE_SEGMENTED_STACKS)
+    bool                                        use_segmented_stack_ = false;
+# endif
+
+    template< typename StackAlloc, typename Fn >
+    static fcontext * create_context( StackAlloc salloc, Fn && fn) {
+        typedef worker_fcontext< Fn, StackAlloc >  func_t;
+
+        stack_context sctx( salloc.allocate() );
+        // reserve space for control structure
+        std::size_t size = sctx.size - sizeof( func_t);
+        void * sp = static_cast< char * >( sctx.sp) - sizeof( func_t);
+#if 0
+        constexpr std::size_t func_alignment = 64; // alignof( func_t);
+        constexpr std::size_t func_size = sizeof( func_t);
+        // reserve space on stack
+        void * sp = static_cast< char * >( sctx.sp) - func_size - func_alignment;
+        // align sp pointer
+        sp = std::align( func_alignment, func_size, sp, func_size + func_alignment);
+        BOOST_ASSERT( nullptr != sp);
+        // calculate remaining size
+        std::size_t size = sctx.size - ( static_cast< char * >( sctx.sp) - static_cast< char * >( sp) );
+#endif
+        // create fast-context
+        fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func);
+        BOOST_ASSERT( nullptr != fctx);
+        // placment new for control structure on fast-context stack
+        return new ( sp) func_t( sctx, salloc, fctx, std::forward< Fn >( fn) );
+    }
+
+    template< typename StackAlloc, typename Fn >
+    static fcontext * create_context( preallocated palloc, StackAlloc salloc, Fn && fn) {
+        typedef worker_fcontext< Fn, StackAlloc >  func_t;
+
+        // reserve space for control structure
+        std::size_t size = palloc.size - sizeof( func_t);
+        void * sp = static_cast< char * >( palloc.sp) - sizeof( func_t);
+#if 0
+        constexpr std::size_t func_alignment = 64; // alignof( func_t);
+        constexpr std::size_t func_size = sizeof( func_t);
+        // reserve space on stack
+        void * sp = static_cast< char * >( palloc.sp) - func_size - func_alignment;
+        // align sp pointer
+        sp = std::align( func_alignment, func_size, sp, func_size + func_alignment);
+        BOOST_ASSERT( nullptr != sp);
+        // calculate remaining size
+        std::size_t size = palloc.size - ( static_cast< char * >( palloc.sp) - static_cast< char * >( sp) );
+#endif
+        // create fast-context
+        fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func);
+        BOOST_ASSERT( nullptr != fctx);
+        // placment new for control structure on fast-context stack
+        return new ( sp) func_t( palloc.sctx, salloc, fctx, std::forward< Fn >( fn) );
+    }
+
+    template< typename StackAlloc, typename Fn, typename Tpl, std::size_t ... I >
+    static fcontext * create_worker_fcontext( StackAlloc salloc,
+                                              Fn && fn_, Tpl && tpl_,
+                                              std::index_sequence< I ... >) {
+        return create_context( salloc,
+                               [fn=std::forward< Fn >( fn_),tpl=std::forward< Tpl >( tpl_)] () mutable {
+                                   try {
+                                       fn(
+                                           // std::tuple_element<> does not perfect forwarding
+                                           std::forward< decltype( std::get< I >( std::declval< Tpl >() ) ) >(
+                                                std::get< I >( std::forward< Tpl >( tpl) ) ) ... );
+                                   } catch (...) {
+                                       std::terminate();
+                                   }
+                               });
+    }
+
+    template< typename StackAlloc, typename Fn, typename Tpl, std::size_t ... I >
+    static fcontext * create_worker_fcontext( preallocated palloc, StackAlloc salloc,
+                                              Fn && fn_, Tpl && tpl_,
+                                              std::index_sequence< I ... >) {
+        return create_context( palloc, salloc,
+                               [fn=std::forward< Fn >( fn_),tpl=std::forward< Tpl >( tpl_)] () mutable {
+                                   try {
+                                       fn(
+                                           // std::tuple_element<> does not perfect forwarding
+                                           std::forward< decltype( std::get< I >( std::declval< Tpl >() ) ) >(
+                                                std::get< I >( std::forward< Tpl >( tpl) ) ) ... );
+                                   } catch (...) {
+                                       std::terminate();
+                                   }
+                               });
+    }
+
+    execution_context() :
+        ptr_( current_ctx_) {
+    }
+
+public:
+    static execution_context current() noexcept {
+        return execution_context();
+    }
+
+# if defined(BOOST_USE_SEGMENTED_STACKS)
+    template< typename Fn, typename ... Args >
+    explicit execution_context( segmented_stack salloc, Fn && fn, Args && ... args) :
+        ptr_( create_worker_fcontext( salloc,
+                                      std::forward< Fn >( fn),
+                                      std::make_tuple( std::forward< Args >( args) ... ),
+                                      std::index_sequence_for< Args ... >() ) ),
+        use_segmented_stack_( true) {
+    }
+
+    template< typename Fn, typename ... Args >
+    explicit execution_context( preallocated palloc, segmented_stack salloc, Fn && fn, Args && ... args) :
+        ptr_( create_worker_fcontext( palloc, salloc,
+                                      std::forward< Fn >( fn),
+                                      std::make_tuple( std::forward< Args >( args) ... ),
+                                      std::index_sequence_for< Args ... >() ) ),
+        use_segmented_stack_( true) {
+    }
+# endif
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    explicit execution_context( StackAlloc salloc, Fn && fn, Args && ... args) :
+        ptr_( create_worker_fcontext( salloc,
+                                      std::forward< Fn >( fn),
+                                      std::make_tuple( std::forward< Args >( args) ... ),
+                                      std::index_sequence_for< Args ... >() ) ) {
+    }
+
+    template< typename StackAlloc, typename Fn, typename ... Args >
+    explicit execution_context( preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args) :
+        ptr_( create_worker_fcontext( palloc, salloc,
+                                      std::forward< Fn >( fn),
+                                      std::make_tuple( std::forward< Args >( args) ... ),
+                                      std::index_sequence_for< Args ... >() ) ) {
+    }
+
+    void resume( bool preserve_fpu = false) noexcept {
+        fcontext * old_ctx( current_ctx_.get() );
+        fcontext * new_ctx( ptr_.get() );
+        current_ctx_ = ptr_;
+# if defined(BOOST_USE_SEGMENTED_STACKS)
+        if ( use_segmented_stack_) {
+            __splitstack_getcontext( old_ctx->sctx.segments_ctx);
+            __splitstack_setcontext( new_ctx->sctx.segments_ctx);
+
+            jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu);
+
+            __splitstack_setcontext( old_ctx->sctx.segments_ctx);
+        } else {
+            jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu);
+        }
+# else
+        jump_fcontext( & old_ctx->fctx, new_ctx->fctx, reinterpret_cast< intptr_t >( new_ctx), preserve_fpu);
+# endif
+    }
+};
+
+}}
+
+# ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+# endif
+
+#endif
+
+#endif // BOOST_CONTEXT_EXECUTION_CONTEXT_H