Chris@16: // Chris@16: // impl/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_IMPL_SPAWN_HPP Chris@16: #define BOOST_ASIO_IMPL_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@16: #include Chris@101: #include Chris@16: #include Chris@16: #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: namespace detail { Chris@16: Chris@16: template Chris@16: class coro_handler Chris@16: { Chris@16: public: Chris@16: coro_handler(basic_yield_context ctx) Chris@16: : coro_(ctx.coro_.lock()), Chris@16: ca_(ctx.ca_), Chris@16: handler_(ctx.handler_), Chris@101: ready_(0), Chris@16: ec_(ctx.ec_), Chris@16: value_(0) Chris@16: { Chris@16: } Chris@16: Chris@16: void operator()(T value) Chris@16: { Chris@16: *ec_ = boost::system::error_code(); Chris@101: *value_ = BOOST_ASIO_MOVE_CAST(T)(value); Chris@101: if (--*ready_ == 0) Chris@101: (*coro_)(); Chris@16: } Chris@16: Chris@16: void operator()(boost::system::error_code ec, T value) Chris@16: { Chris@16: *ec_ = ec; Chris@101: *value_ = BOOST_ASIO_MOVE_CAST(T)(value); Chris@101: if (--*ready_ == 0) Chris@101: (*coro_)(); Chris@16: } Chris@16: Chris@16: //private: Chris@16: shared_ptr::callee_type> coro_; Chris@16: typename basic_yield_context::caller_type& ca_; Chris@16: Handler& handler_; Chris@101: atomic_count* ready_; Chris@16: boost::system::error_code* ec_; Chris@16: T* value_; Chris@16: }; Chris@16: Chris@16: template Chris@16: class coro_handler Chris@16: { Chris@16: public: Chris@16: coro_handler(basic_yield_context ctx) Chris@16: : coro_(ctx.coro_.lock()), Chris@16: ca_(ctx.ca_), Chris@16: handler_(ctx.handler_), Chris@101: ready_(0), Chris@16: ec_(ctx.ec_) Chris@16: { Chris@16: } Chris@16: Chris@16: void operator()() Chris@16: { Chris@16: *ec_ = boost::system::error_code(); Chris@101: if (--*ready_ == 0) Chris@101: (*coro_)(); Chris@16: } Chris@16: Chris@16: void operator()(boost::system::error_code ec) Chris@16: { Chris@16: *ec_ = ec; Chris@101: if (--*ready_ == 0) Chris@101: (*coro_)(); Chris@16: } Chris@16: Chris@16: //private: Chris@16: shared_ptr::callee_type> coro_; Chris@16: typename basic_yield_context::caller_type& ca_; Chris@16: Handler& handler_; Chris@101: atomic_count* ready_; Chris@16: boost::system::error_code* ec_; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void* asio_handler_allocate(std::size_t size, Chris@16: coro_handler* this_handler) Chris@16: { Chris@16: return boost_asio_handler_alloc_helpers::allocate( Chris@16: size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_deallocate(void* pointer, std::size_t size, Chris@16: coro_handler* this_handler) Chris@16: { Chris@16: boost_asio_handler_alloc_helpers::deallocate( Chris@16: pointer, size, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool asio_handler_is_continuation(coro_handler*) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(Function& function, Chris@16: coro_handler* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void asio_handler_invoke(const Function& function, Chris@16: coro_handler* this_handler) Chris@16: { Chris@16: boost_asio_handler_invoke_helpers::invoke( Chris@16: function, this_handler->handler_); Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: #if !defined(GENERATING_DOCUMENTATION) Chris@16: Chris@16: template Chris@16: struct handler_type, ReturnType()> Chris@16: { Chris@16: typedef detail::coro_handler type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct handler_type, ReturnType(Arg1)> Chris@16: { Chris@16: typedef detail::coro_handler type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct handler_type, Chris@16: ReturnType(boost::system::error_code)> Chris@16: { Chris@16: typedef detail::coro_handler type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct handler_type, Chris@16: ReturnType(boost::system::error_code, Arg2)> Chris@16: { Chris@16: typedef detail::coro_handler type; Chris@16: }; Chris@16: Chris@16: template Chris@16: class async_result > Chris@16: { Chris@16: public: Chris@16: typedef T type; Chris@16: Chris@16: explicit async_result(detail::coro_handler& h) Chris@101: : handler_(h), Chris@101: ca_(h.ca_), Chris@101: ready_(2) Chris@16: { Chris@101: h.ready_ = &ready_; Chris@16: out_ec_ = h.ec_; Chris@16: if (!out_ec_) h.ec_ = &ec_; Chris@16: h.value_ = &value_; Chris@16: } Chris@16: Chris@16: type get() Chris@16: { Chris@101: handler_.coro_.reset(); // Must not hold shared_ptr to coro while suspended. Chris@101: if (--ready_ != 0) Chris@101: ca_(); Chris@16: if (!out_ec_ && ec_) throw boost::system::system_error(ec_); Chris@101: return BOOST_ASIO_MOVE_CAST(type)(value_); Chris@16: } Chris@16: Chris@16: private: Chris@101: detail::coro_handler& handler_; Chris@16: typename basic_yield_context::caller_type& ca_; Chris@101: detail::atomic_count ready_; Chris@16: boost::system::error_code* out_ec_; Chris@16: boost::system::error_code ec_; Chris@16: type value_; Chris@16: }; Chris@16: Chris@16: template Chris@16: class async_result > Chris@16: { Chris@16: public: Chris@16: typedef void type; Chris@16: Chris@16: explicit async_result(detail::coro_handler& h) Chris@101: : handler_(h), Chris@101: ca_(h.ca_), Chris@101: ready_(2) Chris@16: { Chris@101: h.ready_ = &ready_; Chris@16: out_ec_ = h.ec_; Chris@16: if (!out_ec_) h.ec_ = &ec_; Chris@16: } Chris@16: Chris@16: void get() Chris@16: { Chris@101: handler_.coro_.reset(); // Must not hold shared_ptr to coro while suspended. Chris@101: if (--ready_ != 0) Chris@101: ca_(); Chris@16: if (!out_ec_ && ec_) throw boost::system::system_error(ec_); Chris@16: } Chris@16: Chris@16: private: Chris@101: detail::coro_handler& handler_; Chris@16: typename basic_yield_context::caller_type& ca_; Chris@101: detail::atomic_count ready_; Chris@16: boost::system::error_code* out_ec_; Chris@16: boost::system::error_code ec_; Chris@16: }; Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: struct spawn_data : private noncopyable Chris@16: { Chris@16: spawn_data(BOOST_ASIO_MOVE_ARG(Handler) handler, Chris@16: bool call_handler, BOOST_ASIO_MOVE_ARG(Function) function) Chris@16: : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), Chris@16: call_handler_(call_handler), Chris@16: function_(BOOST_ASIO_MOVE_CAST(Function)(function)) Chris@16: { Chris@16: } Chris@16: Chris@16: weak_ptr::callee_type> coro_; Chris@16: Handler handler_; Chris@16: bool call_handler_; Chris@16: Function function_; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct coro_entry_point Chris@16: { Chris@16: void operator()(typename basic_yield_context::caller_type& ca) Chris@16: { Chris@16: shared_ptr > data(data_); Chris@101: #if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) Chris@16: ca(); // Yield until coroutine pointer has been initialised. Chris@101: #endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) Chris@16: const basic_yield_context yield( Chris@16: data->coro_, ca, data->handler_); Chris@16: (data->function_)(yield); Chris@16: if (data->call_handler_) Chris@16: (data->handler_)(); Chris@16: } Chris@16: Chris@16: shared_ptr > data_; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct spawn_helper Chris@16: { Chris@16: void operator()() Chris@16: { Chris@16: typedef typename basic_yield_context::callee_type callee_type; Chris@16: coro_entry_point entry_point = { data_ }; Chris@16: shared_ptr coro(new callee_type(entry_point, attributes_)); Chris@16: data_->coro_ = coro; Chris@16: (*coro)(); Chris@16: } Chris@16: Chris@16: shared_ptr > data_; Chris@16: boost::coroutines::attributes attributes_; Chris@16: }; Chris@16: Chris@16: inline void default_spawn_handler() {} Chris@16: Chris@16: } // namespace detail 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: { Chris@16: detail::spawn_helper helper; Chris@16: helper.data_.reset( Chris@16: new detail::spawn_data( Chris@16: BOOST_ASIO_MOVE_CAST(Handler)(handler), true, Chris@16: BOOST_ASIO_MOVE_CAST(Function)(function))); Chris@16: helper.attributes_ = attributes; Chris@16: boost_asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_); Chris@16: } 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: { Chris@16: Handler handler(ctx.handler_); // Explicit copy that might be moved from. Chris@16: detail::spawn_helper helper; Chris@16: helper.data_.reset( Chris@16: new detail::spawn_data( Chris@16: BOOST_ASIO_MOVE_CAST(Handler)(handler), false, Chris@16: BOOST_ASIO_MOVE_CAST(Function)(function))); Chris@16: helper.attributes_ = attributes; Chris@16: boost_asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_); Chris@16: } 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: { Chris@16: boost::asio::spawn(strand.wrap(&detail::default_spawn_handler), Chris@16: BOOST_ASIO_MOVE_CAST(Function)(function), attributes); Chris@16: } 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: { Chris@16: boost::asio::spawn(boost::asio::io_service::strand(io_service), Chris@16: BOOST_ASIO_MOVE_CAST(Function)(function), attributes); Chris@16: } Chris@16: Chris@16: #endif // !defined(GENERATING_DOCUMENTATION) Chris@16: Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_IMPL_SPAWN_HPP