From a5bc3d313e23633a029f9cd87b0ab313a62f091f Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Fri, 28 Nov 2014 19:11:59 +0100 Subject: [PATCH] update examples + execution_context impl --- example/execution_context/Jamfile.v2 | 2 + .../execution_context/coroutine/parser.cpp | 19 ++++--- example/execution_context/parser.cpp | 13 +++-- include/boost/context/execution_context.hpp | 55 +++++++++++-------- include/boost/context/reserve.hpp | 39 +++++++++++++ 5 files changed, 94 insertions(+), 34 deletions(-) create mode 100644 include/boost/context/reserve.hpp diff --git a/example/execution_context/Jamfile.v2 b/example/execution_context/Jamfile.v2 index 7a50f7b..ea440a7 100644 --- a/example/execution_context/Jamfile.v2 +++ b/example/execution_context/Jamfile.v2 @@ -18,6 +18,7 @@ import architecture ; project boost/econtext/example : requirements /boost/context//boost_context + /boost/thread//boost_thread gcc-4.7,on:-fsplit-stack gcc-4.7,on:-DBOOST_USE_SEGMENTED_STACKS gcc-4.8,on:-fsplit-stack @@ -27,6 +28,7 @@ project boost/econtext/example clang-3.4,on:-fsplit-stack clang-3.4,on:-DBOOST_USE_SEGMENTED_STACKS static + multi ; exe jump diff --git a/example/execution_context/coroutine/parser.cpp b/example/execution_context/coroutine/parser.cpp index fa334ea..76bc353 100644 --- a/example/execution_context/coroutine/parser.cpp +++ b/example/execution_context/coroutine/parser.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -44,9 +45,6 @@ public: void run() { scan(); E(); - if (next!='\0'){ - exit(1); - } } private: @@ -92,15 +90,15 @@ private: typedef coroutine coro_t; -int main() { +void foo() { std::istringstream is("1+1"); // invert control flow coro_t::pull_type seq( - boost::context::fixedsize(), - [&is]( coro_t::push_type & yield) { + boost::context::fixedsize(), + [&is]( coro_t::push_type & yield) { Parser p(is,[&yield](char ch){ yield(ch); }); p.run(); - }); + }); // user-code pulls parsed data from parser while(seq){ @@ -108,3 +106,10 @@ int main() { seq(); } } + +int main() { + std::thread t1( foo); + std::thread t2( foo); + t1.join(); + t2.join(); +} diff --git a/example/execution_context/parser.cpp b/example/execution_context/parser.cpp index 33980d5..4457e4f 100644 --- a/example/execution_context/parser.cpp +++ b/example/execution_context/parser.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -43,9 +44,6 @@ public: void run() { scan(); E(); - if (next!='\0'){ - exit(1); - } } private: @@ -89,7 +87,7 @@ private: } }; -int main() { +void foo() { std::istringstream is("1+1"); bool done=false; char c; @@ -105,6 +103,7 @@ int main() { }); p.run(); done=true; + main_ctx.jump_to(); }); // user-code pulls parsed data from parser @@ -113,3 +112,9 @@ int main() { printf("Parsed: %c\n",c); } } + +int main() { + std::thread t( foo); + t.join(); + return 0; +} diff --git a/include/boost/context/execution_context.hpp b/include/boost/context/execution_context.hpp index 17bae5b..fbd2d62 100644 --- a/include/boost/context/execution_context.hpp +++ b/include/boost/context/execution_context.hpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -42,7 +43,7 @@ void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]); namespace boost { namespace context { -class execution_context { +class BOOST_CONTEXT_DECL execution_context { private: struct base_context { std::size_t use_count; @@ -105,6 +106,9 @@ private: }; struct main_context : public base_context { + ~main_context() { + fprintf(stderr,"~main_context()\n"); + } void deallocate() { } @@ -128,44 +132,52 @@ private: static thread_local ptr_t current_ctx_; - bool is_segmented_; boost::intrusive_ptr< base_context > ptr_; execution_context() : - is_segmented_( false), ptr_( current_ctx_) { } + static ptr_t create_main_context() { + static thread_local main_context mctx; // thread_local required? + return ptr_t( & mctx); + } + public: static execution_context current() noexcept { return execution_context(); } -#if defined(BOOST_USE_SEGMENTED_STACKS) - template< typename Fn > - execution_context( segmented salloc, Fn && fn) : - is_segmented_( true), - ptr_() { - typedef side_context< Fn, segmented > func_t; - - stack_context sctx( salloc.allocate() ); - std::size_t size = sctx.size - sizeof( func_t); - void * sp = static_cast< char * >( sctx.sp) - sizeof( func_t); - fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func); - ptr_.reset( new ( sp) func_t( sctx, salloc, std::forward< Fn >( fn), fctx) ); - } -#endif - template< typename StackAlloc, typename Fn > execution_context( StackAlloc salloc, Fn && fn) : - is_segmented_( false), ptr_() { typedef side_context< 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); + // create fast-context fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func); + // placment new for control structure on fast-context stack + ptr_.reset( new ( sp) func_t( sctx, salloc, std::forward< Fn >( fn), fctx) ); + } + + template< typename StackAlloc, typename Fn > + execution_context( reserve & rs, StackAlloc salloc, Fn && fn) : + ptr_() { + typedef side_context< Fn, StackAlloc > func_t; + + stack_context sctx( salloc.allocate() ); + // reserve space for user code + std::size_t size = sctx.size - rs.size; + * rs.vp = static_cast< char * >( sctx.sp) - rs.size; + // reserve space for control structure + size -= sizeof( func_t); + void * sp = static_cast< char * >( * rs.vp) - sizeof( func_t); + // create fast-context + fcontext_t fctx = make_fcontext( sp, size, & execution_context::entry_func); + // placment new for control structure on fast-context stack ptr_.reset( new ( sp) func_t( sctx, salloc, std::forward< Fn >( fn), fctx) ); } @@ -174,15 +186,12 @@ public: ptr_t tmp( current_ctx_); current_ctx_ = ptr_; #if defined(BOOST_USE_SEGMENTED_STACKS) - if ( is_segmented_) { __splitstack_getcontext( tmp->sctx.segments_ctx); __splitstack_setcontext( ptr_->sctx.segments_ctx); jump_fcontext( & tmp->fctx, ptr_->fctx, reinterpret_cast< intptr_t >( ptr_.get() ), preserve_fpu); __splitstack_setcontext( tmp->sctx.segments_ctx); - } else { - jump_fcontext( & tmp->fctx, ptr_->fctx, reinterpret_cast< intptr_t >( ptr_.get() ), preserve_fpu); } #else jump_fcontext( & tmp->fctx, ptr_->fctx, reinterpret_cast< intptr_t >( ptr_.get() ), preserve_fpu); @@ -200,7 +209,7 @@ public: thread_local execution_context::ptr_t -execution_context::current_ctx_ = new execution_context::main_context(); +execution_context::current_ctx_ = execution_context::create_main_context(); }} diff --git a/include/boost/context/reserve.hpp b/include/boost/context/reserve.hpp new file mode 100644 index 0000000..665fe31 --- /dev/null +++ b/include/boost/context/reserve.hpp @@ -0,0 +1,39 @@ + +// 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_RESERVE_H +#define BOOST_CONTEXT_RESERVE_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +struct BOOST_CONTEXT_DECL reserve +{ + void ** vp; + std::size_t size; + + reserve( void ** vp_, std::size_t size_) : + vp( vp_), size( size_) { + } +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_RESERVE_H