Boost logo

Boost-Commit :

From: chris_at_[hidden]
Date: 2008-04-21 01:16:16


Author: chris_kohlhoff
Date: 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
New Revision: 44675
URL: http://svn.boost.org/trac/boost/changeset/44675

Log:
Add new wrapper classes for stream-oriented file descriptors on POSIX platforms.

Added:
   trunk/boost/asio/detail/descriptor_ops.hpp (contents, props changed)
   trunk/boost/asio/detail/reactive_descriptor_service.hpp (contents, props changed)
   trunk/boost/asio/posix/
   trunk/boost/asio/posix/basic_descriptor.hpp (contents, props changed)
   trunk/boost/asio/posix/basic_stream_descriptor.hpp (contents, props changed)
   trunk/boost/asio/posix/descriptor_base.hpp (contents, props changed)
   trunk/boost/asio/posix/stream_descriptor.hpp (contents, props changed)
   trunk/boost/asio/posix/stream_descriptor_service.hpp (contents, props changed)
   trunk/libs/asio/test/posix/
   trunk/libs/asio/test/posix/basic_descriptor.cpp (contents, props changed)
   trunk/libs/asio/test/posix/basic_stream_descriptor.cpp (contents, props changed)
   trunk/libs/asio/test/posix/descriptor_base.cpp (contents, props changed)
   trunk/libs/asio/test/posix/stream_descriptor.cpp (contents, props changed)
   trunk/libs/asio/test/posix/stream_descriptor_service.cpp (contents, props changed)
Text files modified:
   trunk/boost/asio.hpp | 5 +++++
   trunk/libs/asio/test/Jamfile | 5 +++++
   trunk/libs/asio/test/Jamfile.v2 | 10 ++++++++++
   3 files changed, 20 insertions(+), 0 deletions(-)

Modified: trunk/boost/asio.hpp
==============================================================================
--- trunk/boost/asio.hpp (original)
+++ trunk/boost/asio.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -63,6 +63,11 @@
 #include <boost/asio/local/datagram_protocol.hpp>
 #include <boost/asio/local/stream_protocol.hpp>
 #include <boost/asio/placeholders.hpp>
+#include <boost/asio/posix/basic_descriptor.hpp>
+#include <boost/asio/posix/basic_stream_descriptor.hpp>
+#include <boost/asio/posix/descriptor_base.hpp>
+#include <boost/asio/posix/stream_descriptor.hpp>
+#include <boost/asio/posix/stream_descriptor_service.hpp>
 #include <boost/asio/read.hpp>
 #include <boost/asio/read_until.hpp>
 #include <boost/asio/socket_acceptor_service.hpp>

Added: trunk/boost/asio/detail/descriptor_ops.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/detail/descriptor_ops.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,121 @@
+//
+// descriptor_ops.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+#define BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <cerrno>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+inline void clear_error(boost::system::error_code& ec)
+{
+ errno = 0;
+ ec = boost::system::error_code();
+}
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+ boost::system::error_code& ec)
+{
+ ec = boost::system::error_code(errno,
+ boost::asio::error::get_system_category());
+ return return_value;
+}
+
+inline int close(int d, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ return error_wrapper(::close(d), ec);
+}
+
+typedef iovec buf;
+
+inline void init_buf(buf& b, void* data, size_t size)
+{
+ b.iov_base = data;
+ b.iov_len = size;
+}
+
+inline void init_buf(buf& b, const void* data, size_t size)
+{
+ b.iov_base = const_cast<void*>(data);
+ b.iov_len = size;
+}
+
+inline int readv(int d, buf* bufs, size_t count, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ return error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
+}
+
+inline int writev(int d, const buf* bufs, size_t count,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+ return error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
+}
+
+inline int ioctl(int d, long cmd, ioctl_arg_type* arg,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+ return error_wrapper(::ioctl(d, cmd, arg), ec);
+}
+
+inline int poll_read(int d, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ clear_error(ec);
+ return error_wrapper(::poll(&fds, 1, -1), ec);
+}
+
+inline int poll_write(int d, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_error(ec);
+ return error_wrapper(::poll(&fds, 1, -1), ec);
+}
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP

Added: trunk/boost/asio/detail/reactive_descriptor_service.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/detail/reactive_descriptor_service.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,684 @@
+//
+// reactive_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/descriptor_ops.hpp>
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Reactor>
+class reactive_descriptor_service
+ : public boost::asio::detail::service_base<
+ reactive_descriptor_service<Reactor> >
+{
+public:
+ // The native type of a descriptor.
+ typedef int native_type;
+
+ // The implementation type of the descriptor.
+ class implementation_type
+ : private boost::asio::detail::noncopyable
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : descriptor_(-1),
+ flags_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class reactive_descriptor_service<Reactor>;
+
+ // The native descriptor representation.
+ int descriptor_;
+
+ enum
+ {
+ user_set_non_blocking = 1, // The user wants a non-blocking descriptor.
+ internal_non_blocking = 2 // The descriptor has been set non-blocking.
+ };
+
+ // Flags indicating the current state of the descriptor.
+ unsigned char flags_;
+ };
+
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+ // Constructor.
+ reactive_descriptor_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ reactive_descriptor_service<Reactor> >(io_service),
+ reactor_(boost::asio::use_service<Reactor>(io_service))
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Construct a new descriptor implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.descriptor_ = -1;
+ impl.flags_ = 0;
+ }
+
+ // Destroy a descriptor implementation.
+ void destroy(implementation_type& impl)
+ {
+ if (impl.descriptor_ != -1)
+ {
+ reactor_.close_descriptor(impl.descriptor_);
+
+ if (impl.flags_ & implementation_type::internal_non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ boost::system::error_code ignored_ec;
+ descriptor_ops::ioctl(impl.descriptor_,
+ FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::internal_non_blocking;
+ }
+
+ boost::system::error_code ignored_ec;
+ descriptor_ops::close(impl.descriptor_, ignored_ec);
+
+ impl.descriptor_ = -1;
+ }
+ }
+
+ // Assign a native descriptor to a descriptor implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const native_type& native_descriptor, boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(native_descriptor))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.descriptor_ = native_descriptor;
+ impl.flags_ = 0;
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Determine whether the descriptor is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.descriptor_ != -1;
+ }
+
+ // Destroy a descriptor implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ reactor_.close_descriptor(impl.descriptor_);
+
+ if (impl.flags_ & implementation_type::internal_non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ boost::system::error_code ignored_ec;
+ descriptor_ops::ioctl(impl.descriptor_,
+ FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::internal_non_blocking;
+ }
+
+ if (descriptor_ops::close(impl.descriptor_, ec) == -1)
+ return ec;
+
+ impl.descriptor_ = -1;
+ }
+
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Get the native descriptor representation.
+ native_type native(implementation_type& impl)
+ {
+ return impl.descriptor_;
+ }
+
+ // Cancel all operations associated with the descriptor.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ reactor_.cancel_ops(impl.descriptor_);
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Perform an IO control command on the descriptor.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (command.name() == static_cast<int>(FIONBIO))
+ {
+ if (command.get())
+ impl.flags_ |= implementation_type::user_set_non_blocking;
+ else
+ impl.flags_ &= ~implementation_type::user_set_non_blocking;
+ ec = boost::system::error_code();
+ }
+ else
+ {
+ descriptor_ops::ioctl(impl.descriptor_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ }
+ return ec;
+ }
+
+ // Write some data to the descriptor.
+ template <typename ConstBufferSequence>
+ size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Make descriptor non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (descriptor_ops::ioctl(impl.descriptor_,
+ FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Send the data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_sent = descriptor_ops::writev(impl.descriptor_, bufs, i, ec);
+
+ // Check if operation succeeded.
+ if (bytes_sent >= 0)
+ return bytes_sent;
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be written without blocking.
+ size_t write_some(implementation_type& impl,
+ const null_buffers&, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for descriptor to become ready.
+ descriptor_ops::poll_write(impl.descriptor_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class write_handler
+ {
+ public:
+ write_handler(int descriptor, boost::asio::io_service& io_service,
+ const ConstBufferSequence& buffers, Handler handler)
+ : descriptor_(descriptor),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const boost::system::error_code& result)
+ {
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers_.begin();
+ typename ConstBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Write the data.
+ boost::system::error_code ec;
+ int bytes = descriptor_ops::writev(descriptor_, bufs, i, ec);
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
+ return true;
+ }
+
+ private:
+ int descriptor_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous write. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Determine total size of buffers.
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::system::error_code(), 0));
+ return;
+ }
+
+ // Make descriptor non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_write_op(impl.descriptor_,
+ write_handler<ConstBufferSequence, Handler>(
+ impl.descriptor_, this->get_io_service(), buffers, handler));
+ }
+ }
+
+ template <typename Handler>
+ class null_buffers_handler
+ {
+ public:
+ null_buffers_handler(boost::asio::io_service& io_service, Handler handler)
+ : work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const boost::system::error_code& result)
+ {
+ work_.get_io_service().post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ private:
+ boost::asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous wait until data can be written without blocking.
+ template <typename Handler>
+ void async_write_some(implementation_type& impl,
+ const null_buffers&, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_write_op(impl.descriptor_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Read some data from the stream. Returns the number of bytes read.
+ template <typename MutableBufferSequence>
+ size_t read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Make descriptor non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_read = descriptor_ops::readv(impl.descriptor_, bufs, i, ec);
+
+ // Check if operation succeeded.
+ if (bytes_read > 0)
+ return bytes_read;
+
+ // Check for EOF.
+ if (bytes_read == 0)
+ {
+ ec = boost::asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be read without blocking.
+ size_t read_some(implementation_type& impl,
+ const null_buffers& buffers, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for descriptor to become ready.
+ descriptor_ops::poll_read(impl.descriptor_, ec);
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class read_handler
+ {
+ public:
+ read_handler(int descriptor, boost::asio::io_service& io_service,
+ const MutableBufferSequence& buffers, Handler handler)
+ : descriptor_(descriptor),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ bool operator()(const boost::system::error_code& result)
+ {
+ // Check whether the operation was successful.
+ if (result)
+ {
+ io_service_.post(bind_handler(handler_, result, 0));
+ return true;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers_.begin();
+ typename MutableBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Read some data.
+ boost::system::error_code ec;
+ int bytes = descriptor_ops::readv(descriptor_, bufs, i, ec);
+ if (bytes == 0)
+ ec = boost::asio::error::eof;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes));
+ return true;
+ }
+
+ private:
+ int descriptor_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // 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>
+ void async_read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Determine total size of buffers.
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::system::error_code(), 0));
+ return;
+ }
+
+ // Make descriptor non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_read_op(impl.descriptor_,
+ read_handler<MutableBufferSequence, Handler>(
+ impl.descriptor_, this->get_io_service(), buffers, handler));
+ }
+ }
+
+ // Wait until data can be read without blocking.
+ template <typename Handler>
+ void async_read_some(implementation_type& impl,
+ const null_buffers&, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.descriptor_,
+ null_buffers_handler<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+private:
+ // The selector that performs event demultiplexing for the service.
+ Reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP

Added: trunk/boost/asio/posix/basic_descriptor.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/posix/basic_descriptor.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,282 @@
+//
+// basic_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP
+#define BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/basic_io_object.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/posix/descriptor_base.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+
+namespace boost {
+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._at_n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename DescriptorService>
+class basic_descriptor
+ : public basic_io_object<DescriptorService>,
+ public descriptor_base
+{
+public:
+ /// The native representation of a descriptor.
+ typedef typename DescriptorService::native_type native_type;
+
+ /// A basic_descriptor is always the lowest layer.
+ typedef basic_descriptor<DescriptorService> lowest_layer_type;
+
+ /// Construct a basic_descriptor without opening it.
+ /**
+ * This constructor creates a descriptor without opening it.
+ *
+ * @param io_service The io_service object that the descriptor will use to
+ * dispatch handlers for any asynchronous operations performed on the
+ * descriptor.
+ */
+ explicit basic_descriptor(boost::asio::io_service& io_service)
+ : basic_io_object<DescriptorService>(io_service)
+ {
+ }
+
+ /// Construct a basic_descriptor on an existing native descriptor.
+ /**
+ * This constructor creates a descriptor object to hold an existing native
+ * descriptor.
+ *
+ * @param io_service The io_service object that the descriptor will use to
+ * dispatch handlers for any asynchronous operations performed on the
+ * descriptor.
+ *
+ * @param native_descriptor A native descriptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_descriptor(boost::asio::io_service& io_service,
+ const native_type& native_descriptor)
+ : basic_io_object<DescriptorService>(io_service)
+ {
+ boost::system::error_code ec;
+ this->service.assign(this->implementation, native_descriptor, ec);
+ boost::asio::detail::throw_error(ec);
+ }
+
+ /// Get a reference to the lowest layer.
+ /**
+ * This function returns a reference to the lowest layer in a stack of
+ * layers. Since a basic_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;
+ }
+
+ /// 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 boost::system::system_error Thrown on failure.
+ */
+ void assign(const native_type& native_descriptor)
+ {
+ boost::system::error_code ec;
+ this->service.assign(this->implementation, native_descriptor, ec);
+ boost::asio::detail::throw_error(ec);
+ }
+
+ /// 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.
+ */
+ boost::system::error_code assign(const native_type& native_descriptor,
+ boost::system::error_code& ec)
+ {
+ return this->service.assign(this->implementation, native_descriptor, ec);
+ }
+
+ /// Determine whether the descriptor is open.
+ bool is_open() const
+ {
+ return this->service.is_open(this->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
+ * boost::asio::error::operation_aborted error.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void close()
+ {
+ boost::system::error_code ec;
+ this->service.close(this->implementation, ec);
+ boost::asio::detail::throw_error(ec);
+ }
+
+ /// 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
+ * boost::asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ boost::system::error_code close(boost::system::error_code& ec)
+ {
+ return this->service.close(this->implementation, 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_type native()
+ {
+ return this->service.native(this->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 boost::asio::error::operation_aborted error.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void cancel()
+ {
+ boost::system::error_code ec;
+ this->service.cancel(this->implementation, ec);
+ boost::asio::detail::throw_error(ec);
+ }
+
+ /// 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 boost::asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ boost::system::error_code cancel(boost::system::error_code& ec)
+ {
+ return this->service.cancel(this->implementation, 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 boost::system::system_error Thrown on failure.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::posix::descriptor_base::bytes_readable @n
+ * boost::asio::posix::descriptor_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::posix::stream_descriptor descriptor(io_service);
+ * ...
+ * boost::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)
+ {
+ boost::system::error_code ec;
+ this->service.io_control(this->implementation, command, ec);
+ boost::asio::detail::throw_error(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.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::posix::descriptor_base::bytes_readable @n
+ * boost::asio::posix::descriptor_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::posix::stream_descriptor descriptor(io_service);
+ * ...
+ * boost::asio::posix::stream_descriptor::bytes_readable command;
+ * boost::system::error_code ec;
+ * descriptor.io_control(command, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ boost::system::error_code io_control(IoControlCommand& command,
+ boost::system::error_code& ec)
+ {
+ return this->service.io_control(this->implementation, command, ec);
+ }
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ ~basic_descriptor()
+ {
+ }
+};
+
+} // namespace posix
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP

Added: trunk/boost/asio/posix/basic_stream_descriptor.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/posix/basic_stream_descriptor.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,306 @@
+//
+// basic_stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
+#define BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/posix/basic_descriptor.hpp>
+#include <boost/asio/posix/stream_descriptor_service.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+
+#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+ || defined(GENERATING_DOCUMENTATION)
+
+namespace boost {
+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._at_n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename StreamDescriptorService = stream_descriptor_service>
+class basic_stream_descriptor
+ : public basic_descriptor<StreamDescriptorService>
+{
+public:
+ /// The native representation of a descriptor.
+ typedef typename StreamDescriptorService::native_type native_type;
+
+ /// Construct a basic_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_service The io_service object that the stream descriptor will
+ * use to dispatch handlers for any asynchronous operations performed on the
+ * descriptor.
+ */
+ explicit basic_stream_descriptor(boost::asio::io_service& io_service)
+ : basic_descriptor<StreamDescriptorService>(io_service)
+ {
+ }
+
+ /// Construct a basic_stream_descriptor on an existing native descriptor.
+ /**
+ * This constructor creates a stream descriptor object to hold an existing
+ * native descriptor.
+ *
+ * @param io_service The io_service 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 boost::system::system_error Thrown on failure.
+ */
+ basic_stream_descriptor(boost::asio::io_service& io_service,
+ const native_type& native_descriptor)
+ : basic_descriptor<StreamDescriptorService>(io_service, native_descriptor)
+ {
+ }
+
+ /// 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 boost::system::system_error Thrown on failure. An error code of
+ * boost::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(boost::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)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->service.write_some(this->implementation, buffers, ec);
+ boost::asio::detail::throw_error(ec);
+ 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,
+ boost::system::error_code& ec)
+ {
+ return this->service.write_some(this->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 boost::system::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
+ * boost::asio::io_service::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(boost::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>
+ void async_write_some(const ConstBufferSequence& buffers,
+ WriteHandler handler)
+ {
+ this->service.async_write_some(this->implementation, buffers, handler);
+ }
+
+ /// 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 boost::system::system_error Thrown on failure. An error code of
+ * boost::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(boost::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)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->service.read_some(this->implementation, buffers, ec);
+ boost::asio::detail::throw_error(ec);
+ 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,
+ boost::system::error_code& ec)
+ {
+ return this->service.read_some(this->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 boost::system::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
+ * boost::asio::io_service::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(boost::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>
+ void async_read_some(const MutableBufferSequence& buffers,
+ ReadHandler handler)
+ {
+ this->service.async_read_some(this->implementation, buffers, handler);
+ }
+};
+
+} // namespace posix
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+ // || defined(GENERATING_DOCUMENTATION)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP

Added: trunk/boost/asio/posix/descriptor_base.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/posix/descriptor_base.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,95 @@
+//
+// descriptor_base.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP
+#define BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/io_control.hpp>
+#include <boost/asio/detail/socket_option.hpp>
+
+namespace boost {
+namespace asio {
+namespace posix {
+
+/// The descriptor_base class is used as a base for the basic_stream_descriptor
+/// class template so that we have a common place to define the associated
+/// IO control commands.
+class descriptor_base
+{
+public:
+ /// IO control command to set the blocking mode of the descriptor.
+ /**
+ * Implements the FIONBIO IO control command.
+ *
+ * @par Example
+ * @code
+ * boost::asio::posix::stream_descriptor descriptor(io_service);
+ * ...
+ * boost::asio::descriptor_base::non_blocking_io command(true);
+ * descriptor.io_control(command);
+ * @endcode
+ *
+ * @par Concepts:
+ * IoControlCommand.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined non_blocking_io;
+#else
+ typedef boost::asio::detail::io_control::non_blocking_io non_blocking_io;
+#endif
+
+ /// IO control command to get the amount of data that can be read without
+ /// blocking.
+ /**
+ * Implements the FIONREAD IO control command.
+ *
+ * @par Example
+ * @code
+ * boost::asio::posix::stream_descriptor descriptor(io_service);
+ * ...
+ * boost::asio::descriptor_base::bytes_readable command(true);
+ * descriptor.io_control(command);
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ *
+ * @par Concepts:
+ * IoControlCommand.
+ */
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined bytes_readable;
+#else
+ typedef boost::asio::detail::io_control::bytes_readable bytes_readable;
+#endif
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ ~descriptor_base()
+ {
+ }
+};
+
+} // namespace posix
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP

Added: trunk/boost/asio/posix/stream_descriptor.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/posix/stream_descriptor.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,41 @@
+//
+// stream_descriptor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP
+#define BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/posix/basic_stream_descriptor.hpp>
+
+#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+ || defined(GENERATING_DOCUMENTATION)
+
+namespace boost {
+namespace asio {
+namespace posix {
+
+/// Typedef for the typical usage of a stream-oriented descriptor.
+typedef basic_stream_descriptor<> stream_descriptor;
+
+} // namespace posix
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+ // || defined(GENERATING_DOCUMENTATION)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP

Added: trunk/boost/asio/posix/stream_descriptor_service.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/posix/stream_descriptor_service.hpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,202 @@
+//
+// stream_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP
+#define BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/epoll_reactor.hpp>
+#include <boost/asio/detail/kqueue_reactor.hpp>
+#include <boost/asio/detail/select_reactor.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/reactive_descriptor_service.hpp>
+
+#if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
+# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+
+#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
+ || defined(GENERATING_DOCUMENTATION)
+
+namespace boost {
+namespace asio {
+namespace posix {
+
+/// Default service implementation for a stream descriptor.
+class stream_descriptor_service
+#if defined(GENERATING_DOCUMENTATION)
+ : public boost::asio::io_service::service
+#else
+ : public boost::asio::detail::service_base<stream_descriptor_service>
+#endif
+{
+public:
+#if defined(GENERATING_DOCUMENTATION)
+ /// The unique service identifier.
+ static boost::asio::io_service::id id;
+#endif
+
+private:
+ // The type of the platform-specific implementation.
+#if defined(BOOST_ASIO_HAS_EPOLL)
+ typedef detail::reactive_descriptor_service<
+ detail::epoll_reactor<false> > service_impl_type;
+#elif defined(BOOST_ASIO_HAS_KQUEUE)
+ typedef detail::reactive_descriptor_service<
+ detail::kqueue_reactor<false> > service_impl_type;
+#elif defined(BOOST_ASIO_HAS_DEV_POLL)
+ typedef detail::reactive_descriptor_service<
+ detail::dev_poll_reactor<false> > service_impl_type;
+#else
+ typedef detail::reactive_descriptor_service<
+ detail::select_reactor<false> > service_impl_type;
+#endif
+
+public:
+ /// The type of a stream descriptor implementation.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined implementation_type;
+#else
+ typedef service_impl_type::implementation_type implementation_type;
+#endif
+
+ /// The native descriptor type.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_type;
+#else
+ typedef service_impl_type::native_type native_type;
+#endif
+
+ /// Construct a new stream descriptor service for the specified io_service.
+ explicit stream_descriptor_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<stream_descriptor_service>(io_service),
+ service_impl_(boost::asio::use_service<service_impl_type>(io_service))
+ {
+ }
+
+ /// Destroy all user-defined descriptorr objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ /// Construct a new stream descriptor implementation.
+ void construct(implementation_type& impl)
+ {
+ service_impl_.construct(impl);
+ }
+
+ /// Destroy a stream descriptor implementation.
+ void destroy(implementation_type& impl)
+ {
+ service_impl_.destroy(impl);
+ }
+
+ /// Assign an existing native descriptor to a stream descriptor.
+ boost::system::error_code assign(implementation_type& impl,
+ const native_type& native_descriptor, boost::system::error_code& ec)
+ {
+ return service_impl_.assign(impl, native_descriptor, ec);
+ }
+
+ /// Determine whether the descriptor is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return service_impl_.is_open(impl);
+ }
+
+ /// Close a stream descriptor implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.close(impl, ec);
+ }
+
+ /// Get the native descriptor implementation.
+ native_type native(implementation_type& impl)
+ {
+ return service_impl_.native(impl);
+ }
+
+ /// Cancel all asynchronous operations associated with the descriptor.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return service_impl_.cancel(impl, ec);
+ }
+
+ /// Perform an IO control command on the descriptor.
+ template <typename IoControlCommand>
+ boost::system::error_code io_control(implementation_type& impl,
+ IoControlCommand& command, boost::system::error_code& ec)
+ {
+ return service_impl_.io_control(impl, command, ec);
+ }
+
+ /// Write the given data to the stream.
+ template <typename ConstBufferSequence>
+ std::size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, boost::system::error_code& ec)
+ {
+ return service_impl_.write_some(impl, buffers, ec);
+ }
+
+ /// Start an asynchronous write.
+ template <typename ConstBufferSequence, typename WriteHandler>
+ void async_write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, WriteHandler descriptorr)
+ {
+ service_impl_.async_write_some(impl, buffers, descriptorr);
+ }
+
+ /// Read some data from the stream.
+ template <typename MutableBufferSequence>
+ std::size_t read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, boost::system::error_code& ec)
+ {
+ return service_impl_.read_some(impl, buffers, ec);
+ }
+
+ /// Start an asynchronous read.
+ template <typename MutableBufferSequence, typename ReadHandler>
+ void async_read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, ReadHandler descriptorr)
+ {
+ service_impl_.async_read_some(impl, buffers, descriptorr);
+ }
+
+private:
+ // The service that provides the platform-specific implementation.
+ service_impl_type& service_impl_;
+};
+
+} // namespace posix
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+ // || defined(GENERATING_DOCUMENTATION)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP

Modified: trunk/libs/asio/test/Jamfile
==============================================================================
--- trunk/libs/asio/test/Jamfile (original)
+++ trunk/libs/asio/test/Jamfile 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -74,6 +74,11 @@
   [ run local/datagram_protocol.cpp <template>asio_unit_test ]
   [ run local/stream_protocol.cpp <template>asio_unit_test ]
   [ run placeholders.cpp <template>asio_unit_test ]
+ [ run posix/basic_descriptor.cpp <template>asio_unit_test ]
+ [ run posix/basic_stream_descriptor.cpp <template>asio_unit_test ]
+ [ run posix/descriptor_base.cpp <template>asio_unit_test ]
+ [ run posix/stream_descriptor.cpp <template>asio_unit_test ]
+ [ run posix/stream_descriptor_service.cpp <template>asio_unit_test ]
   [ run read.cpp <template>asio_unit_test ]
   [ run read_until.cpp <template>asio_unit_test ]
   [ run socket_acceptor_service.cpp <template>asio_unit_test ]

Modified: trunk/libs/asio/test/Jamfile.v2
==============================================================================
--- trunk/libs/asio/test/Jamfile.v2 (original)
+++ trunk/libs/asio/test/Jamfile.v2 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -126,6 +126,16 @@
   [ link local/stream_protocol.cpp : $(USE_SELECT) : local_stream_protocol_select ]
   [ link placeholders.cpp ]
   [ link placeholders.cpp : $(USE_SELECT) : placeholders_select ]
+ [ link posix/basic_descriptor.cpp : : posix_basic_descriptor ]
+ [ link posix/basic_descriptor.cpp : $(USE_SELECT) : posix_basic_descriptor_select ]
+ [ link posix/basic_stream_descriptor.cpp : : posix_basic_stream_descriptor ]
+ [ link posix/basic_stream_descriptor.cpp : $(USE_SELECT) : posix_basic_stream_descriptor_select ]
+ [ link posix/descriptor_base.cpp : : posix_descriptor_base ]
+ [ link posix/descriptor_base.cpp : $(USE_SELECT) : posix_descriptor_base_select ]
+ [ link posix/stream_descriptor.cpp : : posix_stream_descriptor ]
+ [ link posix/stream_descriptor.cpp : $(USE_SELECT) : posix_stream_descriptor_select ]
+ [ link posix/stream_descriptor_service.cpp : : posix_stream_descriptor_service ]
+ [ link posix/stream_descriptor_service.cpp : $(USE_SELECT) : posix_stream_descriptor_service_select ]
   [ run read.cpp ]
   [ run read.cpp : : : $(USE_SELECT) : read_select ]
   [ run read_until.cpp ]

Added: trunk/libs/asio/test/posix/basic_descriptor.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/posix/basic_descriptor.cpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,27 @@
+//
+// basic_descriptor.cpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include <boost/asio/posix/basic_descriptor.hpp>
+
+#include <boost/asio.hpp>
+#include "../unit_test.hpp"
+
+test_suite* init_unit_test_suite(int argc, char* argv[])
+{
+ test_suite* test = BOOST_TEST_SUITE("posix/basic_descriptor");
+ test->add(BOOST_TEST_CASE(&null_test));
+ return test;
+}

Added: trunk/libs/asio/test/posix/basic_stream_descriptor.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/posix/basic_stream_descriptor.cpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,27 @@
+//
+// basic_stream_descriptor.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include <boost/asio/posix/basic_stream_descriptor.hpp>
+
+#include <boost/asio.hpp>
+#include "../unit_test.hpp"
+
+test_suite* init_unit_test_suite(int argc, char* argv[])
+{
+ test_suite* test = BOOST_TEST_SUITE("posix/basic_stream_descriptor");
+ test->add(BOOST_TEST_CASE(&null_test));
+ return test;
+}

Added: trunk/libs/asio/test/posix/descriptor_base.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/posix/descriptor_base.cpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,27 @@
+//
+// descriptor_base.cpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include <boost/asio/posix/descriptor_base.hpp>
+
+#include <boost/asio.hpp>
+#include "../unit_test.hpp"
+
+test_suite* init_unit_test_suite(int argc, char* argv[])
+{
+ test_suite* test = BOOST_TEST_SUITE("posix/descriptor_base");
+ test->add(BOOST_TEST_CASE(&null_test));
+ return test;
+}

Added: trunk/libs/asio/test/posix/stream_descriptor.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/posix/stream_descriptor.cpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,127 @@
+//
+// stream_descriptor.cpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include <boost/asio/posix/stream_descriptor.hpp>
+
+#include <boost/asio.hpp>
+#include "../unit_test.hpp"
+
+//------------------------------------------------------------------------------
+
+// posix_stream_descriptor_compile test
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The following test checks that all public member functions on the class
+// posix::stream_descriptor compile and link correctly. Runtime failures are
+// ignored.
+
+namespace posix_stream_descriptor_compile {
+
+void write_some_handler(const boost::system::error_code&, std::size_t)
+{
+}
+
+void read_some_handler(const boost::system::error_code&, std::size_t)
+{
+}
+
+void test()
+{
+#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+ using namespace boost::asio;
+ namespace posix = boost::asio::posix;
+
+ try
+ {
+ io_service ios;
+ char mutable_char_buffer[128] = "";
+ const char const_char_buffer[128] = "";
+ posix::descriptor_base::bytes_readable io_control_command;
+ boost::system::error_code ec;
+
+ // basic_stream_descriptor constructors.
+
+ posix::stream_descriptor descriptor1(ios);
+ int native_descriptor1 = -1;
+ posix::stream_descriptor descriptor2(ios, native_descriptor1);
+
+ // basic_io_object functions.
+
+ io_service& ios_ref = descriptor1.io_service();
+ (void)ios_ref;
+
+ // basic_descriptor functions.
+
+ posix::stream_descriptor::lowest_layer_type& lowest_layer
+ = descriptor1.lowest_layer();
+ (void)lowest_layer;
+
+ int native_descriptor2 = -1;
+ descriptor1.assign(native_descriptor2);
+
+ bool is_open = descriptor1.is_open();
+ (void)is_open;
+
+ descriptor1.close();
+ descriptor1.close(ec);
+
+ posix::stream_descriptor::native_type native_descriptor3
+ = descriptor1.native();
+ (void)native_descriptor3;
+
+ descriptor1.cancel();
+ descriptor1.cancel(ec);
+
+ descriptor1.io_control(io_control_command);
+ descriptor1.io_control(io_control_command, ec);
+
+ // basic_stream_descriptor functions.
+
+ descriptor1.write_some(buffer(mutable_char_buffer));
+ descriptor1.write_some(buffer(const_char_buffer));
+ descriptor1.write_some(null_buffers());
+ descriptor1.write_some(buffer(mutable_char_buffer), ec);
+ descriptor1.write_some(buffer(const_char_buffer), ec);
+ descriptor1.write_some(null_buffers(), ec);
+
+ descriptor1.async_write_some(buffer(mutable_char_buffer),
+ write_some_handler);
+ descriptor1.async_write_some(buffer(const_char_buffer),
+ write_some_handler);
+ descriptor1.async_write_some(null_buffers(),
+ write_some_handler);
+
+ descriptor1.read_some(buffer(mutable_char_buffer));
+ descriptor1.read_some(buffer(mutable_char_buffer), ec);
+ descriptor1.read_some(null_buffers(), ec);
+
+ descriptor1.async_read_some(buffer(mutable_char_buffer), read_some_handler);
+ descriptor1.async_read_some(null_buffers(), read_some_handler);
+ }
+ catch (std::exception&)
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+}
+
+} // namespace posix_stream_descriptor_compile
+
+//------------------------------------------------------------------------------
+test_suite* init_unit_test_suite(int argc, char* argv[])
+{
+ test_suite* test = BOOST_TEST_SUITE("posix/stream_descriptor");
+ test->add(BOOST_TEST_CASE(&posix_stream_descriptor_compile::test));
+ return test;
+}

Added: trunk/libs/asio/test/posix/stream_descriptor_service.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/posix/stream_descriptor_service.cpp 2008-04-21 01:16:15 EDT (Mon, 21 Apr 2008)
@@ -0,0 +1,27 @@
+//
+// stream_descriptor_service.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include <boost/asio/posix/stream_descriptor_service.hpp>
+
+#include <boost/asio.hpp>
+#include "../unit_test.hpp"
+
+test_suite* init_unit_test_suite(int argc, char* argv[])
+{
+ test_suite* test = BOOST_TEST_SUITE("posix/stream_descriptor_service");
+ test->add(BOOST_TEST_CASE(&null_test));
+ return test;
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk