Chris@16: // Chris@16: // spawn.hpp Chris@16: // ~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_SPAWN_HPP Chris@16: #define BOOST_ASIO_SPAWN_HPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: Chris@16: /// Context object the represents the currently executing coroutine. Chris@16: /** Chris@16: * The basic_yield_context class is used to represent the currently executing Chris@16: * stackful coroutine. A basic_yield_context may be passed as a handler to an Chris@16: * asynchronous operation. For example: Chris@16: * Chris@16: * @code template Chris@16: * void my_coroutine(basic_yield_context yield) Chris@16: * { Chris@16: * ... Chris@16: * std::size_t n = my_socket.async_read_some(buffer, yield); Chris@16: * ... Chris@16: * } @endcode Chris@16: * Chris@16: * The initiating function (async_read_some in the above example) suspends the Chris@16: * current coroutine. The coroutine is resumed when the asynchronous operation Chris@16: * completes, and the result of the operation is returned. Chris@16: */ Chris@16: template Chris@16: class basic_yield_context Chris@16: { Chris@16: public: Chris@16: /// The coroutine callee type, used by the implementation. Chris@16: /** Chris@16: * When using Boost.Coroutine v1, this type is: Chris@16: * @code typename coroutine @endcode Chris@16: * When using Boost.Coroutine v2 (unidirectional coroutines), this type is: Chris@16: * @code push_coroutine @endcode Chris@16: */ Chris@16: #if defined(GENERATING_DOCUMENTATION) Chris@16: typedef implementation_defined callee_type; Chris@101: #elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2) Chris@16: typedef boost::coroutines::push_coroutine callee_type; Chris@16: #else Chris@16: typedef boost::coroutines::coroutine callee_type; Chris@16: #endif Chris@16: Chris@16: /// The coroutine caller type, used by the implementation. Chris@16: /** Chris@16: * When using Boost.Coroutine v1, this type is: Chris@16: * @code typename coroutine::caller_type @endcode Chris@16: * When using Boost.Coroutine v2 (unidirectional coroutines), this type is: Chris@16: * @code pull_coroutine @endcode Chris@16: */ Chris@16: #if defined(GENERATING_DOCUMENTATION) Chris@16: typedef implementation_defined caller_type; Chris@101: #elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2) Chris@16: typedef boost::coroutines::pull_coroutine caller_type; Chris@16: #else Chris@16: typedef boost::coroutines::coroutine::caller_type caller_type; Chris@16: #endif Chris@16: Chris@16: /// Construct a yield context to represent the specified coroutine. Chris@16: /** Chris@16: * Most applications do not need to use this constructor. Instead, the Chris@16: * spawn() function passes a yield context as an argument to the coroutine Chris@16: * function. Chris@16: */ Chris@16: basic_yield_context( Chris@16: const detail::weak_ptr& coro, Chris@16: caller_type& ca, Handler& handler) Chris@16: : coro_(coro), Chris@16: ca_(ca), Chris@16: handler_(handler), Chris@16: ec_(0) Chris@16: { Chris@16: } Chris@16: Chris@16: /// Return a yield context that sets the specified error_code. Chris@16: /** Chris@16: * By default, when a yield context is used with an asynchronous operation, a Chris@16: * non-success error_code is converted to system_error and thrown. This Chris@16: * operator may be used to specify an error_code object that should instead be Chris@16: * set with the asynchronous operation's result. For example: Chris@16: * Chris@16: * @code template Chris@16: * void my_coroutine(basic_yield_context yield) Chris@16: * { Chris@16: * ... Chris@16: * std::size_t n = my_socket.async_read_some(buffer, yield[ec]); Chris@16: * if (ec) Chris@16: * { Chris@16: * // An error occurred. Chris@16: * } Chris@16: * ... Chris@16: * } @endcode Chris@16: */ Chris@16: basic_yield_context operator[](boost::system::error_code& ec) const Chris@16: { Chris@16: basic_yield_context tmp(*this); Chris@16: tmp.ec_ = &ec; Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: #if defined(GENERATING_DOCUMENTATION) Chris@16: private: Chris@16: #endif // defined(GENERATING_DOCUMENTATION) Chris@16: detail::weak_ptr coro_; Chris@16: caller_type& ca_; Chris@16: Handler& handler_; Chris@16: boost::system::error_code* ec_; Chris@16: }; Chris@16: Chris@16: #if defined(GENERATING_DOCUMENTATION) Chris@16: /// Context object that represents the currently executing coroutine. Chris@16: typedef basic_yield_context yield_context; Chris@16: #else // defined(GENERATING_DOCUMENTATION) Chris@16: typedef basic_yield_context< Chris@16: detail::wrapped_handler< Chris@16: io_service::strand, void(*)(), Chris@16: detail::is_continuation_if_running> > yield_context; Chris@16: #endif // defined(GENERATING_DOCUMENTATION) Chris@16: Chris@16: /** Chris@16: * @defgroup spawn boost::asio::spawn Chris@16: * Chris@16: * @brief Start a new stackful coroutine. Chris@16: * Chris@16: * The spawn() function is a high-level wrapper over the Boost.Coroutine Chris@16: * library. This function enables programs to implement asynchronous logic in a Chris@16: * synchronous manner, as illustrated by the following example: Chris@16: * Chris@16: * @code boost::asio::spawn(my_strand, do_echo); Chris@16: * Chris@16: * // ... Chris@16: * Chris@16: * void do_echo(boost::asio::yield_context yield) Chris@16: * { Chris@16: * try Chris@16: * { Chris@16: * char data[128]; Chris@16: * for (;;) Chris@16: * { Chris@16: * std::size_t length = Chris@16: * my_socket.async_read_some( Chris@16: * boost::asio::buffer(data), yield); Chris@16: * Chris@16: * boost::asio::async_write(my_socket, Chris@16: * boost::asio::buffer(data, length), yield); Chris@16: * } Chris@16: * } Chris@16: * catch (std::exception& e) Chris@16: * { Chris@16: * // ... Chris@16: * } Chris@16: * } @endcode Chris@16: */ Chris@16: /*@{*/ Chris@16: Chris@16: /// Start a new stackful coroutine, calling the specified handler when it Chris@16: /// completes. Chris@16: /** Chris@16: * This function is used to launch a new coroutine. Chris@16: * Chris@16: * @param handler A handler to be called when the coroutine exits. More Chris@16: * importantly, the handler provides an execution context (via the the handler Chris@16: * invocation hook) for the coroutine. The handler must have the signature: Chris@16: * @code void handler(); @endcode Chris@16: * Chris@16: * @param function The coroutine function. The function must have the signature: Chris@16: * @code void function(basic_yield_context yield); @endcode Chris@16: * Chris@16: * @param attributes Boost.Coroutine attributes used to customise the coroutine. Chris@16: */ Chris@16: template Chris@16: void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler, Chris@16: BOOST_ASIO_MOVE_ARG(Function) function, Chris@16: const boost::coroutines::attributes& attributes Chris@16: = boost::coroutines::attributes()); Chris@16: Chris@16: /// Start a new stackful coroutine, inheriting the execution context of another. Chris@16: /** Chris@16: * This function is used to launch a new coroutine. Chris@16: * Chris@16: * @param ctx Identifies the current coroutine as a parent of the new Chris@16: * coroutine. This specifies that the new coroutine should inherit the Chris@16: * execution context of the parent. For example, if the parent coroutine is Chris@16: * executing in a particular strand, then the new coroutine will execute in the Chris@16: * same strand. Chris@16: * Chris@16: * @param function The coroutine function. The function must have the signature: Chris@16: * @code void function(basic_yield_context yield); @endcode Chris@16: * Chris@16: * @param attributes Boost.Coroutine attributes used to customise the coroutine. Chris@16: */ Chris@16: template Chris@16: void spawn(basic_yield_context ctx, Chris@16: BOOST_ASIO_MOVE_ARG(Function) function, Chris@16: const boost::coroutines::attributes& attributes Chris@16: = boost::coroutines::attributes()); Chris@16: Chris@16: /// Start a new stackful coroutine that executes in the context of a strand. Chris@16: /** Chris@16: * This function is used to launch a new coroutine. Chris@16: * Chris@16: * @param strand Identifies a strand. By starting multiple coroutines on the Chris@16: * same strand, the implementation ensures that none of those coroutines can Chris@16: * execute simultaneously. Chris@16: * Chris@16: * @param function The coroutine function. The function must have the signature: Chris@16: * @code void function(yield_context yield); @endcode Chris@16: * Chris@16: * @param attributes Boost.Coroutine attributes used to customise the coroutine. Chris@16: */ Chris@16: template Chris@16: void spawn(boost::asio::io_service::strand strand, Chris@16: BOOST_ASIO_MOVE_ARG(Function) function, Chris@16: const boost::coroutines::attributes& attributes Chris@16: = boost::coroutines::attributes()); Chris@16: Chris@16: /// Start a new stackful coroutine that executes on a given io_service. Chris@16: /** Chris@16: * This function is used to launch a new coroutine. Chris@16: * Chris@16: * @param io_service Identifies the io_service that will run the coroutine. The Chris@16: * new coroutine is implicitly given its own strand within this io_service. Chris@16: * Chris@16: * @param function The coroutine function. The function must have the signature: Chris@16: * @code void function(yield_context yield); @endcode Chris@16: * Chris@16: * @param attributes Boost.Coroutine attributes used to customise the coroutine. Chris@16: */ Chris@16: template Chris@16: void spawn(boost::asio::io_service& io_service, Chris@16: BOOST_ASIO_MOVE_ARG(Function) function, Chris@16: const boost::coroutines::attributes& attributes Chris@16: = boost::coroutines::attributes()); Chris@16: Chris@16: /*@}*/ Chris@16: Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_SPAWN_HPP