diff --git a/examples/asio/detail/promise_handler.hpp b/examples/asio/detail/promise_handler.hpp deleted file mode 100644 index fd6c9c06..00000000 --- a/examples/asio/detail/promise_handler.hpp +++ /dev/null @@ -1,171 +0,0 @@ -// -// promise_handler.hpp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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) -// -// modified by Oliver Kowalke and Nat Goodspeed -// - -#ifndef BOOST_FIBERS_ASIO_DETAIL_PROMISE_HANDLER_HPP -#define BOOST_FIBERS_ASIO_DETAIL_PROMISE_HANDLER_HPP - -#include - -#include -#include - -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace asio { -namespace detail { - -// Completion handler to adapt a promise as a completion handler. -//[fibers_asio_promise_handler_base -template< typename T > -class promise_handler_base { -public: - typedef std::shared_ptr< boost::fibers::promise< T > > promise_ptr; - - // Construct from any promise_completion_token subclass special value. - template< typename Allocator > - promise_handler_base( boost::fibers::asio::promise_completion_token< Allocator > const& pct) : - promise_( std::make_shared< boost::fibers::promise< T > >( - std::allocator_arg, pct.get_allocator() ) ) -//<- - , ecp_( pct.ec_) -//-> - {} - - bool should_set_value( boost::system::error_code const& ec) { - if ( ! ec) { - // whew, success - return true; - } - -//<- - // ec indicates error - if ( ecp_) { - // promise_completion_token bound an error_code variable: set it - * ecp_ = ec; - // This is the odd case: although there's an error, user code - // expressly forbid us to call set_exception(). We've set the - // bound error code -- but future::get() will wait forever unless - // we kick the promise SOMEHOW. Tell subclass to call set_value() - // anyway. - return true; - } -//-> - // no bound error_code: cause promise_ to throw an exception - promise_->set_exception( - std::make_exception_ptr( - boost::system::system_error( ec) ) ); - // caller should NOT call set_value() - return false; - } - - promise_ptr get_promise() const { - return promise_; - } - -private: - promise_ptr promise_; -//<- - boost::system::error_code * ecp_; -//-> -}; -//] - -// generic promise_handler for arbitrary value -//[fibers_asio_promise_handler -template< typename T > -class promise_handler : public promise_handler_base< T > { -private: -//<- - using promise_handler_base< T >::should_set_value; - -//-> -public: - // Construct from any promise_completion_token subclass special value. - template< typename Allocator > - promise_handler( boost::fibers::asio::promise_completion_token< Allocator > const& pct) : - promise_handler_base< T >( pct) { - } - -//<- - void operator()( T t) { - get_promise()->set_value( t); - } -//-> - void operator()( boost::system::error_code const& ec, T t) { - get_promise()->set_value( t); - if ( should_set_value( ec) ) { - get_promise()->set_value( t); - } - } -//<- - using typename promise_handler_base< T >::promise_ptr; - using promise_handler_base< T >::get_promise; -//-> -}; -//] - -// specialize promise_handler for void -template<> -class promise_handler< void > : public promise_handler_base< void > { -private: - using promise_handler_base< void >::should_set_value; - -public: - // Construct from any promise_completion_token subclass special value. - template< typename Allocator > - promise_handler( boost::fibers::asio::promise_completion_token< Allocator > const& pct) : - promise_handler_base< void >( pct) { - } - - void operator()() { - get_promise()->set_value(); - } - - void operator()( boost::system::error_code const& ec) { - if ( should_set_value( ec) ) { - get_promise()->set_value(); - } - } - - using promise_handler_base< void >::promise_ptr; - using promise_handler_base< void >::get_promise; -}; - -// Specialize asio_handler_invoke hook to ensure that any exceptions thrown -// from the handler are propagated back to the caller via the future. -template< typename Function, typename T > -void asio_handler_invoke( Function f, promise_handler< T > * h) { - typename promise_handler< T >::promise_ptr - p( h->get_promise() ); - try { - fprintf(stderr, "before f()\n"); - f(); - fprintf(stderr, "after f()\n"); - } catch ( std::exception const& ec) { - fprintf(stderr, "p->set_exception() : %s\n", ec.what() ); - p->set_exception( std::current_exception() ); - } -} - -}}}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_ASIO_DETAIL_PROMISE_HANDLER_HPP diff --git a/examples/asio/detail/use_future.hpp b/examples/asio/detail/use_future.hpp deleted file mode 100644 index 349e2e09..00000000 --- a/examples/asio/detail/use_future.hpp +++ /dev/null @@ -1,99 +0,0 @@ -// -// use_future.hpp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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) -// -// modified by Oliver Kowalke and Nat Goodspeed -// - -#ifndef BOOST_FIBERS_ASIO_DETAIL_USE_FUTURE_HPP -#define BOOST_FIBERS_ASIO_DETAIL_USE_FUTURE_HPP - -#include -#include - -#include - -#include "promise_handler.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace asio { -namespace detail { - -// use_future_handler is just an alias for promise_handler -- but we must -// distinguish this case to specialize async_result below. -template< typename T > -using use_future_handler = promise_handler< T >; - -}}} - -namespace asio { - -// Handler traits specialisation for use_future_handler. -template< typename T > -class async_result< fibers::asio::detail::use_future_handler< T > > { -public: - // The initiating function will return a future. - typedef boost::fibers::future< T > type; - - // Constructor creates a new promise for the async operation, and obtains the - // corresponding future. - explicit async_result( fibers::asio::detail::use_future_handler< T > & h) { - value_ = h.get_promise()->get_future(); - } - - // Obtain the future to be returned from the initiating function. - type get() { - return boost::move( value_); - } - -private: - type value_; -}; - -// Handler type specialisation for use_future for a nullary callback. -template< typename Allocator, typename ReturnType > -struct handler_type< boost::fibers::asio::use_future_t< Allocator >, ReturnType() > { - typedef fibers::asio::detail::use_future_handler< void > type; -}; - -// Handler type specialisation for use_future for a single-argument callback. -template< typename Allocator, typename ReturnType, typename Arg1 > -struct handler_type< boost::fibers::asio::use_future_t< Allocator >, ReturnType( Arg1) > { - typedef fibers::asio::detail::use_future_handler< Arg1 > type; -}; - -// Handler type specialisation for use_future for a callback passed only -// boost::system::error_code. Note the use of use_future_handler: an -// error_code indicating error will be conveyed to consumer code via -// set_exception(). -template< typename Allocator, typename ReturnType > -struct handler_type< boost::fibers::asio::use_future_t< Allocator >, ReturnType( boost::system::error_code) > { - typedef fibers::asio::detail::use_future_handler< void > type; -}; - -// Handler type specialisation for use_future for a callback passed -// boost::system::error_code plus an arbitrary value. Note the use of a -// single-argument use_future_handler: an error_code indicating error will be -// conveyed to consumer code via set_exception(). -template< typename Allocator, typename ReturnType, typename Arg2 > -struct handler_type< boost::fibers::asio::use_future_t< Allocator >, ReturnType( boost::system::error_code, Arg2) > { - typedef fibers::asio::detail::use_future_handler< Arg2 > type; -}; - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_FIBERS_ASIO_DETAIL_USE_FUTURE_HPP diff --git a/examples/asio/detail/yield.hpp b/examples/asio/detail/yield.hpp index f18b1e1a..1de949d3 100644 --- a/examples/asio/detail/yield.hpp +++ b/examples/asio/detail/yield.hpp @@ -1,25 +1,15 @@ -// -// yield.hpp -// ~~~~~~~~~ -// -// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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) -// -// modified by Oliver Kowalke and Nat Goodspeed -// - #ifndef BOOST_FIBERS_ASIO_DETAIL_YIELD_HPP #define BOOST_FIBERS_ASIO_DETAIL_YIELD_HPP #include +#include #include +#include +#include +#include #include -#include "promise_handler.hpp" - #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif @@ -29,78 +19,163 @@ namespace fibers { namespace asio { namespace detail { -// yield_handler is just an alias for promise_handler -- but we must -// distinguish this case to specialize async_result below. -//[fibers_asio_yield_handler template< typename T > -using yield_handler = promise_handler< T >; -//] - -}}} - -namespace asio { - -// Handler traits specialisation for yield_handler. -template< typename T > -class async_result< fibers::asio::detail::yield_handler< T > > { +class yield_handler +{ public: - // The initiating function will return a value of type T. - typedef T type; + yield_handler( yield_t const& y) : + ctx_( boost::fibers::context::active() ), + ec_( y.ec_), + value_( nullptr) + {} - // Constructor creates a new promise for the async operation, and obtains the - // corresponding future. - explicit async_result( fibers::asio::detail::yield_handler< T > & h) { - future_ = h.get_promise()->get_future(); + void operator()( T t) + { + * ec_ = boost::system::error_code(); + * value_ = std::move( t); + boost::fibers::context::active()->set_ready( ctx_); + } + + void operator()( boost::system::error_code const& ec, T t) + { + * ec_ = ec; + * value_ = std::move( t); + boost::fibers::context::active()->set_ready( ctx_); + } + +//private: + boost::fibers::context * ctx_; + boost::system::error_code * ec_; + T * value_; +}; + +// Completion handler to adapt a void promise as a completion handler. +template<> +class yield_handler< void > +{ +public: + yield_handler( yield_t const& y) : + ctx_( boost::fibers::context::active() ), + ec_( y.ec_) + {} + + void operator()() + { + * ec_ = boost::system::error_code(); + boost::fibers::context::active()->set_ready( ctx_); } - // This blocks the calling fiber until the handler sets either a value or - // an exception. - type get() { - return future_.get(); + void operator()( boost::system::error_code const& ec) + { + * ec_ = ec; + boost::fibers::context::active()->set_ready( ctx_); + } + +//private: + boost::fibers::context * ctx_; + boost::system::error_code * ec_; +}; + +// Specialize asio_handler_invoke hook to ensure that any exceptions thrown +// from the handler are propagated back to the caller +template< typename Fn, typename T > +void asio_handler_invoke( Fn fn, yield_handler< T > * h) { + fn(); +} + +} // namespace detail +} // namespace asio +} // namespace fibers +} // namespace boost + +namespace boost { +namespace asio { + +template< typename T > +class async_result< boost::fibers::asio::detail::yield_handler< T > > +{ +public: + typedef T type; + + explicit async_result( boost::fibers::asio::detail::yield_handler< T > & h) + { + out_ec_ = h.ec_; + if ( ! out_ec_) h.ec_ = & ec_; + h.value_ = & value_; + } + + type get() + { + boost::fibers::context::active()->suspend(); + if ( ! out_ec_ && ec_) + throw_exception( boost::system::system_error( ec_) ); + return std::move( value_); } private: - fibers::future< T > future_; + boost::system::error_code * out_ec_; + boost::system::error_code ec_; + type value_; }; -// Handler type specialisation for yield for a nullary callback. -template< typename Allocator, typename ReturnType > -struct handler_type< boost::fibers::asio::yield_t< Allocator >, - ReturnType() > { - typedef boost::fibers::asio::detail::yield_handler< void > type; +template<> +class async_result< boost::fibers::asio::detail::yield_handler< void > > +{ +public: + typedef void type; + + explicit async_result( boost::fibers::asio::detail::yield_handler< void > & h) + { + out_ec_ = h.ec_; + if ( ! out_ec_) h.ec_ = & ec_; + } + + void get() + { + boost::fibers::context::active()->suspend(); + if ( ! out_ec_ && ec_) + throw_exception( boost::system::system_error( ec_) ); + } + +private: + boost::system::error_code * out_ec_; + boost::system::error_code ec_; }; -// Handler type specialisation for yield for a single-argument callback. -template< typename Allocator, typename ReturnType, typename Arg1 > -struct handler_type< boost::fibers::asio::yield_t< Allocator >, - ReturnType( Arg1) > { - typedef fibers::asio::detail::yield_handler< Arg1 > type; -}; +// Handler type specialisation for use_future. +template< typename ReturnType > +struct handler_type< + boost::fibers::asio::yield_t, + ReturnType() +> +{ typedef boost::fibers::asio::detail::yield_handler< void > type; }; -// Handler type specialisation for yield for a callback passed only -// boost::system::error_code. Note the use of yield_handler: an -// error_code indicating error will be conveyed to consumer code via an -// exception. Normal return implies (! error_code). -template< typename Allocator, typename ReturnType > -struct handler_type< boost::fibers::asio::yield_t< Allocator >, - ReturnType( boost::system::error_code) > { - typedef fibers::asio::detail::yield_handler< void > type; -}; +// Handler type specialisation for use_future. +template< typename ReturnType, typename Arg1 > +struct handler_type< + boost::fibers::asio::yield_t, + ReturnType( Arg1) +> +{ typedef boost::fibers::asio::detail::yield_handler< Arg1 > type; }; -// Handler type specialisation for yield for a callback passed -// boost::system::error_code plus an arbitrary value. Note the use of a -// single-argument yield_handler: an error_code indicating error will be -// conveyed to consumer code via an exception. Normal return implies (! -// error_code). -//[asio_handler_type -template< typename Allocator, typename ReturnType, typename Arg2 > -struct handler_type< boost::fibers::asio::yield_t< Allocator >, - ReturnType( boost::system::error_code, Arg2) > { - typedef fibers::asio::detail::yield_handler< Arg2 > type; -}; -//] +// Handler type specialisation for use_future. +template< typename ReturnType > +struct handler_type< + boost::fibers::asio::yield_t, + ReturnType( boost::system::error_code) +> +{ typedef boost::fibers::asio::detail::yield_handler< void > type; }; -}} +// Handler type specialisation for use_future. +template< typename ReturnType, typename Arg2 > +struct handler_type< + boost::fibers::asio::yield_t, + ReturnType( boost::system::error_code, Arg2) +> +{ typedef boost::fibers::asio::detail::yield_handler< Arg2 > type; }; + +} // namespace asio +} // namespace boost #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX diff --git a/examples/asio/echo_server.cpp b/examples/asio/echo_server.cpp index 9f63d297..7008d624 100644 --- a/examples/asio/echo_server.cpp +++ b/examples/asio/echo_server.cpp @@ -69,9 +69,11 @@ void server( boost::asio::io_service & io_svc, unsigned short port) { boost::fibers::asio::yield[ec]); if ( ec) { std::cerr << "fiber " << id << " : error occured : " << ec.message() << std::endl; - } else { - boost::fibers::fiber( session, socket).detach(); } + if ( io_svc.stopped() ) { + return; + } + boost::fibers::fiber( session, socket).detach(); } std::cout << "fiber " << id << " terminates" << std::endl; } diff --git a/examples/asio/use_future.hpp b/examples/asio/use_future.hpp deleted file mode 100644 index 66c10b0a..00000000 --- a/examples/asio/use_future.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// use_future.hpp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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) -// -// modified by Oliver Kowalke and Nat Goodspeed -// - -#ifndef BOOST_FIBERS_ASIO_USE_FUTURE_HPP -#define BOOST_FIBERS_ASIO_USE_FUTURE_HPP - -#include // std::allocator -#include -#include "promise_completion_token.hpp" - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace fibers { -namespace asio { - -/// Class used to specify that a Boost.Asio asynchronous operation should -/// return a future. -/** - * The use_future_t class is used to indicate that a Boost.Asio asynchronous - * operation should return a boost::fibers::future object. A use_future_t - * object may be passed as a handler to an asynchronous operation, typically - * using the special value @c boost::fibers::asio::use_future. For example: - * - * @code boost::fibers::future my_future - * = my_socket.async_read_some(my_buffer, boost::fibers::asio::use_future); @endcode - * - * The initiating function (async_read_some in the above example) returns a - * future that will receive the result of the operation. If the operation - * completes with an error_code indicating failure, it is converted into a - * system_error and passed back to the caller via the future. - */ -template< typename Allocator = std::allocator< void > > -class use_future_t : public promise_completion_token< Allocator > { -public: - /// Construct using default-constructed allocator. - BOOST_CONSTEXPR use_future_t() { - } - - /// Construct using specified allocator. - explicit use_future_t( Allocator const& allocator) : - promise_completion_token( allocator) { - } - - /// Specify an alternate allocator. - template< typename OtherAllocator > - use_future_t< OtherAllocator > operator[]( OtherAllocator const& allocator) const { - return use_future_t< OtherAllocator >( allocator); - } -}; - -/// A special value, similar to std::nothrow. -BOOST_CONSTEXPR_OR_CONST use_future_t<> use_future; - -}}} // namespace asio - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#include "detail/use_future.hpp" - -#endif // BOOST_FIBERS_ASIO_USE_FUTURE_HPP diff --git a/examples/asio/yield.hpp b/examples/asio/yield.hpp index 1e32e626..93805865 100644 --- a/examples/asio/yield.hpp +++ b/examples/asio/yield.hpp @@ -13,9 +13,9 @@ #ifndef BOOST_FIBERS_ASIO_YIELD_HPP #define BOOST_FIBERS_ASIO_YIELD_HPP -#include // std::allocator +#include + #include -#include "promise_completion_token.hpp" #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX @@ -25,96 +25,21 @@ namespace boost { namespace fibers { namespace asio { -/// Class used to specify that a Boost.Asio asynchronous operation should -/// suspend the calling fiber until completion. -/** - * The yield_t class is used to indicate that a Boost.Asio asynchronous - * operation should suspend the calling fiber until its completion. The - * asynchronous function will either return a suitable value, or will throw an - * exception indicating the error. A yield_t object may be passed as a handler - * to an asynchronous operation, typically using the special value @c - * boost::fibers::asio::yield. For example: - * - * @code std::size_t length_read - * = my_socket.async_read_some(my_buffer, boost::fibers::asio::yield); @endcode - * - * The initiating function (async_read_some in the above example) does not - * return to the calling fiber until the asynchronous read has completed. Like - * its synchronous counterpart, it returns the result of the operation. If the - * operation completes with an error_code indicating failure, it is converted - * into a system_error and thrown as an exception. - * - * To suppress a possible error exception: - * @code - * boost::system::error_code ec; - * std::size_t length_read = - * my_socket.async_read_some(my_buffer, boost::fibers::asio::yield[ec]); - * // test ec for success - * @endcode - * - * The crucial distinction between - * @code - * std::size_t length_read = my_socket.read_some(my_buffer); - * @endcode - * and - * @code - * std::size_t length_read = - * my_socket.async_read_some(my_buffer, boost::fibers::asio::yield); - * @code - * is that read_some() blocks the entire calling @em thread, whereas - * async_read_some(..., boost::fibers::asio::yield) blocks only the - * calling @em fiber, permitting other fibers on the same thread to continue - * running. - * - * To specify an alternate allocator for the internal - * boost::fibers::promise: - * @code - * boost::fibers::asio::yield.with(alloc_instance) - * @endcode - * - * To bind a boost::system::error_code @a ec as well as using an - * alternate allocator: - * @code - * boost::fibers::asio::yield.with(alloc_instance)[ec] - * @endcode - */ -//[fibers_asio_yield_t -template< typename Allocator = std::allocator< void > > -class yield_t : public promise_completion_token< Allocator > { +class yield_t { public: - /// Construct with default-constructed allocator. - BOOST_CONSTEXPR yield_t() { - } -/*= // ... ways to use an alternate allocator or bind an error_code ...*/ -/*=};*/ -//] + constexpr yield_t() = default; - /// Construct using specified allocator. - explicit yield_t( Allocator const& allocator) : - promise_completion_token< Allocator >( allocator) { - } - - /// Specify an alternate allocator. - template< typename OtherAllocator > - yield_t< OtherAllocator > with( OtherAllocator const& allocator) const { - return yield_t< OtherAllocator >( allocator); - } - - /// Bind an error_code to suppress error exception. yield_t operator[]( boost::system::error_code & ec) const { - // Return a copy because typical usage will be on our canonical - // instance. Don't leave the canonical instance with a dangling - // binding to a transient error_code! yield_t tmp; tmp.ec_ = & ec; return tmp; } + +//private: + boost::system::error_code * ec_{ nullptr }; }; -//[fibers_asio_yield -/// A special value, similar to std::nothrow. -BOOST_CONSTEXPR_OR_CONST yield_t<> yield; -//] +BOOST_CONSTEXPR_OR_CONST yield_t yield; }}}