blob: 02e3d89c9bc4eff2108caf1c37671fb7256ff990 [file] [log] [blame]
//
// impl/spawn.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2012 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)
//
#ifndef ASIO_IMPL_SPAWN_HPP
#define ASIO_IMPL_SPAWN_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/shared_ptr.hpp"
#include "asio/handler_type.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Handler, typename T>
class coro_handler
{
public:
coro_handler(basic_yield_context<Handler> ctx)
: coro_(ctx.coro_.lock()),
ca_(ctx.ca_),
handler_(ctx.handler_),
ec_(ctx.ec_),
value_(0)
{
}
void operator()(T value)
{
*ec_ = asio::error_code();
*value_ = value;
(*coro_)();
}
void operator()(asio::error_code ec, T value)
{
*ec_ = ec;
*value_ = value;
(*coro_)();
}
//private:
detail::shared_ptr<boost::coroutines::coroutine<void()> > coro_;
boost::coroutines::coroutine<void()>::caller_type& ca_;
Handler& handler_;
asio::error_code* ec_;
T* value_;
};
template <typename Handler>
class coro_handler<Handler, void>
{
public:
coro_handler(basic_yield_context<Handler> ctx)
: coro_(ctx.coro_.lock()),
ca_(ctx.ca_),
handler_(ctx.handler_),
ec_(ctx.ec_)
{
}
void operator()()
{
*ec_ = asio::error_code();
(*coro_)();
}
void operator()(asio::error_code ec)
{
*ec_ = ec;
(*coro_)();
}
//private:
detail::shared_ptr<boost::coroutines::coroutine<void()> > coro_;
boost::coroutines::coroutine<void()>::caller_type& ca_;
Handler& handler_;
asio::error_code* ec_;
};
template <typename Handler, typename T>
inline void* asio_handler_allocate(std::size_t size,
coro_handler<Handler, T>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename T>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
coro_handler<Handler, T>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Function, typename Handler, typename T>
inline void asio_handler_invoke(Function& function,
coro_handler<Handler, T>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Handler, typename T>
inline void asio_handler_invoke(const Function& function,
coro_handler<Handler, T>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
} // namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <typename Handler, typename ReturnType>
struct handler_type<basic_yield_context<Handler>, ReturnType()>
{
typedef detail::coro_handler<Handler, void> type;
};
template <typename Handler, typename ReturnType, typename Arg1>
struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)>
{
typedef detail::coro_handler<Handler, Arg1> type;
};
template <typename Handler, typename ReturnType>
struct handler_type<basic_yield_context<Handler>,
ReturnType(asio::error_code)>
{
typedef detail::coro_handler<Handler, void> type;
};
template <typename Handler, typename ReturnType, typename Arg2>
struct handler_type<basic_yield_context<Handler>,
ReturnType(asio::error_code, Arg2)>
{
typedef detail::coro_handler<Handler, Arg2> type;
};
template <typename Handler, typename T>
class async_result<detail::coro_handler<Handler, T> >
{
public:
typedef T type;
explicit async_result(detail::coro_handler<Handler, T>& h)
: ca_(h.ca_)
{
out_ec_ = h.ec_;
if (!out_ec_) h.ec_ = &ec_;
h.value_ = &value_;
}
type get()
{
ca_();
if (!out_ec_ && ec_) throw asio::system_error(ec_);
return value_;
}
private:
boost::coroutines::coroutine<void()>::caller_type& ca_;
asio::error_code* out_ec_;
asio::error_code ec_;
type value_;
};
template <typename Handler>
class async_result<detail::coro_handler<Handler, void> >
{
public:
typedef void type;
explicit async_result(detail::coro_handler<Handler, void>& h)
: ca_(h.ca_)
{
out_ec_ = h.ec_;
if (!out_ec_) h.ec_ = &ec_;
}
void get()
{
ca_();
if (!out_ec_ && ec_) throw asio::system_error(ec_);
}
private:
boost::coroutines::coroutine<void()>::caller_type& ca_;
asio::error_code* out_ec_;
asio::error_code ec_;
};
namespace detail {
template <typename Handler, typename Function>
struct spawn_data : private noncopyable
{
spawn_data(ASIO_MOVE_ARG(Handler) handler,
bool call_handler, ASIO_MOVE_ARG(Function) function)
: handler_(ASIO_MOVE_CAST(Handler)(handler)),
call_handler_(call_handler),
function_(ASIO_MOVE_CAST(Function)(function))
{
}
weak_ptr<boost::coroutines::coroutine<void()> > coro_;
Handler handler_;
bool call_handler_;
Function function_;
};
template <typename Handler, typename Function>
struct coro_entry_point
{
void operator()(boost::coroutines::coroutine<void()>::caller_type& ca)
{
shared_ptr<spawn_data<Handler, Function> > data(data_);
ca(); // Yield until coroutine pointer has been initialised.
const basic_yield_context<Handler> yield(
data->coro_, ca, data->handler_);
(data->function_)(yield);
if (data->call_handler_)
(data->handler_)();
}
shared_ptr<spawn_data<Handler, Function> > data_;
};
template <typename Handler, typename Function>
struct spawn_helper
{
void operator()()
{
coro_entry_point<Handler, Function> entry_point = { data_ };
shared_ptr<boost::coroutines::coroutine<void()> > coro(
new boost::coroutines::coroutine<void()>(entry_point, attributes_));
data_->coro_ = coro;
(*coro)();
}
shared_ptr<spawn_data<Handler, Function> > data_;
boost::coroutines::attributes attributes_;
};
inline void default_spawn_handler() {}
} // namespace detail
template <typename Handler, typename Function>
void spawn(ASIO_MOVE_ARG(Handler) handler,
ASIO_MOVE_ARG(Function) function,
const boost::coroutines::attributes& attributes)
{
detail::spawn_helper<Handler, Function> helper;
helper.data_.reset(
new detail::spawn_data<Handler, Function>(
ASIO_MOVE_CAST(Handler)(handler), true,
ASIO_MOVE_CAST(Function)(function)));
helper.attributes_ = attributes;
asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_);
}
template <typename Handler, typename Function>
void spawn(basic_yield_context<Handler> ctx,
ASIO_MOVE_ARG(Function) function,
const boost::coroutines::attributes& attributes)
{
Handler handler(ctx.handler_); // Explicit copy that might be moved from.
detail::spawn_helper<Handler, Function> helper;
helper.data_.reset(
new detail::spawn_data<Handler, Function>(
ASIO_MOVE_CAST(Handler)(handler), false,
ASIO_MOVE_CAST(Function)(function)));
helper.attributes_ = attributes;
asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_);
}
template <typename Function>
void spawn(asio::io_service::strand strand,
ASIO_MOVE_ARG(Function) function,
const boost::coroutines::attributes& attributes)
{
asio::spawn(strand.wrap(&detail::default_spawn_handler),
ASIO_MOVE_CAST(Function)(function), attributes);
}
template <typename Function>
void spawn(asio::io_service& io_service,
ASIO_MOVE_ARG(Function) function,
const boost::coroutines::attributes& attributes)
{
asio::spawn(asio::io_service::strand(io_service),
ASIO_MOVE_CAST(Function)(function), attributes);
}
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IMPL_SPAWN_HPP