Initial implementation of move support for posix descriptors.

This commit is contained in:
Christopher Kohlhoff 2011-03-06 10:03:20 +11:00
parent f52dddfd5c
commit d5b1a7308f
10 changed files with 370 additions and 34 deletions

View File

@ -16,17 +16,39 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if defined(ASIO_HAS_MOVE)
namespace detail
{
// Type trait used to determine whether a service supports move.
template <typename IoObjectService>
class service_has_move
{
public:
static const bool value =
sizeof(service_has_move::eval(static_cast<IoObjectService*>(0))) == 1;
private:
template <typename T>
static auto eval(T*) -> decltype(&T::move_construct, char(0));
static char (&eval(...))[2];
};
}
#endif // defined(ASIO_HAS_MOVE)
/// Base class for all I/O objects.
#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
template <typename IoObjectService>
#else
template <typename IoObjectService,
bool Movable = detail::service_has_move<IoObjectService>::value>
#endif
class basic_io_object
: private noncopyable
{
public:
/// The type of the service that will be used to provide I/O operations.
@ -52,7 +74,7 @@ protected:
/// Construct a basic_io_object.
/**
* Performs:
* @code service.construct(implementation); @endcode
* @code get_service().construct(get_implementation()); @endcode
*/
explicit basic_io_object(asio::io_service& io_service)
: service(asio::use_service<IoObjectService>(io_service))
@ -60,23 +82,154 @@ protected:
service.construct(implementation);
}
#if defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_io_object.
/**
* Performs:
* @code get_service().move_construct(
* get_implementation(), other.get_implementation()); @endcode
*
* @note Available only for services that support movability,
*/
basic_io_object(basic_io_object&& other);
/// Move-assign a basic_io_object.
/**
* Performs:
* @code get_service().move_assign(get_implementation(),
* other.get_service(), other.get_implementation()); @endcode
*
* @note Available only for services that support movability,
*/
basic_io_object& operator=(basic_io_object&& other);
/// Copy construction is not supported.
basic_io_object(const basic_io_object&) = delete;
/// Copy assignment is not supported.
basic_io_object& operator=(const basic_io_object&) = delete;
#endif // defined(GENERATING_DOCUMENTATION)
/// Protected destructor to prevent deletion through this type.
/**
* Performs:
* @code service.destroy(implementation); @endcode
* @code get_service().destroy(get_implementation()); @endcode
*/
~basic_io_object()
{
service.destroy(implementation);
}
/// The service associated with the I/O object.
/// Get the service associated with the I/O object.
service_type& get_service()
{
return service;
}
/// Get the service associated with the I/O object.
const service_type& get_service() const
{
return service;
}
/// (Deprecated: Use get_service().) The service associated with the I/O
/// object.
/**
* @note Available only for services that do not support movability.
*/
service_type& service;
/// The underlying implementation of the I/O object.
/// Get the underlying implementation of the I/O object.
implementation_type& get_implementation()
{
return implementation;
}
/// Get the underlying implementation of the I/O object.
const implementation_type& get_implementation() const
{
return implementation;
}
/// (Deprecated: Use get_implementation().) The underlying implementation of
/// the I/O object.
implementation_type implementation;
private:
basic_io_object(const basic_io_object&);
basic_io_object& operator=(const basic_io_object&);
};
#if defined(ASIO_HAS_MOVE)
// Specialisation for movable objects.
template <typename IoObjectService>
class basic_io_object<IoObjectService, true>
{
public:
typedef IoObjectService service_type;
typedef typename service_type::implementation_type implementation_type;
asio::io_service& get_io_service()
{
return service_->get_io_service();
}
protected:
explicit basic_io_object(asio::io_service& io_service)
: service_(&asio::use_service<IoObjectService>(io_service))
{
service_->construct(implementation);
}
basic_io_object(basic_io_object&& other)
: service_(&other.get_service())
{
service_->move_construct(implementation, other.implementation);
}
~basic_io_object()
{
service_->destroy(implementation);
}
basic_io_object& operator=(basic_io_object&& other)
{
service_->move_assign(implementation,
*other.service_, other.implementation);
service_ = other.service_;
return *this;
}
service_type& get_service()
{
return *service_;
}
const service_type& get_service() const
{
return *service_;
}
implementation_type& get_implementation()
{
return implementation;
}
const implementation_type& get_implementation() const
{
return implementation;
}
implementation_type implementation;
private:
basic_io_object(const basic_io_object&);
void operator=(const basic_io_object&);
IoObjectService* service_;
};
#endif // defined(ASIO_HAS_MOVE)
} // namespace asio
#include "asio/detail/pop_options.hpp"

View File

@ -46,7 +46,7 @@
# define ASIO_DECL
#endif // !defined(ASIO_DECL)
// Support move construction on compilers known to allow it.
// Support move construction as an optimisation on compilers known to allow it.
#if defined(__GNUC__)
# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
@ -65,6 +65,22 @@
# define ASIO_MOVE_CAST(type) static_cast<const type&>
#endif // !defined_ASIO_MOVE_CAST
// Move construction and assignment in the API.
#if !defined(ASIO_DISABLE_MOVE)
# if defined(__GNUC__)
# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
# define ASIO_HAS_MOVE
# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
# endif // defined(__GNUC__)
# if defined(BOOST_MSVC)
# if (_MSC_VER >= 1600)
# define ASIO_HAS_MOVE
# endif // (_MSC_VER >= 1600)
# endif // defined(BOOST_MSVC)
#endif // !defined(ASIO_DISABLE_MOVE)
// Standard library support for system errors.
#if !defined(ASIO_DISABLE_STD_SYSTEM_ERROR)
# if defined(__GNUC__)

View File

@ -88,6 +88,11 @@ public:
int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data, reactor_op* op);
// Move descriptor registration from one descriptor_data object to another.
ASIO_DECL void move_descriptor(socket_type descriptor,
per_descriptor_data& target_descriptor_data,
per_descriptor_data& source_descriptor_data);
// Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op)
{

View File

@ -186,6 +186,14 @@ int epoll_reactor::register_internal_descriptor(
return 0;
}
void epoll_reactor::move_descriptor(socket_type,
epoll_reactor::per_descriptor_data& target_descriptor_data,
epoll_reactor::per_descriptor_data& source_descriptor_data)
{
target_descriptor_data = source_descriptor_data;
source_descriptor_data = 0;
}
void epoll_reactor::start_op(int op_type, socket_type descriptor,
epoll_reactor::per_descriptor_data& descriptor_data,
reactor_op* op, bool allow_speculative)

View File

@ -45,6 +45,37 @@ void reactive_descriptor_service::construct(
impl.state_ = 0;
}
void reactive_descriptor_service::move_construct(
reactive_descriptor_service::implementation_type& impl,
reactive_descriptor_service::implementation_type& other_impl)
{
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
reactor_.move_descriptor(impl.descriptor_,
impl.reactor_data_, other_impl.reactor_data_);
}
void reactive_descriptor_service::move_assign(
reactive_descriptor_service::implementation_type& impl,
reactive_descriptor_service& other_service,
reactive_descriptor_service::implementation_type& other_impl)
{
destroy(impl);
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
other_service.reactor_.move_descriptor(impl.descriptor_,
impl.reactor_data_, other_impl.reactor_data_);
}
void reactive_descriptor_service::destroy(
reactive_descriptor_service::implementation_type& impl)
{

View File

@ -79,6 +79,15 @@ public:
// Construct a new descriptor implementation.
ASIO_DECL void construct(implementation_type& impl);
// Move-construct a new descriptor implementation.
ASIO_DECL void move_construct(implementation_type& impl,
implementation_type& other_impl);
// Move-assign from another descriptor implementation.
ASIO_DECL void move_assign(implementation_type& impl,
reactive_descriptor_service& other_service,
implementation_type& other_impl);
// Destroy a descriptor implementation.
ASIO_DECL void destroy(implementation_type& impl);

View File

@ -86,10 +86,48 @@ public:
: basic_io_object<DescriptorService>(io_service)
{
asio::error_code ec;
this->service.assign(this->implementation, native_descriptor, ec);
this->get_service().assign(this->get_implementation(),
native_descriptor, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_descriptor from another.
/**
* This constructor moves a stream descriptor from one object to another.
*
* @param other The other basic_descriptor object from which the move will
* occur.
*
* @note Following the move, the valid operations for the other object are:
* @li Using it as the target of a move assignment.
* @li Destruction.
*/
basic_descriptor(basic_descriptor&& other)
: basic_io_object<DescriptorService>(
ASIO_MOVE_CAST(basic_descriptor)(other))
{
}
/// Move-assign a basic_descriptor from another.
/**
* This constructor moves a descriptor from one object to another.
*
* @param other The other basic_descriptor object from which the move will
* occur.
*
* @note Following the move, the valid operations for the other object are:
* @li Using it as the target of a move assignment.
* @li Destruction.
*/
basic_descriptor& operator=(basic_descriptor&& other)
{
basic_io_object<DescriptorService>::operator=(
ASIO_MOVE_CAST(basic_descriptor)(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
@ -129,7 +167,8 @@ public:
void assign(const native_handle_type& native_descriptor)
{
asio::error_code ec;
this->service.assign(this->implementation, native_descriptor, ec);
this->get_service().assign(this->get_implementation(),
native_descriptor, ec);
asio::detail::throw_error(ec, "assign");
}
@ -144,13 +183,14 @@ public:
asio::error_code assign(const native_handle_type& native_descriptor,
asio::error_code& ec)
{
return this->service.assign(this->implementation, native_descriptor, ec);
return this->get_service().assign(
this->get_implementation(), native_descriptor, ec);
}
/// Determine whether the descriptor is open.
bool is_open() const
{
return this->service.is_open(this->implementation);
return this->get_service().is_open(this->implementation);
}
/// Close the descriptor.
@ -165,7 +205,7 @@ public:
void close()
{
asio::error_code ec;
this->service.close(this->implementation, ec);
this->get_service().close(this->get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
@ -180,7 +220,7 @@ public:
*/
asio::error_code close(asio::error_code& ec)
{
return this->service.close(this->implementation, ec);
return this->get_service().close(this->get_implementation(), ec);
}
/// (Deprecated: Use native_handle().) Get the native descriptor
@ -192,7 +232,7 @@ public:
*/
native_type native()
{
return this->service.native_handle(this->implementation);
return this->get_service().native_handle(this->implementation);
}
/// Get the native descriptor representation.
@ -203,7 +243,7 @@ public:
*/
native_handle_type native_handle()
{
return this->service.native_handle(this->implementation);
return this->get_service().native_handle(this->implementation);
}
/// Release ownership of the native descriptor implementation.
@ -218,7 +258,7 @@ public:
*/
native_handle_type release()
{
return this->service.release(this->implementation);
return this->get_service().release(this->implementation);
}
/// Cancel all asynchronous operations associated with the descriptor.
@ -232,7 +272,7 @@ public:
void cancel()
{
asio::error_code ec;
this->service.cancel(this->implementation, ec);
this->get_service().cancel(this->get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
@ -246,7 +286,7 @@ public:
*/
asio::error_code cancel(asio::error_code& ec)
{
return this->service.cancel(this->implementation, ec);
return this->get_service().cancel(this->get_implementation(), ec);
}
/// Perform an IO control command on the descriptor.
@ -275,7 +315,7 @@ public:
void io_control(IoControlCommand& command)
{
asio::error_code ec;
this->service.io_control(this->implementation, command, ec);
this->get_service().io_control(this->get_implementation(), command, ec);
asio::detail::throw_error(ec, "io_control");
}
@ -310,7 +350,8 @@ public:
asio::error_code io_control(IoControlCommand& command,
asio::error_code& ec)
{
return this->service.io_control(this->implementation, command, ec);
return this->get_service().io_control(
this->get_implementation(), command, ec);
}
/// Gets the non-blocking mode of the descriptor.
@ -326,7 +367,7 @@ public:
*/
bool non_blocking() const
{
return this->service.non_blocking(this->implementation);
return this->get_service().non_blocking(this->implementation);
}
/// Sets the non-blocking mode of the descriptor.
@ -345,7 +386,7 @@ public:
void non_blocking(bool mode)
{
asio::error_code ec;
this->service.non_blocking(this->implementation, mode, ec);
this->get_service().non_blocking(this->get_implementation(), mode, ec);
asio::detail::throw_error(ec, "non_blocking");
}
@ -365,7 +406,8 @@ public:
asio::error_code non_blocking(
bool mode, asio::error_code& ec)
{
return this->service.non_blocking(this->implementation, mode, ec);
return this->get_service().non_blocking(
this->get_implementation(), mode, ec);
}
/// Gets the non-blocking mode of the native descriptor implementation.
@ -384,7 +426,7 @@ public:
*/
bool native_non_blocking() const
{
return this->service.native_non_blocking(this->implementation);
return this->get_service().native_non_blocking(this->implementation);
}
/// Sets the non-blocking mode of the native descriptor implementation.
@ -405,7 +447,8 @@ public:
void native_non_blocking(bool mode)
{
asio::error_code ec;
this->service.native_non_blocking(this->implementation, mode, ec);
this->get_service().native_non_blocking(
this->get_implementation(), mode, ec);
asio::detail::throw_error(ec, "native_non_blocking");
}
@ -427,7 +470,8 @@ public:
asio::error_code native_non_blocking(
bool mode, asio::error_code& ec)
{
return this->service.native_non_blocking(this->implementation, mode, ec);
return this->get_service().native_non_blocking(
this->get_implementation(), mode, ec);
}
protected:

View File

@ -91,6 +91,43 @@ public:
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_stream_descriptor from another.
/**
* This constructor moves a stream descriptor from one object to another.
*
* @param other The other basic_stream_descriptor object from which the move
* will occur.
*
* @note Following the move, the valid operations for the other object are:
* @li Using it as the target of a move assignment.
* @li Destruction.
*/
basic_stream_descriptor(basic_stream_descriptor&& other)
: basic_descriptor<StreamDescriptorService>(
ASIO_MOVE_CAST(basic_stream_descriptor)(other))
{
}
/// Move-assign a basic_descriptor from another.
/**
* This constructor moves a stream descriptor from one object to another.
*
* @param other The other basic_stream_descriptor object from which the move
* will occur.
*
* @note Following the move, the valid operations for the other object are:
* @li Using it as the target of a move assignment.
* @li Destruction.
*/
basic_stream_descriptor& operator=(basic_stream_descriptor&& other)
{
basic_descriptor<StreamDescriptorService>::operator=(
ASIO_MOVE_CAST(basic_stream_descriptor)(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
@ -122,7 +159,8 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.write_some(this->implementation, buffers, ec);
std::size_t s = this->get_service().write_some(
this->get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
@ -147,7 +185,8 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->service.write_some(this->implementation, buffers, ec);
return this->get_service().write_some(
this->get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
@ -193,8 +232,8 @@ public:
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
this->service.async_write_some(this->implementation, buffers,
ASIO_MOVE_CAST(WriteHandler)(handler));
this->get_service().async_write_some(this->get_implementation(),
buffers, ASIO_MOVE_CAST(WriteHandler)(handler));
}
/// Read some data from the descriptor.
@ -229,7 +268,8 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.read_some(this->implementation, buffers, ec);
std::size_t s = this->get_service().read_some(
this->get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
@ -255,7 +295,8 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->service.read_some(this->implementation, buffers, ec);
return this->get_service().read_some(
this->get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
@ -302,8 +343,8 @@ public:
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
this->service.async_read_some(this->implementation, buffers,
ASIO_MOVE_CAST(ReadHandler)(handler));
this->get_service().async_read_some(this->get_implementation(),
buffers, ASIO_MOVE_CAST(ReadHandler)(handler));
}
};

View File

@ -83,6 +83,23 @@ public:
service_impl_.construct(impl);
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a new stream descriptor implementation.
void move_construct(implementation_type& impl,
implementation_type& other_impl)
{
service_impl_.move_construct(impl, other_impl);
}
/// Move-assign from another stream descriptor implementation.
void move_assign(implementation_type& impl,
stream_descriptor_service& other_service,
implementation_type& other_impl)
{
service_impl_.move_assign(impl, other_service.service_impl_, other_impl);
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroy a stream descriptor implementation.
void destroy(implementation_type& impl)
{

View File

@ -57,6 +57,18 @@ void test()
int native_descriptor1 = -1;
posix::stream_descriptor descriptor2(ios, native_descriptor1);
#if defined(ASIO_HAS_MOVE)
posix::stream_descriptor descriptor3(posix_stream_descriptor(ios));
posix::stream_descriptor descriptor4(std::move(descriptor3));
#endif // defined(ASIO_HAS_MOVE)
// basic_stream_descriptor operators.
#if defined(ASIO_HAS_MOVE)
descriptor3 = posix_stream_descriptor(ios);
descriptor4 = std::move(descriptor3);
#endif // defined(ASIO_HAS_MOVE)
// basic_io_object functions.
io_service& ios_ref = descriptor1.get_io_service();