Promote coroutines TS support classes to asio namespace.
The awaitable<>, co_spawn(), this_coro, detached, and redirect_error facilities have been moved from the asio::experimental namespace to namespace asio. As part of this change, the this_coro::token() awaitable has been superseded by the asio::use_awaitable completion token. Please note that the use_awaitable and redirect_error completion tokens work only with asynchronous operations that use the new form of async_result with member function initiate(). Furthermore, when using use_awaitable, please be aware that the asynchronous operation is not initiated until co_await is applied to the awaitable<>.
This commit is contained in:
parent
171a02ed0d
commit
490743a662
@ -3,6 +3,7 @@ nobase_include_HEADERS = \
|
||||
asio/associated_allocator.hpp \
|
||||
asio/associated_executor.hpp \
|
||||
asio/async_result.hpp \
|
||||
asio/awaitable.hpp \
|
||||
asio/basic_datagram_socket.hpp \
|
||||
asio/basic_deadline_timer.hpp \
|
||||
asio/basic_io_object.hpp \
|
||||
@ -27,11 +28,13 @@ nobase_include_HEADERS = \
|
||||
asio/buffered_write_stream.hpp \
|
||||
asio/buffer.hpp \
|
||||
asio/buffers_iterator.hpp \
|
||||
asio/co_spawn.hpp \
|
||||
asio/completion_condition.hpp \
|
||||
asio/connect.hpp \
|
||||
asio/coroutine.hpp \
|
||||
asio/deadline_timer.hpp \
|
||||
asio/defer.hpp \
|
||||
asio/detached.hpp \
|
||||
asio/detail/array_fwd.hpp \
|
||||
asio/detail/array.hpp \
|
||||
asio/detail/assert.hpp \
|
||||
@ -289,13 +292,6 @@ nobase_include_HEADERS = \
|
||||
asio/execution_context.hpp \
|
||||
asio/executor.hpp \
|
||||
asio/executor_work_guard.hpp \
|
||||
asio/experimental/co_spawn.hpp \
|
||||
asio/experimental/detached.hpp \
|
||||
asio/experimental.hpp \
|
||||
asio/experimental/impl/co_spawn.hpp \
|
||||
asio/experimental/impl/detached.hpp \
|
||||
asio/experimental/impl/redirect_error.hpp \
|
||||
asio/experimental/redirect_error.hpp \
|
||||
asio/generic/basic_endpoint.hpp \
|
||||
asio/generic/datagram_protocol.hpp \
|
||||
asio/generic/detail/endpoint.hpp \
|
||||
@ -308,10 +304,13 @@ nobase_include_HEADERS = \
|
||||
asio/handler_invoke_hook.hpp \
|
||||
asio/high_resolution_timer.hpp \
|
||||
asio.hpp \
|
||||
asio/impl/awaitable.hpp \
|
||||
asio/impl/buffered_read_stream.hpp \
|
||||
asio/impl/buffered_write_stream.hpp \
|
||||
asio/impl/co_spawn.hpp \
|
||||
asio/impl/connect.hpp \
|
||||
asio/impl/defer.hpp \
|
||||
asio/impl/detached.hpp \
|
||||
asio/impl/dispatch.hpp \
|
||||
asio/impl/error_code.ipp \
|
||||
asio/impl/error.ipp \
|
||||
@ -326,6 +325,7 @@ nobase_include_HEADERS = \
|
||||
asio/impl/read_at.hpp \
|
||||
asio/impl/read.hpp \
|
||||
asio/impl/read_until.hpp \
|
||||
asio/impl/redirect_error.hpp \
|
||||
asio/impl/serial_port_base.hpp \
|
||||
asio/impl/serial_port_base.ipp \
|
||||
asio/impl/spawn.hpp \
|
||||
@ -336,6 +336,7 @@ nobase_include_HEADERS = \
|
||||
asio/impl/system_executor.hpp \
|
||||
asio/impl/thread_pool.hpp \
|
||||
asio/impl/thread_pool.ipp \
|
||||
asio/impl/use_awaitable.hpp \
|
||||
asio/impl/use_future.hpp \
|
||||
asio/impl/write_at.hpp \
|
||||
asio/impl/write.hpp \
|
||||
@ -403,6 +404,7 @@ nobase_include_HEADERS = \
|
||||
asio/read_at.hpp \
|
||||
asio/read.hpp \
|
||||
asio/read_until.hpp \
|
||||
asio/redirect_error.hpp \
|
||||
asio/serial_port_base.hpp \
|
||||
asio/serial_port.hpp \
|
||||
asio/signal_set.hpp \
|
||||
@ -443,6 +445,7 @@ nobase_include_HEADERS = \
|
||||
asio/system_error.hpp \
|
||||
asio/system_executor.hpp \
|
||||
asio/system_timer.hpp \
|
||||
asio/this_coro.hpp \
|
||||
asio/thread.hpp \
|
||||
asio/thread_pool.hpp \
|
||||
asio/time_traits.hpp \
|
||||
@ -455,6 +458,7 @@ nobase_include_HEADERS = \
|
||||
asio/ts/socket.hpp \
|
||||
asio/ts/timer.hpp \
|
||||
asio/unyield.hpp \
|
||||
asio/use_awaitable.hpp \
|
||||
asio/use_future.hpp \
|
||||
asio/uses_executor.hpp \
|
||||
asio/version.hpp \
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "asio/associated_allocator.hpp"
|
||||
#include "asio/associated_executor.hpp"
|
||||
#include "asio/async_result.hpp"
|
||||
#include "asio/awaitable.hpp"
|
||||
#include "asio/basic_datagram_socket.hpp"
|
||||
#include "asio/basic_deadline_timer.hpp"
|
||||
#include "asio/basic_io_object.hpp"
|
||||
@ -41,11 +42,13 @@
|
||||
#include "asio/buffered_write_stream_fwd.hpp"
|
||||
#include "asio/buffered_write_stream.hpp"
|
||||
#include "asio/buffers_iterator.hpp"
|
||||
#include "asio/co_spawn.hpp"
|
||||
#include "asio/completion_condition.hpp"
|
||||
#include "asio/connect.hpp"
|
||||
#include "asio/coroutine.hpp"
|
||||
#include "asio/deadline_timer.hpp"
|
||||
#include "asio/defer.hpp"
|
||||
#include "asio/detached.hpp"
|
||||
#include "asio/dispatch.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/error_code.hpp"
|
||||
@ -105,6 +108,7 @@
|
||||
#include "asio/read.hpp"
|
||||
#include "asio/read_at.hpp"
|
||||
#include "asio/read_until.hpp"
|
||||
#include "asio/redirect_error.hpp"
|
||||
#include "asio/serial_port.hpp"
|
||||
#include "asio/serial_port_base.hpp"
|
||||
#include "asio/signal_set.hpp"
|
||||
@ -116,9 +120,11 @@
|
||||
#include "asio/system_error.hpp"
|
||||
#include "asio/system_executor.hpp"
|
||||
#include "asio/system_timer.hpp"
|
||||
#include "asio/this_coro.hpp"
|
||||
#include "asio/thread.hpp"
|
||||
#include "asio/thread_pool.hpp"
|
||||
#include "asio/time_traits.hpp"
|
||||
#include "asio/use_awaitable.hpp"
|
||||
#include "asio/use_future.hpp"
|
||||
#include "asio/uses_executor.hpp"
|
||||
#include "asio/version.hpp"
|
||||
|
123
asio/include/asio/awaitable.hpp
Normal file
123
asio/include/asio/awaitable.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
//
|
||||
// awaitable.hpp
|
||||
// ~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_AWAITABLE_HPP
|
||||
#define ASIO_AWAITABLE_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
|
||||
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include <experimental/coroutine>
|
||||
#include "asio/executor.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
using std::experimental::coroutine_handle;
|
||||
using std::experimental::suspend_always;
|
||||
|
||||
template <typename> class awaitable_thread;
|
||||
template <typename, typename> class awaitable_frame;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// The return type of a coroutine or asynchronous operation.
|
||||
template <typename T, typename Executor = executor>
|
||||
class awaitable
|
||||
{
|
||||
public:
|
||||
/// The type of the awaited value.
|
||||
typedef T value_type;
|
||||
|
||||
/// The executor type that will be used for the coroutine.
|
||||
typedef Executor executor_type;
|
||||
|
||||
/// Default constructor.
|
||||
constexpr awaitable() noexcept
|
||||
: frame_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/// Move constructor.
|
||||
awaitable(awaitable&& other) noexcept
|
||||
: frame_(std::exchange(other.frame_, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~awaitable()
|
||||
{
|
||||
if (frame_)
|
||||
frame_->destroy();
|
||||
}
|
||||
|
||||
/// Checks if the awaitable refers to a future result.
|
||||
bool valid() const noexcept
|
||||
{
|
||||
return !!frame_;
|
||||
}
|
||||
|
||||
#if !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
// Support for co_await keyword.
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Support for co_await keyword.
|
||||
template <class U>
|
||||
void await_suspend(
|
||||
detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h)
|
||||
{
|
||||
frame_->push_frame(&h.promise());
|
||||
}
|
||||
|
||||
// Support for co_await keyword.
|
||||
T await_resume()
|
||||
{
|
||||
return frame_->get();
|
||||
}
|
||||
|
||||
#endif // !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
private:
|
||||
template <typename> friend class detail::awaitable_thread;
|
||||
template <typename, typename> friend class detail::awaitable_frame;
|
||||
|
||||
// Not copy constructible or copy assignable.
|
||||
awaitable(const awaitable&) = delete;
|
||||
awaitable& operator=(const awaitable&) = delete;
|
||||
|
||||
// Construct the awaitable from a coroutine's frame object.
|
||||
explicit awaitable(detail::awaitable_frame<T, Executor>* a)
|
||||
: frame_(a)
|
||||
{
|
||||
}
|
||||
|
||||
detail::awaitable_frame<T, Executor>* frame_;
|
||||
};
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#include "asio/impl/awaitable.hpp"
|
||||
|
||||
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#endif // ASIO_AWAITABLE_HPP
|
88
asio/include/asio/co_spawn.hpp
Normal file
88
asio/include/asio/co_spawn.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
//
|
||||
// co_spawn.hpp
|
||||
// ~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_CO_SPAWN_HPP
|
||||
#define ASIO_CO_SPAWN_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
|
||||
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include "asio/awaitable.hpp"
|
||||
#include "asio/execution_context.hpp"
|
||||
#include "asio/is_executor.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct awaitable_signature;
|
||||
|
||||
template <typename T, typename Executor>
|
||||
struct awaitable_signature<awaitable<T, Executor>>
|
||||
{
|
||||
typedef void type(std::exception_ptr, T);
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
struct awaitable_signature<awaitable<void, Executor>>
|
||||
{
|
||||
typedef void type(std::exception_ptr);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Spawn a new thread of execution.
|
||||
/**
|
||||
* The entry point function object @c f must have the signature:
|
||||
*
|
||||
* @code awaitable<void, E> f(); @endcode
|
||||
*
|
||||
* where @c E is convertible from @c Executor.
|
||||
*/
|
||||
template <typename Executor, typename F, typename CompletionToken>
|
||||
ASIO_INITFN_RESULT_TYPE(CompletionToken,
|
||||
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
|
||||
co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
|
||||
typename enable_if<
|
||||
is_executor<Executor>::value
|
||||
>::type* = 0);
|
||||
|
||||
/// Spawn a new thread of execution.
|
||||
/**
|
||||
* The entry point function object @c f must have the signature:
|
||||
*
|
||||
* @code awaitable<void, E> f(); @endcode
|
||||
*
|
||||
* where @c E is convertible from @c ExecutionContext::executor_type.
|
||||
*/
|
||||
template <typename ExecutionContext, typename F, typename CompletionToken>
|
||||
ASIO_INITFN_RESULT_TYPE(CompletionToken,
|
||||
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
|
||||
co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
|
||||
typename enable_if<
|
||||
is_convertible<ExecutionContext&, execution_context&>::value
|
||||
>::type* = 0);
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#include "asio/impl/co_spawn.hpp"
|
||||
|
||||
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#endif // ASIO_CO_SPAWN_HPP
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
// experimental/detached.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// detached.hpp
|
||||
// ~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_EXPERIMENTAL_DETACHED_HPP
|
||||
#define ASIO_EXPERIMENTAL_DETACHED_HPP
|
||||
#ifndef ASIO_DETACHED_HPP
|
||||
#define ASIO_DETACHED_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@ -21,7 +21,6 @@
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace experimental {
|
||||
|
||||
/// Class used to specify that an asynchronous operation is detached.
|
||||
/**
|
||||
@ -30,9 +29,9 @@ namespace experimental {
|
||||
* detached. That is, there is no completion handler waiting for the
|
||||
* operation's result. A detached_t object may be passed as a handler to an
|
||||
* asynchronous operation, typically using the special value
|
||||
* @c asio::experimental::detached. For example:
|
||||
* @c asio::detached. For example:
|
||||
|
||||
* @code my_socket.async_send(my_buffer, asio::experimental::detached);
|
||||
* @code my_socket.async_send(my_buffer, asio::detached);
|
||||
* @endcode
|
||||
*/
|
||||
class detached_t
|
||||
@ -46,8 +45,7 @@ public:
|
||||
|
||||
/// A special value, similar to std::nothrow.
|
||||
/**
|
||||
* See the documentation for asio::experimental::detached_t for a usage
|
||||
* example.
|
||||
* See the documentation for asio::detached_t for a usage example.
|
||||
*/
|
||||
#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
|
||||
constexpr detached_t detached;
|
||||
@ -55,11 +53,10 @@ constexpr detached_t detached;
|
||||
__declspec(selectany) detached_t detached;
|
||||
#endif
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#include "asio/experimental/impl/detached.hpp"
|
||||
#include "asio/impl/detached.hpp"
|
||||
|
||||
#endif // ASIO_EXPERIMENTAL_DETACHED_HPP
|
||||
#endif // ASIO_DETACHED_HPP
|
@ -33,7 +33,7 @@ public:
|
||||
enum { mem_index = 0 };
|
||||
};
|
||||
|
||||
struct awaitee_tag
|
||||
struct awaitable_frame_tag
|
||||
{
|
||||
enum { mem_index = 1 };
|
||||
};
|
||||
|
@ -1,22 +0,0 @@
|
||||
//
|
||||
// experimental.hpp
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_EXPERIMENTAL_HPP
|
||||
#define ASIO_EXPERIMENTAL_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/experimental/co_spawn.hpp"
|
||||
#include "asio/experimental/detached.hpp"
|
||||
#include "asio/experimental/redirect_error.hpp"
|
||||
|
||||
#endif // ASIO_EXPERIMENTAL_HPP
|
@ -1,226 +0,0 @@
|
||||
//
|
||||
// experimental/co_spawn.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_EXPERIMENTAL_CO_SPAWN_HPP
|
||||
#define ASIO_EXPERIMENTAL_CO_SPAWN_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
|
||||
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include <experimental/coroutine>
|
||||
#include "asio/executor.hpp"
|
||||
#include "asio/strand.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace experimental {
|
||||
namespace detail {
|
||||
|
||||
using std::experimental::coroutine_handle;
|
||||
|
||||
template <typename> class awaiter;
|
||||
template <typename> class awaitee_base;
|
||||
template <typename, typename> class awaitee;
|
||||
template <typename, typename> class await_handler_base;
|
||||
template <typename Executor, typename F, typename CompletionToken>
|
||||
auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace this_coro {
|
||||
|
||||
/// Awaitable type that returns a completion token for the current coroutine.
|
||||
struct token_t {};
|
||||
|
||||
/// Awaitable object that returns a completion token for the current coroutine.
|
||||
constexpr inline token_t token() { return {}; }
|
||||
|
||||
/// Awaitable type that returns the executor of the current coroutine.
|
||||
struct executor_t {};
|
||||
|
||||
/// Awaitable object that returns the executor of the current coroutine.
|
||||
constexpr inline executor_t executor() { return {}; }
|
||||
|
||||
} // namespace this_coro
|
||||
|
||||
/// A completion token that represents the currently executing coroutine.
|
||||
/**
|
||||
* The await_token class is used to represent the currently executing
|
||||
* coroutine. An await_token may be passed as a handler to an asynchronous
|
||||
* operation. For example:
|
||||
*
|
||||
* @code awaitable<void> my_coroutine()
|
||||
* {
|
||||
* await_token token = co_await this_coro::token();
|
||||
* ...
|
||||
* std::size_t n = co_await my_socket.async_read_some(buffer, token);
|
||||
* ...
|
||||
* } @endcode
|
||||
*
|
||||
* The initiating function (async_read_some in the above example) suspends the
|
||||
* current coroutine. The coroutine is resumed when the asynchronous operation
|
||||
* completes, and the result of the operation is returned.
|
||||
*/
|
||||
template <typename Executor>
|
||||
class await_token
|
||||
{
|
||||
public:
|
||||
/// The associated executor type.
|
||||
typedef Executor executor_type;
|
||||
|
||||
/// Copy constructor.
|
||||
await_token(const await_token& other) noexcept
|
||||
: awaiter_(other.awaiter_)
|
||||
{
|
||||
}
|
||||
|
||||
/// Move constructor.
|
||||
await_token(await_token&& other) noexcept
|
||||
: awaiter_(std::exchange(other.awaiter_, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
/// Get the associated executor.
|
||||
executor_type get_executor() const noexcept
|
||||
{
|
||||
return awaiter_->get_executor();
|
||||
}
|
||||
|
||||
private:
|
||||
// No assignment allowed.
|
||||
await_token& operator=(const await_token&) = delete;
|
||||
|
||||
template <typename> friend class detail::awaitee_base;
|
||||
template <typename, typename> friend class detail::await_handler_base;
|
||||
|
||||
// Private constructor used by awaitee_base.
|
||||
explicit await_token(detail::awaiter<Executor>* a)
|
||||
: awaiter_(a)
|
||||
{
|
||||
}
|
||||
|
||||
detail::awaiter<Executor>* awaiter_;
|
||||
};
|
||||
|
||||
/// The return type of a coroutine or asynchronous operation.
|
||||
template <typename T, typename Executor = strand<executor>>
|
||||
class awaitable
|
||||
{
|
||||
public:
|
||||
/// The type of the awaited value.
|
||||
typedef T value_type;
|
||||
|
||||
/// The executor type that will be used for the coroutine.
|
||||
typedef Executor executor_type;
|
||||
|
||||
/// Move constructor.
|
||||
awaitable(awaitable&& other) noexcept
|
||||
: awaitee_(std::exchange(other.awaitee_, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~awaitable()
|
||||
{
|
||||
if (awaitee_)
|
||||
{
|
||||
detail::coroutine_handle<
|
||||
detail::awaitee<T, Executor>>::from_promise(
|
||||
*awaitee_).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
// Support for co_await keyword.
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return awaitee_->ready();
|
||||
}
|
||||
|
||||
// Support for co_await keyword.
|
||||
void await_suspend(detail::coroutine_handle<detail::awaiter<Executor>> h)
|
||||
{
|
||||
awaitee_->attach_caller(h);
|
||||
}
|
||||
|
||||
// Support for co_await keyword.
|
||||
template <class U>
|
||||
void await_suspend(detail::coroutine_handle<detail::awaitee<U, Executor>> h)
|
||||
{
|
||||
awaitee_->attach_caller(h);
|
||||
}
|
||||
|
||||
// Support for co_await keyword.
|
||||
T await_resume()
|
||||
{
|
||||
return awaitee_->get();
|
||||
}
|
||||
|
||||
#endif // !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
private:
|
||||
template <typename, typename> friend class detail::awaitee;
|
||||
template <typename, typename> friend class detail::await_handler_base;
|
||||
|
||||
// Not copy constructible or copy assignable.
|
||||
awaitable(const awaitable&) = delete;
|
||||
awaitable& operator=(const awaitable&) = delete;
|
||||
|
||||
// Construct the awaitable from a coroutine's promise object.
|
||||
explicit awaitable(detail::awaitee<T, Executor>* a) : awaitee_(a) {}
|
||||
|
||||
detail::awaitee<T, Executor>* awaitee_;
|
||||
};
|
||||
|
||||
/// Spawn a new thread of execution.
|
||||
template <typename Executor, typename F, typename CompletionToken,
|
||||
typename = typename enable_if<is_executor<Executor>::value>::type>
|
||||
inline auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token)
|
||||
{
|
||||
return detail::co_spawn(ex, std::forward<F>(f),
|
||||
std::forward<CompletionToken>(token));
|
||||
}
|
||||
|
||||
/// Spawn a new thread of execution.
|
||||
template <typename ExecutionContext, typename F, typename CompletionToken,
|
||||
typename = typename enable_if<
|
||||
is_convertible<ExecutionContext&, execution_context&>::value>::type>
|
||||
inline auto co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token)
|
||||
{
|
||||
return detail::co_spawn(ctx.get_executor(), std::forward<F>(f),
|
||||
std::forward<CompletionToken>(token));
|
||||
}
|
||||
|
||||
/// Spawn a new thread of execution.
|
||||
template <typename Executor, typename F, typename CompletionToken>
|
||||
inline auto co_spawn(const await_token<Executor>& parent,
|
||||
F&& f, CompletionToken&& token)
|
||||
{
|
||||
return detail::co_spawn(parent.get_executor(), std::forward<F>(f),
|
||||
std::forward<CompletionToken>(token));
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#include "asio/experimental/impl/co_spawn.hpp"
|
||||
|
||||
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#endif // ASIO_EXPERIMENTAL_CO_SPAWN_HPP
|
@ -1,843 +0,0 @@
|
||||
//
|
||||
// experimental/impl/co_spawn.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_EXPERIMENTAL_IMPL_CO_SPAWN_HPP
|
||||
#define ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include "asio/async_result.hpp"
|
||||
#include "asio/detail/thread_context.hpp"
|
||||
#include "asio/detail/thread_info_base.hpp"
|
||||
#include "asio/detail/type_traits.hpp"
|
||||
#include "asio/dispatch.hpp"
|
||||
#include "asio/post.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace experimental {
|
||||
namespace detail {
|
||||
|
||||
// Promise object for coroutine at top of thread-of-execution "stack".
|
||||
template <typename Executor>
|
||||
class awaiter
|
||||
{
|
||||
public:
|
||||
struct deleter
|
||||
{
|
||||
void operator()(awaiter* a)
|
||||
{
|
||||
if (a)
|
||||
a->release();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<awaiter, deleter> ptr;
|
||||
|
||||
typedef Executor executor_type;
|
||||
|
||||
~awaiter()
|
||||
{
|
||||
if (has_executor_)
|
||||
static_cast<Executor*>(static_cast<void*>(executor_))->~Executor();
|
||||
}
|
||||
|
||||
void set_executor(const Executor& ex)
|
||||
{
|
||||
new (&executor_) Executor(ex);
|
||||
has_executor_ = true;
|
||||
}
|
||||
|
||||
executor_type get_executor() const noexcept
|
||||
{
|
||||
return *static_cast<const Executor*>(static_cast<const void*>(executor_));
|
||||
}
|
||||
|
||||
awaiter* get_return_object()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
auto initial_suspend()
|
||||
{
|
||||
return std::experimental::suspend_always();
|
||||
}
|
||||
|
||||
auto final_suspend()
|
||||
{
|
||||
return std::experimental::suspend_always();
|
||||
}
|
||||
|
||||
void return_void()
|
||||
{
|
||||
}
|
||||
|
||||
awaiter* add_ref()
|
||||
{
|
||||
++ref_count_;
|
||||
return this;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (--ref_count_ == 0)
|
||||
coroutine_handle<awaiter>::from_promise(*this).destroy();
|
||||
}
|
||||
|
||||
void unhandled_exception()
|
||||
{
|
||||
pending_exception_ = std::current_exception();
|
||||
}
|
||||
|
||||
void rethrow_unhandled_exception()
|
||||
{
|
||||
if (pending_exception_)
|
||||
{
|
||||
std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t ref_count_ = 0;
|
||||
std::exception_ptr pending_exception_ = nullptr;
|
||||
alignas(Executor) unsigned char executor_[sizeof(Executor)];
|
||||
bool has_executor_ = false;
|
||||
};
|
||||
|
||||
// Base promise for coroutines further down the thread-of-execution "stack".
|
||||
template <typename Executor>
|
||||
class awaitee_base
|
||||
{
|
||||
public:
|
||||
#if !defined(ASIO_DISABLE_AWAITEE_RECYCLING)
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return asio::detail::thread_info_base::allocate(
|
||||
asio::detail::thread_info_base::awaitee_tag(),
|
||||
asio::detail::thread_context::thread_call_stack::top(),
|
||||
size);
|
||||
}
|
||||
|
||||
void operator delete(void* pointer, std::size_t size)
|
||||
{
|
||||
asio::detail::thread_info_base::deallocate(
|
||||
asio::detail::thread_info_base::awaitee_tag(),
|
||||
asio::detail::thread_context::thread_call_stack::top(),
|
||||
pointer, size);
|
||||
}
|
||||
#endif // !defined(ASIO_DISABLE_AWAITEE_RECYCLING)
|
||||
|
||||
auto initial_suspend()
|
||||
{
|
||||
return std::experimental::suspend_never();
|
||||
}
|
||||
|
||||
struct final_suspender
|
||||
{
|
||||
awaitee_base* this_;
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(coroutine_handle<void>)
|
||||
{
|
||||
this_->wake_caller();
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
auto final_suspend()
|
||||
{
|
||||
return final_suspender{this};
|
||||
}
|
||||
|
||||
void set_except(std::exception_ptr e)
|
||||
{
|
||||
pending_exception_ = e;
|
||||
}
|
||||
|
||||
void unhandled_exception()
|
||||
{
|
||||
set_except(std::current_exception());
|
||||
}
|
||||
|
||||
void rethrow_exception()
|
||||
{
|
||||
if (pending_exception_)
|
||||
{
|
||||
std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
}
|
||||
|
||||
awaiter<Executor>* top()
|
||||
{
|
||||
return awaiter_;
|
||||
}
|
||||
|
||||
coroutine_handle<void> caller()
|
||||
{
|
||||
return caller_;
|
||||
}
|
||||
|
||||
bool ready() const
|
||||
{
|
||||
return ready_;
|
||||
}
|
||||
|
||||
void wake_caller()
|
||||
{
|
||||
if (caller_)
|
||||
caller_.resume();
|
||||
else
|
||||
ready_ = true;
|
||||
}
|
||||
|
||||
class awaitable_executor
|
||||
{
|
||||
public:
|
||||
explicit awaitable_executor(awaitee_base* a)
|
||||
: this_(a)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return this_->awaiter_ != nullptr;
|
||||
}
|
||||
|
||||
template <typename U, typename Ex>
|
||||
void await_suspend(coroutine_handle<detail::awaitee<U, Ex>> h) noexcept
|
||||
{
|
||||
this_->resume_on_attach_ = h;
|
||||
}
|
||||
|
||||
Executor await_resume()
|
||||
{
|
||||
return this_->awaiter_->get_executor();
|
||||
}
|
||||
|
||||
private:
|
||||
awaitee_base* this_;
|
||||
};
|
||||
|
||||
awaitable_executor await_transform(this_coro::executor_t) noexcept
|
||||
{
|
||||
return awaitable_executor(this);
|
||||
}
|
||||
|
||||
class awaitable_token
|
||||
{
|
||||
public:
|
||||
explicit awaitable_token(awaitee_base* a)
|
||||
: this_(a)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return this_->awaiter_ != nullptr;
|
||||
}
|
||||
|
||||
template <typename U, typename Ex>
|
||||
void await_suspend(coroutine_handle<detail::awaitee<U, Ex>> h) noexcept
|
||||
{
|
||||
this_->resume_on_attach_ = h;
|
||||
}
|
||||
|
||||
await_token<Executor> await_resume()
|
||||
{
|
||||
return await_token<Executor>(this_->awaiter_);
|
||||
}
|
||||
|
||||
private:
|
||||
awaitee_base* this_;
|
||||
};
|
||||
|
||||
awaitable_token await_transform(this_coro::token_t) noexcept
|
||||
{
|
||||
return awaitable_token(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
awaitable<T, Executor> await_transform(awaitable<T, Executor>& t) const
|
||||
{
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
awaitable<T, Executor> await_transform(awaitable<T, Executor>&& t) const
|
||||
{
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
std::experimental::suspend_always await_transform(
|
||||
std::experimental::suspend_always) const
|
||||
{
|
||||
return std::experimental::suspend_always();
|
||||
}
|
||||
|
||||
void attach_caller(coroutine_handle<awaiter<Executor>> h)
|
||||
{
|
||||
this->caller_ = h;
|
||||
this->attach_callees(&h.promise());
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void attach_caller(coroutine_handle<awaitee<U, Executor>> h)
|
||||
{
|
||||
this->caller_ = h;
|
||||
if (h.promise().awaiter_)
|
||||
this->attach_callees(h.promise().awaiter_);
|
||||
else
|
||||
h.promise().unattached_callee_ = this;
|
||||
}
|
||||
|
||||
void attach_callees(awaiter<Executor>* a)
|
||||
{
|
||||
for (awaitee_base* curr = this; curr != nullptr;
|
||||
curr = std::exchange(curr->unattached_callee_, nullptr))
|
||||
{
|
||||
curr->awaiter_ = a;
|
||||
if (curr->resume_on_attach_)
|
||||
return std::exchange(curr->resume_on_attach_, nullptr).resume();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
awaiter<Executor>* awaiter_ = nullptr;
|
||||
coroutine_handle<void> caller_ = nullptr;
|
||||
awaitee_base<Executor>* unattached_callee_ = nullptr;
|
||||
std::exception_ptr pending_exception_ = nullptr;
|
||||
coroutine_handle<void> resume_on_attach_ = nullptr;
|
||||
bool ready_ = false;
|
||||
};
|
||||
|
||||
// Promise object for coroutines further down the thread-of-execution "stack".
|
||||
template <typename T, typename Executor>
|
||||
class awaitee
|
||||
: public awaitee_base<Executor>
|
||||
{
|
||||
public:
|
||||
awaitee()
|
||||
{
|
||||
}
|
||||
|
||||
awaitee(awaitee&& other) noexcept
|
||||
: awaitee_base<Executor>(std::move(other))
|
||||
{
|
||||
}
|
||||
|
||||
~awaitee()
|
||||
{
|
||||
if (has_result_)
|
||||
static_cast<T*>(static_cast<void*>(result_))->~T();
|
||||
}
|
||||
|
||||
awaitable<T, Executor> get_return_object()
|
||||
{
|
||||
return awaitable<T, Executor>(this);
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
void return_value(U&& u)
|
||||
{
|
||||
new (&result_) T(std::forward<U>(u));
|
||||
has_result_ = true;
|
||||
}
|
||||
|
||||
T get()
|
||||
{
|
||||
this->caller_ = nullptr;
|
||||
this->rethrow_exception();
|
||||
return std::move(*static_cast<T*>(static_cast<void*>(result_)));
|
||||
}
|
||||
|
||||
private:
|
||||
alignas(T) unsigned char result_[sizeof(T)];
|
||||
bool has_result_ = false;
|
||||
};
|
||||
|
||||
// Promise object for coroutines further down the thread-of-execution "stack".
|
||||
template <typename Executor>
|
||||
class awaitee<void, Executor>
|
||||
: public awaitee_base<Executor>
|
||||
{
|
||||
public:
|
||||
awaitable<void, Executor> get_return_object()
|
||||
{
|
||||
return awaitable<void, Executor>(this);
|
||||
};
|
||||
|
||||
void return_void()
|
||||
{
|
||||
}
|
||||
|
||||
void get()
|
||||
{
|
||||
this->caller_ = nullptr;
|
||||
this->rethrow_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class awaiter_task
|
||||
{
|
||||
public:
|
||||
typedef Executor executor_type;
|
||||
|
||||
awaiter_task(awaiter<Executor>* a)
|
||||
: awaiter_(a->add_ref())
|
||||
{
|
||||
}
|
||||
|
||||
awaiter_task(awaiter_task&& other) noexcept
|
||||
: awaiter_(std::exchange(other.awaiter_, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
~awaiter_task()
|
||||
{
|
||||
if (awaiter_)
|
||||
{
|
||||
// Coroutine "stack unwinding" must be performed through the executor.
|
||||
executor_type ex(awaiter_->get_executor());
|
||||
(post)(ex,
|
||||
[a = std::move(awaiter_)]() mutable
|
||||
{
|
||||
typename awaiter<Executor>::ptr(std::move(a));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
executor_type get_executor() const noexcept
|
||||
{
|
||||
return awaiter_->get_executor();
|
||||
}
|
||||
|
||||
protected:
|
||||
typename awaiter<Executor>::ptr awaiter_;
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class co_spawn_handler : public awaiter_task<Executor>
|
||||
{
|
||||
public:
|
||||
using awaiter_task<Executor>::awaiter_task;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
coroutine_handle<awaiter<Executor>>::from_promise(*ptr.get()).resume();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class await_handler_base : public awaiter_task<Executor>
|
||||
{
|
||||
public:
|
||||
typedef awaitable<T, Executor> awaitable_type;
|
||||
|
||||
await_handler_base(await_token<Executor> token)
|
||||
: awaiter_task<Executor>(token.awaiter_),
|
||||
awaitee_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
await_handler_base(await_handler_base&& other) noexcept
|
||||
: awaiter_task<Executor>(std::move(other)),
|
||||
awaitee_(std::exchange(other.awaitee_, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
void attach_awaitee(const awaitable<T, Executor>& a)
|
||||
{
|
||||
awaitee_ = a.awaitee_;
|
||||
}
|
||||
|
||||
protected:
|
||||
awaitee<T, Executor>* awaitee_;
|
||||
};
|
||||
|
||||
template <typename, typename...> class await_handler;
|
||||
|
||||
template <typename Executor>
|
||||
class await_handler<Executor, void>
|
||||
: public await_handler_base<Executor, void>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, void>::await_handler_base;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
this->awaitee_->return_void();
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class await_handler<Executor, asio::error_code>
|
||||
: public await_handler_base<Executor, void>
|
||||
{
|
||||
public:
|
||||
typedef void return_type;
|
||||
|
||||
using await_handler_base<Executor, void>::await_handler_base;
|
||||
|
||||
void operator()(const asio::error_code& ec)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
if (ec)
|
||||
{
|
||||
this->awaitee_->set_except(
|
||||
std::make_exception_ptr(asio::system_error(ec)));
|
||||
}
|
||||
else
|
||||
this->awaitee_->return_void();
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class await_handler<Executor, std::exception_ptr>
|
||||
: public await_handler_base<Executor, void>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, void>::await_handler_base;
|
||||
|
||||
void operator()(std::exception_ptr ex)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
if (ex)
|
||||
this->awaitee_->set_except(ex);
|
||||
else
|
||||
this->awaitee_->return_void();
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class await_handler<Executor, T>
|
||||
: public await_handler_base<Executor, T>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, T>::await_handler_base;
|
||||
|
||||
template <typename Arg>
|
||||
void operator()(Arg&& arg)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
this->awaitee_->return_value(std::forward<Arg>(arg));
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class await_handler<Executor, asio::error_code, T>
|
||||
: public await_handler_base<Executor, T>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, T>::await_handler_base;
|
||||
|
||||
template <typename Arg>
|
||||
void operator()(const asio::error_code& ec, Arg&& arg)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
if (ec)
|
||||
{
|
||||
this->awaitee_->set_except(
|
||||
std::make_exception_ptr(asio::system_error(ec)));
|
||||
}
|
||||
else
|
||||
this->awaitee_->return_value(std::forward<Arg>(arg));
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class await_handler<Executor, std::exception_ptr, T>
|
||||
: public await_handler_base<Executor, T>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, T>::await_handler_base;
|
||||
|
||||
template <typename Arg>
|
||||
void operator()(std::exception_ptr ex, Arg&& arg)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
if (ex)
|
||||
this->awaitee_->set_except(ex);
|
||||
else
|
||||
this->awaitee_->return_value(std::forward<Arg>(arg));
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename... Ts>
|
||||
class await_handler
|
||||
: public await_handler_base<Executor, std::tuple<Ts...>>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base;
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(Args&&... args)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
this->awaitee_->return_value(
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename... Ts>
|
||||
class await_handler<Executor, asio::error_code, Ts...>
|
||||
: public await_handler_base<Executor, std::tuple<Ts...>>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base;
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(const asio::error_code& ec, Args&&... args)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
if (ec)
|
||||
{
|
||||
this->awaitee_->set_except(
|
||||
std::make_exception_ptr(asio::system_error(ec)));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->awaitee_->return_value(
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename... Ts>
|
||||
class await_handler<Executor, std::exception_ptr, Ts...>
|
||||
: public await_handler_base<Executor, std::tuple<Ts...>>
|
||||
{
|
||||
public:
|
||||
using await_handler_base<Executor, std::tuple<Ts...>>::await_handler_base;
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(std::exception_ptr ex, Args&&... args)
|
||||
{
|
||||
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
|
||||
if (ex)
|
||||
this->awaitee_->set_except(ex);
|
||||
else
|
||||
{
|
||||
this->awaitee_->return_value(
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
this->awaitee_->wake_caller();
|
||||
ptr->rethrow_unhandled_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct awaitable_signature;
|
||||
|
||||
template <typename T, typename Executor>
|
||||
struct awaitable_signature<awaitable<T, Executor>>
|
||||
{
|
||||
typedef void type(std::exception_ptr, T);
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
struct awaitable_signature<awaitable<void, Executor>>
|
||||
{
|
||||
typedef void type(std::exception_ptr);
|
||||
};
|
||||
|
||||
template <typename T, typename Executor, typename F, typename Handler>
|
||||
awaiter<Executor>* co_spawn_entry_point(awaitable<T, Executor>*,
|
||||
executor_work_guard<Executor> work_guard, F f, Handler handler)
|
||||
{
|
||||
bool done = false;
|
||||
|
||||
try
|
||||
{
|
||||
T t = co_await f();
|
||||
|
||||
done = true;
|
||||
|
||||
(dispatch)(work_guard.get_executor(),
|
||||
[handler = std::move(handler), t = std::move(t)]() mutable
|
||||
{
|
||||
handler(std::exception_ptr(), std::move(t));
|
||||
});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (done)
|
||||
throw;
|
||||
|
||||
(dispatch)(work_guard.get_executor(),
|
||||
[handler = std::move(handler), e = std::current_exception()]() mutable
|
||||
{
|
||||
handler(e, T());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Executor, typename F, typename Handler>
|
||||
awaiter<Executor>* co_spawn_entry_point(awaitable<void, Executor>*,
|
||||
executor_work_guard<Executor> work_guard, F f, Handler handler)
|
||||
{
|
||||
std::exception_ptr e = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
co_await f();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
e = std::current_exception();
|
||||
}
|
||||
|
||||
(dispatch)(work_guard.get_executor(),
|
||||
[handler = std::move(handler), e]() mutable
|
||||
{
|
||||
handler(e);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Executor, typename F, typename CompletionToken>
|
||||
auto co_spawn(const Executor& ex, F&& f, CompletionToken&& token)
|
||||
{
|
||||
typedef typename result_of<F()>::type awaitable_type;
|
||||
typedef typename awaitable_type::executor_type executor_type;
|
||||
typedef typename awaitable_signature<awaitable_type>::type signature_type;
|
||||
|
||||
async_completion<CompletionToken, signature_type> completion(token);
|
||||
|
||||
executor_type ex2(ex);
|
||||
auto work_guard = make_work_guard(completion.completion_handler, ex2);
|
||||
|
||||
auto* a = (co_spawn_entry_point)(
|
||||
static_cast<awaitable_type*>(nullptr), std::move(work_guard),
|
||||
std::forward<F>(f), std::move(completion.completion_handler));
|
||||
|
||||
a->set_executor(ex2);
|
||||
(post)(co_spawn_handler<executor_type>(a));
|
||||
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4033)
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
template <typename T> T dummy_return()
|
||||
{
|
||||
return std::move(*static_cast<T*>(nullptr));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void dummy_return()
|
||||
{
|
||||
}
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
template <typename Awaitable>
|
||||
inline Awaitable make_dummy_awaitable()
|
||||
{
|
||||
for (;;) co_await std::experimental::suspend_always();
|
||||
#if defined(_MSC_VER)
|
||||
co_return dummy_return<typename Awaitable::value_type>();
|
||||
#endif // defined(_MSC_VER)
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
} // namespace detail
|
||||
} // namespace experimental
|
||||
|
||||
template <typename Executor, typename R, typename... Args>
|
||||
class async_result<experimental::await_token<Executor>, R(Args...)>
|
||||
{
|
||||
public:
|
||||
typedef experimental::detail::await_handler<
|
||||
Executor, typename decay<Args>::type...> completion_handler_type;
|
||||
|
||||
typedef typename experimental::detail::await_handler<
|
||||
Executor, Args...>::awaitable_type return_type;
|
||||
|
||||
async_result(completion_handler_type& h)
|
||||
: awaitable_(experimental::detail::make_dummy_awaitable<return_type>())
|
||||
{
|
||||
h.attach_awaitee(awaitable_);
|
||||
}
|
||||
|
||||
return_type get()
|
||||
{
|
||||
return std::move(awaitable_);
|
||||
}
|
||||
|
||||
private:
|
||||
return_type awaitable_;
|
||||
};
|
||||
|
||||
} // namespace asio
|
||||
|
||||
namespace std { namespace experimental {
|
||||
|
||||
template <typename Executor, typename... Args>
|
||||
struct coroutine_traits<
|
||||
asio::experimental::detail::awaiter<Executor>*, Args...>
|
||||
{
|
||||
typedef asio::experimental::detail::awaiter<Executor> promise_type;
|
||||
};
|
||||
|
||||
template <typename T, typename Executor, typename... Args>
|
||||
struct coroutine_traits<
|
||||
asio::experimental::awaitable<T, Executor>, Args...>
|
||||
{
|
||||
typedef asio::experimental::detail::awaitee<T, Executor> promise_type;
|
||||
};
|
||||
|
||||
}} // namespace std::experimental
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_EXPERIMENTAL_IMPL_CO_SPAWN_HPP
|
@ -1,90 +0,0 @@
|
||||
//
|
||||
// experimental/impl/detached.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_EXPERIMENTAL_IMPL_DETACHED_HPP
|
||||
#define ASIO_EXPERIMENTAL_IMPL_DETACHED_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/variadic_templates.hpp"
|
||||
#include "asio/system_error.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace experimental {
|
||||
namespace detail {
|
||||
|
||||
// Class to adapt a detached_t as a completion handler.
|
||||
class detached_handler
|
||||
{
|
||||
public:
|
||||
detached_handler(detached_t)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(Args...)
|
||||
{
|
||||
}
|
||||
|
||||
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
void operator()()
|
||||
{
|
||||
}
|
||||
|
||||
#define ASIO_PRIVATE_DETACHED_DEF(n) \
|
||||
template <ASIO_VARIADIC_TPARAMS(n)> \
|
||||
void operator()(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
|
||||
{ \
|
||||
} \
|
||||
/**/
|
||||
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_DETACHED_DEF)
|
||||
#undef ASIO_PRIVATE_DETACHED_DEF
|
||||
|
||||
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace experimental
|
||||
|
||||
#if !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
template <typename Signature>
|
||||
struct async_result<experimental::detached_t, Signature>
|
||||
{
|
||||
typedef asio::experimental::detail::detached_handler
|
||||
completion_handler_type;
|
||||
|
||||
typedef void return_type;
|
||||
|
||||
explicit async_result(completion_handler_type&)
|
||||
{
|
||||
}
|
||||
|
||||
void get()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_EXPERIMENTAL_IMPL_DETACHED_HPP
|
418
asio/include/asio/impl/awaitable.hpp
Normal file
418
asio/include/asio/impl/awaitable.hpp
Normal file
@ -0,0 +1,418 @@
|
||||
//
|
||||
// impl/awaitable.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_AWAITABLE_HPP
|
||||
#define ASIO_IMPL_AWAITABLE_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include <exception>
|
||||
#include <new>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include "asio/detail/thread_context.hpp"
|
||||
#include "asio/detail/thread_info_base.hpp"
|
||||
#include "asio/detail/type_traits.hpp"
|
||||
#include "asio/post.hpp"
|
||||
#include "asio/system_error.hpp"
|
||||
#include "asio/this_coro.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// An awaitable_thread represents a thread-of-execution that is composed of one
|
||||
// or more "stack frames", with each frame represented by an awaitable_frame.
|
||||
// All execution occurs in the context of the awaitable_thread's executor. An
|
||||
// awaitable_thread continues to "pump" the stack frames by repeatedly resuming
|
||||
// the top stack frame until the stack is empty, or until ownership of the
|
||||
// stack is transferred to another awaitable_thread object.
|
||||
//
|
||||
// +------------------------------------+
|
||||
// | top_of_stack_ |
|
||||
// | V
|
||||
// +--------------+---+ +-----------------+
|
||||
// | | | |
|
||||
// | awaitable_thread |<---------------------------+ awaitable_frame |
|
||||
// | | attached_thread_ | |
|
||||
// +--------------+---+ (Set only when +---+-------------+
|
||||
// | frames are being |
|
||||
// | actively pumped | caller_
|
||||
// | by a thread, and |
|
||||
// | then only for V
|
||||
// | the top frame.) +-----------------+
|
||||
// | | |
|
||||
// | | awaitable_frame |
|
||||
// | | |
|
||||
// | +---+-------------+
|
||||
// | |
|
||||
// | | caller_
|
||||
// | :
|
||||
// | :
|
||||
// | |
|
||||
// | V
|
||||
// | +-----------------+
|
||||
// | bottom_of_stack_ | |
|
||||
// +------------------------------->| awaitable_frame |
|
||||
// | |
|
||||
// +-----------------+
|
||||
|
||||
template <typename Executor>
|
||||
class awaitable_frame_base
|
||||
{
|
||||
public:
|
||||
#if !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return asio::detail::thread_info_base::allocate(
|
||||
asio::detail::thread_info_base::awaitable_frame_tag(),
|
||||
asio::detail::thread_context::thread_call_stack::top(),
|
||||
size);
|
||||
}
|
||||
|
||||
void operator delete(void* pointer, std::size_t size)
|
||||
{
|
||||
asio::detail::thread_info_base::deallocate(
|
||||
asio::detail::thread_info_base::awaitable_frame_tag(),
|
||||
asio::detail::thread_context::thread_call_stack::top(),
|
||||
pointer, size);
|
||||
}
|
||||
#endif // !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
|
||||
|
||||
// The frame starts in a suspended state until the awaitable_thread object
|
||||
// pumps the stack.
|
||||
auto initial_suspend() noexcept
|
||||
{
|
||||
return suspend_always();
|
||||
}
|
||||
|
||||
// On final suspension the frame is popped from the top of the stack.
|
||||
auto final_suspend() noexcept
|
||||
{
|
||||
struct result
|
||||
{
|
||||
awaitable_frame_base* this_;
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(coroutine_handle<void>) noexcept
|
||||
{
|
||||
this_->pop_frame();
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
return result{this};
|
||||
}
|
||||
|
||||
void set_except(std::exception_ptr e) noexcept
|
||||
{
|
||||
pending_exception_ = e;
|
||||
}
|
||||
|
||||
void set_error(const asio::error_code& ec)
|
||||
{
|
||||
this->set_except(std::make_exception_ptr(asio::system_error(ec)));
|
||||
}
|
||||
|
||||
void unhandled_exception()
|
||||
{
|
||||
set_except(std::current_exception());
|
||||
}
|
||||
|
||||
void rethrow_exception()
|
||||
{
|
||||
if (pending_exception_)
|
||||
{
|
||||
std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto await_transform(awaitable<T, Executor> a) const
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
// This await transformation obtains the associated executor of the thread of
|
||||
// execution.
|
||||
auto await_transform(this_coro::executor_t) noexcept
|
||||
{
|
||||
struct result
|
||||
{
|
||||
awaitable_frame_base* this_;
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void await_suspend(coroutine_handle<void>) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
auto await_resume() const noexcept
|
||||
{
|
||||
return this_->attached_thread_->get_executor();
|
||||
}
|
||||
};
|
||||
|
||||
return result{this};
|
||||
}
|
||||
|
||||
// This await transformation is used to run an async operation's initiation
|
||||
// function object after the coroutine has been suspended. This ensures that
|
||||
// immediate resumption of the coroutine in another thread does not cause a
|
||||
// race condition.
|
||||
template <typename Function>
|
||||
auto await_transform(Function f,
|
||||
typename enable_if<
|
||||
is_convertible<
|
||||
typename result_of<Function(awaitable_frame_base*)>::type,
|
||||
awaitable_thread<Executor>*
|
||||
>::value
|
||||
>::type* = 0)
|
||||
{
|
||||
struct result
|
||||
{
|
||||
Function function_;
|
||||
awaitable_frame_base* this_;
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(coroutine_handle<void>) noexcept
|
||||
{
|
||||
function_(this_);
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
return result{std::move(f), this};
|
||||
}
|
||||
|
||||
void attach_thread(awaitable_thread<Executor>* handler) noexcept
|
||||
{
|
||||
attached_thread_ = handler;
|
||||
}
|
||||
|
||||
awaitable_thread<Executor>* detach_thread() noexcept
|
||||
{
|
||||
return std::exchange(attached_thread_, nullptr);
|
||||
}
|
||||
|
||||
void push_frame(awaitable_frame_base<Executor>* caller) noexcept
|
||||
{
|
||||
caller_ = caller;
|
||||
attached_thread_ = caller_->attached_thread_;
|
||||
attached_thread_->top_of_stack_ = this;
|
||||
caller_->attached_thread_ = nullptr;
|
||||
}
|
||||
|
||||
void pop_frame() noexcept
|
||||
{
|
||||
if (caller_)
|
||||
caller_->attached_thread_ = attached_thread_;
|
||||
attached_thread_->top_of_stack_ = caller_;
|
||||
attached_thread_ = nullptr;
|
||||
caller_ = nullptr;
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
coro_.resume();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
coro_.destroy();
|
||||
}
|
||||
|
||||
protected:
|
||||
coroutine_handle<void> coro_ = nullptr;
|
||||
awaitable_thread<Executor>* attached_thread_ = nullptr;
|
||||
awaitable_frame_base<Executor>* caller_ = nullptr;
|
||||
std::exception_ptr pending_exception_ = nullptr;
|
||||
};
|
||||
|
||||
template <typename T, typename Executor>
|
||||
class awaitable_frame
|
||||
: public awaitable_frame_base<Executor>
|
||||
{
|
||||
public:
|
||||
awaitable_frame() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
awaitable_frame(awaitable_frame&& other) noexcept
|
||||
: awaitable_frame_base<Executor>(std::move(other))
|
||||
{
|
||||
}
|
||||
|
||||
~awaitable_frame()
|
||||
{
|
||||
if (has_result_)
|
||||
static_cast<T*>(static_cast<void*>(result_))->~T();
|
||||
}
|
||||
|
||||
awaitable<T, Executor> get_return_object() noexcept
|
||||
{
|
||||
this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
|
||||
return awaitable<T, Executor>(this);
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
void return_value(U&& u)
|
||||
{
|
||||
new (&result_) T(std::forward<U>(u));
|
||||
has_result_ = true;
|
||||
}
|
||||
|
||||
template <typename... Us>
|
||||
void return_values(Us&&... us)
|
||||
{
|
||||
this->return_value(std::forward_as_tuple(std::forward<Us>(us)...));
|
||||
}
|
||||
|
||||
T get()
|
||||
{
|
||||
this->caller_ = nullptr;
|
||||
this->rethrow_exception();
|
||||
return std::move(*static_cast<T*>(static_cast<void*>(result_)));
|
||||
}
|
||||
|
||||
private:
|
||||
alignas(T) unsigned char result_[sizeof(T)];
|
||||
bool has_result_ = false;
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class awaitable_frame<void, Executor>
|
||||
: public awaitable_frame_base<Executor>
|
||||
{
|
||||
public:
|
||||
awaitable<void, Executor> get_return_object()
|
||||
{
|
||||
this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
|
||||
return awaitable<void, Executor>(this);
|
||||
};
|
||||
|
||||
void return_void()
|
||||
{
|
||||
}
|
||||
|
||||
void get()
|
||||
{
|
||||
this->caller_ = nullptr;
|
||||
this->rethrow_exception();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class awaitable_thread
|
||||
{
|
||||
public:
|
||||
typedef Executor executor_type;
|
||||
|
||||
// Construct from the entry point of a new thread of execution.
|
||||
awaitable_thread(awaitable<void, Executor> p, const Executor& ex)
|
||||
: bottom_of_stack_(std::move(p)),
|
||||
top_of_stack_(bottom_of_stack_.frame_),
|
||||
executor_(ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Transfer ownership from another awaitable_thread.
|
||||
awaitable_thread(awaitable_thread&& other) noexcept
|
||||
: bottom_of_stack_(std::move(other.bottom_of_stack_)),
|
||||
top_of_stack_(std::exchange(other.top_of_stack_, nullptr)),
|
||||
executor_(std::move(other.executor_))
|
||||
{
|
||||
}
|
||||
|
||||
// Clean up with a last ditch effort to ensure the thread is unwound within
|
||||
// the context of the executor.
|
||||
~awaitable_thread()
|
||||
{
|
||||
if (bottom_of_stack_.valid())
|
||||
{
|
||||
// Coroutine "stack unwinding" must be performed through the executor.
|
||||
(post)(executor_,
|
||||
[a = std::move(bottom_of_stack_)]() mutable
|
||||
{
|
||||
awaitable<void, Executor>(std::move(a));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
executor_type get_executor() const noexcept
|
||||
{
|
||||
return executor_;
|
||||
}
|
||||
|
||||
// Launch a new thread of execution.
|
||||
void launch()
|
||||
{
|
||||
top_of_stack_->attach_thread(this);
|
||||
pump();
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename> friend class awaitable_frame_base;
|
||||
|
||||
// Repeatedly resume the top stack frame until the stack is empty or until it
|
||||
// has been transferred to another resumable_thread object.
|
||||
void pump()
|
||||
{
|
||||
do top_of_stack_->resume(); while (top_of_stack_);
|
||||
if (bottom_of_stack_.valid())
|
||||
{
|
||||
awaitable<void, Executor> a(std::move(bottom_of_stack_));
|
||||
a.frame_->rethrow_exception();
|
||||
}
|
||||
}
|
||||
|
||||
awaitable<void, Executor> bottom_of_stack_;
|
||||
awaitable_frame_base<Executor>* top_of_stack_;
|
||||
executor_type executor_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
|
||||
namespace std { namespace experimental {
|
||||
|
||||
template <typename T, typename Executor, typename... Args>
|
||||
struct coroutine_traits<asio::awaitable<T, Executor>, Args...>
|
||||
{
|
||||
typedef asio::detail::awaitable_frame<T, Executor> promise_type;
|
||||
};
|
||||
|
||||
}} // namespace std::experimental
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_IMPL_AWAITABLE_HPP
|
138
asio/include/asio/impl/co_spawn.hpp
Normal file
138
asio/include/asio/impl/co_spawn.hpp
Normal file
@ -0,0 +1,138 @@
|
||||
//
|
||||
// impl/co_spawn.hpp
|
||||
// ~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_CO_SPAWN_HPP
|
||||
#define ASIO_IMPL_CO_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/awaitable.hpp"
|
||||
#include "asio/dispatch.hpp"
|
||||
#include "asio/post.hpp"
|
||||
#include "asio/use_awaitable.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename Executor, typename F, typename Handler>
|
||||
awaitable<void, Executor> co_spawn_entry_point(
|
||||
awaitable<T, Executor>*, Executor ex, F f, Handler handler)
|
||||
{
|
||||
auto spawn_work = make_work_guard(ex);
|
||||
auto handler_work = make_work_guard(handler, ex);
|
||||
|
||||
(void) co_await (post)(spawn_work.get_executor(),
|
||||
use_awaitable_t<Executor>{});
|
||||
|
||||
bool done = false;
|
||||
try
|
||||
{
|
||||
T t = co_await f();
|
||||
|
||||
done = true;
|
||||
|
||||
(dispatch)(handler_work.get_executor(),
|
||||
[handler = std::move(handler), t = std::move(t)]() mutable
|
||||
{
|
||||
handler(std::exception_ptr(), std::move(t));
|
||||
});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (done)
|
||||
throw;
|
||||
|
||||
(dispatch)(handler_work.get_executor(),
|
||||
[handler = std::move(handler), e = std::current_exception()]() mutable
|
||||
{
|
||||
handler(e, T());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Executor, typename F, typename Handler>
|
||||
awaitable<void, Executor> co_spawn_entry_point(
|
||||
awaitable<void, Executor>*, Executor ex, F f, Handler handler)
|
||||
{
|
||||
auto spawn_work = make_work_guard(ex);
|
||||
auto handler_work = make_work_guard(handler, ex);
|
||||
|
||||
(void) co_await (post)(spawn_work.get_executor(),
|
||||
use_awaitable_t<Executor>{});
|
||||
|
||||
std::exception_ptr e = nullptr;
|
||||
try
|
||||
{
|
||||
co_await f();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
e = std::current_exception();
|
||||
}
|
||||
|
||||
(dispatch)(handler_work.get_executor(),
|
||||
[handler = std::move(handler), e]() mutable
|
||||
{
|
||||
handler(e);
|
||||
});
|
||||
}
|
||||
|
||||
struct initiate_co_spawn
|
||||
{
|
||||
template <typename Handler, typename Executor, typename F>
|
||||
void operator()(Handler&& handler, const Executor& ex, F&& f) const
|
||||
{
|
||||
typedef typename result_of<F()>::type awaitable_type;
|
||||
typedef typename awaitable_type::executor_type executor_type;
|
||||
|
||||
executor_type ex2(ex);
|
||||
auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),
|
||||
ex2, std::forward<F>(f), std::forward<Handler>(handler));
|
||||
awaitable_handler<executor_type, void>(std::move(a), ex2).launch();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Executor, typename F, typename CompletionToken>
|
||||
inline ASIO_INITFN_RESULT_TYPE(CompletionToken,
|
||||
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
|
||||
co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
|
||||
typename enable_if<
|
||||
is_executor<Executor>::value
|
||||
>::type*)
|
||||
{
|
||||
return async_initiate<CompletionToken,
|
||||
typename detail::awaitable_signature<typename result_of<F()>::type>>(
|
||||
detail::initiate_co_spawn(), token, ex, std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename ExecutionContext, typename F, typename CompletionToken>
|
||||
inline ASIO_INITFN_RESULT_TYPE(CompletionToken,
|
||||
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
|
||||
co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
|
||||
typename enable_if<
|
||||
is_convertible<ExecutionContext&, execution_context&>::value
|
||||
>::type*)
|
||||
{
|
||||
return (co_spawn)(ctx.get_executor(), std::forward<F>(f),
|
||||
std::forward<CompletionToken>(token));
|
||||
}
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_IMPL_CO_SPAWN_HPP
|
130
asio/include/asio/impl/detached.hpp
Normal file
130
asio/include/asio/impl/detached.hpp
Normal file
@ -0,0 +1,130 @@
|
||||
//
|
||||
// impl/detached.hpp
|
||||
// ~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_DETACHED_HPP
|
||||
#define ASIO_IMPL_DETACHED_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/variadic_templates.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Class to adapt a detached_t as a completion handler.
|
||||
class detached_handler
|
||||
{
|
||||
public:
|
||||
typedef void result_type;
|
||||
|
||||
detached_handler(detached_t)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(Args...)
|
||||
{
|
||||
}
|
||||
|
||||
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
void operator()()
|
||||
{
|
||||
}
|
||||
|
||||
#define ASIO_PRIVATE_DETACHED_DEF(n) \
|
||||
template <ASIO_VARIADIC_TPARAMS(n)> \
|
||||
void operator()(ASIO_VARIADIC_TARGS(n)) \
|
||||
{ \
|
||||
} \
|
||||
/**/
|
||||
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_DETACHED_DEF)
|
||||
#undef ASIO_PRIVATE_DETACHED_DEF
|
||||
|
||||
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#if !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
template <typename Signature>
|
||||
struct async_result<detached_t, Signature>
|
||||
{
|
||||
typedef asio::detail::detached_handler completion_handler_type;
|
||||
|
||||
typedef void return_type;
|
||||
|
||||
explicit async_result(completion_handler_type&)
|
||||
{
|
||||
}
|
||||
|
||||
void get()
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Initiation, typename RawCompletionToken, typename... Args>
|
||||
static return_type initiate(
|
||||
ASIO_MOVE_ARG(Initiation) initiation,
|
||||
ASIO_MOVE_ARG(RawCompletionToken),
|
||||
ASIO_MOVE_ARG(Args)... args)
|
||||
{
|
||||
ASIO_MOVE_CAST(Initiation)(initiation)(
|
||||
detail::detached_handler(detached_t()),
|
||||
ASIO_MOVE_CAST(Args)(args)...);
|
||||
}
|
||||
|
||||
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Initiation, typename RawCompletionToken>
|
||||
static return_type initiate(
|
||||
ASIO_MOVE_ARG(Initiation) initiation,
|
||||
ASIO_MOVE_ARG(RawCompletionToken))
|
||||
{
|
||||
ASIO_MOVE_CAST(Initiation)(initiation)(
|
||||
detail::detached_handler(detached_t()));
|
||||
}
|
||||
|
||||
#define ASIO_PRIVATE_INITIATE_DEF(n) \
|
||||
template <typename Initiation, typename RawCompletionToken, \
|
||||
ASIO_VARIADIC_TPARAMS(n)> \
|
||||
static return_type initiate( \
|
||||
ASIO_MOVE_ARG(Initiation) initiation, \
|
||||
ASIO_MOVE_ARG(RawCompletionToken), \
|
||||
ASIO_VARIADIC_MOVE_PARAMS(n)) \
|
||||
{ \
|
||||
ASIO_MOVE_CAST(Initiation)(initiation)( \
|
||||
detail::detached_handler(detached_t()), \
|
||||
ASIO_VARIADIC_MOVE_ARGS(n)); \
|
||||
} \
|
||||
/**/
|
||||
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
|
||||
#undef ASIO_PRIVATE_INITIATE_DEF
|
||||
|
||||
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
};
|
||||
|
||||
#endif // !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_IMPL_DETACHED_HPP
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
// experimental/impl/redirect_error.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// impl/redirect_error.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP
|
||||
#define ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP
|
||||
#ifndef ASIO_IMPL_REDIRECT_ERROR_HPP
|
||||
#define ASIO_IMPL_REDIRECT_ERROR_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@ -29,7 +29,6 @@
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace experimental {
|
||||
namespace detail {
|
||||
|
||||
// Class to adapt a redirect_error_t as a completion handler.
|
||||
@ -37,6 +36,8 @@ template <typename Handler>
|
||||
class redirect_error_handler
|
||||
{
|
||||
public:
|
||||
typedef void result_type;
|
||||
|
||||
template <typename CompletionToken>
|
||||
redirect_error_handler(redirect_error_t<CompletionToken> e)
|
||||
: ec_(e.ec_),
|
||||
@ -44,6 +45,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
template <typename RedirectedHandler>
|
||||
redirect_error_handler(asio::error_code& ec,
|
||||
ASIO_MOVE_ARG(RedirectedHandler) h)
|
||||
: ec_(ec),
|
||||
handler_(ASIO_MOVE_CAST(RedirectedHandler)(h))
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
handler_();
|
||||
@ -210,36 +219,131 @@ struct redirect_error_signature<R(const asio::error_code&)>
|
||||
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
} // namespace detail
|
||||
} // namespace experimental
|
||||
|
||||
#if !defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
template <typename CompletionToken, typename Signature>
|
||||
struct async_result<experimental::redirect_error_t<CompletionToken>, Signature>
|
||||
: async_result<CompletionToken,
|
||||
typename experimental::detail::redirect_error_signature<Signature>::type>
|
||||
struct async_result<redirect_error_t<CompletionToken>, Signature>
|
||||
{
|
||||
typedef experimental::detail::redirect_error_handler<
|
||||
typename async_result<CompletionToken,
|
||||
typename experimental::detail::redirect_error_signature<Signature>::type>
|
||||
::completion_handler_type> completion_handler_type;
|
||||
typedef typename async_result<CompletionToken,
|
||||
typename detail::redirect_error_signature<Signature>::type>
|
||||
::return_type return_type;
|
||||
|
||||
explicit async_result(completion_handler_type& h)
|
||||
: async_result<CompletionToken,
|
||||
typename experimental::detail::redirect_error_signature<
|
||||
Signature>::type>(h.handler_)
|
||||
template <typename Initiation>
|
||||
struct init_wrapper
|
||||
{
|
||||
template <typename Init>
|
||||
init_wrapper(asio::error_code& ec, ASIO_MOVE_ARG(Init) init)
|
||||
: ec_(ec),
|
||||
initiation_(ASIO_MOVE_CAST(Init)(init))
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Handler, typename... Args>
|
||||
void operator()(
|
||||
ASIO_MOVE_ARG(Handler) handler,
|
||||
ASIO_MOVE_ARG(Args)... args)
|
||||
{
|
||||
ASIO_MOVE_CAST(Initiation)(initiation_)(
|
||||
detail::redirect_error_handler<
|
||||
typename decay<Handler>::type>(
|
||||
ec_, ASIO_MOVE_CAST(Handler)(handler)),
|
||||
ASIO_MOVE_CAST(Args)(args)...);
|
||||
}
|
||||
|
||||
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Handler>
|
||||
void operator()(
|
||||
ASIO_MOVE_ARG(Handler) handler)
|
||||
{
|
||||
ASIO_MOVE_CAST(Initiation)(initiation_)(
|
||||
detail::redirect_error_handler<
|
||||
typename decay<Handler>::type>(
|
||||
ec_, ASIO_MOVE_CAST(Handler)(handler)));
|
||||
}
|
||||
|
||||
#define ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \
|
||||
template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
|
||||
void operator()( \
|
||||
ASIO_MOVE_ARG(Handler) handler, \
|
||||
ASIO_VARIADIC_MOVE_PARAMS(n)) \
|
||||
{ \
|
||||
ASIO_MOVE_CAST(Initiation)(initiation_)( \
|
||||
detail::redirect_error_handler< \
|
||||
typename decay<Handler>::type>( \
|
||||
ec_, ASIO_MOVE_CAST(Handler)(handler)), \
|
||||
ASIO_VARIADIC_MOVE_ARGS(n)); \
|
||||
} \
|
||||
/**/
|
||||
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INIT_WRAPPER_DEF)
|
||||
#undef ASIO_PRIVATE_INIT_WRAPPER_DEF
|
||||
|
||||
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
asio::error_code& ec_;
|
||||
Initiation initiation_;
|
||||
};
|
||||
|
||||
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Initiation, typename RawCompletionToken, typename... Args>
|
||||
static return_type initiate(
|
||||
ASIO_MOVE_ARG(Initiation) initiation,
|
||||
ASIO_MOVE_ARG(RawCompletionToken) token,
|
||||
ASIO_MOVE_ARG(Args)... args)
|
||||
{
|
||||
return async_initiate<CompletionToken,
|
||||
typename detail::redirect_error_signature<Signature>::type>(
|
||||
init_wrapper<typename decay<Initiation>::type>(
|
||||
token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)),
|
||||
token.token_, ASIO_MOVE_CAST(Args)(args)...);
|
||||
}
|
||||
|
||||
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Initiation, typename RawCompletionToken>
|
||||
static return_type initiate(
|
||||
ASIO_MOVE_ARG(Initiation) initiation,
|
||||
ASIO_MOVE_ARG(RawCompletionToken) token)
|
||||
{
|
||||
return async_initiate<CompletionToken,
|
||||
typename detail::redirect_error_signature<Signature>::type>(
|
||||
init_wrapper<typename decay<Initiation>::type>(
|
||||
token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)),
|
||||
token.token_);
|
||||
}
|
||||
|
||||
#define ASIO_PRIVATE_INITIATE_DEF(n) \
|
||||
template <typename Initiation, typename RawCompletionToken, \
|
||||
ASIO_VARIADIC_TPARAMS(n)> \
|
||||
static return_type initiate( \
|
||||
ASIO_MOVE_ARG(Initiation) initiation, \
|
||||
ASIO_MOVE_ARG(RawCompletionToken) token, \
|
||||
ASIO_VARIADIC_MOVE_PARAMS(n)) \
|
||||
{ \
|
||||
return async_initiate<CompletionToken, \
|
||||
typename detail::redirect_error_signature<Signature>::type>( \
|
||||
init_wrapper<typename decay<Initiation>::type>( \
|
||||
token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)), \
|
||||
token.token_, ASIO_VARIADIC_MOVE_ARGS(n)); \
|
||||
} \
|
||||
/**/
|
||||
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
|
||||
#undef ASIO_PRIVATE_INITIATE_DEF
|
||||
|
||||
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
};
|
||||
|
||||
template <typename Handler, typename Executor>
|
||||
struct associated_executor<
|
||||
experimental::detail::redirect_error_handler<Handler>, Executor>
|
||||
struct associated_executor<detail::redirect_error_handler<Handler>, Executor>
|
||||
{
|
||||
typedef typename associated_executor<Handler, Executor>::type type;
|
||||
|
||||
static type get(
|
||||
const experimental::detail::redirect_error_handler<Handler>& h,
|
||||
const detail::redirect_error_handler<Handler>& h,
|
||||
const Executor& ex = Executor()) ASIO_NOEXCEPT
|
||||
{
|
||||
return associated_executor<Handler, Executor>::get(h.handler_, ex);
|
||||
@ -247,13 +351,12 @@ struct associated_executor<
|
||||
};
|
||||
|
||||
template <typename Handler, typename Allocator>
|
||||
struct associated_allocator<
|
||||
experimental::detail::redirect_error_handler<Handler>, Allocator>
|
||||
struct associated_allocator<detail::redirect_error_handler<Handler>, Allocator>
|
||||
{
|
||||
typedef typename associated_allocator<Handler, Allocator>::type type;
|
||||
|
||||
static type get(
|
||||
const experimental::detail::redirect_error_handler<Handler>& h,
|
||||
const detail::redirect_error_handler<Handler>& h,
|
||||
const Allocator& a = Allocator()) ASIO_NOEXCEPT
|
||||
{
|
||||
return associated_allocator<Handler, Allocator>::get(h.handler_, a);
|
||||
@ -266,4 +369,4 @@ struct associated_allocator<
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP
|
||||
#endif // ASIO_IMPL_REDIRECT_ERROR_HPP
|
272
asio/include/asio/impl/use_awaitable.hpp
Normal file
272
asio/include/asio/impl/use_awaitable.hpp
Normal file
@ -0,0 +1,272 @@
|
||||
//
|
||||
// impl/use_awaitable.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_USE_AWAITABLE_HPP
|
||||
#define ASIO_IMPL_USE_AWAITABLE_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/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class awaitable_handler_base
|
||||
: public awaitable_thread<Executor>
|
||||
{
|
||||
public:
|
||||
typedef void result_type;
|
||||
typedef awaitable<T, Executor> awaitable_type;
|
||||
|
||||
// Construct from the entry point of a new thread of execution.
|
||||
awaitable_handler_base(awaitable<void, Executor> a, const Executor& ex)
|
||||
: awaitable_thread<Executor>(std::move(a), ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Transfer ownership from another awaitable_thread.
|
||||
explicit awaitable_handler_base(awaitable_thread<Executor>* h)
|
||||
: awaitable_thread<Executor>(std::move(*h))
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
awaitable_frame<T, Executor>* frame() noexcept
|
||||
{
|
||||
return static_cast<awaitable_frame<T, Executor>*>(this->top_of_stack_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename, typename...>
|
||||
class awaitable_handler;
|
||||
|
||||
template <typename Executor>
|
||||
class awaitable_handler<Executor, void>
|
||||
: public awaitable_handler_base<Executor, void>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor, void>::awaitable_handler_base;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
this->frame()->return_void();
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class awaitable_handler<Executor, asio::error_code>
|
||||
: public awaitable_handler_base<Executor, void>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor, void>::awaitable_handler_base;
|
||||
|
||||
void operator()(const asio::error_code& ec)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
if (ec)
|
||||
this->frame()->set_error(ec);
|
||||
else
|
||||
this->frame()->return_void();
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class awaitable_handler<Executor, std::exception_ptr>
|
||||
: public awaitable_handler_base<Executor, void>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor, void>::awaitable_handler_base;
|
||||
|
||||
void operator()(std::exception_ptr ex)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
if (ex)
|
||||
this->frame()->set_except(ex);
|
||||
else
|
||||
this->frame()->return_void();
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class awaitable_handler<Executor, T>
|
||||
: public awaitable_handler_base<Executor, T>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor, T>::awaitable_handler_base;
|
||||
|
||||
template <typename Arg>
|
||||
void operator()(Arg&& arg)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
this->frame()->return_value(std::forward<Arg>(arg));
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class awaitable_handler<Executor, asio::error_code, T>
|
||||
: public awaitable_handler_base<Executor, T>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor, T>::awaitable_handler_base;
|
||||
|
||||
template <typename Arg>
|
||||
void operator()(const asio::error_code& ec, Arg&& arg)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
if (ec)
|
||||
this->frame()->set_error(ec);
|
||||
else
|
||||
this->frame()->return_value(std::forward<Arg>(arg));
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename T>
|
||||
class awaitable_handler<Executor, std::exception_ptr, T>
|
||||
: public awaitable_handler_base<Executor, T>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor, T>::awaitable_handler_base;
|
||||
|
||||
template <typename Arg>
|
||||
void operator()(std::exception_ptr ex, Arg&& arg)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
if (ex)
|
||||
this->frame()->set_except(ex);
|
||||
else
|
||||
this->frame()->return_value(std::forward<Arg>(arg));
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename... Ts>
|
||||
class awaitable_handler
|
||||
: public awaitable_handler_base<Executor, std::tuple<Ts...>>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor,
|
||||
std::tuple<Ts...>>::awaitable_handler_base;
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(Args&&... args)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
this->frame()->return_values(std::forward<Args>(args)...);
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename... Ts>
|
||||
class awaitable_handler<Executor, asio::error_code, Ts...>
|
||||
: public awaitable_handler_base<Executor, std::tuple<Ts...>>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor,
|
||||
std::tuple<Ts...>>::awaitable_handler_base;
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(const asio::error_code& ec, Args&&... args)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
if (ec)
|
||||
this->frame()->set_error(ec);
|
||||
else
|
||||
this->frame()->return_values(std::forward<Args>(args)...);
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename... Ts>
|
||||
class awaitable_handler<Executor, std::exception_ptr, Ts...>
|
||||
: public awaitable_handler_base<Executor, std::tuple<Ts...>>
|
||||
{
|
||||
public:
|
||||
using awaitable_handler_base<Executor,
|
||||
std::tuple<Ts...>>::awaitable_handler_base;
|
||||
|
||||
template <typename... Args>
|
||||
void operator()(std::exception_ptr ex, Args&&... args)
|
||||
{
|
||||
this->frame()->attach_thread(this);
|
||||
if (ex)
|
||||
this->frame()->set_except(ex);
|
||||
else
|
||||
this->frame()->return_values(std::forward<Args>(args)...);
|
||||
this->frame()->pop_frame();
|
||||
this->pump();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Executor, typename R, typename... Args>
|
||||
class async_result<use_awaitable_t<Executor>, R(Args...)>
|
||||
{
|
||||
public:
|
||||
typedef typename detail::awaitable_handler<
|
||||
Executor, typename decay<Args>::type...> handler_type;
|
||||
typedef typename handler_type::awaitable_type return_type;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
template <typename T>
|
||||
static T dummy_return()
|
||||
{
|
||||
return std::move(*static_cast<T*>(nullptr));
|
||||
}
|
||||
|
||||
template <>
|
||||
static void dummy_return()
|
||||
{
|
||||
}
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
template <typename Initiation, typename... InitArgs>
|
||||
static return_type initiate(Initiation initiation,
|
||||
use_awaitable_t<Executor>, InitArgs... args)
|
||||
{
|
||||
co_await [&](auto* frame)
|
||||
{
|
||||
handler_type handler(frame->detach_thread());
|
||||
std::move(initiation)(std::move(handler), std::move(args)...);
|
||||
return static_cast<handler_type*>(nullptr);
|
||||
};
|
||||
|
||||
for (;;) {} // Never reached.
|
||||
#if defined(_MSC_VER)
|
||||
co_return dummy_return<typename return_type::value_type>();
|
||||
#endif // defined(_MSC_VER)
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_IMPL_USE_AWAITABLE_HPP
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
// experimental/redirect_error.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// redirect_error.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef ASIO_EXPERIMENTAL_REDIRECT_ERROR_HPP
|
||||
#define ASIO_EXPERIMENTAL_REDIRECT_ERROR_HPP
|
||||
#ifndef ASIO_REDIRECT_ERROR_HPP
|
||||
#define ASIO_REDIRECT_ERROR_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
@ -22,7 +22,6 @@
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace experimental {
|
||||
|
||||
/// Completion token type used to specify that an error produced by an
|
||||
/// asynchronous operation is captured to an error_code variable.
|
||||
@ -51,17 +50,16 @@ public:
|
||||
/// Create a completion token to capture error_code values to a variable.
|
||||
template <typename CompletionToken>
|
||||
inline redirect_error_t<typename decay<CompletionToken>::type> redirect_error(
|
||||
CompletionToken&& completion_token, asio::error_code& ec)
|
||||
ASIO_MOVE_ARG(CompletionToken) completion_token, asio::error_code& ec)
|
||||
{
|
||||
return redirect_error_t<typename decay<CompletionToken>::type>(
|
||||
ASIO_MOVE_CAST(CompletionToken)(completion_token), ec);
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#include "asio/experimental/impl/redirect_error.hpp"
|
||||
#include "asio/impl/redirect_error.hpp"
|
||||
|
||||
#endif // ASIO_EXPERIMENTAL_REDIRECT_ERROR_HPP
|
||||
#endif // ASIO_REDIRECT_ERROR_HPP
|
45
asio/include/asio/this_coro.hpp
Normal file
45
asio/include/asio/this_coro.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// this_coro.hpp
|
||||
// ~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_THIS_CORO_HPP
|
||||
#define ASIO_THIS_CORO_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
namespace this_coro {
|
||||
|
||||
/// Awaitable type that returns the executor of the current coroutine.
|
||||
struct executor_t
|
||||
{
|
||||
ASIO_CONSTEXPR executor_t()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// Awaitable object that returns the executor of the current coroutine.
|
||||
#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
|
||||
constexpr executor_t executor;
|
||||
#elif defined(ASIO_MSVC)
|
||||
__declspec(selectany) executor_t executor;
|
||||
#endif
|
||||
|
||||
} // namespace this_coro
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#endif // ASIO_THIS_CORO_HPP
|
71
asio/include/asio/use_awaitable.hpp
Normal file
71
asio/include/asio/use_awaitable.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// use_awaitable.hpp
|
||||
// ~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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_USE_AWAITABLE_HPP
|
||||
#define ASIO_USE_AWAITABLE_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
|
||||
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include "asio/awaitable.hpp"
|
||||
|
||||
#include "asio/detail/push_options.hpp"
|
||||
|
||||
namespace asio {
|
||||
|
||||
/// A completion token that represents the currently executing coroutine.
|
||||
/**
|
||||
* The @c use_awaitable_t class, with its value @c use_awaitable, is used to
|
||||
* represent the currently executing coroutine. This completion token may be
|
||||
* passed as a handler to an asynchronous operation. For example:
|
||||
*
|
||||
* @code awaitable<void> my_coroutine()
|
||||
* {
|
||||
* std::size_t n = co_await my_socket.async_read_some(buffer, use_awaitable);
|
||||
* ...
|
||||
* } @endcode
|
||||
*
|
||||
* When used with co_await, the initiating function (@c async_read_some in the
|
||||
* above example) suspends the current coroutine. The coroutine is resumed when
|
||||
* the asynchronous operation completes, and the result of the operation is
|
||||
* returned.
|
||||
*/
|
||||
template <typename Executor = executor>
|
||||
struct use_awaitable_t
|
||||
{
|
||||
ASIO_CONSTEXPR use_awaitable_t()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// A completion token object that represents the currently executing coroutine.
|
||||
/**
|
||||
* See the documentation for asio::use_awaitable_t for a usage example.
|
||||
*/
|
||||
#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
|
||||
constexpr use_awaitable_t<> use_awaitable;
|
||||
#elif defined(ASIO_MSVC)
|
||||
__declspec(selectany) use_awaitable_t<> use_awaitable;
|
||||
#endif
|
||||
|
||||
} // namespace asio
|
||||
|
||||
#include "asio/detail/pop_options.hpp"
|
||||
|
||||
#include "asio/impl/use_awaitable.hpp"
|
||||
|
||||
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#endif // ASIO_USE_AWAITABLE_HPP
|
@ -22,7 +22,7 @@
|
||||
* [link asio.overview.core.concurrency_hint Concurrency Hints]
|
||||
* [link asio.overview.core.coroutine Stackless Coroutines]
|
||||
* [link asio.overview.core.spawn Stackful Coroutines]
|
||||
* [link asio.overview.core.coroutines_ts Coroutines TS Support (experimental)]
|
||||
* [link asio.overview.core.coroutines_ts Coroutines TS Support]
|
||||
* [link asio.overview.networking Networking]
|
||||
* [link asio.overview.networking.protocols TCP, UDP and ICMP]
|
||||
* [link asio.overview.networking.other_protocols Support for Other Protocols]
|
||||
@ -58,7 +58,7 @@
|
||||
* [link asio.overview.core.concurrency_hint Concurrency Hints]
|
||||
* [link asio.overview.core.coroutine Stackless Coroutines]
|
||||
* [link asio.overview.core.spawn Stackful Coroutines]
|
||||
* [link asio.overview.core.coroutines_ts Coroutines TS Support (experimental)]
|
||||
* [link asio.overview.core.coroutines_ts Coroutines TS Support]
|
||||
|
||||
[include overview/basics.qbk]
|
||||
[include overview/async.qbk]
|
||||
|
@ -5,37 +5,33 @@
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[section:coroutines_ts Coroutines TS Support (experimental)]
|
||||
[section:coroutines_ts Coroutines TS Support]
|
||||
|
||||
(Note: "Experimental" means that this interface is provided to gather feedback
|
||||
and may change in subsequent Asio releases.)
|
||||
Support for the Coroutines TS is provided via the [link
|
||||
asio.reference.awaitable `awaitable`] class template, the [link
|
||||
asio.reference.use_awaitable_t `use_awaitable`] completion token, and the [link
|
||||
asio.reference.co_spawn `co_spawn()`] function. These facilities allow programs
|
||||
to implement asynchronous logic in a synchronous manner, in conjunction with
|
||||
the `co_await` keyword, as shown in the following example:
|
||||
|
||||
Experimental support for the Coroutines TS is provided via the [link
|
||||
asio.reference.experimental__co_spawn `experimental::co_spawn()`]
|
||||
function. This `co_spawn()` function enables programs to implement asynchronous
|
||||
logic in a synchronous manner, in conjunction with the `co_await` keyword, as
|
||||
shown in the following example:
|
||||
|
||||
asio::experimental::co_spawn(executor,
|
||||
asio::co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
return echo(std::move(socket));
|
||||
},
|
||||
asio::experimental::detached);
|
||||
asio::detached);
|
||||
|
||||
// ...
|
||||
|
||||
asio::experimental::awaitable<void> echo(tcp::socket socket)
|
||||
asio::awaitable<void> echo(tcp::socket socket)
|
||||
{
|
||||
auto token = co_await asio::experimental::this_coro::token();
|
||||
|
||||
try
|
||||
{
|
||||
char data[1024];
|
||||
for (;;)
|
||||
{
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), token);
|
||||
co_await async_write(socket, asio::buffer(data, n), token);
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), asio::use_awaitable);
|
||||
co_await async_write(socket, asio::buffer(data, n), asio::use_awaitable);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
@ -51,7 +47,7 @@ coroutines; they should all run on the same `strand` so that no explicit
|
||||
synchronisation is required.
|
||||
|
||||
The second argument is a nullary function object that returns a [link
|
||||
asio.reference.experimental__awaitable `asio::awaitable<R>`],
|
||||
asio.reference.awaitable `asio::awaitable<R>`],
|
||||
where `R` is the type of return value produced by the coroutine. In the above
|
||||
example, the coroutine returns `void`.
|
||||
|
||||
@ -59,21 +55,15 @@ The third argument is a completion token, and this is used by `co_spawn()` to
|
||||
produce a completion handler with signature `void(std::exception_ptr, R)`. This
|
||||
completion handler is invoked with the result of the coroutine once it has
|
||||
finished. In the above example we pass a completion token type, [link
|
||||
asio.reference.experimental__detached
|
||||
`asio::experimental::detached`], which is used to explicitly ignore the
|
||||
result of an asynchronous operation.
|
||||
asio.reference.detached `asio::detached`], which is used to explicitly ignore
|
||||
the result of an asynchronous operation.
|
||||
|
||||
In this example the body of the coroutine is implemented in the `echo`
|
||||
function. This function first obtains a completion token that represents the
|
||||
current coroutine:
|
||||
function. When the `use_awaitable` completion token is passed to an
|
||||
asynchronous operation, the operation's initiating function returns an
|
||||
`awaitable` that may be used with the `co_await` keyword:
|
||||
|
||||
auto token = co_await asio::experimental::this_coro::token();
|
||||
|
||||
When this completion token is passed to an asynchronous operation, the
|
||||
operation's initiating function returns an `awaitable` that may be used with
|
||||
the `co_await` keyword:
|
||||
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), token);
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), asio::use_awaitable);
|
||||
|
||||
Where an asynchronous operation's handler signature has the form:
|
||||
|
||||
@ -93,13 +83,13 @@ passed back to the coroutine as a `system_error` exception.
|
||||
|
||||
[heading See Also]
|
||||
|
||||
[link asio.reference.experimental__co_spawn experimental::co_spawn],
|
||||
[link asio.reference.experimental__detached experimental::detached],
|
||||
[link asio.reference.experimental__redirect_error experimental::redirect_error],
|
||||
[link asio.reference.experimental__awaitable experimental::awaitable],
|
||||
[link asio.reference.experimental__await_token experimental::await_token],
|
||||
[link asio.reference.experimental__this_coro__executor experimental::this_coro::executor],
|
||||
[link asio.reference.experimental__this_coro__token experimental::this_coro::token],
|
||||
[link asio.reference.co_spawn co_spawn],
|
||||
[link asio.reference.detached detached],
|
||||
[link asio.reference.redirect_error redirect_error],
|
||||
[link asio.reference.awaitable awaitable],
|
||||
[link asio.reference.use_awaitable_t use_awaitable_t],
|
||||
[link asio.reference.use_awaitable use_awaitable],
|
||||
[link asio.reference.this_coro__executor this_coro::executor],
|
||||
[link asio.examples.cpp17_examples.coroutines_ts_support Coroutines TS examples],
|
||||
[link asio.overview.core.spawn Stackful Coroutines],
|
||||
[link asio.overview.core.coroutine Stackless Coroutines].
|
||||
|
@ -27,6 +27,7 @@
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="asio.reference.coroutine">coroutine</link></member>
|
||||
<member><link linkend="asio.reference.detached_t">detached_t</link></member>
|
||||
<member><link linkend="asio.reference.error_code">error_code</link></member>
|
||||
<member><link linkend="asio.reference.execution_context">execution_context</link></member>
|
||||
<member><link linkend="asio.reference.execution_context__id">execution_context::id</link></member>
|
||||
@ -42,6 +43,7 @@
|
||||
<member><link linkend="asio.reference.service_already_exists">service_already_exists</link></member>
|
||||
<member><link linkend="asio.reference.system_error">system_error</link></member>
|
||||
<member><link linkend="asio.reference.system_executor">system_executor</link></member>
|
||||
<member><link linkend="asio.reference.this_coro__executor_t">this_coro::executor_t</link></member>
|
||||
<member><link linkend="asio.reference.thread">thread</link></member>
|
||||
<member><link linkend="asio.reference.thread_pool">thread_pool</link></member>
|
||||
<member><link linkend="asio.reference.thread_pool__executor_type">thread_pool::executor_type</link></member>
|
||||
@ -57,6 +59,7 @@
|
||||
<member><link linkend="asio.reference.asio_handler_invoke">asio_handler_invoke</link></member>
|
||||
<member><link linkend="asio.reference.asio_handler_is_continuation">asio_handler_is_continuation</link></member>
|
||||
<member><link linkend="asio.reference.bind_executor">bind_executor</link></member>
|
||||
<member><link linkend="asio.reference.co_spawn">co_spawn</link></member>
|
||||
<member><link linkend="asio.reference.dispatch">dispatch</link></member>
|
||||
<member><link linkend="asio.reference.defer">defer</link></member>
|
||||
<member><link linkend="asio.reference.get_associated_allocator">get_associated_allocator</link></member>
|
||||
@ -72,16 +75,21 @@
|
||||
<bridgehead renderas="sect3">Class Templates</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="asio.reference.async_completion">async_completion</link></member>
|
||||
<member><link linkend="asio.reference.awaitable">awaitable</link></member>
|
||||
<member><link linkend="asio.reference.basic_io_object">basic_io_object</link></member>
|
||||
<member><link linkend="asio.reference.basic_yield_context">basic_yield_context</link></member>
|
||||
<member><link linkend="asio.reference.executor_binder">executor_binder</link></member>
|
||||
<member><link linkend="asio.reference.executor_work_guard">executor_work_guard</link></member>
|
||||
<member><link linkend="asio.reference.redirect_error_t">redirect_error_t</link></member>
|
||||
<member><link linkend="asio.reference.strand">strand</link></member>
|
||||
<member><link linkend="asio.reference.use_awaitable_t">use_awaitable_t</link></member>
|
||||
<member><link linkend="asio.reference.use_future_t">use_future_t</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Special Values</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="asio.reference.detached">detached</link></member>
|
||||
<member><link linkend="asio.reference.executor_arg">executor_arg</link></member>
|
||||
<member><link linkend="asio.reference.this_coro__executor">this_coro::executor</link></member>
|
||||
<member><link linkend="asio.reference.use_future">use_future</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Boost.Bind Placeholders</bridgehead>
|
||||
@ -455,11 +463,10 @@
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
<tgroup cols="4">
|
||||
<tgroup cols="3">
|
||||
<colspec colname="a"/>
|
||||
<colspec colname="b"/>
|
||||
<colspec colname="c"/>
|
||||
<colspec colname="d"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry valign="center" namest="a" nameend="b">
|
||||
@ -468,9 +475,6 @@
|
||||
<entry valign="center" namest="c" nameend="c">
|
||||
<bridgehead renderas="sect2">Windows-specific</bridgehead>
|
||||
</entry>
|
||||
<entry valign="center" namest="d" nameend="d">
|
||||
<bridgehead renderas="sect2">Experimental</bridgehead>
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -511,30 +515,6 @@
|
||||
<member><link linkend="asio.reference.windows__stream_handle">windows::stream_handle</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="asio.reference.experimental__detached_t">experimental::detached_t</link></member>
|
||||
<member><link linkend="asio.reference.experimental__this_coro__executor_t">experimental::this_coro::executor_t</link></member>
|
||||
<member><link linkend="asio.reference.experimental__this_coro__token_t">experimental::this_coro::token_t</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Class Templates</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="asio.reference.experimental__awaitable">experimental::awaitable</link></member>
|
||||
<member><link linkend="asio.reference.experimental__await_token">experimental::await_token</link></member>
|
||||
<member><link linkend="asio.reference.experimental__redirect_error_t">experimental::redirect_error_t</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Free Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="asio.reference.experimental__co_spawn">experimental::co_spawn</link></member>
|
||||
<member><link linkend="asio.reference.experimental__this_coro__executor">experimental::this_coro::executor</link></member>
|
||||
<member><link linkend="asio.reference.experimental__this_coro__token">experimental::this_coro::token</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Special Values</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="asio.reference.experimental__detached">experimental::detached</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
@ -1,6 +1,5 @@
|
||||
EXTRA_DIST = \
|
||||
coroutines_ts/chat_server.cpp \
|
||||
coroutines_ts/double_buffered_echo_server.cpp \
|
||||
coroutines_ts/echo_server.cpp \
|
||||
coroutines_ts/range_based_for.cpp \
|
||||
coroutines_ts/refactored_echo_server.cpp
|
||||
|
@ -16,20 +16,24 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <asio/experimental.hpp>
|
||||
#include <asio/awaitable.hpp>
|
||||
#include <asio/detached.hpp>
|
||||
#include <asio/co_spawn.hpp>
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/read_until.hpp>
|
||||
#include <asio/redirect_error.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <asio/use_awaitable.hpp>
|
||||
#include <asio/write.hpp>
|
||||
|
||||
using asio::ip::tcp;
|
||||
using asio::experimental::awaitable;
|
||||
using asio::experimental::co_spawn;
|
||||
using asio::experimental::detached;
|
||||
using asio::experimental::redirect_error;
|
||||
namespace this_coro = asio::experimental::this_coro;
|
||||
using asio::awaitable;
|
||||
using asio::co_spawn;
|
||||
using asio::detached;
|
||||
using asio::redirect_error;
|
||||
using asio::use_awaitable;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
@ -112,14 +116,12 @@ public:
|
||||
private:
|
||||
awaitable<void> reader()
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
try
|
||||
{
|
||||
for (std::string read_msg;;)
|
||||
{
|
||||
std::size_t n = co_await asio::async_read_until(socket_,
|
||||
asio::dynamic_buffer(read_msg, 1024), "\n", token);
|
||||
asio::dynamic_buffer(read_msg, 1024), "\n", use_awaitable);
|
||||
|
||||
room_.deliver(read_msg.substr(0, n));
|
||||
read_msg.erase(0, n);
|
||||
@ -133,8 +135,6 @@ private:
|
||||
|
||||
awaitable<void> writer()
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
try
|
||||
{
|
||||
while (socket_.is_open())
|
||||
@ -142,12 +142,12 @@ private:
|
||||
if (write_msgs_.empty())
|
||||
{
|
||||
asio::error_code ec;
|
||||
co_await timer_.async_wait(redirect_error(token, ec));
|
||||
co_await timer_.async_wait(redirect_error(use_awaitable, ec));
|
||||
}
|
||||
else
|
||||
{
|
||||
co_await asio::async_write(socket_,
|
||||
asio::buffer(write_msgs_.front()), token);
|
||||
asio::buffer(write_msgs_.front()), use_awaitable);
|
||||
write_msgs_.pop_front();
|
||||
}
|
||||
}
|
||||
@ -175,14 +175,12 @@ private:
|
||||
|
||||
awaitable<void> listener(tcp::acceptor acceptor)
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
chat_room room;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::make_shared<chat_session>(
|
||||
co_await acceptor.async_accept(token),
|
||||
co_await acceptor.async_accept(use_awaitable),
|
||||
room
|
||||
)->start();
|
||||
}
|
||||
|
@ -1,97 +0,0 @@
|
||||
//
|
||||
// double_buffered_echo_server.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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)
|
||||
//
|
||||
|
||||
#include <asio/experimental/co_spawn.hpp>
|
||||
#include <asio/experimental/detached.hpp>
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
#include <asio/write.hpp>
|
||||
#include <cstdio>
|
||||
|
||||
using asio::ip::tcp;
|
||||
using asio::experimental::co_spawn;
|
||||
using asio::experimental::detached;
|
||||
namespace this_coro = asio::experimental::this_coro;
|
||||
|
||||
template <typename T>
|
||||
using awaitable = asio::experimental::awaitable<
|
||||
T, asio::io_context::executor_type>;
|
||||
|
||||
awaitable<void> echo(tcp::socket s)
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
try
|
||||
{
|
||||
char data1[1024];
|
||||
char data2[1024];
|
||||
|
||||
char* p1 = data1;
|
||||
char* p2 = data2;
|
||||
|
||||
// Perform initial read into first buffer.
|
||||
size_t n = co_await s.async_read_some(asio::buffer(p1, 1024), token);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// Swap received data to other buffer and initiate write operation.
|
||||
std::swap(p1, p2);
|
||||
auto write_result = asio::async_write(s, asio::buffer(p2, n), token);
|
||||
|
||||
// Perform next read while write operation is in progress.
|
||||
n = co_await s.async_read_some(asio::buffer(p1, 1024), token);
|
||||
|
||||
// Wait for write operation to complete before proceeding.
|
||||
co_await write_result;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::printf("echo Exception: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
awaitable<void> listener()
|
||||
{
|
||||
auto executor = co_await this_coro::executor();
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
tcp::acceptor acceptor(executor, {tcp::v4(), 55555});
|
||||
for (;;)
|
||||
{
|
||||
tcp::socket socket = co_await acceptor.async_accept(token);
|
||||
co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
return echo(std::move(socket));
|
||||
},
|
||||
detached);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
asio::io_context io_context(1);
|
||||
|
||||
asio::signal_set signals(io_context, SIGINT, SIGTERM);
|
||||
signals.async_wait([&](auto, auto){ io_context.stop(); });
|
||||
|
||||
co_spawn(io_context, listener, detached);
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::printf("Exception: %s\n", e.what());
|
||||
}
|
||||
}
|
@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <asio/experimental/co_spawn.hpp>
|
||||
#include <asio/experimental/detached.hpp>
|
||||
#include <asio/co_spawn.hpp>
|
||||
#include <asio/detached.hpp>
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
@ -17,25 +17,21 @@
|
||||
#include <cstdio>
|
||||
|
||||
using asio::ip::tcp;
|
||||
using asio::experimental::co_spawn;
|
||||
using asio::experimental::detached;
|
||||
namespace this_coro = asio::experimental::this_coro;
|
||||
|
||||
template <typename T>
|
||||
using awaitable = asio::experimental::awaitable<
|
||||
T, asio::io_context::executor_type>;
|
||||
using asio::awaitable;
|
||||
using asio::co_spawn;
|
||||
using asio::detached;
|
||||
using asio::use_awaitable;
|
||||
namespace this_coro = asio::this_coro;
|
||||
|
||||
awaitable<void> echo(tcp::socket socket)
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
try
|
||||
{
|
||||
char data[1024];
|
||||
for (;;)
|
||||
{
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), token);
|
||||
co_await async_write(socket, asio::buffer(data, n), token);
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), use_awaitable);
|
||||
co_await async_write(socket, asio::buffer(data, n), use_awaitable);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
@ -46,13 +42,11 @@ awaitable<void> echo(tcp::socket socket)
|
||||
|
||||
awaitable<void> listener()
|
||||
{
|
||||
auto executor = co_await this_coro::executor();
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
auto executor = co_await this_coro::executor;
|
||||
tcp::acceptor acceptor(executor, {tcp::v4(), 55555});
|
||||
for (;;)
|
||||
{
|
||||
tcp::socket socket = co_await acceptor.async_accept(token);
|
||||
tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
|
||||
co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
|
@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <asio/experimental/co_spawn.hpp>
|
||||
#include <asio/experimental/detached.hpp>
|
||||
#include <asio/co_spawn.hpp>
|
||||
#include <asio/detached.hpp>
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
@ -17,10 +17,10 @@
|
||||
#include <cstdio>
|
||||
|
||||
using asio::ip::tcp;
|
||||
using asio::experimental::awaitable;
|
||||
using asio::experimental::co_spawn;
|
||||
using asio::experimental::detached;
|
||||
namespace this_coro = asio::experimental::this_coro;
|
||||
using asio::awaitable;
|
||||
using asio::co_spawn;
|
||||
using asio::detached;
|
||||
using asio::use_awaitable;
|
||||
|
||||
class connection_iter
|
||||
{
|
||||
@ -39,8 +39,7 @@ public:
|
||||
|
||||
awaitable<void> operator++()
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
socket_ = co_await acceptor_->async_accept(token);
|
||||
socket_ = co_await acceptor_->async_accept(use_awaitable);
|
||||
}
|
||||
|
||||
bool operator==(const connection_iter&) const noexcept
|
||||
@ -63,8 +62,7 @@ public:
|
||||
|
||||
awaitable<connection_iter> begin()
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
tcp::socket s = co_await acceptor_.async_accept(token);
|
||||
tcp::socket s = co_await acceptor_.async_accept(use_awaitable);
|
||||
co_return connection_iter(acceptor_, std::move(s));
|
||||
}
|
||||
|
||||
@ -77,11 +75,9 @@ public:
|
||||
|
||||
awaitable<void> listener(tcp::acceptor acceptor)
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
for co_await (tcp::socket s : connections(acceptor))
|
||||
{
|
||||
co_await asio::async_write(s, asio::buffer("hello\r\n", 7), token);
|
||||
co_await asio::async_write(s, asio::buffer("hello\r\n", 7), use_awaitable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <asio/experimental/co_spawn.hpp>
|
||||
#include <asio/experimental/detached.hpp>
|
||||
#include <asio/co_spawn.hpp>
|
||||
#include <asio/detached.hpp>
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
@ -17,21 +17,17 @@
|
||||
#include <cstdio>
|
||||
|
||||
using asio::ip::tcp;
|
||||
using asio::experimental::co_spawn;
|
||||
using asio::experimental::detached;
|
||||
namespace this_coro = asio::experimental::this_coro;
|
||||
|
||||
template <typename T>
|
||||
using awaitable = asio::experimental::awaitable<
|
||||
T, asio::io_context::executor_type>;
|
||||
using asio::awaitable;
|
||||
using asio::co_spawn;
|
||||
using asio::detached;
|
||||
using asio::use_awaitable;
|
||||
namespace this_coro = asio::this_coro;
|
||||
|
||||
awaitable<void> echo_once(tcp::socket& socket)
|
||||
{
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
char data[128];
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), token);
|
||||
co_await async_write(socket, asio::buffer(data, n), token);
|
||||
std::size_t n = co_await socket.async_read_some(asio::buffer(data), use_awaitable);
|
||||
co_await async_write(socket, asio::buffer(data, n), use_awaitable);
|
||||
}
|
||||
|
||||
awaitable<void> echo(tcp::socket socket)
|
||||
@ -55,13 +51,11 @@ awaitable<void> echo(tcp::socket socket)
|
||||
|
||||
awaitable<void> listener()
|
||||
{
|
||||
auto executor = co_await this_coro::executor();
|
||||
auto token = co_await this_coro::token();
|
||||
|
||||
auto executor = co_await this_coro::executor;
|
||||
tcp::acceptor acceptor(executor, {tcp::v4(), 55555});
|
||||
for (;;)
|
||||
{
|
||||
tcp::socket socket = co_await acceptor.async_accept(token);
|
||||
tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
|
||||
co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ check_PROGRAMS = \
|
||||
unit/associated_allocator \
|
||||
unit/associated_executor \
|
||||
unit/async_result \
|
||||
unit/awaitable \
|
||||
unit/basic_datagram_socket \
|
||||
unit/basic_deadline_timer \
|
||||
unit/basic_raw_socket \
|
||||
@ -30,11 +31,13 @@ check_PROGRAMS = \
|
||||
unit/buffered_write_stream \
|
||||
unit/buffer \
|
||||
unit/buffers_iterator \
|
||||
unit/co_spawn \
|
||||
unit/completion_condition \
|
||||
unit/connect \
|
||||
unit/coroutine \
|
||||
unit/deadline_timer \
|
||||
unit/defer \
|
||||
unit/detached \
|
||||
unit/dispatch \
|
||||
unit/error \
|
||||
unit/execution_context \
|
||||
@ -86,6 +89,7 @@ check_PROGRAMS = \
|
||||
unit/read \
|
||||
unit/read_at \
|
||||
unit/read_until \
|
||||
unit/redirect_error \
|
||||
unit/serial_port \
|
||||
unit/serial_port_base \
|
||||
unit/signal_set \
|
||||
@ -96,6 +100,7 @@ check_PROGRAMS = \
|
||||
unit/system_context \
|
||||
unit/system_executor \
|
||||
unit/system_timer \
|
||||
unit/this_coro \
|
||||
unit/thread \
|
||||
unit/time_traits \
|
||||
unit/ts/buffer \
|
||||
@ -106,6 +111,7 @@ check_PROGRAMS = \
|
||||
unit/ts/netfwd \
|
||||
unit/ts/socket \
|
||||
unit/ts/timer \
|
||||
unit/use_awaitable \
|
||||
unit/use_future \
|
||||
unit/uses_executor \
|
||||
unit/wait_traits \
|
||||
@ -145,6 +151,7 @@ TESTS = \
|
||||
unit/associated_allocator \
|
||||
unit/associated_executor \
|
||||
unit/async_result \
|
||||
unit/awaitable \
|
||||
unit/basic_datagram_socket \
|
||||
unit/basic_deadline_timer \
|
||||
unit/basic_raw_socket \
|
||||
@ -162,10 +169,12 @@ TESTS = \
|
||||
unit/buffered_write_stream \
|
||||
unit/buffer \
|
||||
unit/buffers_iterator \
|
||||
unit/co_spawn \
|
||||
unit/completion_condition \
|
||||
unit/connect \
|
||||
unit/deadline_timer \
|
||||
unit/defer \
|
||||
unit/detached \
|
||||
unit/dispatch \
|
||||
unit/error \
|
||||
unit/execution_context \
|
||||
@ -212,6 +221,7 @@ TESTS = \
|
||||
unit/read \
|
||||
unit/read_at \
|
||||
unit/read_until \
|
||||
unit/redirect_error \
|
||||
unit/serial_port \
|
||||
unit/serial_port_base \
|
||||
unit/signal_set \
|
||||
@ -222,6 +232,7 @@ TESTS = \
|
||||
unit/system_context \
|
||||
unit/system_executor \
|
||||
unit/system_timer \
|
||||
unit/this_coro \
|
||||
unit/thread \
|
||||
unit/time_traits \
|
||||
unit/ts/buffer \
|
||||
@ -232,6 +243,7 @@ TESTS = \
|
||||
unit/ts/netfwd \
|
||||
unit/ts/socket \
|
||||
unit/ts/timer \
|
||||
unit/use_awaitable \
|
||||
unit/use_future \
|
||||
unit/uses_executor \
|
||||
unit/wait_traits \
|
||||
@ -275,6 +287,7 @@ endif
|
||||
unit_associated_allocator_SOURCES = unit/associated_allocator.cpp
|
||||
unit_associated_executor_SOURCES = unit/associated_executor.cpp
|
||||
unit_async_result_SOURCES = unit/async_result.cpp
|
||||
unit_awaitable_SOURCES = unit/awaitable.cpp
|
||||
unit_basic_datagram_socket_SOURCES = unit/basic_datagram_socket.cpp
|
||||
unit_basic_deadline_timer_SOURCES = unit/basic_deadline_timer.cpp
|
||||
unit_basic_raw_socket_SOURCES = unit/basic_raw_socket.cpp
|
||||
@ -292,11 +305,13 @@ unit_buffers_iterator_SOURCES = unit/buffers_iterator.cpp
|
||||
unit_buffered_read_stream_SOURCES = unit/buffered_read_stream.cpp
|
||||
unit_buffered_stream_SOURCES = unit/buffered_stream.cpp
|
||||
unit_buffered_write_stream_SOURCES = unit/buffered_write_stream.cpp
|
||||
unit_co_spawn_SOURCES = unit/co_spawn.cpp
|
||||
unit_completion_condition_SOURCES = unit/completion_condition.cpp
|
||||
unit_connect_SOURCES = unit/connect.cpp
|
||||
unit_coroutine_SOURCES = unit/coroutine.cpp
|
||||
unit_deadline_timer_SOURCES = unit/deadline_timer.cpp
|
||||
unit_defer_SOURCES = unit/defer.cpp
|
||||
unit_detached_SOURCES = unit/detached.cpp
|
||||
unit_dispatch_SOURCES = unit/dispatch.cpp
|
||||
unit_error_SOURCES = unit/error.cpp
|
||||
unit_execution_context_SOURCES = unit/execution_context.cpp
|
||||
@ -348,6 +363,7 @@ unit_post_SOURCES = unit/post.cpp
|
||||
unit_read_SOURCES = unit/read.cpp
|
||||
unit_read_at_SOURCES = unit/read_at.cpp
|
||||
unit_read_until_SOURCES = unit/read_until.cpp
|
||||
unit_redirect_error_SOURCES = unit/redirect_error.cpp
|
||||
unit_serial_port_SOURCES = unit/serial_port.cpp
|
||||
unit_serial_port_base_SOURCES = unit/serial_port_base.cpp
|
||||
unit_signal_set_SOURCES = unit/signal_set.cpp
|
||||
@ -358,6 +374,7 @@ unit_streambuf_SOURCES = unit/streambuf.cpp
|
||||
unit_system_context_SOURCES = unit/system_context.cpp
|
||||
unit_system_executor_SOURCES = unit/system_executor.cpp
|
||||
unit_system_timer_SOURCES = unit/system_timer.cpp
|
||||
unit_this_coro_SOURCES = unit/this_coro.cpp
|
||||
unit_thread_SOURCES = unit/thread.cpp
|
||||
unit_time_traits_SOURCES = unit/time_traits.cpp
|
||||
unit_ts_buffer_SOURCES = unit/ts/buffer.cpp
|
||||
@ -368,6 +385,7 @@ unit_ts_net_SOURCES = unit/ts/net.cpp
|
||||
unit_ts_netfwd_SOURCES = unit/ts/netfwd.cpp
|
||||
unit_ts_socket_SOURCES = unit/ts/socket.cpp
|
||||
unit_ts_timer_SOURCES = unit/ts/timer.cpp
|
||||
unit_use_awaitable_SOURCES = unit/use_awaitable.cpp
|
||||
unit_use_future_SOURCES = unit/use_future.cpp
|
||||
unit_uses_executor_SOURCES = unit/uses_executor.cpp
|
||||
unit_wait_traits_SOURCES = unit/wait_traits.cpp
|
||||
|
6
asio/src/tests/unit/.gitignore
vendored
6
asio/src/tests/unit/.gitignore
vendored
@ -10,6 +10,7 @@
|
||||
associated_allocator
|
||||
associated_executor
|
||||
async_result
|
||||
awaitable
|
||||
basic_datagram_socket
|
||||
basic_deadline_timer
|
||||
basic_raw_socket
|
||||
@ -27,11 +28,13 @@ buffered_read_stream
|
||||
buffered_stream
|
||||
buffered_write_stream
|
||||
buffers_iterator
|
||||
co_spawn
|
||||
completion_condition
|
||||
connect
|
||||
coroutine
|
||||
deadline_timer
|
||||
defer
|
||||
detached
|
||||
dispatch
|
||||
error
|
||||
error_handler
|
||||
@ -49,6 +52,7 @@ post
|
||||
read
|
||||
read_at
|
||||
read_until
|
||||
redirect_error
|
||||
serial_port
|
||||
serial_port_base
|
||||
signal_set
|
||||
@ -59,8 +63,10 @@ streambuf
|
||||
system_context
|
||||
system_executor
|
||||
system_timer
|
||||
this_coro
|
||||
thread
|
||||
time_traits
|
||||
use_awaitable
|
||||
use_future
|
||||
uses_executor
|
||||
wait_traits
|
||||
|
25
asio/src/tests/unit/awaitable.cpp
Normal file
25
asio/src/tests/unit/awaitable.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// awaitable.cpp
|
||||
// ~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/awaitable.hpp"
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"awaitable",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
25
asio/src/tests/unit/co_spawn.cpp
Normal file
25
asio/src/tests/unit/co_spawn.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// co_spawn.cpp
|
||||
// ~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/co_spawn.hpp"
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"co_spawn",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
25
asio/src/tests/unit/detached.cpp
Normal file
25
asio/src/tests/unit/detached.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// detached.cpp
|
||||
// ~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/detached.hpp"
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"detached",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
25
asio/src/tests/unit/redirect_error.cpp
Normal file
25
asio/src/tests/unit/redirect_error.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// redirect_error.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/redirect_error.hpp"
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"redirect_error",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
25
asio/src/tests/unit/this_coro.cpp
Normal file
25
asio/src/tests/unit/this_coro.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// this_coro.cpp
|
||||
// ~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/this_coro.hpp"
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"this_coro",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
25
asio/src/tests/unit/use_awaitable.cpp
Normal file
25
asio/src/tests/unit/use_awaitable.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// use_awaitable.cpp
|
||||
// ~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 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)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/use_awaitable.hpp"
|
||||
|
||||
#include "unit_test.hpp"
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"use_awaitable",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
Loading…
Reference in New Issue
Block a user