Add custom I/O executor support to I/O objects.

All I/O objects now have an additional Executor template parameter. This
template parameter defaults to the asio::executor type (the polymorphic
executor wrapper) but can be used to specify a user-defined executor
type.

I/O objects' constructors and functions that previously took an
asio::io_context& now accept either an Executor or a reference to a
concrete ExecutionContext (such as asio::io_context or
asio::thread_pool).

One potential point of breakage in existing user code is when reusing an
I/O object's io_context for constructing another I/O object, as in:

    asio::steady_timer my_timer(my_socket.get_executor().context());

To fix this, either construct the second I/O object using the first I/O
object's executor:

    asio::steady_timer my_timer(my_socket.get_executor());

or otherwise explicitly pass the io_context:

    asio::steady_timer my_timer(my_io_context);
This commit is contained in:
Christopher Kohlhoff 2018-12-26 19:08:42 +11:00
parent 2c689adc90
commit cbe1c5e13d
169 changed files with 8275 additions and 8906 deletions

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,8 @@ nobase_include_HEADERS = \
asio/basic_io_object.hpp \
asio/basic_raw_socket.hpp \
asio/basic_seq_packet_socket.hpp \
asio/basic_serial_port.hpp \
asio/basic_signal_set.hpp \
asio/basic_socket_acceptor.hpp \
asio/basic_socket.hpp \
asio/basic_socket_iostream.hpp \
@ -51,6 +53,7 @@ nobase_include_HEADERS = \
asio/detail/cstddef.hpp \
asio/detail/cstdint.hpp \
asio/detail/date_time_fwd.hpp \
asio/detail/deadline_timer_service.hpp \
asio/detail/dependent_type.hpp \
asio/detail/descriptor_ops.hpp \
asio/detail/descriptor_read_op.hpp \
@ -128,6 +131,7 @@ nobase_include_HEADERS = \
asio/detail/impl/win_thread.ipp \
asio/detail/impl/win_tss_ptr.ipp \
asio/detail/io_control.hpp \
asio/detail/io_object_executor.hpp \
asio/detail/io_object_impl.hpp \
asio/detail/is_buffer_sequence.hpp \
asio/detail/is_executor.hpp \
@ -390,6 +394,8 @@ nobase_include_HEADERS = \
asio/local/stream_protocol.hpp \
asio/packaged_task.hpp \
asio/placeholders.hpp \
asio/posix/basic_descriptor.hpp \
asio/posix/basic_stream_descriptor.hpp \
asio/posix/descriptor_base.hpp \
asio/posix/descriptor.hpp \
asio/posix/stream_descriptor.hpp \
@ -453,6 +459,10 @@ nobase_include_HEADERS = \
asio/uses_executor.hpp \
asio/version.hpp \
asio/wait_traits.hpp \
asio/windows/basic_object_handle.hpp \
asio/windows/basic_overlapped_handle.hpp \
asio/windows/basic_random_access_handle.hpp \
asio/windows/basic_stream_handle.hpp \
asio/windows/object_handle.hpp \
asio/windows/overlapped_handle.hpp \
asio/windows/overlapped_ptr.hpp \

View File

@ -23,6 +23,9 @@
#include "asio/basic_io_object.hpp"
#include "asio/basic_raw_socket.hpp"
#include "asio/basic_seq_packet_socket.hpp"
#include "asio/basic_serial_port.hpp"
#include "asio/basic_signal_set.hpp"
#include "asio/basic_socket.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_socket_streambuf.hpp"
@ -94,6 +97,8 @@
#include "asio/local/stream_protocol.hpp"
#include "asio/packaged_task.hpp"
#include "asio/placeholders.hpp"
#include "asio/posix/basic_descriptor.hpp"
#include "asio/posix/basic_stream_descriptor.hpp"
#include "asio/posix/descriptor.hpp"
#include "asio/posix/descriptor_base.hpp"
#include "asio/posix/stream_descriptor.hpp"
@ -119,6 +124,10 @@
#include "asio/uses_executor.hpp"
#include "asio/version.hpp"
#include "asio/wait_traits.hpp"
#include "asio/windows/basic_object_handle.hpp"
#include "asio/windows/basic_overlapped_handle.hpp"
#include "asio/windows/basic_random_access_handle.hpp"
#include "asio/windows/basic_stream_handle.hpp"
#include "asio/windows/object_handle.hpp"
#include "asio/windows/overlapped_handle.hpp"
#include "asio/windows/overlapped_ptr.hpp"

View File

@ -27,6 +27,15 @@
namespace asio {
#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_datagram_socket;
#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
/// Provides datagram-oriented socket functionality.
/**
* The basic_datagram_socket class template provides asynchronous and blocking
@ -36,17 +45,28 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol>
template <typename Protocol, typename Executor>
class basic_datagram_socket
: public basic_socket<Protocol>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_datagram_socket<Protocol, Executor1> other;
};
/// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<
Protocol>::native_handle_type native_handle_type;
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif
/// The protocol type.
@ -60,12 +80,29 @@ public:
* This constructor creates a datagram socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_datagram_socket(asio::io_context& io_context)
: basic_socket<Protocol>(io_context)
explicit basic_datagram_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}
/// Construct a basic_datagram_socket without opening it.
/**
* This constructor creates a datagram socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_datagram_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}
@ -73,17 +110,37 @@ public:
/**
* This constructor creates and opens a datagram socket.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_context& io_context,
const protocol_type& protocol)
: basic_socket<Protocol>(io_context, protocol)
basic_datagram_socket(const executor_type& ex, const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}
/// Construct and open a basic_datagram_socket.
/**
* This constructor creates and opens a datagram socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_datagram_socket(ExecutionContext& context,
const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}
@ -94,18 +151,42 @@ public:
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the datagram
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_context& io_context,
const endpoint_type& endpoint)
: basic_socket<Protocol>(io_context, endpoint)
basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}
/// Construct a basic_datagram_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a datagram socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the datagram
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_datagram_socket(ExecutionContext& context,
const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}
@ -114,9 +195,8 @@ public:
* This constructor creates a datagram socket object to hold an existing
* native socket.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
@ -124,9 +204,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_context& io_context,
basic_datagram_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol>(io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}
/// Construct a basic_datagram_socket on an existing native socket.
/**
* This constructor creates a datagram socket object to hold an existing
* native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_datagram_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}
@ -139,10 +244,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
basic_datagram_socket(basic_datagram_socket&& other)
: basic_socket<Protocol>(std::move(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -155,11 +261,12 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
basic_datagram_socket& operator=(basic_datagram_socket&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
@ -172,12 +279,16 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
basic_datagram_socket(basic_datagram_socket<Protocol1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol>(std::move(other))
template <typename Protocol1, typename Executor1>
basic_datagram_socket(basic_datagram_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -191,14 +302,17 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_datagram_socket>::type& operator=(
basic_datagram_socket<Protocol1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_datagram_socket&
>::type operator=(basic_datagram_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
@ -315,9 +429,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
@ -346,7 +460,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, 0, init.completion_handler);
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -371,9 +486,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
@ -394,7 +509,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, flags, init.completion_handler);
buffers, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -508,9 +624,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
@ -538,9 +654,9 @@ public:
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send_to(
this->impl_.get_implementation(), buffers, destination, 0,
init.completion_handler);
this->impl_.get_service().async_send_to(this->impl_.get_implementation(),
buffers, destination, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -568,9 +684,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
@ -588,7 +704,7 @@ public:
this->impl_.get_service().async_send_to(
this->impl_.get_implementation(), buffers, destination, flags,
init.completion_handler);
init.completion_handler, this->impl_.get_implementation_executor());
return init.result.get();
}
@ -700,9 +816,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@ -732,7 +848,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_receive(this->impl_.get_implementation(),
buffers, 0, init.completion_handler);
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -757,9 +874,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@ -780,7 +897,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_receive(this->impl_.get_implementation(),
buffers, flags, init.completion_handler);
buffers, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -897,9 +1015,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@ -926,7 +1044,8 @@ public:
this->impl_.get_service().async_receive_from(
this->impl_.get_implementation(), buffers,
sender_endpoint, 0, init.completion_handler);
sender_endpoint, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -956,9 +1075,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
@ -976,7 +1095,8 @@ public:
this->impl_.get_service().async_receive_from(
this->impl_.get_implementation(), buffers,
sender_endpoint, flags, init.completion_handler);
sender_endpoint, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}

View File

@ -26,6 +26,8 @@
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/time_traits.hpp"
#include "asio/detail/push_options.hpp"
@ -51,7 +53,7 @@ namespace asio {
* Performing a blocking wait:
* @code
* // Construct a timer without setting an expiry time.
* asio::deadline_timer timer(io_context);
* asio::deadline_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_from_now(boost::posix_time::seconds(5));
@ -74,7 +76,7 @@ namespace asio {
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::deadline_timer timer(io_context,
* asio::deadline_timer timer(my_context,
* boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
*
* // Start an asynchronous wait.
@ -121,12 +123,13 @@ namespace asio {
* it contains the value asio::error::operation_aborted.
*/
template <typename Time,
typename TimeTraits = asio::time_traits<Time> >
typename TimeTraits = asio::time_traits<Time>,
typename Executor = executor>
class basic_deadline_timer
{
public:
/// The type of the executor associated with the object.
typedef io_context::executor_type executor_type;
typedef Executor executor_type;
/// The time traits type.
typedef TimeTraits traits_type;
@ -143,11 +146,30 @@ public:
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_deadline_timer(asio::io_context& io_context)
: impl_(io_context)
explicit basic_deadline_timer(const executor_type& ex)
: impl_(ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_deadline_timer(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}
@ -155,15 +177,37 @@ public:
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_deadline_timer(asio::io_context& io_context,
const time_type& expiry_time)
: impl_(io_context)
basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
@ -174,15 +218,40 @@ public:
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_deadline_timer(asio::io_context& io_context,
basic_deadline_timer(const executor_type& ex,
const duration_type& expiry_time)
: impl_(io_context)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context,
const duration_type& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().expires_from_now(
@ -199,7 +268,8 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(io_context&) constructor.
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer(basic_deadline_timer&& other)
: impl_(std::move(other.impl_))
@ -215,7 +285,8 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(io_context&) constructor.
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer& operator=(basic_deadline_timer&& other)
{
@ -544,9 +615,9 @@ public:
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
@ -561,7 +632,7 @@ public:
void (asio::error_code)> init(handler);
impl_.get_service().async_wait(impl_.get_implementation(),
init.completion_handler);
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -572,7 +643,8 @@ private:
basic_deadline_timer& operator=(
const basic_deadline_timer&) ASIO_DELETED;
detail::io_object_impl<detail::deadline_timer_service<TimeTraits> > impl_;
detail::io_object_impl<
detail::deadline_timer_service<TimeTraits>, Executor> impl_;
};
} // namespace asio

View File

@ -27,6 +27,15 @@
namespace asio {
#if !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)
#define ASIO_BASIC_RAW_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_raw_socket;
#endif // !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)
/// Provides raw-oriented socket functionality.
/**
* The basic_raw_socket class template provides asynchronous and blocking
@ -36,17 +45,28 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol>
template <typename Protocol, typename Executor>
class basic_raw_socket
: public basic_socket<Protocol>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_raw_socket<Protocol, Executor1> other;
};
/// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<
Protocol>::native_handle_type native_handle_type;
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif
/// The protocol type.
@ -60,12 +80,29 @@ public:
* This constructor creates a raw socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_raw_socket(asio::io_context& io_context)
: basic_socket<Protocol>(io_context)
explicit basic_raw_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}
/// Construct a basic_raw_socket without opening it.
/**
* This constructor creates a raw socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_raw_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}
@ -73,17 +110,36 @@ public:
/**
* This constructor creates and opens a raw socket.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_raw_socket(asio::io_context& io_context,
const protocol_type& protocol)
: basic_socket<Protocol>(io_context, protocol)
basic_raw_socket(const executor_type& ex, const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}
/// Construct and open a basic_raw_socket.
/**
* This constructor creates and opens a raw socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_raw_socket(ExecutionContext& context, const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}
@ -94,18 +150,41 @@ public:
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the raw
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_raw_socket(asio::io_context& io_context,
const endpoint_type& endpoint)
: basic_socket<Protocol>(io_context, endpoint)
basic_raw_socket(const executor_type& ex, const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}
/// Construct a basic_raw_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a raw socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the raw
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}
@ -114,9 +193,8 @@ public:
* This constructor creates a raw socket object to hold an existing
* native socket.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
@ -124,9 +202,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_raw_socket(asio::io_context& io_context,
basic_raw_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol>(io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}
/// Construct a basic_raw_socket on an existing native socket.
/**
* This constructor creates a raw socket object to hold an existing
* native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_raw_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}
@ -139,10 +242,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
basic_raw_socket(basic_raw_socket&& other)
: basic_socket<Protocol>(std::move(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -154,28 +258,34 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
basic_raw_socket& operator=(basic_raw_socket&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_raw_socket from a socket of another protocol type.
/// Move-construct a basic_raw_socket from a socket of another protocol
/// type.
/**
* This constructor moves a raw socket from one object to another.
*
* @param other The other basic_raw_socket object from which the move will
* occur.
* @param other The other basic_raw_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
basic_raw_socket(basic_raw_socket<Protocol1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol>(std::move(other))
template <typename Protocol1, typename Executor1>
basic_raw_socket(basic_raw_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -187,14 +297,17 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_raw_socket>::type& operator=(
basic_raw_socket<Protocol1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_raw_socket&
>::type operator=(basic_raw_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
@ -308,9 +421,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected raw
@ -339,7 +452,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, 0, init.completion_handler);
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -364,9 +478,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected raw
@ -387,7 +501,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, flags, init.completion_handler);
buffers, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -501,9 +616,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
@ -532,7 +647,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send_to(this->impl_.get_implementation(),
buffers, destination, 0, init.completion_handler);
buffers, destination, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -560,9 +676,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
@ -580,7 +696,7 @@ public:
this->impl_.get_service().async_send_to(
this->impl_.get_implementation(), buffers, destination, flags,
init.completion_handler);
init.completion_handler, this->impl_.get_implementation_executor());
return init.result.get();
}
@ -692,9 +808,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@ -724,7 +840,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_receive(this->impl_.get_implementation(),
buffers, 0, init.completion_handler);
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -749,9 +866,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@ -772,7 +889,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_receive(this->impl_.get_implementation(),
buffers, flags, init.completion_handler);
buffers, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -889,9 +1007,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@ -918,7 +1036,8 @@ public:
this->impl_.get_service().async_receive_from(
this->impl_.get_implementation(), buffers,
sender_endpoint, 0, init.completion_handler);
sender_endpoint, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -948,9 +1067,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
@ -968,7 +1087,8 @@ public:
this->impl_.get_service().async_receive_from(
this->impl_.get_implementation(), buffers,
sender_endpoint, flags, init.completion_handler);
sender_endpoint, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}

View File

@ -26,6 +26,15 @@
namespace asio {
#if !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
#define ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_seq_packet_socket;
#endif // !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
/// Provides sequenced packet socket functionality.
/**
* The basic_seq_packet_socket class template provides asynchronous and blocking
@ -35,17 +44,28 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol>
template <typename Protocol, typename Executor>
class basic_seq_packet_socket
: public basic_socket<Protocol>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_seq_packet_socket<Protocol, Executor1> other;
};
/// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<
Protocol>::native_handle_type native_handle_type;
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif
/// The protocol type.
@ -60,12 +80,30 @@ public:
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_seq_packet_socket(asio::io_context& io_context)
: basic_socket<Protocol>(io_context)
explicit basic_seq_packet_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}
/// Construct a basic_seq_packet_socket without opening it.
/**
* This constructor creates a sequenced packet socket without opening it. The
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_seq_packet_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}
@ -75,17 +113,40 @@ public:
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(asio::io_context& io_context,
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol)
: basic_socket<Protocol>(io_context, protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}
/// Construct and open a basic_seq_packet_socket.
/**
* This constructor creates and opens a sequenced_packet socket. The socket
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}
@ -96,18 +157,43 @@ public:
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(asio::io_context& io_context,
basic_seq_packet_socket(const executor_type& ex,
const endpoint_type& endpoint)
: basic_socket<Protocol>(io_context, endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}
/// Construct a basic_seq_packet_socket, opening it and binding it to the
/// given local endpoint.
/**
* This constructor creates a sequenced packet socket and automatically opens
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}
@ -116,9 +202,8 @@ public:
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
@ -126,9 +211,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(asio::io_context& io_context,
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol>(io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}
/// Construct a basic_seq_packet_socket on an existing native socket.
/**
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}
@ -142,10 +252,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket(basic_seq_packet_socket&& other)
: basic_socket<Protocol>(std::move(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -158,11 +269,12 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
@ -176,13 +288,16 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
basic_seq_packet_socket(
basic_seq_packet_socket<Protocol1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol>(std::move(other))
template <typename Protocol1, typename Executor1>
basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -196,14 +311,17 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_seq_packet_socket>::type& operator=(
basic_seq_packet_socket<Protocol1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_seq_packet_socket&
>::type operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
@ -297,9 +415,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
@ -325,7 +443,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, flags, init.completion_handler);
buffers, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -473,9 +592,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@ -503,7 +622,8 @@ public:
this->impl_.get_service().async_receive_with_flags(
this->impl_.get_implementation(), buffers,
0, out_flags, init.completion_handler);
0, out_flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -534,9 +654,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@ -567,7 +687,8 @@ public:
this->impl_.get_service().async_receive_with_flags(
this->impl_.get_implementation(), buffers,
in_flags, out_flags, init.completion_handler);
in_flags, out_flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}

View File

@ -0,0 +1,839 @@
//
// basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_BASIC_SERIAL_PORT_HPP
#define ASIO_BASIC_SERIAL_PORT_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_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/serial_port_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_serial_port_service.hpp"
#else
# include "asio/detail/reactive_serial_port_service.hpp"
#endif
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides serial port functionality.
/**
* The basic_serial_port class provides a wrapper over serial port
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = executor>
class basic_serial_port
: public serial_port_base
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// The native representation of a serial port.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_serial_port_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_serial_port_service::native_handle_type
native_handle_type;
#endif
/// A basic_basic_serial_port is always the lowest layer.
typedef basic_serial_port lowest_layer_type;
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*/
explicit basic_serial_port(const executor_type& ex)
: impl_(ex)
{
}
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*/
template <typename ExecutionContext>
explicit basic_serial_port(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
basic_serial_port(const executor_type& ex, const char* device)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const char* device,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
basic_serial_port(const executor_type& ex, const std::string& device)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const std::string& device,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
basic_serial_port(const executor_type& ex,
const native_handle_type& native_serial_port)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context,
const native_handle_type& native_serial_port,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_serial_port from another.
/**
* This constructor moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port(basic_serial_port&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_serial_port from another.
/**
* This assignment operator moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port& operator=(basic_serial_port&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the serial port.
/**
* This function destroys the serial port, cancelling any outstanding
* asynchronous wait operations associated with the serial port as if by
* calling @c cancel.
*/
~basic_serial_port()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port for the specified device name.
*
* @param device The platform-specific device name.
*
* @throws asio::system_error Thrown on failure.
*/
void open(const std::string& device)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port using the given platform-specific
* device name.
*
* @param device The platform-specific device name.
*
* @param ec Set the indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID open(const std::string& device,
asio::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(), device, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_serial_port)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port,
asio::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the serial port is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the native serial port representation.
/**
* This function may be used to obtain the underlying representation of the
* serial port. This is intended to allow access to native serial port
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the serial port.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the serial port.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @throws asio::system_error Thrown on failure.
*/
void send_break()
{
asio::error_code ec;
impl_.get_service().send_break(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "send_break");
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID send_break(asio::error_code& ec)
{
impl_.get_service().send_break(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @throws asio::system_error Thrown on failure.
*
* @sa SettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
void set_option(const SettableSerialPortOption& option)
{
asio::error_code ec;
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "set_option");
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa SettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option,
asio::error_code& ec)
{
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @throws asio::system_error Thrown on failure.
*
* @sa GettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
void get_option(GettableSerialPortOption& option)
{
asio::error_code ec;
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "get_option");
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa GettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option,
asio::error_code& ec)
{
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the serial port.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the serial port.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the serial port.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.async_write_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);
impl_.get_service().async_write_some(impl_.get_implementation(), buffers,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the serial port.
* The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.async_read_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);
impl_.get_service().async_read_some(impl_.get_implementation(), buffers,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
private:
// Disallow copying and assignment.
basic_serial_port(const basic_serial_port&) ASIO_DELETED;
basic_serial_port& operator=(const basic_serial_port&) ASIO_DELETED;
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_serial_port_service, Executor> impl_;
#endif
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_SERIAL_PORT_HPP

View File

@ -0,0 +1,532 @@
//
// basic_signal_set.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 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_BASIC_SIGNAL_SET_HPP
#define ASIO_BASIC_SIGNAL_SET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/signal_set_service.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
namespace asio {
/// Provides signal functionality.
/**
* The basic_signal_set class provides the ability to perform an asynchronous
* wait for one or more signals to occur.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Example
* Performing an asynchronous wait:
* @code
* void handler(
* const asio::error_code& error,
* int signal_number)
* {
* if (!error)
* {
* // A signal occurred.
* }
* }
*
* ...
*
* // Construct a signal set registered for process termination.
* asio::signal_set signals(my_context, SIGINT, SIGTERM);
*
* // Start an asynchronous wait for one of the signals to occur.
* signals.async_wait(handler);
* @endcode
*
* @par Queueing of signal notifications
*
* If a signal is registered with a signal_set, and the signal occurs when
* there are no waiting handlers, then the signal notification is queued. The
* next async_wait operation on that signal_set will dequeue the notification.
* If multiple notifications are queued, subsequent async_wait operations
* dequeue them one at a time. Signal notifications are dequeued in order of
* ascending signal number.
*
* If a signal number is removed from a signal_set (using the @c remove or @c
* erase member functions) then any queued notifications for that signal are
* discarded.
*
* @par Multiple registration of signals
*
* The same signal number may be registered with different signal_set objects.
* When the signal occurs, one handler is called for each signal_set object.
*
* Note that multiple registration only works for signals that are registered
* using Asio. The application must not also register a signal handler using
* functions such as @c signal() or @c sigaction().
*
* @par Signal masking on POSIX platforms
*
* POSIX allows signals to be blocked using functions such as @c sigprocmask()
* and @c pthread_sigmask(). For signals to be delivered, programs must ensure
* that any signals registered using signal_set objects are unblocked in at
* least one thread.
*/
template <typename Executor = executor>
class basic_signal_set
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*/
explicit basic_signal_set(const executor_type& ex)
: impl_(ex)
{
}
/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*/
template <typename ExecutionContext>
explicit basic_signal_set(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}
/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2, int signal_number_3)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2, int signal_number_3,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add");
}
/// Destroys the signal set.
/**
* This function destroys the signal set, cancelling any outstanding
* asynchronous wait operations associated with the signal set as if by
* calling @c cancel.
*/
~basic_signal_set()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Add a signal to a signal_set.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* @param signal_number The signal to be added to the set.
*
* @throws asio::system_error Thrown on failure.
*/
void add(int signal_number)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "add");
}
/// Add a signal to a signal_set.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* @param signal_number The signal to be added to the set.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID add(int signal_number,
asio::error_code& ec)
{
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Remove a signal from a signal_set.
/**
* This function removes the specified signal from the set. It has no effect
* if the signal is not in the set.
*
* @param signal_number The signal to be removed from the set.
*
* @throws asio::system_error Thrown on failure.
*
* @note Removes any notifications that have been queued for the specified
* signal number.
*/
void remove(int signal_number)
{
asio::error_code ec;
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "remove");
}
/// Remove a signal from a signal_set.
/**
* This function removes the specified signal from the set. It has no effect
* if the signal is not in the set.
*
* @param signal_number The signal to be removed from the set.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Removes any notifications that have been queued for the specified
* signal number.
*/
ASIO_SYNC_OP_VOID remove(int signal_number,
asio::error_code& ec)
{
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Remove all signals from a signal_set.
/**
* This function removes all signals from the set. It has no effect if the set
* is already empty.
*
* @throws asio::system_error Thrown on failure.
*
* @note Removes all queued notifications.
*/
void clear()
{
asio::error_code ec;
impl_.get_service().clear(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "clear");
}
/// Remove all signals from a signal_set.
/**
* This function removes all signals from the set. It has no effect if the set
* is already empty.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Removes all queued notifications.
*/
ASIO_SYNC_OP_VOID clear(asio::error_code& ec)
{
impl_.get_service().clear(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Cancel all operations associated with the signal set.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the signal set. The handler for each cancelled
* operation will be invoked with the asio::error::operation_aborted
* error code.
*
* Cancellation does not alter the set of registered signals.
*
* @throws asio::system_error Thrown on failure.
*
* @note If a registered signal occurred before cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all operations associated with the signal set.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the signal set. The handler for each cancelled
* operation will be invoked with the asio::error::operation_aborted
* error code.
*
* Cancellation does not alter the set of registered signals.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note If a registered signal occurred before cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Start an asynchronous operation to wait for a signal to be delivered.
/**
* This function may be used to initiate an asynchronous wait against the
* signal set. It always returns immediately.
*
* For each call to async_wait(), the supplied handler will be called exactly
* once. The handler will be called when:
*
* @li One of the registered signals in the signal set occurs; or
*
* @li The signal set was cancelled, in which case the handler is passed the
* error code asio::error::operation_aborted.
*
* @param handler The handler to be called when the signal occurs. Copies
* will be made of the handler as required. The function signature of the
* handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* int signal_number // Indicates which signal occurred.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename SignalHandler>
ASIO_INITFN_RESULT_TYPE(SignalHandler,
void (asio::error_code, int))
async_wait(ASIO_MOVE_ARG(SignalHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a SignalHandler.
ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;
async_completion<SignalHandler,
void (asio::error_code, int)> init(handler);
impl_.get_service().async_wait(impl_.get_implementation(),
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
private:
// Disallow copying and assignment.
basic_signal_set(const basic_signal_set&) ASIO_DELETED;
basic_signal_set& operator=(const basic_signal_set&) ASIO_DELETED;
detail::io_object_impl<detail::signal_set_service, Executor> impl_;
};
} // namespace asio
#endif // ASIO_BASIC_SIGNAL_SET_HPP

View File

@ -22,8 +22,11 @@
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/post.hpp"
#include "asio/socket_base.hpp"
#if defined(ASIO_WINDOWS_RUNTIME)
# include "asio/detail/null_socket_service.hpp"
#elif defined(ASIO_HAS_IOCP)
@ -40,6 +43,15 @@
namespace asio {
#if !defined(ASIO_BASIC_SOCKET_FWD_DECL)
#define ASIO_BASIC_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_socket;
#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL)
/// Provides socket functionality.
/**
* The basic_socket class template provides functionality that is common to both
@ -49,13 +61,21 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol>
template <typename Protocol, typename Executor>
class basic_socket
: public socket_base
{
public:
/// The type of the executor associated with the object.
typedef io_context::executor_type executor_type;
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_socket<Protocol, Executor1> other;
};
/// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION)
@ -79,18 +99,35 @@ public:
#if !defined(ASIO_NO_EXTENSIONS)
/// A basic_socket is always the lowest layer.
typedef basic_socket<Protocol> lowest_layer_type;
typedef basic_socket<Protocol, Executor> lowest_layer_type;
#endif // !defined(ASIO_NO_EXTENSIONS)
/// Construct a basic_socket without opening it.
/**
* This constructor creates a socket without opening it.
*
* @param io_context The io_context object that the socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_socket(asio::io_context& io_context)
: impl_(io_context)
explicit basic_socket(const executor_type& ex)
: impl_(ex)
{
}
/// Construct a basic_socket without opening it.
/**
* This constructor creates a socket without opening it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}
@ -98,16 +135,39 @@ public:
/**
* This constructor creates and opens a socket.
*
* @param io_context The io_context object that the socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket(asio::io_context& io_context,
const protocol_type& protocol)
: impl_(io_context)
basic_socket(const executor_type& ex, const protocol_type& protocol)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), protocol, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_socket.
/**
* This constructor creates and opens a socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_socket(ExecutionContext& context, const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), protocol, ec);
@ -121,7 +181,7 @@ public:
* specified endpoint on the local machine. The protocol used is the protocol
* associated with the given endpoint.
*
* @param io_context The io_context object that the socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the socket will
@ -129,9 +189,39 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket(asio::io_context& io_context,
const endpoint_type& endpoint)
: impl_(io_context)
basic_socket(const executor_type& ex, const endpoint_type& endpoint)
: impl_(ex)
{
asio::error_code ec;
const protocol_type protocol = endpoint.protocol();
impl_.get_service().open(impl_.get_implementation(), protocol, ec);
asio::detail::throw_error(ec, "open");
impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
asio::detail::throw_error(ec, "bind");
}
/// Construct a basic_socket, opening it and binding it to the given local
/// endpoint.
/**
* This constructor creates a socket and automatically opens it bound to the
* specified endpoint on the local machine. The protocol used is the protocol
* associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the socket will
* be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_socket(ExecutionContext& context, const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
const protocol_type protocol = endpoint.protocol();
@ -145,7 +235,7 @@ public:
/**
* This constructor creates a socket object to hold an existing native socket.
*
* @param io_context The io_context object that the socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
@ -154,9 +244,37 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket(asio::io_context& io_context,
const protocol_type& protocol, const native_handle_type& native_socket)
: impl_(io_context)
basic_socket(const executor_type& ex, const protocol_type& protocol,
const native_handle_type& native_socket)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
protocol, native_socket, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_socket on an existing native socket.
/**
* This constructor creates a socket object to hold an existing native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket A native socket.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_socket(ExecutionContext& context, const protocol_type& protocol,
const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
@ -173,7 +291,7 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_socket(io_context&) constructor.
* constructed using the @c basic_socket(const executor_type&) constructor.
*/
basic_socket(basic_socket&& other)
: impl_(std::move(other.impl_))
@ -188,7 +306,7 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_socket(io_context&) constructor.
* constructed using the @c basic_socket(const executor_type&) constructor.
*/
basic_socket& operator=(basic_socket&& other)
{
@ -197,7 +315,7 @@ public:
}
// All sockets have access to each other's implementations.
template <typename Protocol1>
template <typename Protocol1, typename Executor1>
friend class basic_socket;
/// Move-construct a basic_socket from a socket of another protocol type.
@ -208,11 +326,14 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_socket(io_context&) constructor.
* constructed using the @c basic_socket(const executor_type&) constructor.
*/
template <typename Protocol1>
basic_socket(basic_socket<Protocol1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
template <typename Protocol1, typename Executor1>
basic_socket(basic_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: impl_(std::move(other.impl_))
{
}
@ -225,11 +346,14 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_socket(io_context&) constructor.
* constructed using the @c basic_socket(const executor_type&) constructor.
*/
template <typename Protocol1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_socket>::type& operator=(basic_socket<Protocol1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_socket&
>::type operator=(basic_socket<Protocol1, Executor1> && other)
{
basic_socket tmp(std::move(other));
impl_ = std::move(tmp.impl_);
@ -283,7 +407,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* socket.open(asio::ip::tcp::v4());
* @endcode
*/
@ -304,7 +428,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* asio::error_code ec;
* socket.open(asio::ip::tcp::v4(), ec);
* if (ec)
@ -393,7 +517,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::error_code ec;
* socket.close(ec);
@ -649,7 +773,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* socket.open(asio::ip::tcp::v4());
* socket.bind(asio::ip::tcp::endpoint(
* asio::ip::tcp::v4(), 12345));
@ -674,7 +798,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* socket.open(asio::ip::tcp::v4());
* asio::error_code ec;
* socket.bind(asio::ip::tcp::endpoint(
@ -709,7 +833,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* asio::ip::tcp::endpoint endpoint(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.connect(endpoint);
@ -745,7 +869,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* asio::ip::tcp::endpoint endpoint(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* asio::error_code ec;
@ -792,9 +916,9 @@ public:
* const asio::error_code& error // Result of operation
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* @code
@ -808,7 +932,7 @@ public:
*
* ...
*
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* asio::ip::tcp::endpoint endpoint(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.async_connect(endpoint, connect_handler);
@ -847,8 +971,8 @@ public:
async_completion<ConnectHandler,
void (asio::error_code)> init(handler);
impl_.get_service().async_connect(
impl_.get_implementation(), peer_endpoint, init.completion_handler);
impl_.get_service().async_connect(impl_.get_implementation(), peer_endpoint,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -881,7 +1005,7 @@ public:
* @par Example
* Setting the IPPROTO_TCP/TCP_NODELAY option:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::no_delay option(true);
* socket.set_option(option);
@ -923,7 +1047,7 @@ public:
* @par Example
* Setting the IPPROTO_TCP/TCP_NODELAY option:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::no_delay option(true);
* asio::error_code ec;
@ -970,7 +1094,7 @@ public:
* @par Example
* Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::socket::keep_alive option;
* socket.get_option(option);
@ -1013,7 +1137,7 @@ public:
* @par Example
* Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::socket::keep_alive option;
* asio::error_code ec;
@ -1048,7 +1172,7 @@ public:
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::socket::bytes_readable command;
* socket.io_control(command);
@ -1078,7 +1202,7 @@ public:
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::socket::bytes_readable command;
* asio::error_code ec;
@ -1439,7 +1563,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::endpoint endpoint = socket.local_endpoint();
* @endcode
@ -1464,7 +1588,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::error_code ec;
* asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);
@ -1489,7 +1613,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
* @endcode
@ -1514,7 +1638,7 @@ public:
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::error_code ec;
* asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
@ -1541,7 +1665,7 @@ public:
* @par Example
* Shutting down the send side of the socket:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* socket.shutdown(asio::ip::tcp::socket::shutdown_send);
* @endcode
@ -1565,7 +1689,7 @@ public:
* @par Example
* Shutting down the send side of the socket:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::error_code ec;
* socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec);
@ -1593,7 +1717,7 @@ public:
* @par Example
* Waiting for a socket to become readable.
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* socket.wait(asio::ip::tcp::socket::wait_read);
* @endcode
@ -1618,7 +1742,7 @@ public:
* @par Example
* Waiting for a socket to become readable.
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::error_code ec;
* socket.wait(asio::ip::tcp::socket::wait_read, ec);
@ -1645,9 +1769,9 @@ public:
* const asio::error_code& error // Result of operation
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* @code
@ -1661,7 +1785,7 @@ public:
*
* ...
*
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* socket.async_wait(asio::ip::tcp::socket::wait_read, wait_handler);
* @endcode
@ -1678,8 +1802,8 @@ public:
async_completion<WaitHandler,
void (asio::error_code)> init(handler);
impl_.get_service().async_wait(impl_.get_implementation(),
w, init.completion_handler);
impl_.get_service().async_wait(impl_.get_implementation(), w,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -1695,11 +1819,14 @@ protected:
}
#if defined(ASIO_WINDOWS_RUNTIME)
detail::io_object_impl<detail::null_socket_service<Protocol> > impl_;
detail::io_object_impl<
detail::null_socket_service<Protocol>, Executor> impl_;
#elif defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_socket_service<Protocol> > impl_;
detail::io_object_impl<
detail::win_iocp_socket_service<Protocol>, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_socket_service<Protocol> > impl_;
detail::io_object_impl<
detail::reactive_socket_service<Protocol>, Executor> impl_;
#endif
private:

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,7 @@
// {
// init_buffers();
// typedef typename Protocol::resolver resolver_type;
// resolver_type resolver(socket().get_executor().context());
// resolver_type resolver(socket().get_executor());
// connect_to_endpoints(
// resolver.resolve(x1, ..., xn, ec_));
// return !ec_ ? this : 0;
@ -60,7 +60,7 @@
{ \
init_buffers(); \
typedef typename Protocol::resolver resolver_type; \
resolver_type resolver(socket().get_executor().context()); \
resolver_type resolver(socket().get_executor()); \
connect_to_endpoints( \
resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \
return !ec_ ? this : 0; \
@ -283,7 +283,7 @@ public:
{
init_buffers();
typedef typename Protocol::resolver resolver_type;
resolver_type resolver(socket().get_executor().context());
resolver_type resolver(socket().get_executor());
connect_to_endpoints(resolver.resolve(x..., ec_));
return !ec_ ? this : 0;
}

View File

@ -27,6 +27,15 @@
namespace asio {
#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_stream_socket;
#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
/// Provides stream-oriented socket functionality.
/**
* The basic_stream_socket class template provides asynchronous and blocking
@ -39,17 +48,28 @@ namespace asio {
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Protocol>
template <typename Protocol, typename Executor>
class basic_stream_socket
: public basic_socket<Protocol>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_stream_socket<Protocol, Executor1> other;
};
/// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<
Protocol>::native_handle_type native_handle_type;
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif
/// The protocol type.
@ -64,11 +84,30 @@ public:
* needs to be opened and then connected or accepted before data can be sent
* or received on it.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_stream_socket(asio::io_context& io_context)
: basic_socket<Protocol>(io_context)
explicit basic_stream_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}
/// Construct a basic_stream_socket without opening it.
/**
* This constructor creates a stream socket without opening it. The socket
* needs to be opened and then connected or accepted before data can be sent
* or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_stream_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}
@ -77,16 +116,37 @@ public:
* This constructor creates and opens a stream socket. The socket needs to be
* connected or accepted before data can be sent or received on it.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_context& io_context,
const protocol_type& protocol)
: basic_socket<Protocol>(io_context, protocol)
basic_stream_socket(const executor_type& ex, const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}
/// Construct and open a basic_stream_socket.
/**
* This constructor creates and opens a stream socket. The socket needs to be
* connected or accepted before data can be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_socket(ExecutionContext& context, const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}
@ -97,7 +157,7 @@ public:
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the stream
@ -105,9 +165,33 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_context& io_context,
const endpoint_type& endpoint)
: basic_socket<Protocol>(io_context, endpoint)
basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}
/// Construct a basic_stream_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a stream socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the stream
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}
@ -116,7 +200,7 @@ public:
* This constructor creates a stream socket object to hold an existing native
* socket.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
@ -125,9 +209,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_context& io_context,
basic_stream_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol>(io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}
/// Construct a basic_stream_socket on an existing native socket.
/**
* This constructor creates a stream socket object to hold an existing native
* socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}
@ -140,10 +249,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c basic_stream_socket(const executor_type&)
* constructor.
*/
basic_stream_socket(basic_stream_socket&& other)
: basic_socket<Protocol>(std::move(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -155,11 +265,12 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c basic_stream_socket(const executor_type&)
* constructor.
*/
basic_stream_socket& operator=(basic_stream_socket&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
@ -172,12 +283,16 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c ,asic_stream_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
basic_stream_socket(basic_stream_socket<Protocol1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol>(std::move(other))
template <typename Protocol1, typename Executor1>
basic_stream_socket(basic_stream_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}
@ -189,14 +304,17 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c basic_stream_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_stream_socket>::type& operator=(
basic_stream_socket<Protocol1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_stream_socket&
>::type operator=(basic_stream_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol>::operator=(std::move(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
@ -327,9 +445,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
@ -357,9 +475,9 @@ public:
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(
this->impl_.get_implementation(), buffers, 0,
init.completion_handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -384,9 +502,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
@ -415,9 +533,9 @@ public:
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(
this->impl_.get_implementation(), buffers, flags,
init.completion_handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -545,9 +663,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
@ -578,7 +696,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_receive(this->impl_.get_implementation(),
buffers, 0, init.completion_handler);
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -603,9 +722,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
@ -637,7 +756,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_receive(this->impl_.get_implementation(),
buffers, flags, init.completion_handler);
buffers, flags, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -721,9 +841,9 @@ public:
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
@ -752,7 +872,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_send(this->impl_.get_implementation(),
buffers, 0, init.completion_handler);
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
@ -838,9 +959,9 @@ public:
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
@ -870,7 +991,8 @@ public:
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_receive(this->impl_.get_implementation(),
buffers, 0, init.completion_handler);
buffers, 0, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}

View File

@ -23,6 +23,7 @@
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/executor.hpp"
#include "asio/wait_traits.hpp"
#if defined(ASIO_HAS_MOVE)
@ -38,7 +39,8 @@ namespace asio {
// Forward declaration with defaulted arguments.
template <typename Clock,
typename WaitTraits = asio::wait_traits<Clock> >
typename WaitTraits = asio::wait_traits<Clock>,
typename Executor = executor>
class basic_waitable_timer;
#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
@ -66,7 +68,7 @@ class basic_waitable_timer;
* Performing a blocking wait (C++11):
* @code
* // Construct a timer without setting an expiry time.
* asio::steady_timer timer(io_context);
* asio::steady_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_after(std::chrono::seconds(5));
@ -89,7 +91,7 @@ class basic_waitable_timer;
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::steady_timer timer(io_context,
* asio::steady_timer timer(my_context,
* std::chrono::steady_clock::now() + std::chrono::seconds(60));
*
* // Start an asynchronous wait.
@ -135,12 +137,12 @@ class basic_waitable_timer;
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*/
template <typename Clock, typename WaitTraits>
template <typename Clock, typename WaitTraits, typename Executor>
class basic_waitable_timer
{
public:
/// The type of the executor associated with the object.
typedef io_context::executor_type executor_type;
typedef Executor executor_type;
/// The clock type.
typedef Clock clock_type;
@ -160,11 +162,30 @@ public:
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_waitable_timer(asio::io_context& io_context)
: impl_(io_context)
explicit basic_waitable_timer(const executor_type& ex)
: impl_(ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}
@ -172,15 +193,38 @@ public:
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor object that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_waitable_timer(asio::io_context& io_context,
const time_point& expiry_time)
: impl_(io_context)
basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const time_point& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
@ -191,15 +235,39 @@ public:
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_waitable_timer(asio::io_context& io_context,
const duration& expiry_time)
: impl_(io_context)
basic_waitable_timer(const executor_type& ex, const duration& expiry_time)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const duration& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().expires_after(
@ -216,7 +284,8 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(io_context&) constructor.
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer(basic_waitable_timer&& other)
: impl_(std::move(other.impl_))
@ -232,7 +301,8 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(io_context&) constructor.
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer& operator=(basic_waitable_timer&& other)
{
@ -616,9 +686,9 @@ public:
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
@ -633,7 +703,7 @@ public:
void (asio::error_code)> init(handler);
impl_.get_service().async_wait(impl_.get_implementation(),
init.completion_handler);
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -646,7 +716,8 @@ private:
detail::io_object_impl<
detail::deadline_timer_service<
detail::chrono_time_traits<Clock, WaitTraits> > > impl_;
detail::chrono_time_traits<Clock, WaitTraits> >,
executor_type > impl_;
};
} // namespace asio

View File

@ -82,13 +82,13 @@ struct is_endpoint_sequence
* Otherwise, contains the error from the last connection attempt.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::connect(s, r.resolve(q)); @endcode
*/
template <typename Protocol, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);
@ -113,9 +113,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
* default-constructed endpoint.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* asio::connect(s, r.resolve(q), ec);
* if (ec)
@ -123,8 +123,8 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
* // An error occurred.
* } @endcode
*/
template <typename Protocol, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, asio::error_code& ec,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);
@ -154,8 +154,8 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename Iterator>
Iterator connect(basic_socket<Protocol>& s, Iterator begin,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
/// (Deprecated: Use range overload.) Establishes a socket connection by trying
@ -182,8 +182,8 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename Iterator>
Iterator connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
#endif // !defined(ASIO_NO_DEPRECATED)
@ -209,14 +209,15 @@ Iterator connect(basic_socket<Protocol>& s,
* Otherwise, contains the error from the last connection attempt.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::connect(s, e.begin(), e.end()); @endcode
*/
template <typename Protocol, typename Iterator>
Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end);
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end);
/// Establishes a socket connection by trying each endpoint in a sequence.
/**
@ -240,10 +241,10 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end);
* endpoint. Otherwise, the end iterator.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* asio::connect(s, e.begin(), e.end(), ec);
* if (ec)
@ -251,8 +252,8 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end);
* // An error occurred.
* } @endcode
*/
template <typename Protocol, typename Iterator>
Iterator connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, asio::error_code& ec);
/// Establishes a socket connection by trying each endpoint in a sequence.
@ -299,16 +300,16 @@ Iterator connect(basic_socket<Protocol>& s,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* tcp::endpoint e = asio::connect(s,
* r.resolve(q), my_connect_condition());
* std::cout << "Connected to: " << e << std::endl; @endcode
*/
template <typename Protocol, typename EndpointSequence,
typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);
@ -358,9 +359,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* tcp::endpoint e = asio::connect(s,
* r.resolve(q), my_connect_condition(), ec);
@ -373,9 +374,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
* std::cout << "Connected to: " << e << std::endl;
* } @endcode
*/
template <typename Protocol, typename EndpointSequence,
typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
asio::error_code& ec,
typename enable_if<is_endpoint_sequence<
@ -417,8 +418,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, ConnectCondition connect_condition,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
@ -457,8 +459,9 @@ Iterator connect(basic_socket<Protocol>& s,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol>& s, Iterator begin,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ConnectCondition connect_condition, asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
#endif // !defined(ASIO_NO_DEPRECATED)
@ -509,16 +512,17 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* tcp::resolver::results_type::iterator i = asio::connect(
* s, e.begin(), e.end(), my_connect_condition());
* std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode
*/
template <typename Protocol, typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol>& s, Iterator begin,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition);
/// Establishes a socket connection by trying each endpoint in a sequence.
@ -568,10 +572,10 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* tcp::resolver::results_type::iterator i = asio::connect(
* s, e.begin(), e.end(), my_connect_condition());
@ -584,9 +588,11 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin,
* std::cout << "Connected to: " << i->endpoint() << std::endl;
* } @endcode
*/
template <typename Protocol, typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
ConnectCondition connect_condition, asio::error_code& ec);
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, ConnectCondition connect_condition,
asio::error_code& ec);
/*@}*/
@ -625,14 +631,14 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
* const typename Protocol::endpoint& endpoint
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
*
* // ...
*
@ -659,11 +665,12 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
* // ...
* } @endcode
*/
template <typename Protocol, typename EndpointSequence,
typename RangeConnectHandler>
template <typename Protocol, typename Executor,
typename EndpointSequence, typename RangeConnectHandler>
ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))
async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints,
ASIO_MOVE_ARG(RangeConnectHandler) handler,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);
@ -696,18 +703,19 @@ async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename Iterator, typename IteratorConnectHandler>
template <typename Protocol, typename Executor,
typename Iterator, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ASIO_MOVE_ARG(IteratorConnectHandler) handler,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
#endif // !defined(ASIO_NO_DEPRECATED)
@ -741,13 +749,13 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* @code std::vector<tcp::endpoint> endpoints = ...;
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::async_connect(s,
* endpoints.begin(), endpoints.end(),
* connect_handler);
@ -761,10 +769,11 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
* // ...
* } @endcode
*/
template <typename Protocol, typename Iterator, typename IteratorConnectHandler>
template <typename Protocol, typename Executor,
typename Iterator, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,
ASIO_MOVE_ARG(IteratorConnectHandler) handler);
/// Asynchronously establishes a socket connection by trying each endpoint in a
@ -805,9 +814,9 @@ async_connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* The following connect condition function object can be used to output
@ -824,9 +833,9 @@ async_connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
*
* // ...
*
@ -862,12 +871,12 @@ async_connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
* }
* } @endcode
*/
template <typename Protocol, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))
async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
ConnectCondition connect_condition,
async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
ASIO_MOVE_ARG(RangeConnectHandler) handler,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);
@ -911,19 +920,19 @@ async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
@ -969,9 +978,9 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* The following connect condition function object can be used to output
@ -988,9 +997,9 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
*
* // ...
*
@ -1027,11 +1036,11 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
* }
* } @endcode
*/
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler);

View File

@ -205,7 +205,7 @@ class coroutine_ref;
* {
* do
* {
* socket_.reset(new tcp::socket(io_context_));
* socket_.reset(new tcp::socket(my_context_));
* yield acceptor->async_accept(*socket_, *this);
* fork server(*this)();
* } while (is_parent());
@ -227,7 +227,7 @@ class coroutine_ref;
* Note that @c fork doesn't do the actual forking by itself. It is the
* application's responsibility to create a clone of the coroutine and call it.
* The clone can be called immediately, as above, or scheduled for delayed
* execution using something like io_context::post().
* execution using something like asio::post().
*
* @par Alternate macro names
*

View File

@ -18,7 +18,7 @@
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/memory.hpp"
@ -43,7 +43,7 @@ namespace detail {
template <typename Time_Traits>
class deadline_timer_service
: public service_base<deadline_timer_service<Time_Traits> >
: public execution_context_service_base<deadline_timer_service<Time_Traits> >
{
public:
// The time type.
@ -63,9 +63,10 @@ public:
};
// Constructor.
deadline_timer_service(asio::io_context& io_context)
: service_base<deadline_timer_service<Time_Traits> >(io_context),
scheduler_(asio::use_service<timer_scheduler>(io_context))
deadline_timer_service(execution_context& context)
: execution_context_service_base<
deadline_timer_service<Time_Traits> >(context),
scheduler_(asio::use_service<timer_scheduler>(context))
{
scheduler_.init_task();
scheduler_.add_timer_queue(timer_queue_);
@ -225,14 +226,15 @@ public:
}
// Start an asynchronous wait on the timer.
template <typename Handler>
void async_wait(implementation_type& impl, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_wait(implementation_type& impl,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler> op;
typedef wait_handler<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
impl.might_have_pending_waits = true;

View File

@ -66,20 +66,21 @@ private:
MutableBufferSequence buffers_;
};
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class descriptor_read_op
: public descriptor_read_op_base<MutableBufferSequence>
{
public:
ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
descriptor_read_op(int descriptor,
const MutableBufferSequence& buffers, Handler& handler)
descriptor_read_op(int descriptor, const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: descriptor_read_op_base<MutableBufferSequence>(
descriptor, buffers, &descriptor_read_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -89,7 +90,7 @@ public:
// Take ownership of the handler object.
descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -116,6 +117,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -66,20 +66,21 @@ private:
ConstBufferSequence buffers_;
};
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
class descriptor_write_op
: public descriptor_write_op_base<ConstBufferSequence>
{
public:
ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
descriptor_write_op(int descriptor,
const ConstBufferSequence& buffers, Handler& handler)
descriptor_write_op(int descriptor, const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: descriptor_write_op_base<ConstBufferSequence>(
descriptor, buffers, &descriptor_write_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -89,7 +90,7 @@ public:
// Take ownership of the handler object.
descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -116,6 +117,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -27,24 +27,41 @@ namespace detail {
// A helper class template to allow completion handlers to be dispatched
// through either the new executors framework or the old invocaton hook. The
// primary template uses the new executors framework.
template <typename Handler, typename Executor
= typename associated_executor<Handler>::type>
template <typename Handler,
typename IoExecutor = system_executor, typename HandlerExecutor
= typename associated_executor<Handler, IoExecutor>::type>
class handler_work
{
public:
explicit handler_work(Handler& handler) ASIO_NOEXCEPT
: executor_(associated_executor<Handler>::get(handler))
: io_executor_(),
executor_(asio::get_associated_executor(handler, io_executor_))
{
}
handler_work(Handler& handler, const IoExecutor& io_ex) ASIO_NOEXCEPT
: io_executor_(io_ex),
executor_(asio::get_associated_executor(handler, io_executor_))
{
}
static void start(Handler& handler) ASIO_NOEXCEPT
{
Executor ex(associated_executor<Handler>::get(handler));
HandlerExecutor ex(asio::get_associated_executor(handler));
ex.on_work_started();
}
static void start(Handler& handler,
const IoExecutor& io_ex) ASIO_NOEXCEPT
{
HandlerExecutor ex(asio::get_associated_executor(handler, io_ex));
ex.on_work_started();
io_ex.on_work_started();
}
~handler_work()
{
io_executor_.on_work_finished();
executor_.on_work_finished();
}
@ -52,7 +69,7 @@ public:
void complete(Function& function, Handler& handler)
{
executor_.dispatch(ASIO_MOVE_CAST(Function)(function),
associated_allocator<Handler>::get(handler));
asio::get_associated_allocator(handler));
}
private:
@ -60,7 +77,8 @@ private:
handler_work(const handler_work&);
handler_work& operator=(const handler_work&);
typename associated_executor<Handler>::type executor_;
IoExecutor io_executor_;
HandlerExecutor executor_;
};
// This specialisation dispatches a handler through the old invocation hook.
@ -68,7 +86,7 @@ private:
// system_executor will dispatch through the hook anyway. However, by doing
// this we avoid an extra copy of the handler.
template <typename Handler>
class handler_work<Handler, system_executor>
class handler_work<Handler, system_executor, system_executor>
{
public:
explicit handler_work(Handler&) ASIO_NOEXCEPT {}

View File

@ -30,9 +30,9 @@ namespace asio {
namespace detail {
reactive_descriptor_service::reactive_descriptor_service(
asio::io_context& io_context)
: service_base<reactive_descriptor_service>(io_context),
reactor_(asio::use_service<reactor>(io_context))
execution_context& context)
: execution_context_service_base<reactive_descriptor_service>(context),
reactor_(asio::use_service<reactor>(context))
{
reactor_.init_task();
}

View File

@ -30,9 +30,9 @@ namespace asio {
namespace detail {
reactive_serial_port_service::reactive_serial_port_service(
asio::io_context& io_context)
: service_base<reactive_serial_port_service>(io_context),
descriptor_service_(io_context)
execution_context& context)
: execution_context_service_base<reactive_serial_port_service>(context),
descriptor_service_(context)
{
}

View File

@ -28,9 +28,8 @@ namespace asio {
namespace detail {
reactive_socket_service_base::reactive_socket_service_base(
asio::io_context& io_context)
: io_context_(io_context),
reactor_(use_service<reactor>(io_context))
execution_context& context)
: reactor_(use_service<reactor>(context))
{
reactor_.init_task();
}

View File

@ -23,25 +23,30 @@
namespace asio {
namespace detail {
class resolver_service_base::work_io_context_runner
class resolver_service_base::work_scheduler_runner
{
public:
work_io_context_runner(asio::io_context& io_context)
: io_context_(io_context) {}
void operator()() { io_context_.run(); }
work_scheduler_runner(scheduler_impl& work_scheduler)
: work_scheduler_(work_scheduler)
{
}
void operator()()
{
asio::error_code ec;
work_scheduler_.run(ec);
}
private:
asio::io_context& io_context_;
scheduler_impl& work_scheduler_;
};
resolver_service_base::resolver_service_base(
asio::io_context& io_context)
: io_context_impl_(asio::use_service<io_context_impl>(io_context)),
work_io_context_(new asio::io_context(-1)),
work_io_context_impl_(asio::use_service<
io_context_impl>(*work_io_context_)),
work_(asio::make_work_guard(*work_io_context_)),
resolver_service_base::resolver_service_base(execution_context& context)
: scheduler_(asio::use_service<scheduler_impl>(context)),
work_scheduler_(new scheduler_impl(context, -1, false)),
work_thread_(0)
{
work_scheduler_->work_started();
}
resolver_service_base::~resolver_service_base()
@ -51,34 +56,35 @@ resolver_service_base::~resolver_service_base()
void resolver_service_base::base_shutdown()
{
work_.reset();
if (work_io_context_.get())
if (work_scheduler_.get())
{
work_io_context_->stop();
work_scheduler_->work_finished();
work_scheduler_->stop();
if (work_thread_.get())
{
work_thread_->join();
work_thread_.reset();
}
work_io_context_.reset();
work_scheduler_.reset();
}
}
void resolver_service_base::base_notify_fork(
asio::io_context::fork_event fork_ev)
execution_context::fork_event fork_ev)
{
if (work_thread_.get())
{
if (fork_ev == asio::io_context::fork_prepare)
if (fork_ev == execution_context::fork_prepare)
{
work_io_context_->stop();
work_scheduler_->stop();
work_thread_->join();
work_thread_.reset();
}
else
{
work_io_context_->restart();
work_scheduler_->restart();
work_thread_.reset(new asio::detail::thread(
work_io_context_runner(*work_io_context_)));
work_scheduler_runner(*work_scheduler_)));
}
}
}
@ -92,7 +98,7 @@ void resolver_service_base::construct(
void resolver_service_base::destroy(
resolver_service_base::implementation_type& impl)
{
ASIO_HANDLER_OPERATION((io_context_impl_.context(),
ASIO_HANDLER_OPERATION((scheduler_.context(),
"resolver", &impl, 0, "cancel"));
impl.reset();
@ -114,7 +120,7 @@ void resolver_service_base::move_assign(implementation_type& impl,
void resolver_service_base::cancel(
resolver_service_base::implementation_type& impl)
{
ASIO_HANDLER_OPERATION((io_context_impl_.context(),
ASIO_HANDLER_OPERATION((scheduler_.context(),
"resolver", &impl, 0, "cancel"));
impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
@ -123,16 +129,16 @@ void resolver_service_base::cancel(
void resolver_service_base::start_resolve_op(resolve_op* op)
{
if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
io_context_impl_.concurrency_hint()))
scheduler_.concurrency_hint()))
{
start_work_thread();
io_context_impl_.work_started();
work_io_context_impl_.post_immediate_completion(op, false);
scheduler_.work_started();
work_scheduler_->post_immediate_completion(op, false);
}
else
{
op->ec_ = asio::error::operation_not_supported;
io_context_impl_.post_immediate_completion(op, false);
scheduler_.post_immediate_completion(op, false);
}
}
@ -142,7 +148,7 @@ void resolver_service_base::start_work_thread()
if (!work_thread_.get())
{
work_thread_.reset(new asio::detail::thread(
work_io_context_runner(*work_io_context_)));
work_scheduler_runner(*work_scheduler_)));
}
}

View File

@ -23,12 +23,31 @@
#include "asio/detail/reactor.hpp"
#include "asio/detail/scheduler.hpp"
#include "asio/detail/scheduler_thread_info.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class scheduler::thread_function
{
public:
explicit thread_function(scheduler* s)
: this_(s)
{
}
void operator()()
{
asio::error_code ec;
this_->run(ec);
}
private:
scheduler* this_;
};
struct scheduler::task_cleanup
{
~task_cleanup()
@ -84,8 +103,8 @@ struct scheduler::work_cleanup
thread_info* this_thread_;
};
scheduler::scheduler(
asio::execution_context& ctx, int concurrency_hint)
scheduler::scheduler(asio::execution_context& ctx,
int concurrency_hint, bool own_thread)
: asio::detail::execution_context_service_base<scheduler>(ctx),
one_thread_(concurrency_hint == 1
|| !ASIO_CONCURRENCY_HINT_IS_LOCKING(
@ -99,17 +118,44 @@ scheduler::scheduler(
outstanding_work_(0),
stopped_(false),
shutdown_(false),
concurrency_hint_(concurrency_hint)
concurrency_hint_(concurrency_hint),
thread_(0)
{
ASIO_HANDLER_TRACKING_INIT;
if (own_thread)
{
++outstanding_work_;
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(thread_function(this));
}
}
scheduler::~scheduler()
{
if (thread_)
{
thread_->join();
delete thread_;
}
}
void scheduler::shutdown()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
if (thread_)
stop_all_threads(lock);
lock.unlock();
// Join thread to ensure task operation is returned to queue.
if (thread_)
{
thread_->join();
delete thread_;
thread_ = 0;
}
// Destroy handler objects.
while (!op_queue_.empty())
{

View File

@ -118,14 +118,13 @@ public:
// && !defined(ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
signal_set_service::signal_set_service(
asio::io_context& io_context)
: service_base<signal_set_service>(io_context),
io_context_(asio::use_service<io_context_impl>(io_context)),
signal_set_service::signal_set_service(execution_context& context)
: execution_context_service_base<signal_set_service>(context),
scheduler_(asio::use_service<scheduler_impl>(context)),
#if !defined(ASIO_WINDOWS) \
&& !defined(ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
reactor_(asio::use_service<reactor>(io_context)),
reactor_(asio::use_service<reactor>(context)),
#endif // !defined(ASIO_WINDOWS)
// && !defined(ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@ -169,11 +168,10 @@ void signal_set_service::shutdown()
}
}
io_context_.abandon_operations(ops);
scheduler_.abandon_operations(ops);
}
void signal_set_service::notify_fork(
asio::io_context::fork_event fork_ev)
void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
{
#if !defined(ASIO_WINDOWS) \
&& !defined(ASIO_WINDOWS_RUNTIME) \
@ -183,7 +181,7 @@ void signal_set_service::notify_fork(
switch (fork_ev)
{
case asio::io_context::fork_prepare:
case execution_context::fork_prepare:
{
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = true;
@ -192,7 +190,7 @@ void signal_set_service::notify_fork(
reactor_.cleanup_descriptor_data(reactor_data_);
}
break;
case asio::io_context::fork_parent:
case execution_context::fork_parent:
if (state->fork_prepared_)
{
int read_descriptor = state->read_descriptor_;
@ -202,7 +200,7 @@ void signal_set_service::notify_fork(
read_descriptor, reactor_data_, new pipe_read_op);
}
break;
case asio::io_context::fork_child:
case execution_context::fork_child:
if (state->fork_prepared_)
{
asio::detail::signal_blocker blocker;
@ -441,7 +439,7 @@ asio::error_code signal_set_service::cancel(
signal_set_service::implementation_type& impl,
asio::error_code& ec)
{
ASIO_HANDLER_OPERATION((io_context_.context(),
ASIO_HANDLER_OPERATION((scheduler_.context(),
"signal_set", &impl, 0, "cancel"));
op_queue<operation> ops;
@ -457,7 +455,7 @@ asio::error_code signal_set_service::cancel(
}
}
io_context_.post_deferred_completions(ops);
scheduler_.post_deferred_completions(ops);
ec = asio::error_code();
return ec;
@ -493,7 +491,7 @@ void signal_set_service::deliver_signal(int signal_number)
reg = reg->next_in_table_;
}
service->io_context_.post_deferred_completions(ops);
service->scheduler_.post_deferred_completions(ops);
service = service->next_;
}
@ -510,17 +508,17 @@ void signal_set_service::add_service(signal_set_service* service)
open_descriptors();
#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
// If an io_context object is thread-unsafe then it must be the only
// io_context used to create signal_set objects.
// If a scheduler_ object is thread-unsafe then it must be the only
// scheduler used to create signal_set objects.
if (state->service_list_ != 0)
{
if (!ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
service->io_context_.concurrency_hint())
service->scheduler_.concurrency_hint())
|| !ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
state->service_list_->io_context_.concurrency_hint()))
state->service_list_->scheduler_.concurrency_hint()))
{
std::logic_error ex(
"Thread-unsafe io_context objects require "
"Thread-unsafe execution context objects require "
"exclusive access to signal handling.");
asio::detail::throw_exception(ex);
}
@ -639,7 +637,7 @@ void signal_set_service::close_descriptors()
void signal_set_service::start_wait_op(
signal_set_service::implementation_type& impl, signal_op* op)
{
io_context_.work_started();
scheduler_.work_started();
signal_state* state = get_signal_state();
static_mutex::scoped_lock lock(state->mutex_);
@ -651,7 +649,7 @@ void signal_set_service::start_wait_op(
{
--reg->undelivered_;
op->signal_number_ = reg->signal_number_;
io_context_.post_deferred_completion(op);
scheduler_.post_deferred_completion(op);
return;
}

View File

@ -65,10 +65,9 @@ public:
}
};
win_iocp_handle_service::win_iocp_handle_service(
asio::io_context& io_context)
: service_base<win_iocp_handle_service>(io_context),
iocp_service_(asio::use_service<win_iocp_io_context>(io_context)),
win_iocp_handle_service::win_iocp_handle_service(execution_context& context)
: execution_context_service_base<win_iocp_handle_service>(context),
iocp_service_(asio::use_service<win_iocp_io_context>(context)),
mutex_(),
impl_list_(0)
{

View File

@ -24,6 +24,7 @@
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/limits.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/win_iocp_io_context.hpp"
@ -32,6 +33,22 @@
namespace asio {
namespace detail {
struct win_iocp_io_context::thread_function
{
explicit thread_function(win_iocp_io_context* s)
: this_(s)
{
}
void operator()()
{
asio::error_code ec;
this_->run(ec);
}
win_iocp_io_context* this_;
};
struct win_iocp_io_context::work_finished_on_block_exit
{
~work_finished_on_block_exit()
@ -62,7 +79,7 @@ struct win_iocp_io_context::timer_thread_function
};
win_iocp_io_context::win_iocp_io_context(
asio::execution_context& ctx, int concurrency_hint)
asio::execution_context& ctx, int concurrency_hint, bool own_thread)
: execution_context_service_base<win_iocp_io_context>(ctx),
iocp_(),
outstanding_work_(0),
@ -84,6 +101,21 @@ win_iocp_io_context::win_iocp_io_context(
asio::error::get_system_category());
asio::detail::throw_error(ec, "iocp");
}
if (own_thread)
{
::InterlockedIncrement(&outstanding_work_);
thread_.reset(new asio::detail::thread(thread_function(this)));
}
}
win_iocp_io_context::~win_iocp_io_context()
{
if (thread_.get())
{
thread_->join();
thread_.reset();
}
}
void win_iocp_io_context::shutdown()
@ -97,6 +129,13 @@ void win_iocp_io_context::shutdown()
::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE);
}
if (thread_.get())
{
thread_->join();
thread_.reset();
::InterlockedDecrement(&outstanding_work_);
}
while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
{
op_queue<win_iocp_operation> ops;

View File

@ -29,9 +29,9 @@ namespace asio {
namespace detail {
win_iocp_serial_port_service::win_iocp_serial_port_service(
asio::io_context& io_context)
: service_base<win_iocp_serial_port_service>(io_context),
handle_service_(io_context)
execution_context& context)
: execution_context_service_base<win_iocp_serial_port_service>(context),
handle_service_(context)
{
}

View File

@ -27,9 +27,9 @@ namespace asio {
namespace detail {
win_iocp_socket_service_base::win_iocp_socket_service_base(
asio::io_context& io_context)
: io_context_(io_context),
iocp_service_(use_service<win_iocp_io_context>(io_context)),
execution_context& context)
: context_(context),
iocp_service_(use_service<win_iocp_io_context>(context)),
reactor_(0),
connect_ex_(0),
nt_set_info_(0),
@ -707,7 +707,7 @@ select_reactor& win_iocp_socket_service_base::get_reactor()
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!r)
{
r = &(use_service<select_reactor>(io_context_));
r = &(use_service<select_reactor>(context_));
interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
}
return *r;

View File

@ -27,10 +27,9 @@
namespace asio {
namespace detail {
win_object_handle_service::win_object_handle_service(
asio::io_context& io_context)
: service_base<win_object_handle_service>(io_context),
io_context_(asio::use_service<io_context_impl>(io_context)),
win_object_handle_service::win_object_handle_service(execution_context& context)
: execution_context_service_base<win_object_handle_service>(context),
scheduler_(asio::use_service<scheduler_impl>(context)),
mutex_(),
impl_list_(0),
shutdown_(false)
@ -52,7 +51,7 @@ void win_object_handle_service::shutdown()
lock.unlock();
io_context_.abandon_operations(ops);
scheduler_.abandon_operations(ops);
}
void win_object_handle_service::construct(
@ -178,7 +177,7 @@ void win_object_handle_service::destroy(
if (is_open(impl))
{
ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
&impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
HANDLE wait_handle = impl.wait_handle_;
@ -203,7 +202,7 @@ void win_object_handle_service::destroy(
::CloseHandle(impl.handle_);
impl.handle_ = INVALID_HANDLE_VALUE;
io_context_.post_deferred_completions(ops);
scheduler_.post_deferred_completions(ops);
}
}
@ -228,7 +227,7 @@ asio::error_code win_object_handle_service::close(
{
if (is_open(impl))
{
ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
&impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
mutex::scoped_lock lock(mutex_);
@ -264,7 +263,7 @@ asio::error_code win_object_handle_service::close(
asio::error::get_system_category());
}
io_context_.post_deferred_completions(completed_ops);
scheduler_.post_deferred_completions(completed_ops);
}
else
{
@ -280,7 +279,7 @@ asio::error_code win_object_handle_service::cancel(
{
if (is_open(impl))
{
ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
&impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
mutex::scoped_lock lock(mutex_);
@ -306,7 +305,7 @@ asio::error_code win_object_handle_service::cancel(
ec = asio::error_code();
io_context_.post_deferred_completions(completed_ops);
scheduler_.post_deferred_completions(completed_ops);
}
else
{
@ -340,7 +339,7 @@ void win_object_handle_service::wait(
void win_object_handle_service::start_wait_op(
win_object_handle_service::implementation_type& impl, wait_op* op)
{
io_context_.work_started();
scheduler_.work_started();
if (is_open(impl))
{
@ -358,13 +357,13 @@ void win_object_handle_service::start_wait_op(
else
{
lock.unlock();
io_context_.post_deferred_completion(op);
scheduler_.post_deferred_completion(op);
}
}
else
{
op->ec_ = asio::error::bad_descriptor;
io_context_.post_deferred_completion(op);
scheduler_.post_deferred_completion(op);
}
}
@ -391,7 +390,7 @@ void win_object_handle_service::register_wait_callback(
}
lock.unlock();
io_context_.post_deferred_completions(completed_ops);
scheduler_.post_deferred_completions(completed_ops);
}
}
@ -433,9 +432,9 @@ void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
}
}
io_context_impl& ioc = impl->owner_->io_context_;
scheduler_impl& sched = impl->owner_->scheduler_;
lock.unlock();
ioc.post_deferred_completions(completed_ops);
sched.post_deferred_completions(completed_ops);
}
}

View File

@ -30,9 +30,9 @@ namespace asio {
namespace detail {
winrt_ssocket_service_base::winrt_ssocket_service_base(
asio::io_context& io_context)
: io_context_(use_service<io_context_impl>(io_context)),
async_manager_(use_service<winrt_async_manager>(io_context)),
execution_context& context)
: scheduler_(use_service<scheduler_impl>(context)),
async_manager_(use_service<winrt_async_manager>(context)),
mutex_(),
impl_list_(0)
{
@ -398,7 +398,7 @@ void winrt_ssocket_service_base::start_connect_op(
if (!is_open(impl))
{
op->ec_ = asio::error::bad_descriptor;
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@ -427,7 +427,7 @@ void winrt_ssocket_service_base::start_connect_op(
if (op->ec_)
{
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@ -442,7 +442,7 @@ void winrt_ssocket_service_base::start_connect_op(
{
op->ec_ = asio::error_code(
e->HResult, asio::system_category());
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
}
}
@ -493,14 +493,14 @@ void winrt_ssocket_service_base::start_send_op(
if (flags)
{
op->ec_ = asio::error::operation_not_supported;
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
if (!is_open(impl))
{
op->ec_ = asio::error::bad_descriptor;
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@ -511,7 +511,7 @@ void winrt_ssocket_service_base::start_send_op(
if (bufs.all_empty())
{
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@ -522,7 +522,7 @@ void winrt_ssocket_service_base::start_send_op(
{
op->ec_ = asio::error_code(e->HResult,
asio::system_category());
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
}
}
@ -584,14 +584,14 @@ void winrt_ssocket_service_base::start_receive_op(
if (flags)
{
op->ec_ = asio::error::operation_not_supported;
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
if (!is_open(impl))
{
op->ec_ = asio::error::bad_descriptor;
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@ -602,7 +602,7 @@ void winrt_ssocket_service_base::start_receive_op(
if (bufs.all_empty())
{
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
return;
}
@ -615,7 +615,7 @@ void winrt_ssocket_service_base::start_receive_op(
{
op->ec_ = asio::error_code(e->HResult,
asio::system_category());
io_context_.post_immediate_completion(op, is_continuation);
scheduler_.post_immediate_completion(op, is_continuation);
}
}

View File

@ -46,12 +46,12 @@ void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue,
if (shutdown_)
{
io_context_.post_immediate_completion(op, false);
scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
io_context_.work_started();
scheduler_.work_started();
if (earliest)
event_.signal(lock);
}
@ -65,7 +65,7 @@ std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue,
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
io_context_.post_deferred_completions(ops);
scheduler_.post_deferred_completions(ops);
return n;
}

View File

@ -27,10 +27,9 @@
namespace asio {
namespace detail {
winrt_timer_scheduler::winrt_timer_scheduler(
asio::io_context& io_context)
: asio::detail::service_base<winrt_timer_scheduler>(io_context),
io_context_(use_service<io_context_impl>(io_context)),
winrt_timer_scheduler::winrt_timer_scheduler(execution_context& context)
: execution_context_service_base<winrt_timer_scheduler>(context),
scheduler_(use_service<scheduler_impl>(context)),
mutex_(),
event_(),
timer_queues_(),
@ -64,10 +63,10 @@ void winrt_timer_scheduler::shutdown()
op_queue<operation> ops;
timer_queues_.get_all_timers(ops);
io_context_.abandon_operations(ops);
scheduler_.abandon_operations(ops);
}
void winrt_timer_scheduler::notify_fork(asio::io_context::fork_event)
void winrt_timer_scheduler::notify_fork(execution_context::fork_event)
{
}
@ -89,7 +88,7 @@ void winrt_timer_scheduler::run_thread()
if (!ops.empty())
{
lock.unlock();
io_context_.post_deferred_completions(ops);
scheduler_.post_deferred_completions(ops);
lock.lock();
}
}

View File

@ -0,0 +1,127 @@
//
// io_object_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 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_DETAIL_IO_OBJECT_EXECUTOR_HPP
#define ASIO_DETAIL_IO_OBJECT_EXECUTOR_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/handler_invoke_helpers.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/io_context.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Wrap the (potentially polymorphic) executor so that we can bypass it when
// dispatching on a target executor that has a native I/O implementation.
template <typename Executor>
class io_object_executor
{
public:
io_object_executor(const Executor& ex, bool native_implementation)
: executor_(ex),
has_native_impl_(native_implementation)
{
}
execution_context& context() const ASIO_NOEXCEPT
{
return executor_.context();
}
void on_work_started() const ASIO_NOEXCEPT
{
if (is_same<Executor, io_context::executor_type>::value
|| has_native_impl_)
{
// When using a native implementation, work is already counted by the
// execution context.
}
else
{
executor_.on_work_started();
}
}
void on_work_finished() const ASIO_NOEXCEPT
{
if (is_same<Executor, io_context::executor_type>::value
|| has_native_impl_)
{
// When using a native implementation, work is already counted by the
// execution context.
}
else
{
executor_.on_work_finished();
}
}
template <typename F, typename A>
void dispatch(ASIO_MOVE_ARG(F) f, const A& a) const
{
if (is_same<Executor, io_context::executor_type>::value
|| has_native_impl_)
{
// When using a native implementation, I/O completion handlers are
// already dispatched according to the execution context's executor's
// rules. We can call the function directly.
typename decay<F>::type function(ASIO_MOVE_CAST(F)(f));
asio_handler_invoke_helpers::invoke(function, function);
}
else
{
executor_.dispatch(ASIO_MOVE_CAST(F)(f), a);
}
}
template <typename F, typename A>
void post(ASIO_MOVE_ARG(F) f, const A& a) const
{
executor_.post(ASIO_MOVE_CAST(F)(f), a);
}
template <typename F, typename A>
void defer(ASIO_MOVE_ARG(F) f, const A& a) const
{
executor_.defer(ASIO_MOVE_CAST(F)(f), a);
}
friend bool operator==(const io_object_executor& a,
const io_object_executor& b) ASIO_NOEXCEPT
{
return a.executor_ == b.executor_
&& a.has_native_impl_ == b.has_native_impl_;
}
friend bool operator!=(const io_object_executor& a,
const io_object_executor& b) ASIO_NOEXCEPT
{
return a.executor_ != b.executor_
|| a.has_native_impl_ != b.has_native_impl_;
}
private:
Executor executor_;
const bool has_native_impl_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP

View File

@ -15,7 +15,10 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <new>
#include "asio/detail/config.hpp"
#include "asio/detail/io_object_executor.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/io_context.hpp"
#include "asio/detail/push_options.hpp"
@ -23,7 +26,8 @@
namespace asio {
namespace detail {
template <typename IoObjectService>
template <typename IoObjectService,
typename Executor = io_context::executor_type>
class io_object_impl
{
public:
@ -34,11 +38,28 @@ public:
typedef typename service_type::implementation_type implementation_type;
// The type of the executor associated with the object.
typedef asio::io_context::executor_type executor_type;
typedef Executor executor_type;
// Construct an I/O object.
explicit io_object_impl(asio::io_context& io_context)
: service_(&asio::use_service<IoObjectService>(io_context))
// The type of executor to be used when implementing asynchronous operations.
typedef io_object_executor<Executor> implementation_executor_type;
// Construct an I/O object using an executor.
explicit io_object_impl(const executor_type& ex)
: executor_(ex),
service_(&asio::use_service<IoObjectService>(ex.context())),
has_native_impl_(is_same<Executor, io_context::executor_type>::value)
{
service_->construct(implementation_);
}
// Construct an I/O object using an execution context.
template <typename ExecutionContext>
explicit io_object_impl(ExecutionContext& context,
typename enable_if<is_convertible<
ExecutionContext&, execution_context&>::value>::type* = 0)
: executor_(context.get_executor()),
service_(&asio::use_service<IoObjectService>(context)),
has_native_impl_(is_same<ExecutionContext, io_context>::value)
{
service_->construct(implementation_);
}
@ -46,16 +67,19 @@ public:
#if defined(ASIO_HAS_MOVE)
// Move-construct an I/O object.
io_object_impl(io_object_impl&& other)
: service_(&other.get_service())
: executor_(other.get_executor()),
service_(&other.get_service()),
has_native_impl_(other.has_native_impl_)
{
service_->move_construct(implementation_, other.implementation_);
}
// Perform a converting move-construction of an I/O object.
template <typename IoObjectService1>
io_object_impl(io_object_impl<IoObjectService1>&& other)
: service_(&asio::use_service<IoObjectService>(
other.get_service().get_io_context()))
template <typename IoObjectService1, typename Executor1>
io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other)
: executor_(other.get_executor()),
service_(&asio::use_service<IoObjectService>(executor_.context())),
has_native_impl_(is_same<Executor1, io_context::executor_type>::value)
{
service_->converting_move_construct(implementation_,
other.get_service(), other.get_implementation());
@ -72,31 +96,29 @@ public:
// Move-assign an I/O object.
io_object_impl& operator=(io_object_impl&& other)
{
service_->move_assign(implementation_,
*other.service_, other.implementation_);
service_ = other.service_;
if (this != &other)
{
service_->move_assign(implementation_,
*other.service_, other.implementation_);
executor_.~executor_type();
new (&executor_) executor_type(std::move(other.executor_));
service_ = other.service_;
has_native_impl_ = other.has_native_impl_;
}
return *this;
}
#endif // defined(ASIO_HAS_MOVE)
#if !defined(ASIO_NO_DEPRECATED)
// Deprecated access to underlying I/O context.
asio::io_context& get_io_context()
{
return service_->get_io_context();
}
// Deprecated access to underlying I/O context.
asio::io_context& get_io_service()
{
return service_->get_io_context();
}
#endif // !defined(ASIO_NO_DEPRECATED)
// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return service_->get_io_context().get_executor();
return executor_;
}
// Get the executor to be used when implementing asynchronous operations.
implementation_executor_type get_implementation_executor() ASIO_NOEXCEPT
{
return io_object_executor<Executor>(executor_, has_native_impl_);
}
// Get the service associated with the I/O object.
@ -128,11 +150,17 @@ private:
io_object_impl(const io_object_impl&);
io_object_impl& operator=(const io_object_impl&);
// The associated executor.
executor_type executor_;
// The service associated with the I/O object.
service_type* service_;
// The underlying implementation of the I/O object.
implementation_type implementation_;
// Whether the executor has a native I/O implementation.
bool has_native_impl_;
};
} // namespace detail

View File

@ -21,7 +21,8 @@
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/post.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/bind_handler.hpp"
@ -32,7 +33,7 @@ namespace detail {
template <typename Protocol>
class null_socket_service :
public service_base<null_socket_service<Protocol> >
public execution_context_service_base<null_socket_service<Protocol> >
{
public:
// The protocol type.
@ -50,9 +51,8 @@ public:
};
// Constructor.
null_socket_service(asio::io_context& io_context)
: service_base<null_socket_service<Protocol> >(io_context),
io_context_(io_context)
null_socket_service(execution_context& context)
: execution_context_service_base<null_socket_service<Protocol> >(context)
{
}
@ -272,23 +272,25 @@ public:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_send(implementation_type&, const ConstBufferSequence&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_send(implementation_type&, const null_buffers&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Receive some data from the peer. Returns the number of bytes received.
@ -310,23 +312,26 @@ public:
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive(implementation_type&, const MutableBufferSequence&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Wait until data can be received without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_receive(implementation_type&, const null_buffers&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Receive some data with associated flags. Returns the number of bytes
@ -351,25 +356,28 @@ public:
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive_with_flags(implementation_type&,
const MutableBufferSequence&, socket_base::message_flags,
socket_base::message_flags&, Handler& handler)
socket_base::message_flags&, Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive_with_flags(implementation_type&,
const null_buffers&, socket_base::message_flags,
socket_base::message_flags&, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_receive_with_flags(implementation_type&, const null_buffers&,
socket_base::message_flags, socket_base::message_flags&,
Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Send a datagram to the specified endpoint. Returns the number of bytes
@ -394,24 +402,27 @@ public:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_send_to(implementation_type&, const ConstBufferSequence&,
const endpoint_type&, socket_base::message_flags,
Handler& handler)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_send_to(implementation_type&, const null_buffers&,
const endpoint_type&, socket_base::message_flags, Handler& handler)
const endpoint_type&, socket_base::message_flags,
Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Receive a datagram with the endpoint of the sender. Returns the number of
@ -437,25 +448,28 @@ public:
// Start an asynchronous receive. The buffer for the data being received and
// the sender_endpoint object must both be valid for the lifetime of the
// asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
void async_receive_from(implementation_type&,
const MutableBufferSequence&, endpoint_type&,
socket_base::message_flags, Handler& handler)
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive_from(implementation_type&, const MutableBufferSequence&,
endpoint_type&, socket_base::message_flags, Handler& handler,
const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive_from(implementation_type&,
const null_buffers&, endpoint_type&,
socket_base::message_flags, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_receive_from(implementation_type&, const null_buffers&,
endpoint_type&, socket_base::message_flags, Handler& handler,
const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
asio::post(io_ex, detail::bind_handler(
handler, ec, bytes_transferred));
}
// Accept a new connection.
@ -469,12 +483,12 @@ public:
// Start an asynchronous accept. The peer and peer_endpoint objects
// must be valid until the accept's handler is invoked.
template <typename Socket, typename Handler>
void async_accept(implementation_type&, Socket&,
endpoint_type*, Handler& handler)
template <typename Socket, typename Handler, typename IoExecutor>
void async_accept(implementation_type&, Socket&, endpoint_type*,
Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
io_context_.post(detail::bind_handler(handler, ec));
asio::post(io_ex, detail::bind_handler(handler, ec));
}
// Connect the socket to the specified endpoint.
@ -486,16 +500,13 @@ public:
}
// Start an asynchronous connect.
template <typename Handler>
void async_connect(implementation_type&,
const endpoint_type&, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_connect(implementation_type&, const endpoint_type&,
Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
io_context_.post(detail::bind_handler(handler, ec));
asio::post(io_ex, detail::bind_handler(handler, ec));
}
private:
asio::io_context& io_context_;
};
} // namespace detail

View File

@ -22,7 +22,7 @@
&& !defined(__CYGWIN__)
#include "asio/buffer.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/descriptor_ops.hpp"
@ -42,7 +42,7 @@ namespace asio {
namespace detail {
class reactive_descriptor_service :
public service_base<reactive_descriptor_service>
public execution_context_service_base<reactive_descriptor_service>
{
public:
// The native type of a descriptor.
@ -75,8 +75,7 @@ public:
};
// Constructor.
ASIO_DECL reactive_descriptor_service(
asio::io_context& io_context);
ASIO_DECL reactive_descriptor_service(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void shutdown();
@ -190,18 +189,19 @@ public:
// Asynchronously wait for the descriptor to become ready to read, ready to
// write, or to have pending error conditions.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_wait(implementation_type& impl,
posix::descriptor_base::wait_type w, Handler& handler)
posix::descriptor_base::wait_type w,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_wait_op<Handler> op;
typedef reactive_wait_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
&impl, impl.descriptor_, "async_wait"));
@ -253,18 +253,19 @@ public:
// Start an asynchronous write. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler& handler)
const ConstBufferSequence& buffers, Handler& handler,
const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef descriptor_write_op<ConstBufferSequence, Handler> op;
typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.descriptor_, buffers, handler);
p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
&impl, impl.descriptor_, "async_write_some"));
@ -276,18 +277,18 @@ public:
}
// Start an asynchronous wait until data can be written without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_write_some(implementation_type& impl,
const null_buffers&, Handler& handler)
const null_buffers&, Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
&impl, impl.descriptor_, "async_write_some(null_buffers)"));
@ -320,18 +321,20 @@ public:
// Start an asynchronous read. The buffer for the data being read must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler& handler)
const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef descriptor_read_op<MutableBufferSequence, Handler> op;
typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.descriptor_, buffers, handler);
p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
&impl, impl.descriptor_, "async_read_some"));
@ -343,18 +346,18 @@ public:
}
// Wait until data can be read without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_read_some(implementation_type& impl,
const null_buffers&, Handler& handler)
const null_buffers&, Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
&impl, impl.descriptor_, "async_read_some(null_buffers)"));

View File

@ -27,18 +27,19 @@
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class reactive_null_buffers_op : public reactor_op
{
public:
ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op);
reactive_null_buffers_op(Handler& handler)
reactive_null_buffers_op(Handler& handler, const IoExecutor& io_ex)
: reactor_op(&reactive_null_buffers_op::do_perform,
&reactive_null_buffers_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static status do_perform(reactor_op*)
@ -53,7 +54,7 @@ public:
// Take ownership of the handler object.
reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -80,6 +81,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -23,7 +23,7 @@
#include <string>
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/detail/descriptor_ops.hpp"
#include "asio/detail/reactive_descriptor_service.hpp"
@ -35,7 +35,7 @@ namespace detail {
// Extend reactive_descriptor_service to provide serial port support.
class reactive_serial_port_service :
public service_base<reactive_serial_port_service>
public execution_context_service_base<reactive_serial_port_service>
{
public:
// The native type of a serial port.
@ -44,8 +44,7 @@ public:
// The implementation type of the serial port.
typedef reactive_descriptor_service::implementation_type implementation_type;
ASIO_DECL reactive_serial_port_service(
asio::io_context& io_context);
ASIO_DECL reactive_serial_port_service(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void shutdown();
@ -156,11 +155,12 @@ public:
// Start an asynchronous write. The data being written must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler& handler)
const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
descriptor_service_.async_write_some(impl, buffers, handler);
descriptor_service_.async_write_some(impl, buffers, handler, io_ex);
}
// Read some data. Returns the number of bytes received.
@ -173,11 +173,13 @@ public:
// Start an asynchronous read. The buffer for the data being received must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler& handler)
const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
descriptor_service_.async_read_some(impl, buffers, handler);
descriptor_service_.async_read_some(impl, buffers, handler, io_ex);
}
private:

View File

@ -85,7 +85,8 @@ private:
std::size_t addrlen_;
};
template <typename Socket, typename Protocol, typename Handler>
template <typename Socket, typename Protocol,
typename Handler, typename IoExecutor>
class reactive_socket_accept_op :
public reactive_socket_accept_op_base<Socket, Protocol>
{
@ -94,12 +95,14 @@ public:
reactive_socket_accept_op(socket_type socket,
socket_ops::state_type state, Socket& peer, const Protocol& protocol,
typename Protocol::endpoint* peer_endpoint, Handler& handler)
typename Protocol::endpoint* peer_endpoint, Handler& handler,
const IoExecutor& io_ex)
: reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer,
protocol, peer_endpoint, &reactive_socket_accept_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -109,7 +112,7 @@ public:
// Take ownership of the handler object.
reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
// On success, assign new connection to peer socket object.
if (owner)
@ -140,11 +143,13 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
#if defined(ASIO_HAS_MOVE)
template <typename Protocol, typename Handler>
template <typename Protocol, typename PeerIoExecutor,
typename Handler, typename IoExecutor>
class reactive_socket_move_accept_op :
private Protocol::socket,
public reactive_socket_accept_op_base<typename Protocol::socket, Protocol>
@ -152,16 +157,18 @@ class reactive_socket_move_accept_op :
public:
ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op);
reactive_socket_move_accept_op(io_context& ioc, socket_type socket,
socket_ops::state_type state, const Protocol& protocol,
typename Protocol::endpoint* peer_endpoint, Handler& handler)
: Protocol::socket(ioc),
reactive_socket_move_accept_op(const PeerIoExecutor& peer_io_ex,
socket_type socket, socket_ops::state_type state,
const Protocol& protocol, typename Protocol::endpoint* peer_endpoint,
Handler& handler, const IoExecutor& io_ex)
: Protocol::socket(peer_io_ex),
reactive_socket_accept_op_base<typename Protocol::socket, Protocol>(
socket, state, *this, protocol, peer_endpoint,
&reactive_socket_move_accept_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -172,7 +179,7 @@ public:
reactive_socket_move_accept_op* o(
static_cast<reactive_socket_move_accept_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
// On success, assign new connection to peer socket object.
if (owner)
@ -205,6 +212,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
#endif // defined(ASIO_HAS_MOVE)

View File

@ -54,18 +54,20 @@ private:
socket_type socket_;
};
template <typename Handler>
template <typename Handler, typename IoExecutor>
class reactive_socket_connect_op : public reactive_socket_connect_op_base
{
public:
ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op);
reactive_socket_connect_op(socket_type socket, Handler& handler)
reactive_socket_connect_op(socket_type socket,
Handler& handler, const IoExecutor& io_ex)
: reactive_socket_connect_op_base(socket,
&reactive_socket_connect_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -76,7 +78,7 @@ public:
reactive_socket_connect_op* o
(static_cast<reactive_socket_connect_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -103,6 +105,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -74,21 +74,22 @@ private:
socket_base::message_flags flags_;
};
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class reactive_socket_recv_op :
public reactive_socket_recv_op_base<MutableBufferSequence>
{
public:
ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op);
reactive_socket_recv_op(socket_type socket,
socket_ops::state_type state, const MutableBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
reactive_socket_recv_op(socket_type socket, socket_ops::state_type state,
const MutableBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
: reactive_socket_recv_op_base<MutableBufferSequence>(socket, state,
buffers, flags, &reactive_socket_recv_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -98,7 +99,7 @@ public:
// Take ownership of the handler object.
reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -125,6 +126,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -75,7 +75,8 @@ private:
socket_base::message_flags flags_;
};
template <typename MutableBufferSequence, typename Endpoint, typename Handler>
template <typename MutableBufferSequence, typename Endpoint,
typename Handler, typename IoExecutor>
class reactive_socket_recvfrom_op :
public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>
{
@ -84,13 +85,15 @@ public:
reactive_socket_recvfrom_op(socket_type socket, int protocol_type,
const MutableBufferSequence& buffers, Endpoint& endpoint,
socket_base::message_flags flags, Handler& handler)
socket_base::message_flags flags, Handler& handler,
const IoExecutor& io_ex)
: reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>(
socket, protocol_type, buffers, endpoint, flags,
&reactive_socket_recvfrom_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -101,7 +104,7 @@ public:
reactive_socket_recvfrom_op* o(
static_cast<reactive_socket_recvfrom_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -128,6 +131,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -70,7 +70,7 @@ private:
socket_base::message_flags& out_flags_;
};
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class reactive_socket_recvmsg_op :
public reactive_socket_recvmsg_op_base<MutableBufferSequence>
{
@ -79,12 +79,14 @@ public:
reactive_socket_recvmsg_op(socket_type socket,
const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, Handler& handler)
socket_base::message_flags& out_flags, Handler& handler,
const IoExecutor& io_ex)
: reactive_socket_recvmsg_op_base<MutableBufferSequence>(socket, buffers,
in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -95,7 +97,7 @@ public:
reactive_socket_recvmsg_op* o(
static_cast<reactive_socket_recvmsg_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -122,6 +124,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -73,21 +73,22 @@ private:
socket_base::message_flags flags_;
};
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
class reactive_socket_send_op :
public reactive_socket_send_op_base<ConstBufferSequence>
{
public:
ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op);
reactive_socket_send_op(socket_type socket,
socket_ops::state_type state, const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
reactive_socket_send_op(socket_type socket, socket_ops::state_type state,
const ConstBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
: reactive_socket_send_op_base<ConstBufferSequence>(socket,
state, buffers, flags, &reactive_socket_send_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -97,7 +98,7 @@ public:
// Take ownership of the handler object.
reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -124,6 +125,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -69,7 +69,8 @@ private:
socket_base::message_flags flags_;
};
template <typename ConstBufferSequence, typename Endpoint, typename Handler>
template <typename ConstBufferSequence, typename Endpoint,
typename Handler, typename IoExecutor>
class reactive_socket_sendto_op :
public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>
{
@ -78,12 +79,14 @@ public:
reactive_socket_sendto_op(socket_type socket,
const ConstBufferSequence& buffers, const Endpoint& endpoint,
socket_base::message_flags flags, Handler& handler)
socket_base::message_flags flags, Handler& handler,
const IoExecutor& io_ex)
: reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(socket,
buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -93,7 +96,7 @@ public:
// Take ownership of the handler object.
reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -120,6 +123,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -21,7 +21,7 @@
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/memory.hpp"
@ -45,7 +45,7 @@ namespace detail {
template <typename Protocol>
class reactive_socket_service :
public service_base<reactive_socket_service<Protocol> >,
public execution_context_service_base<reactive_socket_service<Protocol> >,
public reactive_socket_service_base
{
public:
@ -73,9 +73,10 @@ public:
};
// Constructor.
reactive_socket_service(asio::io_context& io_context)
: service_base<reactive_socket_service<Protocol> >(io_context),
reactive_socket_service_base(io_context)
reactive_socket_service(execution_context& context)
: execution_context_service_base<
reactive_socket_service<Protocol> >(context),
reactive_socket_service_base(context)
{
}
@ -239,21 +240,22 @@ public:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_send_to(implementation_type& impl,
const ConstBufferSequence& buffers,
const endpoint_type& destination, socket_base::message_flags flags,
Handler& handler)
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_sendto_op<ConstBufferSequence,
endpoint_type, Handler> op;
endpoint_type, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler);
p.p = new (p.v) op(impl.socket_, buffers,
destination, flags, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_send_to"));
@ -263,18 +265,19 @@ public:
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_send_to(implementation_type& impl, const null_buffers&,
const endpoint_type&, socket_base::message_flags, Handler& handler)
const endpoint_type&, socket_base::message_flags,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_send_to(null_buffers)"));
@ -322,22 +325,24 @@ public:
// Start an asynchronous receive. The buffer for the data being received and
// the sender_endpoint object must both be valid for the lifetime of the
// asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
socket_base::message_flags flags, Handler& handler)
socket_base::message_flags flags, Handler& handler,
const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_recvfrom_op<MutableBufferSequence,
endpoint_type, Handler> op;
endpoint_type, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
int protocol = impl.protocol_.type();
p.p = new (p.v) op(impl.socket_, protocol,
buffers, sender_endpoint, flags, handler);
p.p = new (p.v) op(impl.socket_, protocol, buffers,
sender_endpoint, flags, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_receive_from"));
@ -350,19 +355,19 @@ public:
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive_from(implementation_type& impl,
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags flags, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_receive_from(implementation_type& impl, const null_buffers&,
endpoint_type& sender_endpoint, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_receive_from(null_buffers)"));
@ -407,49 +412,21 @@ public:
return ec;
}
#if defined(ASIO_HAS_MOVE)
// Accept a new connection.
typename Protocol::socket accept(implementation_type& impl,
io_context* peer_io_context, endpoint_type* peer_endpoint,
asio::error_code& ec)
{
typename Protocol::socket peer(
peer_io_context ? *peer_io_context : io_context_);
std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
peer_endpoint ? &addr_len : 0, ec));
// On success, assign new connection to peer socket object.
if (new_socket.get() != invalid_socket)
{
if (peer_endpoint)
peer_endpoint->resize(addr_len);
peer.assign(impl.protocol_, new_socket.get(), ec);
if (!ec)
new_socket.release();
}
return peer;
}
#endif // defined(ASIO_HAS_MOVE)
// Start an asynchronous accept. The peer and peer_endpoint objects must be
// valid until the accept's handler is invoked.
template <typename Socket, typename Handler>
template <typename Socket, typename Handler, typename IoExecutor>
void async_accept(implementation_type& impl, Socket& peer,
endpoint_type* peer_endpoint, Handler& handler)
endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_accept_op<Socket, Protocol, Handler> op;
typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, impl.state_, peer,
impl.protocol_, peer_endpoint, handler);
impl.protocol_, peer_endpoint, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_accept"));
@ -461,20 +438,21 @@ public:
#if defined(ASIO_HAS_MOVE)
// Start an asynchronous accept. The peer_endpoint object must be valid until
// the accept's handler is invoked.
template <typename Handler>
void async_accept(implementation_type& impl,
asio::io_context* peer_io_context,
endpoint_type* peer_endpoint, Handler& handler)
template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
void async_move_accept(implementation_type& impl,
const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_move_accept_op<Protocol, Handler> op;
typedef reactive_socket_move_accept_op<Protocol,
PeerIoExecutor, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(peer_io_context ? *peer_io_context : io_context_,
impl.socket_, impl.state_, impl.protocol_, peer_endpoint, handler);
p.p = new (p.v) op(peer_io_ex, impl.socket_, impl.state_,
impl.protocol_, peer_endpoint, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_accept"));
@ -494,18 +472,19 @@ public:
}
// Start an asynchronous connect.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, Handler& handler)
const endpoint_type& peer_endpoint,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_connect_op<Handler> op;
typedef reactive_socket_connect_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, handler);
p.p = new (p.v) op(impl.socket_, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_connect"));

View File

@ -22,7 +22,7 @@
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/memory.hpp"
@ -62,8 +62,7 @@ public:
};
// Constructor.
ASIO_DECL reactive_socket_service_base(
asio::io_context& io_context);
ASIO_DECL reactive_socket_service_base(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void base_shutdown();
@ -193,18 +192,18 @@ public:
// Asynchronously wait for the socket to become ready to read, ready to
// write, or to have pending error conditions.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_wait(base_implementation_type& impl,
socket_base::wait_type w, Handler& handler)
socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_wait_op<Handler> op;
typedef reactive_wait_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_wait"));
@ -257,19 +256,21 @@ public:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_send(base_implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
const ConstBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
typedef reactive_socket_send_op<
ConstBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
p.p = new (p.v) op(impl.socket_, impl.state_,
buffers, flags, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_send"));
@ -282,18 +283,18 @@ public:
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_send(base_implementation_type& impl, const null_buffers&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_send(null_buffers)"));
@ -327,19 +328,22 @@ public:
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive(base_implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
const MutableBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op;
typedef reactive_socket_recv_op<
MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
p.p = new (p.v) op(impl.socket_, impl.state_,
buffers, flags, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_receive"));
@ -356,18 +360,19 @@ public:
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive(base_implementation_type& impl, const null_buffers&,
socket_base::message_flags flags, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_receive(base_implementation_type& impl,
const null_buffers&, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_receive(null_buffers)"));
@ -411,19 +416,23 @@ public:
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive_with_flags(base_implementation_type& impl,
const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, Handler& handler)
socket_base::message_flags& out_flags, Handler& handler,
const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op;
typedef reactive_socket_recvmsg_op<
MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler);
p.p = new (p.v) op(impl.socket_, buffers,
in_flags, out_flags, handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_receive_with_flags"));
@ -437,19 +446,20 @@ public:
}
// Wait until data can be received without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_receive_with_flags(base_implementation_type& impl,
const null_buffers&, socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, Handler& handler)
socket_base::message_flags& out_flags, Handler& handler,
const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_null_buffers_op<Handler> op;
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
&impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
@ -489,9 +499,6 @@ protected:
reactor_op* op, bool is_continuation,
const socket_addr_type* addr, size_t addrlen);
// The io_context that owns this socket service.
io_context& io_context_;
// The selector that performs event demultiplexing for the service.
reactor& reactor_;
};

View File

@ -27,18 +27,19 @@
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class reactive_wait_op : public reactor_op
{
public:
ASIO_DEFINE_HANDLER_PTR(reactive_wait_op);
reactive_wait_op(Handler& handler)
reactive_wait_op(Handler& handler, const IoExecutor& io_ex)
: reactor_op(&reactive_wait_op::do_perform,
&reactive_wait_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static status do_perform(reactor_op*)
@ -53,7 +54,7 @@ public:
// Take ownership of the handler object.
reactive_wait_op* o(static_cast<reactive_wait_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -80,6 +81,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -17,7 +17,6 @@
#include "asio/detail/config.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/ip/basic_resolver_results.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/fenced_block.hpp"
@ -27,12 +26,18 @@
#include "asio/detail/resolve_op.hpp"
#include "asio/detail/socket_ops.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Protocol, typename Handler>
template <typename Protocol, typename Handler, typename IoExecutor>
class resolve_endpoint_op : public resolve_op
{
public:
@ -41,15 +46,23 @@ public:
typedef typename Protocol::endpoint endpoint_type;
typedef asio::ip::basic_resolver_results<Protocol> results_type;
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token,
const endpoint_type& endpoint, io_context_impl& ioc, Handler& handler)
const endpoint_type& endpoint, scheduler_impl& sched,
Handler& handler, const IoExecutor& io_ex)
: resolve_op(&resolve_endpoint_op::do_complete),
cancel_token_(cancel_token),
endpoint_(endpoint),
io_context_impl_(ioc),
handler_(ASIO_MOVE_CAST(Handler)(handler))
scheduler_(sched),
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -59,9 +72,9 @@ public:
// Take ownership of the operation object.
resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
if (owner && owner != &o->io_context_impl_)
if (owner && owner != &o->scheduler_)
{
// The operation is being run on the worker io_context. Time to perform
// the resolver operation.
@ -75,7 +88,7 @@ public:
o->results_ = results_type::create(o->endpoint_, host_name, service_name);
// Pass operation back to main io_context for completion.
o->io_context_impl_.post_deferred_completion(o);
o->scheduler_.post_deferred_completion(o);
p.v = p.p = 0;
}
else
@ -109,8 +122,9 @@ public:
private:
socket_ops::weak_cancel_token_type cancel_token_;
endpoint_type endpoint_;
io_context_impl& io_context_impl_;
scheduler_impl& scheduler_;
Handler handler_;
IoExecutor io_executor_;
results_type results_;
};

View File

@ -17,7 +17,6 @@
#include "asio/detail/config.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/ip/basic_resolver_results.hpp"
#include "asio/detail/bind_handler.hpp"
@ -28,12 +27,18 @@
#include "asio/detail/resolve_op.hpp"
#include "asio/detail/socket_ops.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Protocol, typename Handler>
template <typename Protocol, typename Handler, typename IoExecutor>
class resolve_query_op : public resolve_op
{
public:
@ -42,16 +47,24 @@ public:
typedef asio::ip::basic_resolver_query<Protocol> query_type;
typedef asio::ip::basic_resolver_results<Protocol> results_type;
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
resolve_query_op(socket_ops::weak_cancel_token_type cancel_token,
const query_type& query, io_context_impl& ioc, Handler& handler)
const query_type& query, scheduler_impl& sched,
Handler& handler, const IoExecutor& io_ex)
: resolve_op(&resolve_query_op::do_complete),
cancel_token_(cancel_token),
query_(query),
io_context_impl_(ioc),
scheduler_(sched),
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex),
addrinfo_(0)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
~resolve_query_op()
@ -68,7 +81,7 @@ public:
resolve_query_op* o(static_cast<resolve_query_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
if (owner && owner != &o->io_context_impl_)
if (owner && owner != &o->scheduler_)
{
// The operation is being run on the worker io_context. Time to perform
// the resolver operation.
@ -79,7 +92,7 @@ public:
o->query_.hints(), &o->addrinfo_, o->ec_);
// Pass operation back to main io_context for completion.
o->io_context_impl_.post_deferred_completion(o);
o->scheduler_.post_deferred_completion(o);
p.v = p.p = 0;
}
else
@ -88,7 +101,7 @@ public:
// handler is ready to be delivered.
// Take ownership of the operation's outstanding work.
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -121,8 +134,9 @@ public:
private:
socket_ops::weak_cancel_token_type cancel_token_;
query_type query_;
io_context_impl& io_context_impl_;
scheduler_impl& scheduler_;
Handler handler_;
IoExecutor io_executor_;
asio::detail::addrinfo_type* addrinfo_;
};

View File

@ -34,7 +34,7 @@ namespace detail {
template <typename Protocol>
class resolver_service :
public service_base<resolver_service<Protocol> >,
public execution_context_service_base<resolver_service<Protocol> >,
public resolver_service_base
{
public:
@ -52,9 +52,9 @@ public:
typedef asio::ip::basic_resolver_results<Protocol> results_type;
// Constructor.
resolver_service(asio::io_context& io_context)
: service_base<resolver_service<Protocol> >(io_context),
resolver_service_base(io_context)
resolver_service(execution_context& context)
: execution_context_service_base<resolver_service<Protocol> >(context),
resolver_service_base(context)
{
}
@ -65,7 +65,7 @@ public:
}
// Perform any fork-related housekeeping.
void notify_fork(asio::io_context::fork_event fork_ev)
void notify_fork(execution_context::fork_event fork_ev)
{
this->base_notify_fork(fork_ev);
}
@ -85,17 +85,17 @@ public:
}
// Asynchronously resolve a query to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl,
const query_type& query, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_resolve(implementation_type& impl, const query_type& query,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef resolve_query_op<Protocol, Handler> op;
typedef resolve_query_op<Protocol, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl, query, io_context_impl_, handler);
p.p = new (p.v) op(impl, query, scheduler_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_impl_.context(),
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "resolver", &impl, 0, "async_resolve"));
start_resolve_op(p.p);
@ -117,17 +117,17 @@ public:
}
// Asynchronously resolve an endpoint to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl,
const endpoint_type& endpoint, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef resolve_endpoint_op<Protocol, Handler> op;
typedef resolve_endpoint_op<Protocol, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl, endpoint, io_context_impl_, handler);
p.p = new (p.v) op(impl, endpoint, scheduler_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_impl_.context(),
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "resolver", &impl, 0, "async_resolve"));
start_resolve_op(p.p);

View File

@ -17,8 +17,7 @@
#include "asio/detail/config.hpp"
#include "asio/error.hpp"
#include "asio/executor_work_guard.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/resolve_op.hpp"
@ -27,6 +26,12 @@
#include "asio/detail/scoped_ptr.hpp"
#include "asio/detail/thread.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
namespace asio {
@ -40,7 +45,7 @@ public:
typedef socket_ops::shared_cancel_token_type implementation_type;
// Constructor.
ASIO_DECL resolver_service_base(asio::io_context& io_context);
ASIO_DECL resolver_service_base(execution_context& context);
// Destructor.
ASIO_DECL ~resolver_service_base();
@ -50,7 +55,7 @@ public:
// Perform any fork-related housekeeping.
ASIO_DECL void base_notify_fork(
asio::io_context::fork_event fork_ev);
execution_context::fork_event fork_ev);
// Construct a new resolver implementation.
ASIO_DECL void construct(implementation_type& impl);
@ -101,28 +106,26 @@ protected:
};
#endif // !defined(ASIO_WINDOWS_RUNTIME)
// Helper class to run the work io_context in a thread.
class work_io_context_runner;
// Helper class to run the work scheduler in a thread.
class work_scheduler_runner;
// Start the work thread if it's not already running.
// Start the work scheduler if it's not already running.
ASIO_DECL void start_work_thread();
// The io_context implementation used to post completions.
io_context_impl& io_context_impl_;
// The scheduler implementation used to post completions.
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
scheduler_impl& scheduler_;
private:
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// Private io_context used for performing asynchronous host resolution.
asio::detail::scoped_ptr<asio::io_context> work_io_context_;
// The work io_context implementation used to post completions.
io_context_impl& work_io_context_impl_;
// Work for the private io_context to perform.
asio::executor_work_guard<
asio::io_context::executor_type> work_;
// Private scheduler used for performing asynchronous host resolution.
asio::detail::scoped_ptr<scheduler_impl> work_scheduler_;
// Thread used for running the work io_context's run loop.
asio::detail::scoped_ptr<asio::detail::thread> work_thread_;

View File

@ -25,6 +25,7 @@
#include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_fwd.hpp"
#include "asio/detail/scheduler_operation.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/thread_context.hpp"
#include "asio/detail/push_options.hpp"
@ -44,7 +45,10 @@ public:
// Constructor. Specifies the number of concurrent threads that are likely to
// run the scheduler. If set to 1 certain optimisation are performed.
ASIO_DECL scheduler(asio::execution_context& ctx,
int concurrency_hint = 0);
int concurrency_hint = 0, bool own_thread = true);
// Destructor.
ASIO_DECL ~scheduler();
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void shutdown();
@ -156,6 +160,10 @@ private:
ASIO_DECL void wake_one_thread_and_unlock(
mutex::scoped_lock& lock);
// Helper class to run the scheduler in its own thread.
class thread_function;
friend class thread_function;
// Helper class to perform task-related operations on block exit.
struct task_cleanup;
friend struct task_cleanup;
@ -199,6 +207,9 @@ private:
// The concurrency hint used to initialise the scheduler.
const int concurrency_hint_;
// The thread that is running the scheduler.
asio::detail::thread* thread_;
};
} // namespace detail

View File

@ -29,17 +29,18 @@
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class signal_handler : public signal_op
{
public:
ASIO_DEFINE_HANDLER_PTR(signal_handler);
signal_handler(Handler& h)
signal_handler(Handler& h, const IoExecutor& io_ex)
: signal_op(&signal_handler::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(h))
handler_(ASIO_MOVE_CAST(Handler)(h)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -49,7 +50,7 @@ public:
// Take ownership of the handler object.
signal_handler* h(static_cast<signal_handler*>(base));
ptr p = { asio::detail::addressof(h->handler_), h, h };
handler_work<Handler> w(h->handler_);
handler_work<Handler, IoExecutor> w(h->handler_, h->io_executor_);
ASIO_HANDLER_COMPLETION((*h));
@ -76,6 +77,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -20,7 +20,7 @@
#include <cstddef>
#include <signal.h>
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/op_queue.hpp"
@ -28,6 +28,12 @@
#include "asio/detail/signal_op.hpp"
#include "asio/detail/socket_types.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
# include "asio/detail/reactor.hpp"
#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
@ -48,7 +54,7 @@ extern ASIO_DECL struct signal_state* get_signal_state();
extern "C" ASIO_DECL void asio_signal_handler(int signal_number);
class signal_set_service :
public service_base<signal_set_service>
public execution_context_service_base<signal_set_service>
{
public:
// Type used for tracking an individual signal registration.
@ -109,7 +115,7 @@ public:
};
// Constructor.
ASIO_DECL signal_set_service(asio::io_context& io_context);
ASIO_DECL signal_set_service(execution_context& context);
// Destructor.
ASIO_DECL ~signal_set_service();
@ -119,7 +125,7 @@ public:
// Perform fork-related housekeeping.
ASIO_DECL void notify_fork(
asio::io_context::fork_event fork_ev);
asio::execution_context::fork_event fork_ev);
// Construct a new signal_set implementation.
ASIO_DECL void construct(implementation_type& impl);
@ -144,16 +150,17 @@ public:
asio::error_code& ec);
// Start an asynchronous operation to wait for a signal to be delivered.
template <typename Handler>
void async_wait(implementation_type& impl, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_wait(implementation_type& impl,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef signal_handler<Handler> op;
typedef signal_handler<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((io_context_.context(),
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "signal_set", &impl, 0, "async_wait"));
start_wait_op(impl, p.p);
@ -179,8 +186,13 @@ private:
// Helper function to start a wait operation.
ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);
// The io_context instance used for dispatching handlers.
io_context_impl& io_context_;
// The scheduler used for dispatching handlers.
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
scheduler_impl& scheduler_;
#if !defined(ASIO_WINDOWS) \
&& !defined(ASIO_WINDOWS_RUNTIME) \

View File

@ -64,6 +64,12 @@ public:
}
}
// Test whether the group is empty.
bool empty() const
{
return first_ == 0;
}
private:
// Structure used to track a single thread in the group.
struct item

View File

@ -19,26 +19,27 @@
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/handler_work.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/wait_op.hpp"
#include "asio/io_context.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class wait_handler : public wait_op
{
public:
ASIO_DEFINE_HANDLER_PTR(wait_handler);
wait_handler(Handler& h)
wait_handler(Handler& h, const IoExecutor& ex)
: wait_op(&wait_handler::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(h))
handler_(ASIO_MOVE_CAST(Handler)(h)),
io_executor_(ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -48,7 +49,7 @@ public:
// Take ownership of the handler object.
wait_handler* h(static_cast<wait_handler*>(base));
ptr p = { asio::detail::addressof(h->handler_), h, h };
handler_work<Handler> w(h->handler_);
handler_work<Handler, IoExecutor> w(h->handler_, h->io_executor_);
ASIO_HANDLER_COMPLETION((*h));
@ -75,6 +76,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -34,19 +34,20 @@
namespace asio {
namespace detail {
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class win_iocp_handle_read_op : public operation
{
public:
ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op);
win_iocp_handle_read_op(
const MutableBufferSequence& buffers, Handler& handler)
win_iocp_handle_read_op(const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: operation(&win_iocp_handle_read_op::do_complete),
buffers_(buffers),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -58,7 +59,7 @@ public:
// Take ownership of the operation object.
win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -99,6 +100,7 @@ public:
private:
MutableBufferSequence buffers_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -21,7 +21,7 @@
#if defined(ASIO_HAS_IOCP)
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/cstdint.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
@ -38,7 +38,7 @@ namespace asio {
namespace detail {
class win_iocp_handle_service :
public service_base<win_iocp_handle_service>
public execution_context_service_base<win_iocp_handle_service>
{
public:
// The native type of a stream handle.
@ -75,7 +75,7 @@ public:
implementation_type* prev_;
};
ASIO_DECL win_iocp_handle_service(asio::io_context& io_context);
ASIO_DECL win_iocp_handle_service(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void shutdown();
@ -142,15 +142,17 @@ public:
// Start an asynchronous write. The data being written must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler& handler)
const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
typedef win_iocp_handle_write_op<
ConstBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
p.p = new (p.v) op(buffers, handler, io_ex);
ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some"));
@ -163,15 +165,17 @@ public:
// Start an asynchronous write at a specified offset. The data being written
// must be valid for the lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
void async_write_some_at(implementation_type& impl, uint64_t offset,
const ConstBufferSequence& buffers, Handler& handler)
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_write_some_at(implementation_type& impl,
uint64_t offset, const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
typedef win_iocp_handle_write_op<
ConstBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
p.p = new (p.v) op(buffers, handler, io_ex);
ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at"));
@ -204,15 +208,18 @@ public:
// Start an asynchronous read. The buffer for the data being received must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler& handler)
const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
typedef win_iocp_handle_read_op<
MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
p.p = new (p.v) op(buffers, handler, io_ex);
ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some"));
@ -226,15 +233,18 @@ public:
// Start an asynchronous read at a specified offset. The buffer for the data
// being received must be valid for the lifetime of the asynchronous
// operation.
template <typename MutableBufferSequence, typename Handler>
void async_read_some_at(implementation_type& impl, uint64_t offset,
const MutableBufferSequence& buffers, Handler& handler)
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_read_some_at(implementation_type& impl,
uint64_t offset, const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
typedef win_iocp_handle_read_op<
MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
p.p = new (p.v) op(buffers, handler, io_ex);
ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at"));
@ -251,22 +261,24 @@ private:
const null_buffers& buffers, asio::error_code& ec);
size_t write_some_at(implementation_type& impl, uint64_t offset,
const null_buffers& buffers, asio::error_code& ec);
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_write_some(implementation_type& impl,
const null_buffers& buffers, Handler& handler);
template <typename Handler>
const null_buffers& buffers, Handler& handler,
const IoExecutor& io_ex);
template <typename Handler, typename IoExecutor>
void async_write_some_at(implementation_type& impl, uint64_t offset,
const null_buffers& buffers, Handler& handler);
const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);
size_t read_some(implementation_type& impl,
const null_buffers& buffers, asio::error_code& ec);
size_t read_some_at(implementation_type& impl, uint64_t offset,
const null_buffers& buffers, asio::error_code& ec);
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_read_some(implementation_type& impl,
const null_buffers& buffers, Handler& handler);
template <typename Handler>
const null_buffers& buffers, Handler& handler,
const IoExecutor& io_ex);
template <typename Handler, typename IoExecutor>
void async_read_some_at(implementation_type& impl, uint64_t offset,
const null_buffers& buffers, Handler& handler);
const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);
// Helper class for waiting for synchronous operations to complete.
class overlapped_wrapper;

View File

@ -34,18 +34,20 @@
namespace asio {
namespace detail {
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
class win_iocp_handle_write_op : public operation
{
public:
ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op);
win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler& handler)
win_iocp_handle_write_op(const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: operation(&win_iocp_handle_write_op::do_complete),
buffers_(buffers),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -54,7 +56,7 @@ public:
// Take ownership of the operation object.
win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -91,6 +93,7 @@ public:
private:
ConstBufferSequence buffers_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -48,7 +48,10 @@ public:
// Constructor. Specifies a concurrency hint that is passed through to the
// underlying I/O completion port.
ASIO_DECL win_iocp_io_context(asio::execution_context& ctx,
int concurrency_hint = -1);
int concurrency_hint = -1, bool own_thread = true);
// Destructor.
ASIO_DECL ~win_iocp_io_context();
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void shutdown();
@ -287,6 +290,10 @@ private:
// Timeout to use with GetQueuedCompletionStatus.
const DWORD gqcs_timeout_;
// Helper class to run the scheduler in its own thread.
struct thread_function;
friend struct thread_function;
// Function object for processing timeouts in a background thread.
struct timer_thread_function;
friend struct timer_thread_function;
@ -311,6 +318,9 @@ private:
// The concurrency hint used to initialise the io_context.
const int concurrency_hint_;
// The thread that is running the io_context.
scoped_ptr<thread> thread_;
};
} // namespace detail

View File

@ -34,20 +34,21 @@
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class win_iocp_null_buffers_op : public reactor_op
{
public:
ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op);
win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token,
Handler& handler)
Handler& handler, const IoExecutor& io_ex)
: reactor_op(&win_iocp_null_buffers_op::do_perform,
&win_iocp_null_buffers_op::do_complete),
cancel_token_(cancel_token),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static status do_perform(reactor_op*)
@ -64,7 +65,7 @@ public:
// Take ownership of the operation object.
win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -109,6 +110,7 @@ public:
private:
socket_ops::weak_cancel_token_type cancel_token_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -22,7 +22,7 @@
#include <string>
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/win_iocp_handle_service.hpp"
#include "asio/detail/push_options.hpp"
@ -32,7 +32,7 @@ namespace detail {
// Extend win_iocp_handle_service to provide serial port support.
class win_iocp_serial_port_service :
public service_base<win_iocp_serial_port_service>
public execution_context_service_base<win_iocp_serial_port_service>
{
public:
// The native type of a serial port.
@ -42,8 +42,7 @@ public:
typedef win_iocp_handle_service::implementation_type implementation_type;
// Constructor.
ASIO_DECL win_iocp_serial_port_service(
asio::io_context& io_context);
ASIO_DECL win_iocp_serial_port_service(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void shutdown();
@ -151,11 +150,12 @@ public:
// Start an asynchronous write. The data being written must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_write_some(implementation_type& impl,
const ConstBufferSequence& buffers, Handler& handler)
const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
handle_service_.async_write_some(impl, buffers, handler);
handle_service_.async_write_some(impl, buffers, handler, io_ex);
}
// Read some data. Returns the number of bytes received.
@ -168,11 +168,13 @@ public:
// Start an asynchronous read. The buffer for the data being received must be
// valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_read_some(implementation_type& impl,
const MutableBufferSequence& buffers, Handler& handler)
const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
{
handle_service_.async_read_some(impl, buffers, handler);
handle_service_.async_read_some(impl, buffers, handler, io_ex);
}
private:

View File

@ -35,7 +35,8 @@
namespace asio {
namespace detail {
template <typename Socket, typename Protocol, typename Handler>
template <typename Socket, typename Protocol,
typename Handler, typename IoExecutor>
class win_iocp_socket_accept_op : public operation
{
public:
@ -44,7 +45,7 @@ public:
win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service,
socket_type socket, Socket& peer, const Protocol& protocol,
typename Protocol::endpoint* peer_endpoint,
bool enable_connection_aborted, Handler& handler)
bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
: operation(&win_iocp_socket_accept_op::do_complete),
socket_service_(socket_service),
socket_(socket),
@ -52,9 +53,10 @@ public:
protocol_(protocol),
peer_endpoint_(peer_endpoint),
enable_connection_aborted_(enable_connection_aborted),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
socket_holder& new_socket()
@ -81,7 +83,7 @@ public:
// Take ownership of the operation object.
win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
if (owner)
{
@ -155,11 +157,13 @@ private:
unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
bool enable_connection_aborted_;
Handler handler_;
IoExecutor io_executor_;
};
#if defined(ASIO_HAS_MOVE)
template <typename Protocol, typename Handler>
template <typename Protocol, typename PeerIoExecutor,
typename Handler, typename IoExecutor>
class win_iocp_socket_move_accept_op : public operation
{
public:
@ -167,19 +171,20 @@ public:
win_iocp_socket_move_accept_op(
win_iocp_socket_service_base& socket_service, socket_type socket,
const Protocol& protocol, asio::io_context& peer_io_context,
const Protocol& protocol, const PeerIoExecutor& peer_io_ex,
typename Protocol::endpoint* peer_endpoint,
bool enable_connection_aborted, Handler& handler)
bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)
: operation(&win_iocp_socket_move_accept_op::do_complete),
socket_service_(socket_service),
socket_(socket),
peer_(peer_io_context),
peer_(peer_io_ex),
protocol_(protocol),
peer_endpoint_(peer_endpoint),
enable_connection_aborted_(enable_connection_aborted),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
socket_holder& new_socket()
@ -207,7 +212,7 @@ public:
win_iocp_socket_move_accept_op* o(
static_cast<win_iocp_socket_move_accept_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
if (owner)
{
@ -283,6 +288,7 @@ private:
unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
bool enable_connection_aborted_;
Handler handler_;
IoExecutor io_executor_;
};
#endif // defined(ASIO_HAS_MOVE)

View File

@ -56,18 +56,20 @@ public:
bool connect_ex_;
};
template <typename Handler>
template <typename Handler, typename IoExecutor>
class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base
{
public:
ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op);
win_iocp_socket_connect_op(socket_type socket, Handler& handler)
win_iocp_socket_connect_op(socket_type socket,
Handler& handler, const IoExecutor& io_ex)
: win_iocp_socket_connect_op_base(socket,
&win_iocp_socket_connect_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -80,7 +82,7 @@ public:
win_iocp_socket_connect_op* o(
static_cast<win_iocp_socket_connect_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
if (owner)
{
@ -115,6 +117,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -34,7 +34,7 @@
namespace asio {
namespace detail {
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class win_iocp_socket_recv_op : public operation
{
public:
@ -42,14 +42,16 @@ public:
win_iocp_socket_recv_op(socket_ops::state_type state,
socket_ops::weak_cancel_token_type cancel_token,
const MutableBufferSequence& buffers, Handler& handler)
const MutableBufferSequence& buffers, Handler& handler,
const IoExecutor& io_ex)
: operation(&win_iocp_socket_recv_op::do_complete),
state_(state),
cancel_token_(cancel_token),
buffers_(buffers),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -61,7 +63,7 @@ public:
// Take ownership of the operation object.
win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -105,6 +107,7 @@ private:
socket_ops::weak_cancel_token_type cancel_token_;
MutableBufferSequence buffers_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -34,7 +34,8 @@
namespace asio {
namespace detail {
template <typename MutableBufferSequence, typename Endpoint, typename Handler>
template <typename MutableBufferSequence, typename Endpoint,
typename Handler, typename IoExecutor>
class win_iocp_socket_recvfrom_op : public operation
{
public:
@ -42,15 +43,17 @@ public:
win_iocp_socket_recvfrom_op(Endpoint& endpoint,
socket_ops::weak_cancel_token_type cancel_token,
const MutableBufferSequence& buffers, Handler& handler)
const MutableBufferSequence& buffers, Handler& handler,
const IoExecutor& io_ex)
: operation(&win_iocp_socket_recvfrom_op::do_complete),
endpoint_(endpoint),
endpoint_size_(static_cast<int>(endpoint.capacity())),
cancel_token_(cancel_token),
buffers_(buffers),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
int& endpoint_size()
@ -68,7 +71,7 @@ public:
win_iocp_socket_recvfrom_op* o(
static_cast<win_iocp_socket_recvfrom_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -113,6 +116,7 @@ private:
socket_ops::weak_cancel_token_type cancel_token_;
MutableBufferSequence buffers_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -35,7 +35,7 @@
namespace asio {
namespace detail {
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class win_iocp_socket_recvmsg_op : public operation
{
public:
@ -44,14 +44,16 @@ public:
win_iocp_socket_recvmsg_op(
socket_ops::weak_cancel_token_type cancel_token,
const MutableBufferSequence& buffers,
socket_base::message_flags& out_flags, Handler& handler)
socket_base::message_flags& out_flags,
Handler& handler, const IoExecutor& io_ex)
: operation(&win_iocp_socket_recvmsg_op::do_complete),
cancel_token_(cancel_token),
buffers_(buffers),
out_flags_(out_flags),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -64,7 +66,7 @@ public:
win_iocp_socket_recvmsg_op* o(
static_cast<win_iocp_socket_recvmsg_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -106,6 +108,7 @@ private:
MutableBufferSequence buffers_;
socket_base::message_flags& out_flags_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -34,20 +34,22 @@
namespace asio {
namespace detail {
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
class win_iocp_socket_send_op : public operation
{
public:
ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op);
win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token,
const ConstBufferSequence& buffers, Handler& handler)
const ConstBufferSequence& buffers, Handler& handler,
const IoExecutor& io_ex)
: operation(&win_iocp_socket_send_op::do_complete),
cancel_token_(cancel_token),
buffers_(buffers),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -59,7 +61,7 @@ public:
// Take ownership of the operation object.
win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -99,6 +101,7 @@ private:
socket_ops::weak_cancel_token_type cancel_token_;
ConstBufferSequence buffers_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -21,7 +21,7 @@
#include <cstring>
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
@ -51,7 +51,7 @@ namespace detail {
template <typename Protocol>
class win_iocp_socket_service :
public service_base<win_iocp_socket_service<Protocol> >,
public execution_context_service_base<win_iocp_socket_service<Protocol> >,
public win_iocp_socket_service_base
{
public:
@ -129,9 +129,10 @@ public:
};
// Constructor.
win_iocp_socket_service(asio::io_context& io_context)
: service_base<win_iocp_socket_service<Protocol> >(io_context),
win_iocp_socket_service_base(io_context)
win_iocp_socket_service(execution_context& context)
: execution_context_service_base<
win_iocp_socket_service<Protocol> >(context),
win_iocp_socket_service_base(context)
{
}
@ -323,18 +324,20 @@ public:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_send_to(implementation_type& impl,
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags, Handler& handler)
socket_base::message_flags flags, Handler& handler,
const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
typedef win_iocp_socket_send_op<
ConstBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_send_to"));
buffer_sequence_adapter<asio::const_buffer,
@ -347,17 +350,18 @@ public:
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_send_to(implementation_type& impl, const null_buffers&,
const endpoint_type&, socket_base::message_flags, Handler& handler)
const endpoint_type&, socket_base::message_flags, Handler& handler,
const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_send_to(null_buffers)"));
start_reactor_op(impl, select_reactor::write_op, p.p);
@ -403,19 +407,22 @@ public:
// Start an asynchronous receive. The buffer for the data being received and
// the sender_endpoint object must both be valid for the lifetime of the
// asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endp,
socket_base::message_flags flags, Handler& handler)
socket_base::message_flags flags, Handler& handler,
const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_recvfrom_op<
MutableBufferSequence, endpoint_type, Handler> op;
typedef win_iocp_socket_recvfrom_op<MutableBufferSequence,
endpoint_type, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler);
p.p = new (p.v) op(sender_endp, impl.cancel_token_,
buffers, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_receive_from"));
buffer_sequence_adapter<asio::mutable_buffer,
@ -427,18 +434,18 @@ public:
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive_from(implementation_type& impl,
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags flags, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_receive_from(implementation_type& impl, const null_buffers&,
endpoint_type& sender_endpoint, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_receive_from(null_buffers)"));
// Reset endpoint since it can be given no sensible value at this time.
@ -478,50 +485,23 @@ public:
return ec;
}
#if defined(ASIO_HAS_MOVE)
// Accept a new connection.
typename Protocol::socket accept(implementation_type& impl,
io_context* peer_io_context, endpoint_type* peer_endpoint,
asio::error_code& ec)
{
typename Protocol::socket peer(
peer_io_context ? *peer_io_context : io_context_);
std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
peer_endpoint ? &addr_len : 0, ec));
// On success, assign new connection to peer socket object.
if (new_socket.get() != invalid_socket)
{
if (peer_endpoint)
peer_endpoint->resize(addr_len);
peer.assign(impl.protocol_, new_socket.get(), ec);
if (!ec)
new_socket.release();
}
return peer;
}
#endif // defined(ASIO_HAS_MOVE)
// Start an asynchronous accept. The peer and peer_endpoint objects
// must be valid until the accept's handler is invoked.
template <typename Socket, typename Handler>
template <typename Socket, typename Handler, typename IoExecutor>
void async_accept(implementation_type& impl, Socket& peer,
endpoint_type* peer_endpoint, Handler& handler)
endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op;
typedef win_iocp_socket_accept_op<Socket,
protocol_type, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
bool enable_connection_aborted =
(impl.state_ & socket_ops::enable_connection_aborted) != 0;
p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_,
peer_endpoint, enable_connection_aborted, handler);
peer_endpoint, enable_connection_aborted, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_accept"));
start_accept_op(impl, peer.is_open(), p.p->new_socket(),
@ -534,22 +514,23 @@ public:
#if defined(ASIO_HAS_MOVE)
// Start an asynchronous accept. The peer and peer_endpoint objects
// must be valid until the accept's handler is invoked.
template <typename Handler>
void async_accept(implementation_type& impl,
asio::io_context* peer_io_context,
endpoint_type* peer_endpoint, Handler& handler)
template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
void async_move_accept(implementation_type& impl,
const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_move_accept_op<protocol_type, Handler> op;
typedef win_iocp_socket_move_accept_op<
protocol_type, PeerIoExecutor, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
bool enable_connection_aborted =
(impl.state_ & socket_ops::enable_connection_aborted) != 0;
p.p = new (p.v) op(*this, impl.socket_, impl.protocol_,
peer_io_context ? *peer_io_context : io_context_,
peer_endpoint, enable_connection_aborted, handler);
peer_io_ex, peer_endpoint, enable_connection_aborted,
handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_accept"));
start_accept_op(impl, false, p.p->new_socket(),
@ -570,17 +551,18 @@ public:
}
// Start an asynchronous connect.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, Handler& handler)
const endpoint_type& peer_endpoint, Handler& handler,
const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_connect_op<Handler> op;
typedef win_iocp_socket_connect_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.socket_, handler);
p.p = new (p.v) op(impl.socket_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_connect"));
start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(),

View File

@ -20,7 +20,7 @@
#if defined(ASIO_HAS_IOCP)
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
@ -85,8 +85,7 @@ public:
};
// Constructor.
ASIO_DECL win_iocp_socket_service_base(
asio::io_context& io_context);
ASIO_DECL win_iocp_socket_service_base(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void base_shutdown();
@ -210,20 +209,20 @@ public:
// Asynchronously wait for the socket to become ready to read, ready to
// write, or to have pending error conditions.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_wait(base_implementation_type& impl,
socket_base::wait_type w, Handler& handler)
socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_wait_op<Handler> op;
typedef win_iocp_wait_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_wait"));
switch (w)
@ -271,18 +270,19 @@ public:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_send(base_implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
const ConstBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
typedef win_iocp_socket_send_op<
ConstBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_send"));
buffer_sequence_adapter<asio::const_buffer,
@ -295,17 +295,17 @@ public:
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_send(base_implementation_type& impl, const null_buffers&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_send(null_buffers)"));
start_reactor_op(impl, select_reactor::write_op, p.p);
@ -337,18 +337,21 @@ public:
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive(base_implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
const MutableBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op;
typedef win_iocp_socket_recv_op<
MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler);
p.p = new (p.v) op(impl.state_, impl.cancel_token_,
buffers, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_receive"));
buffer_sequence_adapter<asio::mutable_buffer,
@ -361,17 +364,18 @@ public:
}
// Wait until data can be received without blocking.
template <typename Handler>
void async_receive(base_implementation_type& impl, const null_buffers&,
socket_base::message_flags flags, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_receive(base_implementation_type& impl,
const null_buffers&, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_receive(null_buffers)"));
start_null_buffers_receive_op(impl, flags, p.p);
@ -410,18 +414,22 @@ public:
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive_with_flags(base_implementation_type& impl,
const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, Handler& handler)
socket_base::message_flags& out_flags, Handler& handler,
const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_socket_recvmsg_op<MutableBufferSequence, Handler> op;
typedef win_iocp_socket_recvmsg_op<
MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, buffers, out_flags, handler);
p.p = new (p.v) op(impl.cancel_token_,
buffers, out_flags, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_receive_with_flags"));
buffer_sequence_adapter<asio::mutable_buffer,
@ -432,18 +440,19 @@ public:
}
// Wait until data can be received without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_receive_with_flags(base_implementation_type& impl,
const null_buffers&, socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, Handler& handler)
socket_base::message_flags& out_flags, Handler& handler,
const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef win_iocp_null_buffers_op<Handler> op;
typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(impl.cancel_token_, handler);
p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
ASIO_HANDLER_CREATION((context_, *p.p, "socket",
&impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
// Reset out_flags since it can be given no sensible value at this time.
@ -518,8 +527,8 @@ protected:
base_implementation_type& impl);
// Helper function to get the reactor. If no reactor has been created yet, a
// new one is obtained from the io_context and a pointer to it is cached in
// this service.
// new one is obtained from the execution context and a pointer to it is
// cached in this service.
ASIO_DECL select_reactor& get_reactor();
// The type of a ConnectEx function pointer, as old SDKs may not provide it.
@ -553,8 +562,8 @@ protected:
// - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);
// The io_context used to obtain the reactor, if required.
asio::io_context& io_context_;
// The execution context used to obtain the reactor, if required.
execution_context& context_;
// The IOCP service used for running asynchronous operations and dispatching
// handlers.

View File

@ -34,20 +34,21 @@
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class win_iocp_wait_op : public reactor_op
{
public:
ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op);
win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token,
Handler& handler)
Handler& handler, const IoExecutor& io_ex)
: reactor_op(&win_iocp_wait_op::do_perform,
&win_iocp_wait_op::do_complete),
cancel_token_(cancel_token),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static status do_perform(reactor_op*)
@ -64,7 +65,7 @@ public:
// Take ownership of the operation object.
win_iocp_wait_op* o(static_cast<win_iocp_wait_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -109,6 +110,7 @@ public:
private:
socket_ops::weak_cancel_token_type cancel_token_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -24,7 +24,13 @@
#include "asio/detail/memory.hpp"
#include "asio/detail/wait_handler.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
@ -32,7 +38,7 @@ namespace asio {
namespace detail {
class win_object_handle_service :
public service_base<win_object_handle_service>
public execution_context_service_base<win_object_handle_service>
{
public:
// The native type of an object handle.
@ -79,8 +85,7 @@ public:
};
// Constructor.
ASIO_DECL win_object_handle_service(
asio::io_context& io_context);
ASIO_DECL win_object_handle_service(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void shutdown();
@ -129,16 +134,17 @@ public:
asio::error_code& ec);
/// Start an asynchronous wait.
template <typename Handler>
void async_wait(implementation_type& impl, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_wait(implementation_type& impl,
Handler& handler, const IoExecutor& io_ex)
{
// Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler> op;
typedef wait_handler<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((io_context_.context(), *p.p, "object_handle",
ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "object_handle",
&impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "async_wait"));
start_wait_op(impl, p.p);
@ -157,8 +163,13 @@ private:
static ASIO_DECL VOID CALLBACK wait_callback(
PVOID param, BOOLEAN timeout);
// The io_context implementation used to post completions.
io_context_impl& io_context_;
// The scheduler used to post completions.
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
scheduler_impl& scheduler_;
// Mutex to protect access to internal state.
mutex mutex_;

View File

@ -23,7 +23,13 @@
#include "asio/detail/atomic_count.hpp"
#include "asio/detail/winrt_async_op.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
@ -31,13 +37,13 @@ namespace asio {
namespace detail {
class winrt_async_manager
: public asio::detail::service_base<winrt_async_manager>
: public execution_context_service_base<winrt_async_manager>
{
public:
// Constructor.
winrt_async_manager(asio::io_context& io_context)
: asio::detail::service_base<winrt_async_manager>(io_context),
io_context_(use_service<io_context_impl>(io_context)),
winrt_async_manager(execution_context& context)
: execution_context_service_base<winrt_async_manager>(context),
scheduler_(use_service<scheduler_impl>(context)),
outstanding_ops_(1)
{
}
@ -185,12 +191,12 @@ public:
asio::system_category());
break;
}
io_context_.post_deferred_completion(handler);
scheduler_.post_deferred_completion(handler);
if (--outstanding_ops_ == 0)
promise_.set_value();
});
io_context_.work_started();
scheduler_.work_started();
++outstanding_ops_;
action->Completed = on_completed;
}
@ -222,12 +228,12 @@ public:
asio::system_category());
break;
}
io_context_.post_deferred_completion(handler);
scheduler_.post_deferred_completion(handler);
if (--outstanding_ops_ == 0)
promise_.set_value();
});
io_context_.work_started();
scheduler_.work_started();
++outstanding_ops_;
operation->Completed = on_completed;
}
@ -263,19 +269,24 @@ public:
asio::system_category());
break;
}
io_context_.post_deferred_completion(handler);
scheduler_.post_deferred_completion(handler);
if (--outstanding_ops_ == 0)
promise_.set_value();
});
io_context_.work_started();
scheduler_.work_started();
++outstanding_ops_;
operation->Completed = on_completed;
}
private:
// The io_context implementation used to post completed handlers.
io_context_impl& io_context_;
// The scheduler implementation used to post completed handlers.
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
scheduler_impl& scheduler_;
// Count of outstanding operations.
atomic_count outstanding_ops_;

View File

@ -33,7 +33,7 @@
namespace asio {
namespace detail {
template <typename Protocol, typename Handler>
template <typename Protocol, typename Handler, typename IoExecutor>
class winrt_resolve_op :
public winrt_async_op<
Windows::Foundation::Collections::IVectorView<
@ -46,15 +46,17 @@ public:
typedef asio::ip::basic_resolver_query<Protocol> query_type;
typedef asio::ip::basic_resolver_results<Protocol> results_type;
winrt_resolve_op(const query_type& query, Handler& handler)
winrt_resolve_op(const query_type& query,
Handler& handler, const IoExecutor& io_ex)
: winrt_async_op<
Windows::Foundation::Collections::IVectorView<
Windows::Networking::EndpointPair^>^>(
&winrt_resolve_op::do_complete),
query_(query),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -63,7 +65,7 @@ public:
// Take ownership of the operation object.
winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -106,6 +108,7 @@ public:
private:
query_type query_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -21,6 +21,7 @@
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/ip/basic_resolver_results.hpp"
#include "asio/post.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/socket_ops.hpp"
@ -28,6 +29,12 @@
#include "asio/detail/winrt_resolve_op.hpp"
#include "asio/detail/winrt_utils.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
namespace asio {
@ -35,7 +42,7 @@ namespace detail {
template <typename Protocol>
class winrt_resolver_service :
public service_base<winrt_resolver_service<Protocol> >
public execution_context_service_base<winrt_resolver_service<Protocol> >
{
public:
// The implementation type of the resolver. A cancellation token is used to
@ -53,10 +60,11 @@ public:
typedef asio::ip::basic_resolver_results<Protocol> results_type;
// Constructor.
winrt_resolver_service(asio::io_context& io_context)
: service_base<winrt_resolver_service<Protocol> >(io_context),
io_context_(use_service<io_context_impl>(io_context)),
async_manager_(use_service<winrt_async_manager>(io_context))
winrt_resolver_service(execution_context& context)
: execution_context_service_base<
winrt_resolver_service<Protocol> >(context),
scheduler_(use_service<scheduler_impl>(context)),
async_manager_(use_service<winrt_async_manager>(context))
{
}
@ -71,7 +79,7 @@ public:
}
// Perform any fork-related housekeeping.
void notify_fork(asio::io_context::fork_event)
void notify_fork(execution_context::fork_event)
{
}
@ -130,20 +138,20 @@ public:
}
// Asynchronously resolve a query to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl,
const query_type& query, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_resolve(implementation_type& impl, const query_type& query,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef winrt_resolve_op<Protocol, Handler> op;
typedef winrt_resolve_op<Protocol, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(query, handler);
p.p = new (p.v) op(query, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_.context(),
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "resolver", &impl, 0, "async_resolve"));
(void)impl;
@ -159,7 +167,7 @@ public:
{
p.p->ec_ = asio::error_code(
e->HResult, asio::system_category());
io_context_.post_immediate_completion(p.p, is_continuation);
scheduler_.post_immediate_completion(p.p, is_continuation);
p.v = p.p = 0;
}
}
@ -173,18 +181,24 @@ public:
}
// Asynchronously resolve an endpoint to a list of entries.
template <typename Handler>
void async_resolve(implementation_type&,
const endpoint_type&, Handler& handler)
template <typename Handler, typename IoExecutor>
void async_resolve(implementation_type&, const endpoint_type&,
Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const results_type results;
io_context_.get_io_context().post(
detail::bind_handler(handler, ec, results));
asio::post(io_ex, detail::bind_handler(handler, ec, results));
}
private:
io_context_impl& io_context_;
// The scheduler implementation used for delivering completions.
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
scheduler_impl& scheduler_;
winrt_async_manager& async_manager_;
};

View File

@ -33,18 +33,19 @@
namespace asio {
namespace detail {
template <typename Handler>
template <typename Handler, typename IoExecutor>
class winrt_socket_connect_op :
public winrt_async_op<void>
{
public:
ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op);
winrt_socket_connect_op(Handler& handler)
winrt_socket_connect_op(Handler& handler, const IoExecutor& io_ex)
: winrt_async_op<void>(&winrt_socket_connect_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -53,7 +54,7 @@ public:
// Take ownership of the operation object.
winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -80,6 +81,7 @@ public:
private:
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -33,20 +33,22 @@
namespace asio {
namespace detail {
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class winrt_socket_recv_op :
public winrt_async_op<Windows::Storage::Streams::IBuffer^>
{
public:
ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op);
winrt_socket_recv_op(const MutableBufferSequence& buffers, Handler& handler)
winrt_socket_recv_op(const MutableBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: winrt_async_op<Windows::Storage::Streams::IBuffer^>(
&winrt_socket_recv_op::do_complete),
buffers_(buffers),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -55,7 +57,7 @@ public:
// Take ownership of the operation object.
winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -100,6 +102,7 @@ public:
private:
MutableBufferSequence buffers_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -33,19 +33,21 @@
namespace asio {
namespace detail {
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
class winrt_socket_send_op :
public winrt_async_op<unsigned int>
{
public:
ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op);
winrt_socket_send_op(const ConstBufferSequence& buffers, Handler& handler)
winrt_socket_send_op(const ConstBufferSequence& buffers,
Handler& handler, const IoExecutor& io_ex)
: winrt_async_op<unsigned int>(&winrt_socket_send_op::do_complete),
buffers_(buffers),
handler_(ASIO_MOVE_CAST(Handler)(handler))
handler_(ASIO_MOVE_CAST(Handler)(handler)),
io_executor_(io_ex)
{
handler_work<Handler>::start(handler_);
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
}
static void do_complete(void* owner, operation* base,
@ -54,7 +56,7 @@ public:
// Take ownership of the operation object.
winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
ASIO_HANDLER_COMPLETION((*o));
@ -91,6 +93,7 @@ public:
private:
ConstBufferSequence buffers_;
Handler handler_;
IoExecutor io_executor_;
};
} // namespace detail

View File

@ -20,7 +20,7 @@
#if defined(ASIO_WINDOWS_RUNTIME)
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/winrt_socket_connect_op.hpp"
#include "asio/detail/winrt_ssocket_service_base.hpp"
@ -33,7 +33,7 @@ namespace detail {
template <typename Protocol>
class winrt_ssocket_service :
public service_base<winrt_ssocket_service<Protocol> >,
public execution_context_service_base<winrt_ssocket_service<Protocol> >,
public winrt_ssocket_service_base
{
public:
@ -61,9 +61,9 @@ public:
};
// Constructor.
winrt_ssocket_service(asio::io_context& io_context)
: service_base<winrt_ssocket_service<Protocol> >(io_context),
winrt_ssocket_service_base(io_context)
winrt_ssocket_service(execution_context& context)
: execution_context_service_base<winrt_ssocket_service<Protocol> >(context),
winrt_ssocket_service_base(context)
{
}
@ -210,20 +210,21 @@ public:
}
// Start an asynchronous connect.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, Handler& handler)
const endpoint_type& peer_endpoint,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef winrt_socket_connect_op<Handler> op;
typedef winrt_socket_connect_op<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_ex);
ASIO_HANDLER_CREATION((io_context_.context(),
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "socket", &impl, 0, "async_connect"));
start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation);

View File

@ -21,7 +21,7 @@
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/memory.hpp"
@ -30,6 +30,12 @@
#include "asio/detail/winrt_socket_recv_op.hpp"
#include "asio/detail/winrt_socket_send_op.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#include "asio/detail/push_options.hpp"
namespace asio {
@ -61,8 +67,7 @@ public:
};
// Constructor.
ASIO_DECL winrt_ssocket_service_base(
asio::io_context& io_context);
ASIO_DECL winrt_ssocket_service_base(execution_context& context);
// Destroy all user-defined handler objects owned by the service.
ASIO_DECL void base_shutdown();
@ -192,21 +197,21 @@ public:
// Start an asynchronous send. The data being sent must be valid for the
// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
void async_send(base_implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
const ConstBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef winrt_socket_send_op<ConstBufferSequence, Handler> op;
typedef winrt_socket_send_op<ConstBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
p.p = new (p.v) op(buffers, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_.context(),
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "socket", &impl, 0, "async_send"));
start_send_op(impl,
@ -217,13 +222,13 @@ public:
}
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_send(base_implementation_type&, const null_buffers&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.get_io_context().post(
asio::post(io_ex,
detail::bind_handler(handler, ec, bytes_transferred));
}
@ -248,21 +253,22 @@ public:
// Start an asynchronous receive. The buffer for the data being received
// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
template <typename MutableBufferSequence,
typename Handler, typename IoExecutor>
void async_receive(base_implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
const MutableBufferSequence& buffers, socket_base::message_flags flags,
Handler& handler, const IoExecutor& io_ex)
{
bool is_continuation =
asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef winrt_socket_recv_op<MutableBufferSequence, Handler> op;
typedef winrt_socket_recv_op<MutableBufferSequence, Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(buffers, handler);
p.p = new (p.v) op(buffers, handler, io_ex);
ASIO_HANDLER_CREATION((io_context_.context(),
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "socket", &impl, 0, "async_receive"));
start_receive_op(impl,
@ -273,13 +279,13 @@ public:
}
// Wait until data can be received without blocking.
template <typename Handler>
template <typename Handler, typename IoExecutor>
void async_receive(base_implementation_type&, const null_buffers&,
socket_base::message_flags, Handler& handler)
socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
{
asio::error_code ec = asio::error::operation_not_supported;
const std::size_t bytes_transferred = 0;
io_context_.get_io_context().post(
asio::post(io_ex,
detail::bind_handler(handler, ec, bytes_transferred));
}
@ -332,8 +338,13 @@ protected:
winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
bool is_continuation);
// The io_context implementation used for delivering completions.
io_context_impl& io_context_;
// The scheduler implementation used for delivering completions.
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
scheduler_impl& scheduler_;
// The manager that keeps track of outstanding operations.
winrt_async_manager& async_manager_;

View File

@ -28,7 +28,13 @@
#include "asio/detail/timer_queue_base.hpp"
#include "asio/detail/timer_queue_set.hpp"
#include "asio/detail/wait_op.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_io_context.hpp"
#else // defined(ASIO_HAS_IOCP)
# include "asio/detail/scheduler.hpp"
#endif // defined(ASIO_HAS_IOCP)
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/thread.hpp"
@ -40,11 +46,11 @@ namespace asio {
namespace detail {
class winrt_timer_scheduler
: public asio::detail::service_base<winrt_timer_scheduler>
: public execution_context_service_base<winrt_timer_scheduler>
{
public:
// Constructor.
ASIO_DECL winrt_timer_scheduler(asio::io_context& io_context);
ASIO_DECL winrt_timer_scheduler(execution_context& context);
// Destructor.
ASIO_DECL ~winrt_timer_scheduler();
@ -53,8 +59,7 @@ public:
ASIO_DECL void shutdown();
// Recreate internal descriptors following a fork.
ASIO_DECL void notify_fork(
asio::io_context::fork_event fork_ev);
ASIO_DECL void notify_fork(execution_context::fork_event fork_ev);
// Initialise the task. No effect as this class uses its own thread.
ASIO_DECL void init_task();
@ -100,8 +105,13 @@ private:
// Helper function to remove a timer queue.
ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
// The io_context implementation used to post completions.
io_context_impl& io_context_;
// The scheduler implementation used to post completions.
#if defined(ASIO_HAS_IOCP)
typedef class win_iocp_io_context scheduler_impl;
#else
typedef class scheduler scheduler_impl;
#endif
scheduler_impl& scheduler_;
// Mutex used to protect internal variables.
asio::detail::mutex mutex_;

View File

@ -109,13 +109,14 @@ public:
class id;
class service;
protected:
public:
/// Constructor.
ASIO_DECL execution_context();
/// Destructor.
ASIO_DECL ~execution_context();
protected:
/// Shuts down all services in the context.
/**
* This function is implemented as follows:

View File

@ -100,8 +100,8 @@ namespace detail
}
}
template <typename Protocol, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type*)
@ -112,8 +112,8 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
return result;
}
template <typename Protocol, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, asio::error_code& ec,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type*)
@ -124,8 +124,8 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
}
#if !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator>
Iterator connect(basic_socket<Protocol>& s, Iterator begin,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
{
asio::error_code ec;
@ -134,8 +134,8 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin,
return result;
}
template <typename Protocol, typename Iterator>
inline Iterator connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename Iterator>
inline Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
{
@ -143,8 +143,9 @@ inline Iterator connect(basic_socket<Protocol>& s,
}
#endif // !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator>
Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end)
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end)
{
asio::error_code ec;
Iterator result = connect(s, begin, end, ec);
@ -152,16 +153,16 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end)
return result;
}
template <typename Protocol, typename Iterator>
inline Iterator connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor, typename Iterator>
inline Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, asio::error_code& ec)
{
return connect(s, begin, end, detail::default_connect_condition(), ec);
}
template <typename Protocol, typename EndpointSequence,
typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type*)
@ -173,9 +174,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
return result;
}
template <typename Protocol, typename EndpointSequence,
typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
asio::error_code& ec,
typename enable_if<is_endpoint_sequence<
@ -187,8 +188,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol>& s,
}
#if !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, ConnectCondition connect_condition,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
{
@ -198,8 +200,9 @@ Iterator connect(basic_socket<Protocol>& s,
return result;
}
template <typename Protocol, typename Iterator, typename ConnectCondition>
inline Iterator connect(basic_socket<Protocol>& s,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
inline Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, ConnectCondition connect_condition,
asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
@ -208,8 +211,9 @@ inline Iterator connect(basic_socket<Protocol>& s,
}
#endif // !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol>& s, Iterator begin,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition)
{
asio::error_code ec;
@ -218,9 +222,11 @@ Iterator connect(basic_socket<Protocol>& s, Iterator begin,
return result;
}
template <typename Protocol, typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
ConnectCondition connect_condition, asio::error_code& ec)
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition,
asio::error_code& ec)
{
ec = asio::error_code();
@ -284,12 +290,12 @@ namespace detail
}
};
template <typename Protocol, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
class range_connect_op : base_from_connect_condition<ConnectCondition>
{
public:
range_connect_op(basic_socket<Protocol>& sock,
range_connect_op(basic_socket<Protocol, Executor>& sock,
const EndpointSequence& endpoints,
const ConnectCondition& connect_condition,
RangeConnectHandler& handler)
@ -381,69 +387,71 @@ namespace detail
}
//private:
basic_socket<Protocol>& socket_;
basic_socket<Protocol, Executor>& socket_;
EndpointSequence endpoints_;
std::size_t index_;
int start_;
RangeConnectHandler handler_;
};
template <typename Protocol, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
inline void* asio_handler_allocate(std::size_t size,
range_connect_op<Protocol, EndpointSequence,
range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Protocol, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
range_connect_op<Protocol, EndpointSequence,
range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Protocol, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
inline bool asio_handler_is_continuation(
range_connect_op<Protocol, EndpointSequence,
range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Function, typename Protocol, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
template <typename Function, typename Executor, typename Protocol,
typename EndpointSequence, typename ConnectCondition,
typename RangeConnectHandler>
inline void asio_handler_invoke(Function& function,
range_connect_op<Protocol, EndpointSequence,
range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Protocol, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
template <typename Function, typename Executor, typename Protocol,
typename EndpointSequence, typename ConnectCondition,
typename RangeConnectHandler>
inline void asio_handler_invoke(const Function& function,
range_connect_op<Protocol, EndpointSequence,
range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
class iterator_connect_op : base_from_connect_condition<ConnectCondition>
{
public:
iterator_connect_op(basic_socket<Protocol>& sock,
iterator_connect_op(basic_socket<Protocol, Executor>& sock,
const Iterator& begin, const Iterator& end,
const ConnectCondition& connect_condition,
IteratorConnectHandler& handler)
@ -527,57 +535,59 @@ namespace detail
}
//private:
basic_socket<Protocol>& socket_;
basic_socket<Protocol, Executor>& socket_;
Iterator iter_;
Iterator end_;
int start_;
IteratorConnectHandler handler_;
};
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
inline void* asio_handler_allocate(std::size_t size,
iterator_connect_op<Protocol, Iterator,
iterator_connect_op<Protocol, Executor, Iterator,
ConnectCondition, IteratorConnectHandler>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
iterator_connect_op<Protocol, Iterator,
iterator_connect_op<Protocol, Executor, Iterator,
ConnectCondition, IteratorConnectHandler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
inline bool asio_handler_is_continuation(
iterator_connect_op<Protocol, Iterator,
iterator_connect_op<Protocol, Executor, Iterator,
ConnectCondition, IteratorConnectHandler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Function, typename Protocol, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
template <typename Function, typename Executor, typename Protocol,
typename Iterator, typename ConnectCondition,
typename IteratorConnectHandler>
inline void asio_handler_invoke(Function& function,
iterator_connect_op<Protocol, Iterator,
iterator_connect_op<Protocol, Executor, Iterator,
ConnectCondition, IteratorConnectHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Protocol, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
template <typename Function, typename Executor, typename Protocol,
typename Iterator, typename ConnectCondition,
typename IteratorConnectHandler>
inline void asio_handler_invoke(const Function& function,
iterator_connect_op<Protocol, Iterator,
iterator_connect_op<Protocol, Executor, Iterator,
ConnectCondition, IteratorConnectHandler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
@ -587,17 +597,17 @@ namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler, typename Allocator>
struct associated_allocator<
detail::range_connect_op<Protocol, EndpointSequence,
detail::range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>, Allocator>
{
typedef typename associated_allocator<
RangeConnectHandler, Allocator>::type type;
static type get(
const detail::range_connect_op<Protocol, EndpointSequence,
const detail::range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>& h,
const Allocator& a = Allocator()) ASIO_NOEXCEPT
{
@ -606,38 +616,39 @@ struct associated_allocator<
}
};
template <typename Protocol, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler, typename Executor>
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler, typename Executor1>
struct associated_executor<
detail::range_connect_op<Protocol, EndpointSequence,
ConnectCondition, RangeConnectHandler>, Executor>
detail::range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>, Executor1>
{
typedef typename associated_executor<
RangeConnectHandler, Executor>::type type;
RangeConnectHandler, Executor1>::type type;
static type get(
const detail::range_connect_op<Protocol, EndpointSequence,
ConnectCondition, RangeConnectHandler>& h,
const Executor& ex = Executor()) ASIO_NOEXCEPT
const detail::range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, RangeConnectHandler>& h,
const Executor1& ex = Executor1()) ASIO_NOEXCEPT
{
return associated_executor<RangeConnectHandler,
Executor>::get(h.handler_, ex);
Executor1>::get(h.handler_, ex);
}
};
template <typename Protocol, typename Iterator, typename ConnectCondition,
typename IteratorConnectHandler, typename Allocator>
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler,
typename Allocator>
struct associated_allocator<
detail::iterator_connect_op<Protocol, Iterator,
ConnectCondition, IteratorConnectHandler>,
detail::iterator_connect_op<Protocol, Executor,
Iterator, ConnectCondition, IteratorConnectHandler>,
Allocator>
{
typedef typename associated_allocator<
IteratorConnectHandler, Allocator>::type type;
static type get(
const detail::iterator_connect_op<Protocol, Iterator,
ConnectCondition, IteratorConnectHandler>& h,
const detail::iterator_connect_op<Protocol, Executor,
Iterator, ConnectCondition, IteratorConnectHandler>& h,
const Allocator& a = Allocator()) ASIO_NOEXCEPT
{
return associated_allocator<IteratorConnectHandler,
@ -645,33 +656,35 @@ struct associated_allocator<
}
};
template <typename Protocol, typename Iterator, typename ConnectCondition,
typename IteratorConnectHandler, typename Executor>
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler,
typename Executor1>
struct associated_executor<
detail::iterator_connect_op<Protocol, Iterator,
ConnectCondition, IteratorConnectHandler>,
Executor>
detail::iterator_connect_op<Protocol, Executor,
Iterator, ConnectCondition, IteratorConnectHandler>,
Executor1>
{
typedef typename associated_executor<
IteratorConnectHandler, Executor>::type type;
IteratorConnectHandler, Executor1>::type type;
static type get(
const detail::iterator_connect_op<Protocol, Iterator,
ConnectCondition, IteratorConnectHandler>& h,
const Executor& ex = Executor()) ASIO_NOEXCEPT
const detail::iterator_connect_op<Protocol, Executor,
Iterator, ConnectCondition, IteratorConnectHandler>& h,
const Executor1& ex = Executor1()) ASIO_NOEXCEPT
{
return associated_executor<IteratorConnectHandler,
Executor>::get(h.handler_, ex);
Executor1>::get(h.handler_, ex);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename EndpointSequence,
typename RangeConnectHandler>
template <typename Protocol, typename Executor,
typename EndpointSequence, typename RangeConnectHandler>
inline ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))
async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints,
ASIO_MOVE_ARG(RangeConnectHandler) handler,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type*)
@ -685,8 +698,8 @@ async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
void (asio::error_code, typename Protocol::endpoint)>
init(handler);
detail::range_connect_op<Protocol, EndpointSequence,
detail::default_connect_condition,
detail::range_connect_op<Protocol, Executor,
EndpointSequence, detail::default_connect_condition,
ASIO_HANDLER_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))>(s,
endpoints, detail::default_connect_condition(),
@ -696,11 +709,11 @@ async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
}
#if !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator,
typename IteratorConnectHandler>
template <typename Protocol, typename Executor,
typename Iterator, typename IteratorConnectHandler>
inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ASIO_MOVE_ARG(IteratorConnectHandler) handler,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
{
@ -712,7 +725,7 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
async_completion<IteratorConnectHandler,
void (asio::error_code, Iterator)> init(handler);
detail::iterator_connect_op<Protocol, Iterator,
detail::iterator_connect_op<Protocol, Executor, Iterator,
detail::default_connect_condition, ASIO_HANDLER_TYPE(
IteratorConnectHandler, void (asio::error_code, Iterator))>(s,
begin, Iterator(), detail::default_connect_condition(),
@ -722,10 +735,11 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
}
#endif // !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator, typename IteratorConnectHandler>
template <typename Protocol, typename Executor,
typename Iterator, typename IteratorConnectHandler>
inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,
ASIO_MOVE_ARG(IteratorConnectHandler) handler)
{
// If you get an error on the following line it means that your handler does
@ -736,7 +750,7 @@ async_connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
async_completion<IteratorConnectHandler,
void (asio::error_code, Iterator)> init(handler);
detail::iterator_connect_op<Protocol, Iterator,
detail::iterator_connect_op<Protocol, Executor, Iterator,
detail::default_connect_condition, ASIO_HANDLER_TYPE(
IteratorConnectHandler, void (asio::error_code, Iterator))>(s,
begin, end, detail::default_connect_condition(),
@ -745,12 +759,12 @@ async_connect(basic_socket<Protocol>& s, Iterator begin, Iterator end,
return init.result.get();
}
template <typename Protocol, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
inline ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))
async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
ConnectCondition connect_condition,
async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
ASIO_MOVE_ARG(RangeConnectHandler) handler,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type*)
@ -764,7 +778,7 @@ async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
void (asio::error_code, typename Protocol::endpoint)>
init(handler);
detail::range_connect_op<Protocol, EndpointSequence,
detail::range_connect_op<Protocol, Executor, EndpointSequence,
ConnectCondition, ASIO_HANDLER_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))>(s,
endpoints, connect_condition, init.completion_handler)(
@ -774,11 +788,11 @@ async_connect(basic_socket<Protocol>& s, const EndpointSequence& endpoints,
}
#if !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)
@ -791,8 +805,8 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
async_completion<IteratorConnectHandler,
void (asio::error_code, Iterator)> init(handler);
detail::iterator_connect_op<Protocol, Iterator,
ConnectCondition, ASIO_HANDLER_TYPE(
detail::iterator_connect_op<Protocol, Executor,
Iterator, ConnectCondition, ASIO_HANDLER_TYPE(
IteratorConnectHandler, void (asio::error_code, Iterator))>(s,
begin, Iterator(), connect_condition, init.completion_handler)(
asio::error_code(), 1);
@ -801,11 +815,11 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
}
#endif // !defined(ASIO_NO_DEPRECATED)
template <typename Protocol, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol>& s, Iterator begin,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler)
{
@ -817,8 +831,8 @@ async_connect(basic_socket<Protocol>& s, Iterator begin,
async_completion<IteratorConnectHandler,
void (asio::error_code, Iterator)> init(handler);
detail::iterator_connect_op<Protocol, Iterator,
ConnectCondition, ASIO_HANDLER_TYPE(
detail::iterator_connect_op<Protocol, Executor,
Iterator, ConnectCondition, ASIO_HANDLER_TYPE(
IteratorConnectHandler, void (asio::error_code, Iterator))>(s,
begin, end, connect_condition, init.completion_handler)(
asio::error_code(), 1);

View File

@ -34,13 +34,14 @@
namespace asio {
io_context::io_context()
: impl_(add_impl(new impl_type(*this, ASIO_CONCURRENCY_HINT_DEFAULT)))
: impl_(add_impl(new impl_type(*this,
ASIO_CONCURRENCY_HINT_DEFAULT, false)))
{
}
io_context::io_context(int concurrency_hint)
: impl_(add_impl(new impl_type(*this, concurrency_hint == 1
? ASIO_CONCURRENCY_HINT_1 : concurrency_hint)))
? ASIO_CONCURRENCY_HINT_1 : concurrency_hint, false)))
{
}

View File

@ -34,7 +34,7 @@ struct system_context::thread_function
};
system_context::system_context()
: scheduler_(use_service<detail::scheduler>(*this))
: scheduler_(add_scheduler(new detail::scheduler(*this, 0, false)))
{
scheduler_.work_started();
@ -66,6 +66,13 @@ void system_context::join()
threads_.join();
}
detail::scheduler& system_context::add_scheduler(detail::scheduler* s)
{
detail::scoped_ptr<detail::scheduler> scoped_impl(s);
asio::add_service<detail::scheduler>(*this, scoped_impl.get());
return *scoped_impl.release();
}
} // namespace asio
#include "asio/detail/pop_options.hpp"

View File

@ -34,7 +34,7 @@ struct thread_pool::thread_function
};
thread_pool::thread_pool()
: scheduler_(use_service<detail::scheduler>(*this))
: scheduler_(add_scheduler(new detail::scheduler(*this, 0, false)))
{
scheduler_.work_started();
@ -44,7 +44,8 @@ thread_pool::thread_pool()
}
thread_pool::thread_pool(std::size_t num_threads)
: scheduler_(use_service<detail::scheduler>(*this))
: scheduler_(add_scheduler(new detail::scheduler(*this, num_threads == 1
? ASIO_CONCURRENCY_HINT_1 : num_threads, false)))
{
scheduler_.work_started();
@ -65,8 +66,18 @@ void thread_pool::stop()
void thread_pool::join()
{
scheduler_.work_finished();
threads_.join();
if (!threads_.empty())
{
scheduler_.work_finished();
threads_.join();
}
}
detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s)
{
detail::scoped_ptr<detail::scheduler> scoped_impl(s);
asio::add_service<detail::scheduler>(*this, scoped_impl.get());
return *scoped_impl.release();
}
} // namespace asio

View File

@ -23,7 +23,8 @@
#include "asio/detail/string_view.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/ip/basic_resolver_results.hpp"
@ -43,6 +44,15 @@
namespace asio {
namespace ip {
#if !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)
#define ASIO_IP_BASIC_RESOLVER_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename InternetProtocol, typename Executor = executor>
class basic_resolver;
#endif // !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)
/// Provides endpoint resolution functionality.
/**
* The basic_resolver class template provides the ability to resolve a query
@ -52,13 +62,13 @@ namespace ip {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename InternetProtocol>
template <typename InternetProtocol, typename Executor>
class basic_resolver
: public resolver_base
{
public:
/// The type of the executor associated with the object.
typedef io_context::executor_type executor_type;
typedef Executor executor_type;
/// The protocol type.
typedef InternetProtocol protocol_type;
@ -77,16 +87,33 @@ public:
/// The results type.
typedef basic_resolver_results<InternetProtocol> results_type;
/// Constructor.
/// Construct with executor.
/**
* This constructor creates a basic_resolver.
*
* @param io_context The io_context object that the resolver will use to
* @param ex The I/O executor that the resolver will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* resolver.
*/
explicit basic_resolver(asio::io_context& io_context)
: impl_(io_context)
explicit basic_resolver(const executor_type& ex)
: impl_(ex)
{
}
/// Construct with execution context.
/**
* This constructor creates a basic_resolver.
*
* @param context An execution context which provides the I/O executor that
* the resolver will use, by default, to dispatch handlers for any
* asynchronous operations performed on the resolver.
*/
template <typename ExecutionContext>
explicit basic_resolver(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}
@ -99,7 +126,7 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_resolver(io_context&) constructor.
* constructed using the @c basic_resolver(const executor_type&) constructor.
*/
basic_resolver(basic_resolver&& other)
: impl_(std::move(other.impl_))
@ -116,7 +143,7 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_resolver(io_context&) constructor.
* constructed using the @c basic_resolver(const executor_type&) constructor.
*/
basic_resolver& operator=(basic_resolver&& other)
{
@ -573,9 +600,9 @@ public:
* resolver::results_type results // Resolved endpoints as a range.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* A successful resolve operation is guaranteed to pass a non-empty range to
* the handler.
@ -594,8 +621,8 @@ public:
asio::async_completion<ResolveHandler,
void (asio::error_code, results_type)> init(handler);
impl_.get_service().async_resolve(
impl_.get_implementation(), q, init.completion_handler);
impl_.get_service().async_resolve(impl_.get_implementation(), q,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -625,9 +652,9 @@ public:
* resolver::results_type results // Resolved endpoints as a range.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* A successful resolve operation is guaranteed to pass a non-empty range to
* the handler.
@ -682,9 +709,9 @@ public:
* resolver::results_type results // Resolved endpoints as a range.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* A successful resolve operation is guaranteed to pass a non-empty range to
* the handler.
@ -719,8 +746,8 @@ public:
asio::async_completion<ResolveHandler,
void (asio::error_code, results_type)> init(handler);
impl_.get_service().async_resolve(
impl_.get_implementation(), q, init.completion_handler);
impl_.get_service().async_resolve(impl_.get_implementation(), q,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -752,9 +779,9 @@ public:
* resolver::results_type results // Resolved endpoints as a range.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* A successful resolve operation is guaranteed to pass a non-empty range to
* the handler.
@ -812,9 +839,9 @@ public:
* resolver::results_type results // Resolved endpoints as a range.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* A successful resolve operation is guaranteed to pass a non-empty range to
* the handler.
@ -850,8 +877,8 @@ public:
asio::async_completion<ResolveHandler,
void (asio::error_code, results_type)> init(handler);
impl_.get_service().async_resolve(
impl_.get_implementation(), q, init.completion_handler);
impl_.get_service().async_resolve(impl_.get_implementation(), q,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -915,9 +942,9 @@ public:
* resolver::results_type results // Resolved endpoints as a range.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* A successful resolve operation is guaranteed to pass a non-empty range to
* the handler.
@ -936,8 +963,8 @@ public:
asio::async_completion<ResolveHandler,
void (asio::error_code, results_type)> init(handler);
impl_.get_service().async_resolve(
impl_.get_implementation(), e, init.completion_handler);
impl_.get_service().async_resolve(impl_.get_implementation(), e,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
@ -949,10 +976,12 @@ private:
# if defined(ASIO_WINDOWS_RUNTIME)
asio::detail::io_object_impl<
asio::detail::winrt_resolver_service<InternetProtocol> > impl_;
asio::detail::winrt_resolver_service<InternetProtocol>,
Executor> impl_;
# else
asio::detail::io_object_impl<
asio::detail::resolver_service<InternetProtocol> > impl_;
asio::detail::resolver_service<InternetProtocol>,
Executor> impl_;
# endif
};

View File

@ -32,7 +32,7 @@ namespace multicast {
* @par Examples
* Setting the option to join a multicast group:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::address multicast_address =
* asio::ip::address::from_string("225.0.0.1");
@ -60,7 +60,7 @@ typedef asio::ip::detail::socket_option::multicast_request<
* @par Examples
* Setting the option to leave a multicast group:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::address multicast_address =
* asio::ip::address::from_string("225.0.0.1");
@ -88,7 +88,7 @@ typedef asio::ip::detail::socket_option::multicast_request<
* @par Examples
* Setting the option:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::address_v4 local_interface =
* asio::ip::address_v4::from_string("1.2.3.4");
@ -116,7 +116,7 @@ typedef asio::ip::detail::socket_option::network_interface<
* @par Examples
* Setting the option:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::multicast::hops option(4);
* socket.set_option(option);
@ -125,7 +125,7 @@ typedef asio::ip::detail::socket_option::network_interface<
* @par
* Getting the current option value:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::multicast::hops option;
* socket.get_option(option);
@ -153,7 +153,7 @@ typedef asio::ip::detail::socket_option::multicast_hops<
* @par Examples
* Setting the option:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::multicast::enable_loopback option(true);
* socket.set_option(option);
@ -162,7 +162,7 @@ typedef asio::ip::detail::socket_option::multicast_hops<
* @par
* Getting the current option value:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::multicast::enable_loopback option;
* socket.get_option(option);

View File

@ -99,7 +99,7 @@ public:
* @par Examples
* Setting the option:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::no_delay option(true);
* socket.set_option(option);
@ -108,7 +108,7 @@ public:
* @par
* Getting the current option value:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::tcp::no_delay option;
* socket.get_option(option);

View File

@ -32,7 +32,7 @@ namespace unicast {
* @par Examples
* Setting the option:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::unicast::hops option(4);
* socket.set_option(option);
@ -41,7 +41,7 @@ namespace unicast {
* @par
* Getting the current option value:
* @code
* asio::ip::udp::socket socket(io_context);
* asio::ip::udp::socket socket(my_context);
* ...
* asio::ip::unicast::hops option;
* socket.get_option(option);

View File

@ -31,7 +31,7 @@ namespace ip {
* @par Examples
* Setting the option:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::v6_only option(true);
* socket.set_option(option);
@ -40,7 +40,7 @@ namespace ip {
* @par
* Getting the current option value:
* @code
* asio::ip::tcp::socket socket(io_context);
* asio::ip::tcp::socket socket(my_context);
* ...
* asio::ip::v6_only option;
* socket.get_option(option);

View File

@ -32,27 +32,28 @@ namespace asio {
namespace local {
/// Create a pair of connected sockets.
template <typename Protocol>
void connect_pair(basic_socket<Protocol>& socket1,
basic_socket<Protocol>& socket2);
template <typename Protocol, typename Executor1, typename Executor2>
void connect_pair(basic_socket<Protocol, Executor1>& socket1,
basic_socket<Protocol, Executor2>& socket2);
/// Create a pair of connected sockets.
template <typename Protocol>
ASIO_SYNC_OP_VOID connect_pair(basic_socket<Protocol>& socket1,
basic_socket<Protocol>& socket2, asio::error_code& ec);
template <typename Protocol, typename Executor1, typename Executor2>
ASIO_SYNC_OP_VOID connect_pair(basic_socket<Protocol, Executor1>& socket1,
basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec);
template <typename Protocol>
inline void connect_pair(basic_socket<Protocol>& socket1,
basic_socket<Protocol>& socket2)
template <typename Protocol, typename Executor1, typename Executor2>
inline void connect_pair(basic_socket<Protocol, Executor1>& socket1,
basic_socket<Protocol, Executor2>& socket2)
{
asio::error_code ec;
connect_pair(socket1, socket2, ec);
asio::detail::throw_error(ec, "connect_pair");
}
template <typename Protocol>
inline ASIO_SYNC_OP_VOID connect_pair(basic_socket<Protocol>& socket1,
basic_socket<Protocol>& socket2, asio::error_code& ec)
template <typename Protocol, typename Executor1, typename Executor2>
inline ASIO_SYNC_OP_VOID connect_pair(
basic_socket<Protocol, Executor1>& socket1,
basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec)
{
// Check that this function is only being used with a UNIX domain socket.
asio::local::basic_endpoint<Protocol>* tmp

View File

@ -0,0 +1,661 @@
//
// posix/basic_descriptor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 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_POSIX_BASIC_DESCRIPTOR_HPP
#define ASIO_POSIX_BASIC_DESCRIPTOR_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_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/reactive_descriptor_service.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/posix/descriptor_base.hpp"
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace posix {
/// Provides POSIX descriptor functionality.
/**
* The posix::basic_descriptor class template provides the ability to wrap a
* POSIX descriptor.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = executor>
class basic_descriptor
: public descriptor_base
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// The native representation of a descriptor.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A descriptor is always the lowest layer.
typedef basic_descriptor lowest_layer_type;
/// Construct a descriptor without opening it.
/**
* This constructor creates a descriptor without opening it.
*
* @param ex The I/O executor that the descriptor will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*/
explicit basic_descriptor(const executor_type& ex)
: impl_(ex)
{
}
/// Construct a descriptor without opening it.
/**
* This constructor creates a descriptor without opening it.
*
* @param context An execution context which provides the I/O executor that
* the descriptor will use, by default, to dispatch handlers for any
* asynchronous operations performed on the descriptor.
*/
template <typename ExecutionContext>
explicit basic_descriptor(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}
/// Construct a descriptor on an existing native descriptor.
/**
* This constructor creates a descriptor object to hold an existing native
* descriptor.
*
* @param ex The I/O executor that the descriptor will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*
* @param native_descriptor A native descriptor.
*
* @throws asio::system_error Thrown on failure.
*/
basic_descriptor(const executor_type& ex,
const native_handle_type& native_descriptor)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_descriptor, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a descriptor on an existing native descriptor.
/**
* This constructor creates a descriptor object to hold an existing native
* descriptor.
*
* @param context An execution context which provides the I/O executor that
* the descriptor will use, by default, to dispatch handlers for any
* asynchronous operations performed on the descriptor.
*
* @param native_descriptor A native descriptor.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_descriptor(ExecutionContext& context,
const native_handle_type& native_descriptor,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_descriptor, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a descriptor from another.
/**
* This constructor moves a descriptor from one object to another.
*
* @param other The other descriptor object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_descriptor(const executor_type&)
* constructor.
*/
basic_descriptor(basic_descriptor&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a descriptor from another.
/**
* This assignment operator moves a descriptor from one object to another.
*
* @param other The other descriptor object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_descriptor(const executor_type&)
* constructor.
*/
basic_descriptor& operator=(basic_descriptor&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a descriptor cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a descriptor cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native descriptor to the descriptor.
/*
* This function opens the descriptor to hold an existing native descriptor.
*
* @param native_descriptor A native descriptor.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_descriptor)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_descriptor, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native descriptor to the descriptor.
/*
* This function opens the descriptor to hold an existing native descriptor.
*
* @param native_descriptor A native descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor,
asio::error_code& ec)
{
impl_.get_service().assign(
impl_.get_implementation(), native_descriptor, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the descriptor is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the descriptor.
/**
* This function is used to close the descriptor. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the descriptor.
/**
* This function is used to close the descriptor. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the native descriptor representation.
/**
* This function may be used to obtain the underlying representation of the
* descriptor. This is intended to allow access to native descriptor
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Release ownership of the native descriptor implementation.
/**
* This function may be used to obtain the underlying representation of the
* descriptor. After calling this function, @c is_open() returns false. The
* caller is responsible for closing the descriptor.
*
* All outstanding asynchronous read or write operations will finish
* immediately, and the handlers for cancelled operations will be passed the
* asio::error::operation_aborted error.
*/
native_handle_type release()
{
return impl_.get_service().release(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the descriptor.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the descriptor.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Perform an IO control command on the descriptor.
/**
* This function is used to execute an IO control command on the descriptor.
*
* @param command The IO control command to be performed on the descriptor.
*
* @throws asio::system_error Thrown on failure.
*
* @sa IoControlCommand @n
* asio::posix::descriptor_base::bytes_readable @n
* asio::posix::descriptor_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::posix::stream_descriptor descriptor(my_context);
* ...
* asio::posix::stream_descriptor::bytes_readable command;
* descriptor.io_control(command);
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
void io_control(IoControlCommand& command)
{
asio::error_code ec;
impl_.get_service().io_control(impl_.get_implementation(), command, ec);
asio::detail::throw_error(ec, "io_control");
}
/// Perform an IO control command on the descriptor.
/**
* This function is used to execute an IO control command on the descriptor.
*
* @param command The IO control command to be performed on the descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa IoControlCommand @n
* asio::posix::descriptor_base::bytes_readable @n
* asio::posix::descriptor_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::posix::stream_descriptor descriptor(my_context);
* ...
* asio::posix::stream_descriptor::bytes_readable command;
* asio::error_code ec;
* descriptor.io_control(command, ec);
* if (ec)
* {
* // An error occurred.
* }
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
asio::error_code& ec)
{
impl_.get_service().io_control(impl_.get_implementation(), command, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Gets the non-blocking mode of the descriptor.
/**
* @returns @c true if the descriptor's synchronous operations will fail with
* asio::error::would_block if they are unable to perform the requested
* operation immediately. If @c false, synchronous operations will block
* until complete.
*
* @note The non-blocking mode has no effect on the behaviour of asynchronous
* operations. Asynchronous operations will never fail with the error
* asio::error::would_block.
*/
bool non_blocking() const
{
return impl_.get_service().non_blocking(impl_.get_implementation());
}
/// Sets the non-blocking mode of the descriptor.
/**
* @param mode If @c true, the descriptor's synchronous operations will fail
* with asio::error::would_block if they are unable to perform the
* requested operation immediately. If @c false, synchronous operations will
* block until complete.
*
* @throws asio::system_error Thrown on failure.
*
* @note The non-blocking mode has no effect on the behaviour of asynchronous
* operations. Asynchronous operations will never fail with the error
* asio::error::would_block.
*/
void non_blocking(bool mode)
{
asio::error_code ec;
impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
asio::detail::throw_error(ec, "non_blocking");
}
/// Sets the non-blocking mode of the descriptor.
/**
* @param mode If @c true, the descriptor's synchronous operations will fail
* with asio::error::would_block if they are unable to perform the
* requested operation immediately. If @c false, synchronous operations will
* block until complete.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note The non-blocking mode has no effect on the behaviour of asynchronous
* operations. Asynchronous operations will never fail with the error
* asio::error::would_block.
*/
ASIO_SYNC_OP_VOID non_blocking(
bool mode, asio::error_code& ec)
{
impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Gets the non-blocking mode of the native descriptor implementation.
/**
* This function is used to retrieve the non-blocking mode of the underlying
* native descriptor. This mode has no effect on the behaviour of the
* descriptor object's synchronous operations.
*
* @returns @c true if the underlying descriptor is in non-blocking mode and
* direct system calls may fail with asio::error::would_block (or the
* equivalent system error).
*
* @note The current non-blocking mode is cached by the descriptor object.
* Consequently, the return value may be incorrect if the non-blocking mode
* was set directly on the native descriptor.
*/
bool native_non_blocking() const
{
return impl_.get_service().native_non_blocking(
impl_.get_implementation());
}
/// Sets the non-blocking mode of the native descriptor implementation.
/**
* This function is used to modify the non-blocking mode of the underlying
* native descriptor. It has no effect on the behaviour of the descriptor
* object's synchronous operations.
*
* @param mode If @c true, the underlying descriptor is put into non-blocking
* mode and direct system calls may fail with asio::error::would_block
* (or the equivalent system error).
*
* @throws asio::system_error Thrown on failure. If the @c mode is
* @c false, but the current value of @c non_blocking() is @c true, this
* function fails with asio::error::invalid_argument, as the
* combination does not make sense.
*/
void native_non_blocking(bool mode)
{
asio::error_code ec;
impl_.get_service().native_non_blocking(
impl_.get_implementation(), mode, ec);
asio::detail::throw_error(ec, "native_non_blocking");
}
/// Sets the non-blocking mode of the native descriptor implementation.
/**
* This function is used to modify the non-blocking mode of the underlying
* native descriptor. It has no effect on the behaviour of the descriptor
* object's synchronous operations.
*
* @param mode If @c true, the underlying descriptor is put into non-blocking
* mode and direct system calls may fail with asio::error::would_block
* (or the equivalent system error).
*
* @param ec Set to indicate what error occurred, if any. If the @c mode is
* @c false, but the current value of @c non_blocking() is @c true, this
* function fails with asio::error::invalid_argument, as the
* combination does not make sense.
*/
ASIO_SYNC_OP_VOID native_non_blocking(
bool mode, asio::error_code& ec)
{
impl_.get_service().native_non_blocking(
impl_.get_implementation(), mode, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Wait for the descriptor to become ready to read, ready to write, or to
/// have pending error conditions.
/**
* This function is used to perform a blocking wait for a descriptor to enter
* a ready to read, write or error condition state.
*
* @param w Specifies the desired descriptor state.
*
* @par Example
* Waiting for a descriptor to become readable.
* @code
* asio::posix::stream_descriptor descriptor(my_context);
* ...
* descriptor.wait(asio::posix::stream_descriptor::wait_read);
* @endcode
*/
void wait(wait_type w)
{
asio::error_code ec;
impl_.get_service().wait(impl_.get_implementation(), w, ec);
asio::detail::throw_error(ec, "wait");
}
/// Wait for the descriptor to become ready to read, ready to write, or to
/// have pending error conditions.
/**
* This function is used to perform a blocking wait for a descriptor to enter
* a ready to read, write or error condition state.
*
* @param w Specifies the desired descriptor state.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* Waiting for a descriptor to become readable.
* @code
* asio::posix::stream_descriptor descriptor(my_context);
* ...
* asio::error_code ec;
* descriptor.wait(asio::posix::stream_descriptor::wait_read, ec);
* @endcode
*/
ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)
{
impl_.get_service().wait(impl_.get_implementation(), w, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Asynchronously wait for the descriptor to become ready to read, ready to
/// write, or to have pending error conditions.
/**
* This function is used to perform an asynchronous wait for a descriptor to
* enter a ready to read, write or error condition state.
*
* @param w Specifies the desired descriptor state.
*
* @param handler The handler to be called when the wait operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* @code
* void wait_handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Wait succeeded.
* }
* }
*
* ...
*
* asio::posix::stream_descriptor descriptor(my_context);
* ...
* descriptor.async_wait(
* asio::posix::stream_descriptor::wait_read,
* wait_handler);
* @endcode
*/
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
void (asio::error_code))
async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
async_completion<WaitHandler,
void (asio::error_code)> init(handler);
impl_.get_service().async_wait(impl_.get_implementation(), w,
init.completion_handler, impl_.get_implementation_executor());
return init.result.get();
}
protected:
/// Protected destructor to prevent deletion through this type.
/**
* This function destroys the descriptor, cancelling any outstanding
* asynchronous wait operations associated with the descriptor as if by
* calling @c cancel.
*/
~basic_descriptor()
{
}
detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
private:
// Disallow copying and assignment.
basic_descriptor(const basic_descriptor&) ASIO_DELETED;
basic_descriptor& operator=(const basic_descriptor&) ASIO_DELETED;
};
} // namespace posix
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP

View File

@ -0,0 +1,407 @@
//
// posix/basic_stream_descriptor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 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_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
#define ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/posix/descriptor.hpp"
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace posix {
/// Provides stream-oriented descriptor functionality.
/**
* The posix::basic_stream_descriptor class template provides asynchronous and
* blocking stream-oriented descriptor functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Executor = executor>
class basic_stream_descriptor
: public basic_descriptor<Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// The native representation of a descriptor.
typedef typename basic_descriptor<Executor>::native_handle_type
native_handle_type;
/// Construct a stream descriptor without opening it.
/**
* This constructor creates a stream descriptor without opening it. The
* descriptor needs to be opened and then connected or accepted before data
* can be sent or received on it.
*
* @param ex The I/O executor that the descriptor will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*/
explicit basic_stream_descriptor(const executor_type& ex)
: basic_descriptor<Executor>(ex)
{
}
/// Construct a stream descriptor without opening it.
/**
* This constructor creates a stream descriptor without opening it. The
* descriptor needs to be opened and then connected or accepted before data
* can be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the descriptor will use, by default, to dispatch handlers for any
* asynchronous operations performed on the descriptor.
*/
template <typename ExecutionContext>
explicit basic_stream_descriptor(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_descriptor<Executor>(context)
{
}
/// Construct a stream descriptor on an existing native descriptor.
/**
* This constructor creates a stream descriptor object to hold an existing
* native descriptor.
*
* @param ex The I/O executor that the descriptor will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*
* @param native_descriptor The new underlying descriptor implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_descriptor(const executor_type& ex,
const native_handle_type& native_descriptor)
: basic_descriptor<Executor>(ex, native_descriptor)
{
}
/// Construct a stream descriptor on an existing native descriptor.
/**
* This constructor creates a stream descriptor object to hold an existing
* native descriptor.
*
* @param context An execution context which provides the I/O executor that
* the descriptor will use, by default, to dispatch handlers for any
* asynchronous operations performed on the descriptor.
*
* @param native_descriptor The new underlying descriptor implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_descriptor(ExecutionContext& context,
const native_handle_type& native_descriptor,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_descriptor<Executor>(context, native_descriptor)
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a stream descriptor from another.
/**
* This constructor moves a stream descriptor from one object to another.
*
* @param other The other stream descriptor object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_descriptor(const executor_type&)
* constructor.
*/
basic_stream_descriptor(basic_stream_descriptor&& other)
: descriptor(std::move(other))
{
}
/// Move-assign a stream descriptor from another.
/**
* This assignment operator moves a stream descriptor from one object to
* another.
*
* @param other The other stream descriptor object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_descriptor(const executor_type&)
* constructor.
*/
basic_stream_descriptor& operator=(basic_stream_descriptor&& other)
{
descriptor::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Write some data to the descriptor.
/**
* This function is used to write data to the stream descriptor. The function
* call will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the descriptor.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the descriptor.
/**
* This function is used to write data to the stream descriptor. The function
* call will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream
* descriptor. The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the descriptor.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
asio::async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_write_some(
this->impl_.get_implementation(),
buffers, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
/// Read some data from the descriptor.
/**
* This function is used to read data from the stream descriptor. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the descriptor.
/**
* This function is used to read data from the stream descriptor. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream
* descriptor. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.async_read_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
asio::async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);
this->impl_.get_service().async_read_some(
this->impl_.get_implementation(),
buffers, init.completion_handler,
this->impl_.get_implementation_executor());
return init.result.get();
}
};
} // namespace posix
} // namespace asio
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP

View File

@ -20,594 +20,18 @@
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/reactive_descriptor_service.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/posix/descriptor_base.hpp"
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
#include "asio/posix/basic_descriptor.hpp"
namespace asio {
namespace posix {
/// Provides POSIX descriptor functionality.
/**
* The posix::descriptor class template provides the ability to wrap a
* POSIX descriptor.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
class descriptor
: public descriptor_base
{
public:
/// The type of the executor associated with the object.
typedef io_context::executor_type executor_type;
/// The native representation of a descriptor.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A descriptor is always the lowest layer.
typedef descriptor lowest_layer_type;
/// Construct a descriptor without opening it.
/**
* This constructor creates a descriptor without opening it.
*
* @param io_context The io_context object that the descriptor will use to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*/
explicit descriptor(asio::io_context& io_context)
: impl_(io_context)
{
}
/// Construct a descriptor on an existing native descriptor.
/**
* This constructor creates a descriptor object to hold an existing native
* descriptor.
*
* @param io_context The io_context object that the descriptor will use to
* dispatch handlers for any asynchronous operations performed on the
* descriptor.
*
* @param native_descriptor A native descriptor.
*
* @throws asio::system_error Thrown on failure.
*/
descriptor(asio::io_context& io_context,
const native_handle_type& native_descriptor)
: impl_(io_context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_descriptor, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a descriptor from another.
/**
* This constructor moves a descriptor from one object to another.
*
* @param other The other descriptor object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c descriptor(io_context&) constructor.
*/
descriptor(descriptor&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a descriptor from another.
/**
* This assignment operator moves a descriptor from one object to another.
*
* @param other The other descriptor object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c descriptor(io_context&) constructor.
*/
descriptor& operator=(descriptor&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a descriptor cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a descriptor cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native descriptor to the descriptor.
/*
* This function opens the descriptor to hold an existing native descriptor.
*
* @param native_descriptor A native descriptor.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_descriptor)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_descriptor, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native descriptor to the descriptor.
/*
* This function opens the descriptor to hold an existing native descriptor.
*
* @param native_descriptor A native descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor,
asio::error_code& ec)
{
impl_.get_service().assign(
impl_.get_implementation(), native_descriptor, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the descriptor is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the descriptor.
/**
* This function is used to close the descriptor. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the descriptor.
/**
* This function is used to close the descriptor. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the native descriptor representation.
/**
* This function may be used to obtain the underlying representation of the
* descriptor. This is intended to allow access to native descriptor
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Release ownership of the native descriptor implementation.
/**
* This function may be used to obtain the underlying representation of the
* descriptor. After calling this function, @c is_open() returns false. The
* caller is responsible for closing the descriptor.
*
* All outstanding asynchronous read or write operations will finish
* immediately, and the handlers for cancelled operations will be passed the
* asio::error::operation_aborted error.
*/
native_handle_type release()
{
return impl_.get_service().release(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the descriptor.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the descriptor.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Perform an IO control command on the descriptor.
/**
* This function is used to execute an IO control command on the descriptor.
*
* @param command The IO control command to be performed on the descriptor.
*
* @throws asio::system_error Thrown on failure.
*
* @sa IoControlCommand @n
* asio::posix::descriptor_base::bytes_readable @n
* asio::posix::descriptor_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::posix::stream_descriptor descriptor(io_context);
* ...
* asio::posix::stream_descriptor::bytes_readable command;
* descriptor.io_control(command);
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
void io_control(IoControlCommand& command)
{
asio::error_code ec;
impl_.get_service().io_control(impl_.get_implementation(), command, ec);
asio::detail::throw_error(ec, "io_control");
}
/// Perform an IO control command on the descriptor.
/**
* This function is used to execute an IO control command on the descriptor.
*
* @param command The IO control command to be performed on the descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa IoControlCommand @n
* asio::posix::descriptor_base::bytes_readable @n
* asio::posix::descriptor_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::posix::stream_descriptor descriptor(io_context);
* ...
* asio::posix::stream_descriptor::bytes_readable command;
* asio::error_code ec;
* descriptor.io_control(command, ec);
* if (ec)
* {
* // An error occurred.
* }
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
asio::error_code& ec)
{
impl_.get_service().io_control(impl_.get_implementation(), command, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Gets the non-blocking mode of the descriptor.
/**
* @returns @c true if the descriptor's synchronous operations will fail with
* asio::error::would_block if they are unable to perform the requested
* operation immediately. If @c false, synchronous operations will block
* until complete.
*
* @note The non-blocking mode has no effect on the behaviour of asynchronous
* operations. Asynchronous operations will never fail with the error
* asio::error::would_block.
*/
bool non_blocking() const
{
return impl_.get_service().non_blocking(impl_.get_implementation());
}
/// Sets the non-blocking mode of the descriptor.
/**
* @param mode If @c true, the descriptor's synchronous operations will fail
* with asio::error::would_block if they are unable to perform the
* requested operation immediately. If @c false, synchronous operations will
* block until complete.
*
* @throws asio::system_error Thrown on failure.
*
* @note The non-blocking mode has no effect on the behaviour of asynchronous
* operations. Asynchronous operations will never fail with the error
* asio::error::would_block.
*/
void non_blocking(bool mode)
{
asio::error_code ec;
impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
asio::detail::throw_error(ec, "non_blocking");
}
/// Sets the non-blocking mode of the descriptor.
/**
* @param mode If @c true, the descriptor's synchronous operations will fail
* with asio::error::would_block if they are unable to perform the
* requested operation immediately. If @c false, synchronous operations will
* block until complete.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note The non-blocking mode has no effect on the behaviour of asynchronous
* operations. Asynchronous operations will never fail with the error
* asio::error::would_block.
*/
ASIO_SYNC_OP_VOID non_blocking(
bool mode, asio::error_code& ec)
{
impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Gets the non-blocking mode of the native descriptor implementation.
/**
* This function is used to retrieve the non-blocking mode of the underlying
* native descriptor. This mode has no effect on the behaviour of the
* descriptor object's synchronous operations.
*
* @returns @c true if the underlying descriptor is in non-blocking mode and
* direct system calls may fail with asio::error::would_block (or the
* equivalent system error).
*
* @note The current non-blocking mode is cached by the descriptor object.
* Consequently, the return value may be incorrect if the non-blocking mode
* was set directly on the native descriptor.
*/
bool native_non_blocking() const
{
return impl_.get_service().native_non_blocking(
impl_.get_implementation());
}
/// Sets the non-blocking mode of the native descriptor implementation.
/**
* This function is used to modify the non-blocking mode of the underlying
* native descriptor. It has no effect on the behaviour of the descriptor
* object's synchronous operations.
*
* @param mode If @c true, the underlying descriptor is put into non-blocking
* mode and direct system calls may fail with asio::error::would_block
* (or the equivalent system error).
*
* @throws asio::system_error Thrown on failure. If the @c mode is
* @c false, but the current value of @c non_blocking() is @c true, this
* function fails with asio::error::invalid_argument, as the
* combination does not make sense.
*/
void native_non_blocking(bool mode)
{
asio::error_code ec;
impl_.get_service().native_non_blocking(
impl_.get_implementation(), mode, ec);
asio::detail::throw_error(ec, "native_non_blocking");
}
/// Sets the non-blocking mode of the native descriptor implementation.
/**
* This function is used to modify the non-blocking mode of the underlying
* native descriptor. It has no effect on the behaviour of the descriptor
* object's synchronous operations.
*
* @param mode If @c true, the underlying descriptor is put into non-blocking
* mode and direct system calls may fail with asio::error::would_block
* (or the equivalent system error).
*
* @param ec Set to indicate what error occurred, if any. If the @c mode is
* @c false, but the current value of @c non_blocking() is @c true, this
* function fails with asio::error::invalid_argument, as the
* combination does not make sense.
*/
ASIO_SYNC_OP_VOID native_non_blocking(
bool mode, asio::error_code& ec)
{
impl_.get_service().native_non_blocking(
impl_.get_implementation(), mode, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Wait for the descriptor to become ready to read, ready to write, or to
/// have pending error conditions.
/**
* This function is used to perform a blocking wait for a descriptor to enter
* a ready to read, write or error condition state.
*
* @param w Specifies the desired descriptor state.
*
* @par Example
* Waiting for a descriptor to become readable.
* @code
* asio::posix::stream_descriptor descriptor(io_context);
* ...
* descriptor.wait(asio::posix::stream_descriptor::wait_read);
* @endcode
*/
void wait(wait_type w)
{
asio::error_code ec;
impl_.get_service().wait(impl_.get_implementation(), w, ec);
asio::detail::throw_error(ec, "wait");
}
/// Wait for the descriptor to become ready to read, ready to write, or to
/// have pending error conditions.
/**
* This function is used to perform a blocking wait for a descriptor to enter
* a ready to read, write or error condition state.
*
* @param w Specifies the desired descriptor state.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* Waiting for a descriptor to become readable.
* @code
* asio::posix::stream_descriptor descriptor(io_context);
* ...
* asio::error_code ec;
* descriptor.wait(asio::posix::stream_descriptor::wait_read, ec);
* @endcode
*/
ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)
{
impl_.get_service().wait(impl_.get_implementation(), w, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Asynchronously wait for the descriptor to become ready to read, ready to
/// write, or to have pending error conditions.
/**
* This function is used to perform an asynchronous wait for a descriptor to
* enter a ready to read, write or error condition state.
*
* @param w Specifies the desired descriptor state.
*
* @param handler The handler to be called when the wait operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
*
* @par Example
* @code
* void wait_handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Wait succeeded.
* }
* }
*
* ...
*
* asio::posix::stream_descriptor descriptor(io_context);
* ...
* descriptor.async_wait(
* asio::posix::stream_descriptor::wait_read,
* wait_handler);
* @endcode
*/
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
void (asio::error_code))
async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
async_completion<WaitHandler,
void (asio::error_code)> init(handler);
impl_.get_service().async_wait(
impl_.get_implementation(), w, init.completion_handler);
return init.result.get();
}
protected:
/// Protected destructor to prevent deletion through this type.
/**
* This function destroys the descriptor, cancelling any outstanding
* asynchronous wait operations associated with the descriptor as if by
* calling @c cancel.
*/
~descriptor()
{
}
detail::io_object_impl<detail::reactive_descriptor_service> impl_;
private:
// Disallow copying and assignment.
descriptor(const descriptor&) ASIO_DELETED;
descriptor& operator=(const descriptor&) ASIO_DELETED;
};
/// Typedef for the typical usage of basic_descriptor.
typedef basic_descriptor<> descriptor;
} // namespace posix
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
// || defined(GENERATING_DOCUMENTATION)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_POSIX_DESCRIPTOR_HPP

View File

@ -56,7 +56,7 @@ public:
*
* @par Example
* @code
* asio::posix::stream_descriptor descriptor(io_context);
* asio::posix::stream_descriptor descriptor(my_context);
* ...
* asio::descriptor_base::bytes_readable command(true);
* descriptor.io_control(command);

View File

@ -16,331 +16,17 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/posix/descriptor.hpp"
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
|| defined(GENERATING_DOCUMENTATION)
#include "asio/posix/basic_stream_descriptor.hpp"
namespace asio {
namespace posix {
/// Provides stream-oriented descriptor functionality.
/**
* The posix::stream_descriptor class template provides asynchronous and
* blocking stream-oriented descriptor functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
class stream_descriptor
: public descriptor
{
public:
/// Construct a stream_descriptor without opening it.
/**
* This constructor creates a stream descriptor without opening it. The
* descriptor needs to be opened and then connected or accepted before data
* can be sent or received on it.
*
* @param io_context The io_context object that the stream descriptor will
* use to dispatch handlers for any asynchronous operations performed on the
* descriptor.
*/
explicit stream_descriptor(asio::io_context& io_context)
: descriptor(io_context)
{
}
/// Construct a stream_descriptor on an existing native descriptor.
/**
* This constructor creates a stream descriptor object to hold an existing
* native descriptor.
*
* @param io_context The io_context object that the stream descriptor will
* use to dispatch handlers for any asynchronous operations performed on the
* descriptor.
*
* @param native_descriptor The new underlying descriptor implementation.
*
* @throws asio::system_error Thrown on failure.
*/
stream_descriptor(asio::io_context& io_context,
const native_handle_type& native_descriptor)
: descriptor(io_context, native_descriptor)
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a stream_descriptor from another.
/**
* This constructor moves a stream descriptor from one object to another.
*
* @param other The other stream_descriptor object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c stream_descriptor(io_context&) constructor.
*/
stream_descriptor(stream_descriptor&& other)
: descriptor(std::move(other))
{
}
/// Move-assign a stream_descriptor from another.
/**
* This assignment operator moves a stream descriptor from one object to
* another.
*
* @param other The other stream_descriptor object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c stream_descriptor(io_context&) constructor.
*/
stream_descriptor& operator=(stream_descriptor&& other)
{
descriptor::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Write some data to the descriptor.
/**
* This function is used to write data to the stream descriptor. The function
* call will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the descriptor.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the descriptor.
/**
* This function is used to write data to the stream descriptor. The function
* call will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the descriptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream
* descriptor. The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the descriptor.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
asio::async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);
impl_.get_service().async_write_some(
impl_.get_implementation(), buffers, init.completion_handler);
return init.result.get();
}
/// Read some data from the descriptor.
/**
* This function is used to read data from the stream descriptor. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the descriptor.
/**
* This function is used to read data from the stream descriptor. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream
* descriptor. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* descriptor.async_read_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
asio::async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);
impl_.get_service().async_read_some(
impl_.get_implementation(), buffers, init.completion_handler);
return init.result.get();
}
};
/// Typedef for the typical usage of a stream-oriented descriptor.
typedef basic_stream_descriptor<> stream_descriptor;
} // namespace posix
} // namespace asio

Some files were not shown because too many files have changed in this diff Show More