diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 4954465..f17f570 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -18,11 +18,11 @@ project boost/coroutine gcc-4.7,on:"-static-libgcc" gcc-4.8,on:-fsplit-stack gcc-4.8,on:"-static-libgcc" - static - multi - : source-location ../src + shared:BOOST_COROUTINES_DYN_LINK=1 + BOOST_COROUTINES_SOURCE : usage-requirements - shared:BOOST_COROUTINES_DYN_LINK=1 + shared:BOOST_COROUTINES_DYN_LINK=1 + : source-location ../src ; alias allocator_sources @@ -45,8 +45,6 @@ explicit allocator_sources ; lib boost_coroutine : allocator_sources detail/coroutine_context.cpp - : shared:BOOST_COROUTINES_DYN_LINK=1 - : : shared:../../context/build//boost_context ; diff --git a/example/asio/stream_client.cpp b/example/asio/stream_client.cpp deleted file mode 100644 index a20d5d3..0000000 --- a/example/asio/stream_client.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -int main( int argc, char* argv[]) -{ - try - { - std::string host, msg, port; - int timeout = 1; - boost::program_options::options_description desc("allowed options"); - desc.add_options() - ("help,h", "help message") - ("host,a", boost::program_options::value< std::string >( & host), "host running the service") - ("port,p", boost::program_options::value< std::string >( & port), "port service is listening") - ("message,m", boost::program_options::value< std::string >( & msg), "message to send") - ("timeout,t", boost::program_options::value< int >( & timeout), "timeout between message 'exit' message in seconds"); - - boost::program_options::variables_map vm; - boost::program_options::store( - boost::program_options::parse_command_line( - argc, - argv, - desc), - vm); - boost::program_options::notify( vm); - - if ( vm.count("help") ) { - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - - boost::asio::io_service io_service; - - boost::asio::ip::tcp::resolver resolver( io_service); - boost::asio::ip::tcp::resolver::query query( boost::asio::ip::tcp::v4(), host, port); - boost::asio::ip::tcp::resolver::iterator iterator( resolver.resolve( query) ); - - boost::asio::ip::tcp::socket s( io_service); - s.connect( * iterator); - - msg.append("\n"); // each message is terminated by newline - boost::asio::write( s, boost::asio::buffer( msg, msg.size() ) ); - std::cout << msg << " sendet" << std::endl; - boost::this_thread::sleep( boost::posix_time::seconds( timeout) ); - std::string exit("exit\n"); // newline - boost::asio::write( s, boost::asio::buffer( exit, exit.size() ) ); - std::cout << exit << " sendet" << std::endl; - - std::cout << "Done" << std::endl; - return EXIT_SUCCESS; - } - catch ( std::exception const& e) - { - std::cerr << "Exception: " << e.what() << "\n"; - } - - return EXIT_FAILURE; -} diff --git a/example/asio/stream_server.cpp b/example/asio/stream_server.cpp deleted file mode 100644 index bb77906..0000000 --- a/example/asio/stream_server.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#define NOMINMAX - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef boost::tuple< boost::system::error_code, std::size_t > tuple_t; -typedef boost::coroutines::coroutine< void( boost::system::error_code, std::size_t) > coro_t; - -class inbuf : public std::streambuf, - private boost::noncopyable -{ -private: - static const std::streamsize pb_size; - - enum - { bf_size = 16 }; - - int fetch_() - { - std::streamsize num = std::min( - static_cast< std::streamsize >( gptr() - eback() ), pb_size); - - std::memmove( - buffer_ + ( pb_size - num), - gptr() - num, num); - - s_.async_read_some( - boost::asio::buffer( buffer_ + pb_size, bf_size - pb_size), - boost::bind( & coro_t::operator(), & coro_, _1, _2) ); - ca_(); - - boost::system::error_code ec; - std::size_t n = 0; - - boost::tie( ec, n) = ca_.get(); - if ( ec) - { - setg( 0, 0, 0); - return -1; - } - - setg( buffer_ + pb_size - num, buffer_ + pb_size, buffer_ + pb_size + n); - return n; - } - - boost::asio::ip::tcp::socket & s_; - coro_t & coro_; - coro_t::caller_type & ca_; - char buffer_[bf_size]; - -protected: - virtual int underflow() - { - if ( gptr() < egptr() ) - return traits_type::to_int_type( * gptr() ); - - if ( 0 > fetch_() ) - return traits_type::eof(); - else - return traits_type::to_int_type( * gptr() ); - } - -public: - inbuf( - boost::asio::ip::tcp::socket & s, - coro_t & coro, - coro_t::caller_type & ca) : - s_( s), coro_( coro), ca_( ca), buffer_() - { setg( buffer_ + 4, buffer_ + 4, buffer_ + 4); } -}; -const std::streamsize inbuf::pb_size = 4; - -class session : private boost::noncopyable -{ -private: - void handle_read_( coro_t::caller_type & ca) - { - inbuf buf( socket_, coro_, ca); - std::istream s( & buf); - - std::string msg; - do - { - std::getline( s, msg); - std::cout << msg << std::endl; - } while ( "exit" != msg); - io_service_.post( - boost::bind( - & session::destroy_, this) ); - } - - void destroy_() - { delete this; } - - coro_t coro_; - boost::asio::io_service & io_service_; - boost::asio::ip::tcp::socket socket_; - -public: - session( boost::asio::io_service & io_service) : - coro_(), - io_service_( io_service), - socket_( io_service_) - {} - - boost::asio::ip::tcp::socket & socket() - { return socket_; } - - void start() - { coro_ = coro_t( boost::bind( & session::handle_read_, this, _1) ); } -}; - -class server : public boost::enable_shared_from_this< server > -{ -private: - boost::asio::io_service & io_service_; - boost::asio::ip::tcp::acceptor acceptor_; - - void handle_accept_( session * new_session, boost::system::error_code const& error) - { - if ( ! error) - { - new_session->start(); - start(); - } - } - - server( boost::asio::io_service & io_service, short port) : - io_service_( io_service), - acceptor_( - io_service_, - boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), port) ) - {} - -public: - typedef boost::shared_ptr< server > ptr_t; - - static ptr_t create( boost::asio::io_service & io_service, short port) - { return ptr_t( new server( io_service, port) ); } - - void start() - { - session * new_session( new session( io_service_) ); - acceptor_.async_accept( - new_session->socket(), - boost::bind( & server::handle_accept_, this->shared_from_this(), - new_session, boost::asio::placeholders::error) ); - } -}; - -int main( int argc, char * argv[]) -{ - try - { - int port = 0; - boost::program_options::options_description desc("allowed options"); - desc.add_options() - ("help,h", "help message") - ("port,p", boost::program_options::value< int >( & port), "port service is listening"); - - boost::program_options::variables_map vm; - boost::program_options::store( - boost::program_options::parse_command_line( - argc, - argv, - desc), - vm); - boost::program_options::notify( vm); - - if ( vm.count("help") ) { - std::cout << desc << std::endl; - return EXIT_SUCCESS; - } - { - boost::asio::io_service io_service; - io_service.post( - boost::bind( - & server::start, - server::create( - io_service, port) ) ); - io_service.run(); - } - std::cout << "Done" << std::endl; - - return EXIT_SUCCESS; - } - catch ( std::exception const& e) - { std::cerr << "Exception: " << e.what() << std::endl; } - - return EXIT_FAILURE; -} - diff --git a/example/Jamfile.v2 b/example/cpp03/Jamfile.v2 similarity index 81% rename from example/Jamfile.v2 rename to example/cpp03/Jamfile.v2 index 9aa27af..ed49320 100644 --- a/example/Jamfile.v2 +++ b/example/cpp03/Jamfile.v2 @@ -31,14 +31,14 @@ else if [ os.name ] = HPUX project boost/coroutine/example : requirements - ../build//boost_coroutine + ../../build//boost_coroutine /boost/program_options//boost_program_options /boost/system//boost_system /boost/thread//boost_thread gcc-4.7,on:-fsplit-stack gcc-4.8,on:-fsplit-stack - multi static + multi ; exe segmented_stack @@ -68,19 +68,3 @@ exe unwind exe same_fringe : same_fringe.cpp ; - -#exe asio/stream_client -# : asio/stream_client.cpp -# ; -# -#exe asio/stream_server -# : asio/stream_server.cpp -# ; - -#exe same_fringe11 -# : c++11/same_fringe.cpp -# ; -# -#exe fibonacci11 -# : c++11/fibonacci.cpp -# ; diff --git a/example/echo.cpp b/example/cpp03/echo.cpp similarity index 100% rename from example/echo.cpp rename to example/cpp03/echo.cpp diff --git a/example/cpp03/echosse.cpp b/example/cpp03/echosse.cpp new file mode 100644 index 0000000..d43190d --- /dev/null +++ b/example/cpp03/echosse.cpp @@ -0,0 +1,60 @@ + +// Copyright Oliver Kowalke 2009. +// 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) + +#include +#include +#include + +#include +#include + +void echoSSE( int i) +{ + __m128i xmm; + xmm = _mm_set_epi32(i, i+1, i+2, i+3); + uint32_t v32[4]; + + memcpy(&v32, &xmm, 16); + + std::cout << v32[0]; + std::cout << v32[1]; + std::cout << v32[2]; + std::cout << v32[3]; +} + +void echo( boost::coroutines::push_coroutine< void > & c, int i) +{ + std::cout << i << ":"; + echoSSE(i); + c(); +} + +void runit( boost::coroutines::push_coroutine< void > & ca) +{ + std::cout << "started! "; + for ( int i = 0; i < 10; ++i) + { + boost::coroutines::pull_coroutine< void > c( boost::bind( echo, _1, i) ); + while ( c) + c(); + ca(); + } +} + +int main( int argc, char * argv[]) +{ + { + boost::coroutines::pull_coroutine< void > c( runit); + while ( c) { + std::cout << "-"; + c(); + } + } + + std::cout << "\nDone" << std::endl; + + return EXIT_SUCCESS; +} diff --git a/example/fibonacci.cpp b/example/cpp03/fibonacci.cpp similarity index 100% rename from example/fibonacci.cpp rename to example/cpp03/fibonacci.cpp diff --git a/example/parallel.cpp b/example/cpp03/parallel.cpp similarity index 100% rename from example/parallel.cpp rename to example/cpp03/parallel.cpp diff --git a/example/power.cpp b/example/cpp03/power.cpp similarity index 100% rename from example/power.cpp rename to example/cpp03/power.cpp diff --git a/example/same_fringe.cpp b/example/cpp03/same_fringe.cpp similarity index 100% rename from example/same_fringe.cpp rename to example/cpp03/same_fringe.cpp diff --git a/example/segmented_stack.cpp b/example/cpp03/segmented_stack.cpp similarity index 100% rename from example/segmented_stack.cpp rename to example/cpp03/segmented_stack.cpp diff --git a/example/tree.h b/example/cpp03/tree.h similarity index 100% rename from example/tree.h rename to example/cpp03/tree.h diff --git a/example/unwind.cpp b/example/cpp03/unwind.cpp similarity index 100% rename from example/unwind.cpp rename to example/cpp03/unwind.cpp diff --git a/example/cpp11/Jamfile.v2 b/example/cpp11/Jamfile.v2 new file mode 100644 index 0000000..8cec863 --- /dev/null +++ b/example/cpp11/Jamfile.v2 @@ -0,0 +1,54 @@ +# Boost.Coroutine Library Examples Jamfile + +# Copyright Oliver Kowalke 2009. +# 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) + +# For more information, see http://www.boost.org/ + +import common ; +import feature ; +import indirect ; +import modules ; +import os ; +import toolset ; + +if [ os.name ] = SOLARIS +{ + lib socket ; + lib nsl ; +} +else if [ os.name ] = NT +{ + lib ws2_32 ; + lib mswsock ; +} +else if [ os.name ] = HPUX +{ + lib ipv6 ; +} + +project boost/coroutine/example + : requirements + ../../build//boost_coroutine + /boost/program_options//boost_program_options + /boost/system//boost_system + /boost/thread//boost_thread + gcc-4.7,on:-fsplit-stack + gcc-4.8,on:-fsplit-stack + static + multi + ; + +exe same_fringe + : same_fringe.cpp + ; + +exe fibonacci + : fibonacci.cpp + ; + +exe await_emu + : await_emu.cpp + ; diff --git a/example/cpp11/await_emu.cpp b/example/cpp11/await_emu.cpp new file mode 100644 index 0000000..8e149dd --- /dev/null +++ b/example/cpp11/await_emu.cpp @@ -0,0 +1,197 @@ +// Copyright Evgeny Panasyuk 2013. +// 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) + +// e-mail: E?????[dot]P???????[at]gmail.??? + +// Full emulation of await feature from C# language in C++ based on Stackful Coroutines from +// Boost.Coroutine library. +// This proof-of-concept shows that exact syntax of await feature can be emulated with help of +// Stackful Coroutines, demonstrating that it is superior mechanism. +// Main aim of this proof-of-concept is to draw attention to Stackful Coroutines. + +#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#define BOOST_THREAD_PROVIDES_FUTURE +#define BOOST_RESULT_OF_USE_DECLTYPE + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost; + +// ___________________________________________________________ // + +template +class concurrent_queue +{ + queue q; + mutex m; + condition_variable c; +public: + template + void push(U &&u) + { + lock_guard l(m); + q.push( forward(u) ); + c.notify_one(); + } + void pop(T &result) + { + unique_lock u(m); + c.wait(u, [&]{return !q.empty();} ); + result = move_if_noexcept(q.front()); + q.pop(); + } +}; + +typedef std::function Task; +concurrent_queue main_tasks; +auto finished = false; + +void reschedule() +{ + this_thread::sleep_for(chrono::milliseconds( rand() % 2000 )); +} + +// ___________________________________________________________ // + +#ifdef BOOST_COROUTINES_UNIDIRECT +typedef coroutines::pull_coroutine coro_pull; +typedef coroutines::push_coroutine coro_push; +#else +typedef coroutines::coroutine coro_pull; +typedef coroutines::coroutine::caller_type coro_push; +#endif +struct CurrentCoro +{ + std::shared_ptr coro; + coro_push *caller; +}; +/*should be thread_local*/ stack coro_stack; + +template +auto asynchronous(F f) -> future +{ + typedef promise CoroPromise; + + CoroPromise coro_promise; + auto coro_future = coro_promise.get_future(); + + // It is possible to avoid shared_ptr and use move-semantic, + // but it would require to refuse use of std::function (it requires CopyConstructable), + // and would lead to further complication and is unjustified + // for purposes of this proof-of-concept + CurrentCoro current_coro = + { + make_shared(std::bind( [f](CoroPromise &coro_promise, coro_push &caller) + { + caller(); + coro_stack.top().caller = &caller; + coro_promise.set_value( f() ); + }, std::move(coro_promise), placeholders::_1 )) + }; + + coro_stack.push( std::move(current_coro) ); + (*coro_stack.top().coro)(); + coro_stack.pop(); + +#ifdef _MSC_VER + return std::move( coro_future ); +#else + return coro_future; +#endif +} + +struct Awaiter +{ + template + auto operator*(Future &&ft) -> decltype(ft.get()) + { + typedef decltype(ft.get()) Result; + + auto &¤t_coro = coro_stack.top(); + auto result = ft.then([current_coro](Future &ft) -> Result + { + main_tasks.push([current_coro] + { + coro_stack.push(std::move(current_coro)); + (*coro_stack.top().coro)(); + coro_stack.pop(); + }); + return ft.get(); + }); + (*coro_stack.top().caller)(); + return result.get(); + } +}; +#define await Awaiter()* + +// ___________________________________________________________ // + +void async_user_handler(); + +int main() +{ + srand(time(0)); + + // Custom scheduling is not required - can be integrated + // to other systems transparently + main_tasks.push([] + { + asynchronous([] + { + return async_user_handler(), + finished = true; + }); + }); + + Task task; + while(!finished) + { + main_tasks.pop(task); + task(); + } +} + +// __________________________________________________________________ // + +int bar(int i) +{ + // await is not limited by "one level" as in C# + auto result = await async([i]{ return reschedule(), i*100; }); + return result + i*10; +} + +int foo(int i) +{ + cout << i << ":\tbegin" << endl; + cout << await async([i]{ return reschedule(), i*10; }) << ":\tbody" << endl; + cout << bar(i) << ":\tend" << endl; + return i*1000; +} + +void async_user_handler() +{ + vector> fs; + + for(auto i=0; i!=5; ++i) + fs.push_back( asynchronous([i]{ return foo(i+1); }) ); + + BOOST_FOREACH(auto &&f, fs) + cout << await f << ":\tafter end" << endl; +} diff --git a/example/c++11/fibonacci.cpp b/example/cpp11/fibonacci.cpp similarity index 100% rename from example/c++11/fibonacci.cpp rename to example/cpp11/fibonacci.cpp diff --git a/example/c++11/same_fringe.cpp b/example/cpp11/same_fringe.cpp similarity index 100% rename from example/c++11/same_fringe.cpp rename to example/cpp11/same_fringe.cpp diff --git a/example/c++11/tree.h b/example/cpp11/tree.h similarity index 100% rename from example/c++11/tree.h rename to example/cpp11/tree.h diff --git a/include/boost/coroutine/detail/config.hpp b/include/boost/coroutine/detail/config.hpp index d33eef7..618235c 100644 --- a/include/boost/coroutine/detail/config.hpp +++ b/include/boost/coroutine/detail/config.hpp @@ -14,16 +14,12 @@ # undef BOOST_COROUTINES_DECL #endif -#if defined(BOOST_HAS_DECLSPEC) -# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK) -# if ! defined(BOOST_DYN_LINK) -# define BOOST_DYN_LINK -# endif -# if defined(BOOST_COROUTINES_SOURCE) -# define BOOST_COROUTINES_DECL BOOST_SYMBOL_EXPORT -# else -# define BOOST_COROUTINES_DECL BOOST_SYMBOL_IMPORT -# endif +#if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK) ) && ! defined(BOOST_COROUTINES_STATIC_LINK) +# if defined(BOOST_COROUTINES_SOURCE) +# define BOOST_COROUTINES_DECL BOOST_SYMBOL_EXPORT +# define BOOST_COROUTINES_BUILD_DLL +# else +# define BOOST_COROUTINES_DECL BOOST_SYMBOL_IMPORT # endif #endif @@ -32,7 +28,7 @@ #endif #if ! defined(BOOST_COROUTINES_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_COROUTINES_NO_LIB) -# define BOOST_LIB_NAME boost_context +# define BOOST_LIB_NAME boost_coroutine # if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_COROUTINES_DYN_LINK) # define BOOST_DYN_LINK # endif @@ -54,6 +50,10 @@ # define BOOST_COROUTINES_OLD #endif +#if defined(BOOST_COROUTINES_BIDIRECT) +# define BOOST_COROUTINES_OLD +#endif + #if ! defined(BOOST_COROUTINES_OLD) # define BOOST_COROUTINES_UNIDIRECT #endif diff --git a/performance/Jamfile.v2 b/performance/Jamfile.v2 index ea6a346..d5a9787 100644 --- a/performance/Jamfile.v2 +++ b/performance/Jamfile.v2 @@ -19,8 +19,8 @@ project boost/context/performance /boost/coroutine//boost_coroutine gcc-4.7,on:-fsplit-stack gcc-4.8,on:-fsplit-stack - static "-lrt" + static multi ; diff --git a/src/detail/coroutine_context.cpp b/src/detail/coroutine_context.cpp index 981bc8e..82d32aa 100644 --- a/src/detail/coroutine_context.cpp +++ b/src/detail/coroutine_context.cpp @@ -4,8 +4,6 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_COROUTINES_SOURCE - #include "boost/coroutine/detail/coroutine_context.hpp" #ifdef BOOST_MSVC diff --git a/src/detail/segmented_stack_allocator.cpp b/src/detail/segmented_stack_allocator.cpp index 2a9485c..732e230 100644 --- a/src/detail/segmented_stack_allocator.cpp +++ b/src/detail/segmented_stack_allocator.cpp @@ -4,8 +4,6 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_COROUTINES_SOURCE - #include #include diff --git a/src/detail/standard_stack_allocator_posix.cpp b/src/detail/standard_stack_allocator_posix.cpp index ed9c6fe..26731e2 100644 --- a/src/detail/standard_stack_allocator_posix.cpp +++ b/src/detail/standard_stack_allocator_posix.cpp @@ -4,8 +4,6 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_COROUTINES_SOURCE - #include "boost/coroutine/detail/standard_stack_allocator.hpp" extern "C" { diff --git a/src/detail/standard_stack_allocator_windows.cpp b/src/detail/standard_stack_allocator_windows.cpp index a6997eb..651498e 100644 --- a/src/detail/standard_stack_allocator_windows.cpp +++ b/src/detail/standard_stack_allocator_windows.cpp @@ -4,8 +4,6 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_COROUTINES_SOURCE - #include "boost/coroutine/detail/standard_stack_allocator.hpp" extern "C" {