asio sync

This commit is contained in:
Marcos Pinto 2007-11-23 23:36:34 +00:00
parent 8a833af738
commit ffa2066046
65 changed files with 2886 additions and 579 deletions

View File

@ -1,74 +0,0 @@
//
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2007 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_HPP
#define ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/basic_datagram_socket.hpp"
#include "asio/basic_deadline_timer.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_socket_streambuf.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/basic_streambuf.hpp"
#include "asio/buffer.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/buffered_stream.hpp"
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/completion_condition.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/deadline_timer.hpp"
#include "asio/error.hpp"
#include "asio/error_code.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/handler_invoke_hook.hpp"
#include "asio/io_service.hpp"
#include "asio/ip/address.hpp"
#include "asio/ip/address_v4.hpp"
#include "asio/ip/address_v6.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
#include "asio/ip/basic_resolver_entry.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/ip/host_name.hpp"
#include "asio/ip/multicast.hpp"
#include "asio/ip/resolver_query_base.hpp"
#include "asio/ip/resolver_service.hpp"
#include "asio/ip/tcp.hpp"
#include "asio/ip/udp.hpp"
#include "asio/ip/unicast.hpp"
#include "asio/ip/v6_only.hpp"
#include "asio/is_read_buffered.hpp"
#include "asio/is_write_buffered.hpp"
#include "asio/placeholders.hpp"
#include "asio/read.hpp"
#include "asio/read_until.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp"
#include "asio/strand.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/streambuf.hpp"
#include "asio/system_error.hpp"
#include "asio/thread.hpp"
#include "asio/time_traits.hpp"
#include "asio/version.hpp"
#include "asio/write.hpp"
#endif // ASIO_HPP

View File

@ -0,0 +1,4 @@
Copyright (c) 2003-2007 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)

View File

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -732,8 +732,8 @@ public:
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::system_error& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* const asio::error_code& error, // Result of operation.
* 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

View File

@ -34,7 +34,8 @@ public:
/// The underlying implementation type of I/O object.
typedef typename service_type::implementation_type implementation_type;
/// Get the io_service associated with the object.
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
/**
* This function may be used to obtain the io_service object that the I/O
* object uses to dispatch handlers for asynchronous operations.
@ -44,7 +45,20 @@ public:
*/
asio::io_service& io_service()
{
return service.io_service();
return service.get_io_service();
}
/// Get the io_service associated with the object.
/**
* This function may be used to obtain the io_service object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_service object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_service& get_io_service()
{
return service.get_io_service();
}
protected:

View File

@ -0,0 +1,252 @@
//
// basic_resolver.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2006 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_RESOLVER_HPP
#define ASIO_BASIC_RESOLVER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/error_handler.hpp"
#include "asio/resolver_service.hpp"
namespace asio {
/// Provides endpoint resolution functionality.
/**
* The basic_resolver class template provides the ability to resolve a query
* to a list of endpoints.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* Async_Object, Error_Source.
*/
template <typename Protocol, typename Service = resolver_service<Protocol> >
class basic_resolver
: public basic_io_object<Service>
{
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The query type.
typedef typename Protocol::resolver_query query;
/// The iterator type.
typedef typename Protocol::resolver_iterator iterator;
/// The type used for reporting errors.
typedef asio::error error_type;
/// Constructor.
/**
* This constructor creates a basic_resolver.
*
* @param io_service The io_service object that the resolver will use to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_resolver(asio::io_service& io_service)
: basic_io_object<Service>(io_service)
{
}
/// Cancel any asynchronous operations that are waiting on the resolver.
/**
* This function forces the completion of any pending asynchronous
* operations on the host resolver. The handler for each cancelled operation
* will be invoked with the asio::error::operation_aborted error code.
*/
void cancel()
{
return this->service.cancel(this->implementation);
}
/// Resolve a query to a list of entries.
/**
* This function is used to resolve a query into a list of endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries.
*
* @throws asio::error Thrown on failure.
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
iterator resolve(const query& q)
{
return this->service.resolve(this->implementation, q, throw_error());
}
/// Resolve a query to a list of entries.
/**
* This function is used to resolve a query into a list of endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries. Returns a default constructed iterator if an error
* occurs.
*
* @param error_handler A handler to be called when the operation completes,
* to indicate whether or not an error has occurred. Copies will be made of
* the handler as required. The function signature of the handler must be:
* @code void error_handler(
* const asio::error& error // Result of operation.
* ); @endcode
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
template <typename Error_Handler>
iterator resolve(const query& q, Error_Handler error_handler)
{
return this->service.resolve(this->implementation, q, error_handler);
}
/// Asynchronously resolve a query to a list of entries.
/**
* This function is used to asynchronously resolve a query into a list of
* endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @param handler The handler to be called when the resolve 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& error, // Result of operation.
* resolver::iterator iterator // Forward-only iterator that can be used to
* // traverse the list of endpoint entries.
* ); @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_service::post().
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful resolve operation is guaranteed to pass at least one
* entry to the handler.
*/
template <typename Handler>
void async_resolve(const query& q, Handler handler)
{
return this->service.async_resolve(this->implementation, q, handler);
}
/// Resolve an endpoint to a list of entries.
/**
* This function is used to resolve an endpoint into a list of endpoint
* entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries.
*
* @throws asio::error Thrown on failure.
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
iterator resolve(const endpoint_type& e)
{
return this->service.resolve(this->implementation, e, throw_error());
}
/// Resolve an endpoint to a list of entries.
/**
* This function is used to resolve an endpoint into a list of endpoint
* entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries. Returns a default constructed iterator if an error
* occurs.
*
* @param error_handler A handler to be called when the operation completes,
* to indicate whether or not an error has occurred. Copies will be made of
* the handler as required. The function signature of the handler must be:
* @code void error_handler(
* const asio::error& error // Result of operation.
* ); @endcode
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
template <typename Error_Handler>
iterator resolve(const endpoint_type& e, Error_Handler error_handler)
{
return this->service.resolve(this->implementation, e, error_handler);
}
/// Asynchronously resolve an endpoint to a list of entries.
/**
* This function is used to asynchronously resolve an endpoint into a list of
* endpoint entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @param handler The handler to be called when the resolve 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& error, // Result of operation.
* resolver::iterator iterator // Forward-only iterator that can be used to
* // traverse the list of endpoint entries.
* ); @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_service::post().
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful resolve operation is guaranteed to pass at least one
* entry to the handler.
*/
template <typename Handler>
void async_resolve(const endpoint_type& e, Handler handler)
{
return this->service.async_resolve(this->implementation, e, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_RESOLVER_HPP

View File

@ -564,7 +564,8 @@ public:
if (this->service.open(this->implementation,
peer_endpoint.protocol(), ec))
{
this->io_service().post(asio::detail::bind_handler(handler, ec));
this->get_io_service().post(
asio::detail::bind_handler(handler, ec));
return;
}
}

View File

@ -27,7 +27,7 @@
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_MSVC)
# if defined(_HAS_ITERATOR_DEBUGGING)
# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)
# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# define ASIO_ENABLE_BUFFER_DEBUGGING
# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
@ -390,6 +390,11 @@ public:
{
}
~buffer_debug_check()
{
iter_ = Iterator();
}
void operator()()
{
*iter_;

View File

@ -93,10 +93,17 @@ public:
return next_layer_.lowest_layer();
}
/// Get the io_service associated with the object.
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
asio::io_service& io_service()
{
return next_layer_.io_service();
return next_layer_.get_io_service();
}
/// Get the io_service associated with the object.
asio::io_service& get_io_service()
{
return next_layer_.get_io_service();
}
/// Close the stream.
@ -207,7 +214,7 @@ public:
buffer(
storage_.data() + previous_size,
storage_.size() - previous_size),
fill_handler<ReadHandler>(io_service(),
fill_handler<ReadHandler>(get_io_service(),
storage_, previous_size, handler));
}
@ -295,12 +302,12 @@ public:
if (storage_.empty())
{
async_fill(read_some_handler<MutableBufferSequence, ReadHandler>(
io_service(), storage_, buffers, handler));
get_io_service(), storage_, buffers, handler));
}
else
{
std::size_t length = copy(buffers);
io_service().post(detail::bind_handler(
get_io_service().post(detail::bind_handler(
handler, asio::error_code(), length));
}
}

View File

@ -83,10 +83,17 @@ public:
return stream_impl_.lowest_layer();
}
/// Get the io_service associated with the object.
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
asio::io_service& io_service()
{
return stream_impl_.io_service();
return stream_impl_.get_io_service();
}
/// Get the io_service associated with the object.
asio::io_service& get_io_service()
{
return stream_impl_.get_io_service();
}
/// Close the stream.

View File

@ -94,10 +94,17 @@ public:
return next_layer_.lowest_layer();
}
/// Get the io_service associated with the object.
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
asio::io_service& io_service()
{
return next_layer_.io_service();
return next_layer_.get_io_service();
}
/// Get the io_service associated with the object.
asio::io_service& get_io_service()
{
return next_layer_.get_io_service();
}
/// Close the stream.
@ -165,7 +172,7 @@ public:
void async_flush(WriteHandler handler)
{
async_write(next_layer_, buffer(storage_.data(), storage_.size()),
flush_handler<WriteHandler>(io_service(), storage_, handler));
flush_handler<WriteHandler>(get_io_service(), storage_, handler));
}
/// Write the given data to the stream. Returns the number of bytes written.
@ -253,12 +260,12 @@ public:
if (storage_.size() == storage_.capacity())
{
async_flush(write_some_handler<ConstBufferSequence, WriteHandler>(
io_service(), storage_, buffers, handler));
get_io_service(), storage_, buffers, handler));
}
else
{
std::size_t bytes_copied = copy(buffers);
io_service().post(detail::bind_handler(
get_io_service().post(detail::bind_handler(
handler, asio::error_code(), bytes_copied));
}
}

View File

@ -64,6 +64,9 @@ private:
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::reactive_socket_service<
Protocol, detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::reactive_socket_service<
Protocol, detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::reactive_socket_service<
Protocol, detail::select_reactor<false> > service_impl_type;

View File

@ -29,6 +29,7 @@
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/select_reactor.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/win_iocp_io_service.hpp"
namespace asio {
@ -62,13 +63,16 @@ private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP)
typedef detail::deadline_timer_service<
traits_type, detail::select_reactor<true> > service_impl_type;
traits_type, detail::win_iocp_io_service> service_impl_type;
#elif defined(ASIO_HAS_EPOLL)
typedef detail::deadline_timer_service<
traits_type, detail::epoll_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::deadline_timer_service<
traits_type, detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::deadline_timer_service<
traits_type, detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::deadline_timer_service<
traits_type, detail::select_reactor<false> > service_impl_type;

View File

@ -180,7 +180,7 @@ public:
{
impl.might_have_pending_waits = true;
scheduler_.schedule_timer(timer_queue_, impl.expiry,
wait_handler<Handler>(this->io_service(), handler), &impl);
wait_handler<Handler>(this->get_io_service(), handler), &impl);
}
private:

View File

@ -0,0 +1,647 @@
//
// dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 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_DEV_POLL_REACTOR_HPP
#define ASIO_DETAIL_DEV_POLL_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/dev_poll_reactor_fwd.hpp"
#if defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include <sys/devpoll.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class dev_poll_reactor
: public asio::detail::service_base<dev_poll_reactor<Own_Thread> >
{
public:
// Constructor.
dev_poll_reactor(asio::io_service& io_service)
: asio::detail::service_base<
dev_poll_reactor<Own_Thread> >(io_service),
mutex_(),
dev_poll_fd_(do_dev_poll_create()),
wait_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false)
{
// Start the reactor's internal thread only if needed.
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&dev_poll_reactor::call_run_thread, this));
}
// Add the interrupter's descriptor to /dev/poll.
::pollfd ev = { 0 };
ev.fd = interrupter_.read_descriptor();
ev.events = POLLIN | POLLERR;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
// Destructor.
~dev_poll_reactor()
{
shutdown_service();
::close(dev_poll_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
{
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLIN | POLLERR | POLLHUP;
if (write_op_queue_.has_operation(descriptor))
ev.events |= POLLOUT;
if (except_op_queue_.has_operation(descriptor))
ev.events |= POLLPRI;
interrupter_.interrupt();
}
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLOUT | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
if (except_op_queue_.has_operation(descriptor))
ev.events |= POLLPRI;
interrupter_.interrupt();
}
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLPRI | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
if (write_op_queue_.has_operation(descriptor))
ev.events |= POLLOUT;
interrupter_.interrupt();
}
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler);
need_mod = except_op_queue_.enqueue_operation(descriptor, handler)
&& need_mod;
if (need_mod)
{
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
interrupter_.interrupt();
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// dev_poll_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from /dev/poll.
::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLREMOVE;
interrupter_.interrupt();
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
timer_queues_.push_back(&timer_queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
if (timer_queues_[i] == &timer_queue)
{
timer_queues_.erase(timer_queues_.begin() + i);
return;
}
}
}
// Schedule a timer in the given timer queue to expire at the specified
// absolute time. The handler object will be invoked when the timer expires.
template <typename Time_Traits, typename Handler>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
std::size_t n = timer_queue.cancel_timer(token);
if (n > 0)
interrupter_.interrupt();
return n;
}
private:
friend class task_io_service<dev_poll_reactor<Own_Thread> >;
// Run /dev/poll once until interrupted or events are ready to be dispatched.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
cleanup_operations_and_timers(lock);
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
cleanup_operations_and_timers(lock);
return;
}
// Write the pending event registration changes to the /dev/poll descriptor.
std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
errno = 0;
int result = ::write(dev_poll_fd_,
&pending_event_changes_[0], events_size);
if (result != static_cast<int>(events_size))
{
for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
{
int descriptor = pending_event_changes_[i].fd;
asio::error_code ec = asio::error_code(
errno, asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
pending_event_changes_.clear();
pending_event_change_index_.clear();
int timeout = block ? get_timeout() : 0;
wait_in_progress_ = true;
lock.unlock();
// Block on the /dev/poll descriptor.
::pollfd events[128] = { { 0 } };
::dvpoll dp = { 0 };
dp.dp_fds = events;
dp.dp_nfds = 128;
dp.dp_timeout = timeout;
int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].fd;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else
{
bool more_reads = false;
bool more_writes = false;
bool more_except = false;
asio::error_code ec;
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
more_except = except_op_queue_.dispatch_operation(descriptor, ec);
else
more_except = except_op_queue_.has_operation(descriptor);
if (events[i].events & (POLLIN | POLLERR | POLLHUP))
more_reads = read_op_queue_.dispatch_operation(descriptor, ec);
else
more_reads = read_op_queue_.has_operation(descriptor);
if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
more_writes = write_op_queue_.dispatch_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
if ((events[i].events == POLLHUP)
&& !more_except && !more_reads && !more_writes)
{
// If we have only an POLLHUP event and no operations associated
// with the descriptor then we need to delete the descriptor from
// /dev/poll. The poll operation might produce POLLHUP events even
// if they are not specifically requested, so if we do not remove the
// descriptor we can end up in a tight polling loop.
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLREMOVE;
ev.revents = 0;
::write(dev_poll_fd_, &ev, sizeof(ev));
}
else
{
::pollfd ev = { 0 };
ev.fd = descriptor;
ev.events = POLLERR | POLLHUP;
if (more_reads)
ev.events |= POLLIN;
if (more_writes)
ev.events |= POLLOUT;
if (more_except)
ev.events |= POLLPRI;
ev.revents = 0;
int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
if (result != sizeof(ev))
{
ec = asio::error_code(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
timer_queues_[i]->dispatch_cancellations();
}
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
cleanup_operations_and_timers(lock);
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(dev_poll_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// Create the /dev/poll file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_dev_poll_create()
{
int fd = ::open("/dev/poll", O_RDWR);
if (fd == -1)
{
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::get_system_category()),
"/dev/poll"));
}
return fd;
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the /dev/poll DP_POLL operation. The timeout
// value is returned as a number of milliseconds. A return value of -1
// indicates that the poll should block indefinitely.
int get_timeout()
{
if (all_timer_queues_are_empty())
return -1;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
int milliseconds = minimum_wait_duration.total_milliseconds();
return milliseconds > 0 ? milliseconds : 1;
}
else
{
return 0;
}
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the dev_poll_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Clean up operations and timers. We must not hold the lock since the
// destructors may make calls back into this reactor. We make a copy of the
// vector of timer queues since the original may be modified while the lock
// is not held.
void cleanup_operations_and_timers(
asio::detail::mutex::scoped_lock& lock)
{
timer_queues_for_cleanup_ = timer_queues_;
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
timer_queues_for_cleanup_[i]->cleanup_timers();
}
// Add a pending event entry for the given descriptor.
::pollfd& add_pending_event_change(int descriptor)
{
hash_map<int, std::size_t>::iterator iter
= pending_event_change_index_.find(descriptor);
if (iter == pending_event_change_index_.end())
{
std::size_t index = pending_event_changes_.size();
pending_event_changes_.reserve(pending_event_changes_.size() + 1);
pending_event_change_index_.insert(std::make_pair(descriptor, index));
pending_event_changes_.push_back(::pollfd());
pending_event_changes_[index].fd = descriptor;
pending_event_changes_[index].revents = 0;
return pending_event_changes_[index];
}
else
{
return pending_event_changes_[iter->second];
}
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The /dev/poll file descriptor.
int dev_poll_fd_;
// Vector of /dev/poll events waiting to be written to the descriptor.
std::vector< ::pollfd> pending_event_changes_;
// Hash map to associate a descriptor with a pending event change index.
hash_map<int, std::size_t> pending_event_change_index_;
// Whether the DP_POLL operation is currently in progress
bool wait_in_progress_;
// The interrupter is used to break a blocking DP_POLL operation.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// A copy of the timer queues, used when cleaning up timers. The copy is
// stored as a class data member to avoid unnecessary memory allocation.
std::vector<timer_queue_base*> timer_queues_for_cleanup_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_DEV_POLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP

View File

@ -0,0 +1,40 @@
//
// dev_poll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 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_DEV_POLL_REACTOR_FWD_HPP
#define ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#if !defined(ASIO_DISABLE_DEV_POLL)
#if defined(__sun) // This service is only supported on Solaris.
// Define this to indicate that /dev/poll is supported on the target platform.
#define ASIO_HAS_DEV_POLL 1
namespace asio {
namespace detail {
template <bool Own_Thread>
class dev_poll_reactor;
} // namespace detail
} // namespace asio
#endif // defined(__sun)
#endif // !defined(ASIO_DISABLE_DEV_POLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP

View File

@ -155,10 +155,12 @@ public:
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
@ -189,10 +191,12 @@ public:
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
@ -219,10 +223,12 @@ public:
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
@ -251,10 +257,12 @@ public:
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
@ -419,23 +427,40 @@ private:
else
more_writes = write_op_queue_.has_operation(descriptor);
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLERR | EPOLLHUP;
if (more_reads)
ev.events |= EPOLLIN;
if (more_writes)
ev.events |= EPOLLOUT;
if (more_except)
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0)
if ((events[i].events == EPOLLHUP)
&& !more_except && !more_reads && !more_writes)
{
ec = asio::error_code(errno,
asio::error::system_category);
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
// If we have only an EPOLLHUP event and no operations associated
// with the descriptor then we need to delete the descriptor from
// epoll. The epoll_wait system call will produce EPOLLHUP events
// even if they are not specifically requested, so if we do not
// remove the descriptor we can end up in a tight loop of repeated
// calls to epoll_wait.
epoll_event ev = { 0, { 0 } };
epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
}
else
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLERR | EPOLLHUP;
if (more_reads)
ev.events |= EPOLLIN;
if (more_writes)
ev.events |= EPOLLOUT;
if (more_except)
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0 && errno == ENOENT)
result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
{
ec = asio::error_code(errno,
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
}
@ -493,7 +518,7 @@ private:
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::system_category),
asio::error::get_system_category()),
"epoll"));
}
return fd;
@ -531,7 +556,8 @@ private:
if (minimum_wait_duration > boost::posix_time::time_duration())
{
return minimum_wait_duration.total_milliseconds();
int milliseconds = minimum_wait_duration.total_milliseconds();
return milliseconds > 0 ? milliseconds : 1;
}
else
{

View File

@ -0,0 +1,219 @@
//
// handler_queue.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 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_HANDLER_QUEUE_HPP
#define ASIO_DETAIL_HANDLER_QUEUE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class handler_queue
: private noncopyable
{
public:
// Base class for handlers in the queue.
class handler
: private noncopyable
{
public:
void invoke()
{
invoke_func_(this);
}
void destroy()
{
destroy_func_(this);
}
protected:
typedef void (*invoke_func_type)(handler*);
typedef void (*destroy_func_type)(handler*);
handler(invoke_func_type invoke_func,
destroy_func_type destroy_func)
: next_(0),
invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
}
~handler()
{
}
private:
friend class handler_queue;
handler* next_;
invoke_func_type invoke_func_;
destroy_func_type destroy_func_;
};
// Smart point to manager handler lifetimes.
class scoped_ptr
: private noncopyable
{
public:
explicit scoped_ptr(handler* h)
: handler_(h)
{
}
~scoped_ptr()
{
if (handler_)
handler_->destroy();
}
handler* get() const
{
return handler_;
}
handler* release()
{
handler* tmp = handler_;
handler_ = 0;
return tmp;
}
private:
handler* handler_;
};
// Constructor.
handler_queue()
: front_(0),
back_(0)
{
}
// Wrap a handler to be pushed into the queue.
template <typename Handler>
static handler* wrap(Handler h)
{
// Allocate and construct an object to wrap the handler.
typedef handler_wrapper<Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(h);
handler_ptr<alloc_traits> ptr(raw_ptr, h);
return ptr.release();
}
// Get the handler at the front of the queue.
handler* front()
{
return front_;
}
// Pop a handler from the front of the queue.
void pop()
{
if (front_)
{
handler* tmp = front_;
front_ = front_->next_;
if (front_ == 0)
back_ = 0;
tmp->next_= 0;
}
}
// Push a handler on to the back of the queue.
void push(handler* h)
{
h->next_ = 0;
if (back_)
{
back_->next_ = h;
back_ = h;
}
else
{
front_ = back_ = h;
}
}
// Whether the queue is empty.
bool empty() const
{
return front_ == 0;
}
private:
// Template wrapper for handlers.
template <typename Handler>
class handler_wrapper
: public handler
{
public:
handler_wrapper(Handler h)
: handler(
&handler_wrapper<Handler>::do_call,
&handler_wrapper<Handler>::do_destroy),
handler_(h)
{
}
static void do_call(handler* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made.
Handler handler(h->handler_);
// Free the memory associated with the handler.
ptr.reset();
// Make the upcall.
asio_handler_invoke_helpers::invoke(handler, &handler);
}
static void do_destroy(handler* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
}
private:
Handler handler_;
};
// The front of the queue.
handler* front_;
// The back of the queue.
handler* back_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HANDLER_QUEUE_HPP

View File

@ -151,7 +151,7 @@ public:
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
read_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
@ -178,7 +178,7 @@ public:
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
@ -204,7 +204,7 @@ public:
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
@ -228,7 +228,7 @@ public:
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
@ -243,7 +243,7 @@ public:
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno,
asio::error::system_category);
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
@ -397,7 +397,7 @@ private:
if (events[i].flags & EV_ERROR)
{
asio::error_code error(
events[i].data, asio::error::system_category);
events[i].data, asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, error);
read_op_queue_.dispatch_all_operations(descriptor, error);
}
@ -428,7 +428,7 @@ private:
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code error(errno,
asio::error::system_category);
asio::error::get_system_category());
except_op_queue_.dispatch_all_operations(descriptor, error);
read_op_queue_.dispatch_all_operations(descriptor, error);
}
@ -440,7 +440,7 @@ private:
if (events[i].flags & EV_ERROR)
{
asio::error_code error(
events[i].data, asio::error::system_category);
events[i].data, asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, error);
}
else
@ -458,7 +458,7 @@ private:
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code error(errno,
asio::error::system_category);
asio::error::get_system_category());
write_op_queue_.dispatch_all_operations(descriptor, error);
}
}
@ -515,7 +515,7 @@ private:
boost::throw_exception(
asio::system_error(
asio::error_code(errno,
asio::error::system_category),
asio::error::get_system_category()),
"kqueue"));
}
return fd;

View File

@ -19,6 +19,7 @@
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
@ -27,6 +28,8 @@
#include <fcntl.h>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
@ -46,6 +49,13 @@ public:
write_descriptor_ = pipe_fds[1];
::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
}
else
{
asio::error_code ec(errno,
asio::error::get_system_category());
asio::system_error e(ec, "pipe_select_interrupter");
boost::throw_exception(e);
}
}
// Destructor.

View File

@ -48,7 +48,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"event");
boost::throw_exception(e);
}

View File

@ -58,7 +58,7 @@ public:
}
private:
fd_set fd_set_;
mutable fd_set fd_set_;
socket_type max_descriptor_;
};

View File

@ -51,7 +51,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
@ -70,7 +71,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
@ -83,7 +85,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}

View File

@ -53,7 +53,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"thread");
boost::throw_exception(e);
}

View File

@ -47,7 +47,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"tss");
boost::throw_exception(e);
}

View File

@ -157,7 +157,8 @@ public:
if (int err = reactor_.register_descriptor(sock.get()))
{
ec = asio::error_code(err, asio::error::system_category);
ec = asio::error_code(err,
asio::error::get_system_category());
return ec;
}
@ -181,7 +182,8 @@ public:
if (int err = reactor_.register_descriptor(native_socket))
{
ec = asio::error_code(err, asio::error::system_category);
ec = asio::error_code(err,
asio::error::get_system_category());
return ec;
}
@ -450,7 +452,7 @@ public:
}
endpoint_type endpoint;
socket_addr_len_type addr_len = endpoint.capacity();
std::size_t addr_len = endpoint.capacity();
if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
return endpoint_type();
endpoint.resize(addr_len);
@ -468,7 +470,7 @@ public:
}
endpoint_type endpoint;
socket_addr_len_type addr_len = endpoint.capacity();
std::size_t addr_len = endpoint.capacity();
if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
return endpoint_type();
endpoint.resize(addr_len);
@ -624,7 +626,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
@ -645,7 +647,7 @@ public:
// A request to receive 0 bytes on a stream socket is a no-op.
if (total_buffer_size == 0)
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error_code(), 0));
return;
}
@ -658,7 +660,7 @@ public:
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{
this->io_service().post(bind_handler(handler, ec, 0));
this->get_io_service().post(bind_handler(handler, ec, 0));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
@ -666,7 +668,7 @@ public:
reactor_.start_write_op(impl.socket_,
send_handler<ConstBufferSequence, Handler>(
impl.socket_, this->io_service(), buffers, flags, handler));
impl.socket_, this->get_io_service(), buffers, flags, handler));
}
}
@ -804,7 +806,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
@ -816,7 +818,7 @@ public:
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{
this->io_service().post(bind_handler(handler, ec, 0));
this->get_io_service().post(bind_handler(handler, ec, 0));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
@ -824,7 +826,7 @@ public:
reactor_.start_write_op(impl.socket_,
send_to_handler<ConstBufferSequence, Handler>(
impl.socket_, this->io_service(), buffers,
impl.socket_, this->get_io_service(), buffers,
destination, flags, handler));
}
}
@ -975,7 +977,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
@ -996,7 +998,7 @@ public:
// A request to receive 0 bytes on a stream socket is a no-op.
if (total_buffer_size == 0)
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error_code(), 0));
return;
}
@ -1009,7 +1011,7 @@ public:
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{
this->io_service().post(bind_handler(handler, ec, 0));
this->get_io_service().post(bind_handler(handler, ec, 0));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
@ -1019,13 +1021,13 @@ public:
{
reactor_.start_except_op(impl.socket_,
receive_handler<MutableBufferSequence, Handler>(
impl.socket_, this->io_service(), buffers, flags, handler));
impl.socket_, this->get_io_service(), buffers, flags, handler));
}
else
{
reactor_.start_read_op(impl.socket_,
receive_handler<MutableBufferSequence, Handler>(
impl.socket_, this->io_service(), buffers, flags, handler));
impl.socket_, this->get_io_service(), buffers, flags, handler));
}
}
}
@ -1073,7 +1075,7 @@ public:
for (;;)
{
// Try to complete the operation without blocking.
socket_addr_len_type addr_len = sender_endpoint.capacity();
std::size_t addr_len = sender_endpoint.capacity();
int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags,
sender_endpoint.data(), &addr_len, ec);
@ -1144,7 +1146,7 @@ public:
}
// Receive some data.
socket_addr_len_type addr_len = sender_endpoint_.capacity();
std::size_t addr_len = sender_endpoint_.capacity();
asio::error_code ec;
int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_,
sender_endpoint_.data(), &addr_len, ec);
@ -1181,7 +1183,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
}
else
@ -1193,7 +1195,7 @@ public:
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{
this->io_service().post(bind_handler(handler, ec, 0));
this->get_io_service().post(bind_handler(handler, ec, 0));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
@ -1201,7 +1203,7 @@ public:
reactor_.start_read_op(impl.socket_,
receive_from_handler<MutableBufferSequence, Handler>(
impl.socket_, this->io_service(), buffers,
impl.socket_, this->get_io_service(), buffers,
sender_endpoint, flags, handler));
}
}
@ -1242,7 +1244,7 @@ public:
// Try to complete the operation without blocking.
asio::error_code ec;
socket_holder new_socket;
socket_addr_len_type addr_len = 0;
std::size_t addr_len = 0;
if (peer_endpoint)
{
addr_len = peer_endpoint->capacity();
@ -1327,7 +1329,7 @@ public:
// Accept the waiting connection.
asio::error_code ec;
socket_holder new_socket;
socket_addr_len_type addr_len = 0;
std::size_t addr_len = 0;
if (peer_endpoint_)
{
addr_len = peer_endpoint_->capacity();
@ -1384,12 +1386,12 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor));
}
else if (peer.is_open())
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::already_open));
}
else
@ -1401,7 +1403,7 @@ public:
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{
this->io_service().post(bind_handler(handler, ec));
this->get_io_service().post(bind_handler(handler, ec));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
@ -1409,7 +1411,7 @@ public:
reactor_.start_read_op(impl.socket_,
accept_handler<Socket, Handler>(
impl.socket_, this->io_service(),
impl.socket_, this->get_io_service(),
peer, impl.protocol_, peer_endpoint,
(impl.flags_ & implementation_type::enable_connection_aborted) != 0,
handler));
@ -1489,7 +1491,7 @@ public:
if (connect_error)
{
ec = asio::error_code(connect_error,
asio::error::system_category);
asio::error::get_system_category());
io_service_.post(bind_handler(handler_, ec));
return true;
}
@ -1515,7 +1517,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor));
return;
}
@ -1527,7 +1529,7 @@ public:
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{
this->io_service().post(bind_handler(handler, ec));
this->get_io_service().post(bind_handler(handler, ec));
return;
}
impl.flags_ |= implementation_type::internal_non_blocking;
@ -1541,7 +1543,7 @@ public:
{
// The connect operation has finished successfully so we need to post the
// handler immediately.
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error_code()));
}
else if (ec == asio::error::in_progress
@ -1551,13 +1553,13 @@ public:
// until the socket becomes writeable.
boost::shared_ptr<bool> completed(new bool(false));
reactor_.start_write_and_except_ops(impl.socket_,
connect_handler<Handler>(
impl.socket_, completed, this->io_service(), reactor_, handler));
connect_handler<Handler>(impl.socket_, completed,
this->get_io_service(), reactor_, handler));
}
else
{
// The connect operation has failed, so post the handler immediately.
this->io_service().post(bind_handler(handler, ec));
this->get_io_service().post(bind_handler(handler, ec));
}
}

View File

@ -213,7 +213,7 @@ public:
start_work_thread();
work_io_service_->post(
resolve_query_handler<Handler>(
impl, query, this->io_service(), handler));
impl, query, this->get_io_service(), handler));
}
}
@ -309,7 +309,7 @@ public:
start_work_thread();
work_io_service_->post(
resolve_endpoint_handler<Handler>(
impl, endpoint, this->io_service(), handler));
impl, endpoint, this->get_io_service(), handler));
}
}

View File

@ -26,9 +26,6 @@
#include <cerrno>
#include <boost/detail/workaround.hpp>
#include <new>
#if defined(__MACH__) && defined(__APPLE__)
# include <AvailabilityMacros.h>
#endif // defined(__MACH__) && defined(__APPLE__)
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
@ -38,12 +35,24 @@ namespace asio {
namespace detail {
namespace socket_ops {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
struct msghdr { int msg_namelen; };
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#if defined(__hpux)
// HP-UX doesn't declare these functions extern "C", so they are declared again
// here to avoid linker errors about undefined symbols.
extern "C" char* if_indextoname(unsigned int, char*);
extern "C" unsigned int if_nametoindex(const char*);
#endif // defined(__hpux)
inline void clear_error(asio::error_code& ec)
{
errno = 0;
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
WSASetLastError(0);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#else
errno = 0;
#endif
ec = asio::error_code();
}
@ -53,22 +62,36 @@ inline ReturnType error_wrapper(ReturnType return_value,
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
ec = asio::error_code(WSAGetLastError(),
asio::error::system_category);
asio::error::get_system_category());
#else
ec = asio::error_code(errno, asio::error::system_category);
ec = asio::error_code(errno,
asio::error::get_system_category());
#endif
return return_value;
}
template <typename SockLenType>
inline socket_type call_accept(SockLenType msghdr::*,
socket_type s, socket_addr_type* addr, std::size_t* addrlen)
{
SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
if (addrlen)
*addrlen = (std::size_t)tmp_addrlen;
return result;
}
inline socket_type accept(socket_type s, socket_addr_type* addr,
socket_addr_len_type* addrlen, asio::error_code& ec)
std::size_t* addrlen, asio::error_code& ec)
{
clear_error(ec);
#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec);
socket_type new_s = error_wrapper(call_accept(
&msghdr::msg_namelen, s, addr, addrlen), ec);
if (new_s == invalid_socket)
return new_s;
#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
int optval = 1;
int result = error_wrapper(::setsockopt(new_s,
SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
@ -77,25 +100,45 @@ inline socket_type accept(socket_type s, socket_addr_type* addr,
::close(new_s);
return invalid_socket;
}
#endif
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
clear_error(ec);
#endif
return new_s;
#else
return error_wrapper(::accept(s, addr, addrlen), ec);
#endif
}
template <typename SockLenType>
inline int call_bind(SockLenType msghdr::*,
socket_type s, const socket_addr_type* addr, std::size_t addrlen)
{
return ::bind(s, addr, (SockLenType)addrlen);
}
inline int bind(socket_type s, const socket_addr_type* addr,
socket_addr_len_type addrlen, asio::error_code& ec)
std::size_t addrlen, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::bind(s, addr, addrlen), ec);
int result = error_wrapper(call_bind(
&msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
#endif
return result;
}
inline int close(socket_type s, asio::error_code& ec)
{
clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::closesocket(s), ec);
int result = error_wrapper(::closesocket(s), ec);
# if defined(UNDER_CE)
if (result == 0)
clear_error(ec);
# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::close(s), ec);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@ -104,20 +147,43 @@ inline int close(socket_type s, asio::error_code& ec)
inline int shutdown(socket_type s, int what, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::shutdown(s, what), ec);
int result = error_wrapper(::shutdown(s, what), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
#endif
return result;
}
template <typename SockLenType>
inline int call_connect(SockLenType msghdr::*,
socket_type s, const socket_addr_type* addr, std::size_t addrlen)
{
return ::connect(s, addr, (SockLenType)addrlen);
}
inline int connect(socket_type s, const socket_addr_type* addr,
socket_addr_len_type addrlen, asio::error_code& ec)
std::size_t addrlen, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::connect(s, addr, addrlen), ec);
int result = error_wrapper(call_connect(
&msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
#endif
return result;
}
inline int listen(socket_type s, int backlog, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::listen(s, backlog), ec);
int result = error_wrapper(::listen(s, backlog), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
#endif
return result;
}
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@ -148,6 +214,28 @@ inline void init_buf(buf& b, const void* data, size_t size)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
}
inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
{
name = addr;
}
inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
{
name = const_cast<socket_addr_type*>(addr);
}
template <typename T>
inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
{
name = reinterpret_cast<T>(addr);
}
template <typename T>
inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
{
name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
}
inline int recv(socket_type s, buf* bufs, size_t count, int flags,
asio::error_code& ec)
{
@ -161,22 +249,20 @@ inline int recv(socket_type s, buf* bufs, size_t count, int flags,
recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
if (result != 0)
return -1;
# if defined(UNDER_CE)
clear_error(ec);
# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msghdr msg = msghdr();
msg.msg_iov = bufs;
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
return error_wrapper(::recvmsg(s, &msg, flags), ec);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
}
inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
socket_addr_type* addr, socket_addr_len_type* addrlen,
socket_addr_type* addr, std::size_t* addrlen,
asio::error_code& ec)
{
clear_error(ec);
@ -185,25 +271,22 @@ inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
DWORD recv_buf_count = static_cast<DWORD>(count);
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int tmp_addrlen = (int)*addrlen;
int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
&bytes_transferred, &recv_flags, addr, addrlen, 0, 0), ec);
&bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
*addrlen = (std::size_t)tmp_addrlen;
if (result != 0)
return -1;
# if defined(UNDER_CE)
clear_error(ec);
# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg;
#if defined(__MACH__) && defined(__APPLE__) \
&& (MAC_OS_X_VERSION_MAX_ALLOWED < 1040)
msg.msg_name = reinterpret_cast<char*>(addr);
#else
msg.msg_name = addr;
#endif
msghdr msg = msghdr();
init_msghdr_msg_name(msg.msg_name, addr);
msg.msg_namelen = *addrlen;
msg.msg_iov = bufs;
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
*addrlen = msg.msg_namelen;
return result;
@ -223,16 +306,14 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags,
send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
if (result != 0)
return -1;
# if defined(UNDER_CE)
clear_error(ec);
# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msghdr msg = msghdr();
msg.msg_iov = const_cast<buf*>(bufs);
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
#if defined(__linux__)
flags |= MSG_NOSIGNAL;
#endif // defined(__linux__)
@ -241,7 +322,7 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags,
}
inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
const socket_addr_type* addr, socket_addr_len_type addrlen,
const socket_addr_type* addr, std::size_t addrlen,
asio::error_code& ec)
{
clear_error(ec);
@ -250,24 +331,20 @@ inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
DWORD send_buf_count = static_cast<DWORD>(count);
DWORD bytes_transferred = 0;
int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
send_buf_count, &bytes_transferred, flags, addr, addrlen, 0, 0), ec);
send_buf_count, &bytes_transferred, flags, addr,
static_cast<int>(addrlen), 0, 0), ec);
if (result != 0)
return -1;
# if defined(UNDER_CE)
clear_error(ec);
# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg;
#if defined(__MACH__) && defined(__APPLE__) \
&& (MAC_OS_X_VERSION_MAX_ALLOWED < 1040)
msg.msg_name = reinterpret_cast<char*>(const_cast<socket_addr_type*>(addr));
#else
msg.msg_name = const_cast<socket_addr_type*>(addr);
#endif
msghdr msg = msghdr();
init_msghdr_msg_name(msg.msg_name, addr);
msg.msg_namelen = addrlen;
msg.msg_iov = const_cast<buf*>(bufs);
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
#if defined(__linux__)
flags |= MSG_NOSIGNAL;
#endif // defined(__linux__)
@ -295,6 +372,10 @@ inline socket_type socket(int af, int type, int protocol,
reinterpret_cast<const char*>(&optval), sizeof(optval));
}
# if defined(UNDER_CE)
clear_error(ec);
# endif
return s;
#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
socket_type s = error_wrapper(::socket(af, type, protocol), ec);
@ -316,8 +397,17 @@ inline socket_type socket(int af, int type, int protocol,
#endif
}
template <typename SockLenType>
inline int call_setsockopt(SockLenType msghdr::*,
socket_type s, int level, int optname,
const void* optval, std::size_t optlen)
{
return ::setsockopt(s, level, optname,
(const char*)optval, (SockLenType)optlen);
}
inline int setsockopt(socket_type s, int level, int optname,
const void* optval, size_t optlen, asio::error_code& ec)
const void* optval, std::size_t optlen, asio::error_code& ec)
{
if (level == custom_socket_option_level && optname == always_fail_option)
{
@ -342,15 +432,27 @@ inline int setsockopt(socket_type s, int level, int optname,
}
ec = asio::error::fault;
return -1;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#else // defined(__BORLANDC__)
clear_error(ec);
return error_wrapper(::setsockopt(s, level, optname,
reinterpret_cast<const char*>(optval), static_cast<int>(optlen)), ec);
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
return error_wrapper(::setsockopt(s, level, optname, optval,
static_cast<socklen_t>(optlen)), ec);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
s, level, optname, optval, optlen), ec);
# if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
# endif
return result;
#endif // defined(__BORLANDC__)
}
template <typename SockLenType>
inline int call_getsockopt(SockLenType msghdr::*,
socket_type s, int level, int optname,
void* optval, std::size_t* optlen)
{
SockLenType tmp_optlen = (SockLenType)*optlen;
int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
*optlen = (std::size_t)tmp_optlen;
return result;
}
inline int getsockopt(socket_type s, int level, int optname, void* optval,
@ -394,10 +496,8 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval,
return -1;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
int tmp_optlen = static_cast<int>(*optlen);
int result = error_wrapper(::getsockopt(s, level, optname,
reinterpret_cast<char*>(optval), &tmp_optlen), ec);
*optlen = static_cast<size_t>(tmp_optlen);
int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
s, level, optname, optval, optlen), ec);
if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
&& ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
{
@ -409,13 +509,15 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval,
*static_cast<DWORD*>(optval) = 1;
clear_error(ec);
}
# if defined(UNDER_CE)
if (result == 0)
clear_error(ec);
# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
socklen_t tmp_optlen = static_cast<socklen_t>(*optlen);
int result = error_wrapper(::getsockopt(s, level, optname,
optval, &tmp_optlen), ec);
*optlen = static_cast<size_t>(tmp_optlen);
int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
s, level, optname, optval, optlen), ec);
#if defined(__linux__)
if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
&& (optname == SO_SNDBUF || optname == SO_RCVBUF))
@ -432,18 +534,50 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval,
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
}
template <typename SockLenType>
inline int call_getpeername(SockLenType msghdr::*,
socket_type s, socket_addr_type* addr, std::size_t* addrlen)
{
SockLenType tmp_addrlen = (SockLenType)*addrlen;
int result = ::getpeername(s, addr, &tmp_addrlen);
*addrlen = (std::size_t)tmp_addrlen;
return result;
}
inline int getpeername(socket_type s, socket_addr_type* addr,
socket_addr_len_type* addrlen, asio::error_code& ec)
std::size_t* addrlen, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::getpeername(s, addr, addrlen), ec);
int result = error_wrapper(call_getpeername(
&msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
#endif
return result;
}
template <typename SockLenType>
inline int call_getsockname(SockLenType msghdr::*,
socket_type s, socket_addr_type* addr, std::size_t* addrlen)
{
SockLenType tmp_addrlen = (SockLenType)*addrlen;
int result = ::getsockname(s, addr, &tmp_addrlen);
*addrlen = (std::size_t)tmp_addrlen;
return result;
}
inline int getsockname(socket_type s, socket_addr_type* addr,
socket_addr_len_type* addrlen, asio::error_code& ec)
std::size_t* addrlen, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::getsockname(s, addr, addrlen), ec);
int result = error_wrapper(call_getsockname(
&msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
#endif
return result;
}
inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
@ -451,7 +585,12 @@ inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
{
clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::ioctlsocket(s, cmd, arg), ec);
int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
# if defined(UNDER_CE)
if (result == 0)
clear_error(ec);
# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::ioctl(s, cmd, arg), ec);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@ -482,8 +621,22 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds,
&& timeout->tv_usec > 0 && timeout->tv_usec < 1000)
timeout->tv_usec = 1000;
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::select(nfds, readfds,
#if defined(__hpux) && defined(__HP_aCC)
timespec ts;
ts.tv_sec = timeout ? timeout->tv_sec : 0;
ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
return error_wrapper(::pselect(nfds, readfds,
writefds, exceptfds, timeout ? &ts : 0, 0), ec);
#else
int result = error_wrapper(::select(nfds, readfds,
writefds, exceptfds, timeout), ec);
# if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result >= 0)
clear_error(ec);
# endif
return result;
#endif
}
inline int poll_read(socket_type s, asio::error_code& ec)
@ -493,7 +646,12 @@ inline int poll_read(socket_type s, asio::error_code& ec)
FD_ZERO(&fds);
FD_SET(s, &fds);
clear_error(ec);
return error_wrapper(::select(s, &fds, 0, 0, 0), ec);
int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
# if defined(UNDER_CE)
if (result >= 0)
clear_error(ec);
# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
pollfd fds;
fds.fd = s;
@ -511,7 +669,12 @@ inline int poll_write(socket_type s, asio::error_code& ec)
FD_ZERO(&fds);
FD_SET(s, &fds);
clear_error(ec);
return error_wrapper(::select(s, 0, &fds, 0, 0), ec);
int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
# if defined(UNDER_CE)
if (result >= 0)
clear_error(ec);
# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
pollfd fds;
fds.fd = s;
@ -559,9 +722,17 @@ inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
}
DWORD string_length = static_cast<DWORD>(length);
#if defined(BOOST_NO_ANSI_APIS)
LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
int result = error_wrapper(::WSAAddressToStringW(
reinterpret_cast<sockaddr*>(&address),
address_length, 0, string_buffer, &string_length), ec);
::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
#else
int result = error_wrapper(::WSAAddressToStringA(
reinterpret_cast<sockaddr*>(&address),
address_length, 0, dest, &string_length), ec);
#endif
// Windows may set error code on success.
if (result != socket_error_retval)
@ -605,10 +776,20 @@ inline int inet_pton(int af, const char* src, void* dest,
sockaddr_storage_type address;
int address_length = sizeof(sockaddr_storage_type);
#if defined(BOOST_NO_ANSI_APIS)
int num_wide_chars = strlen(src) + 1;
LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
int result = error_wrapper(::WSAStringToAddressW(
wide_buffer, af, 0,
reinterpret_cast<sockaddr*>(&address),
&address_length), ec);
#else
int result = error_wrapper(::WSAStringToAddressA(
const_cast<char*>(src), af, 0,
reinterpret_cast<sockaddr*>(&address),
&address_length), ec);
#endif
if (af == AF_INET)
{
@ -642,6 +823,11 @@ inline int inet_pton(int af, const char* src, void* dest,
if (result == socket_error_retval && !ec)
ec = asio::error::invalid_argument;
#if defined(UNDER_CE)
if (result != socket_error_retval)
clear_error(ec);
#endif
return result == socket_error_retval ? -1 : 1;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int result = error_wrapper(::inet_pton(af, src, dest), ec);
@ -668,7 +854,12 @@ inline int inet_pton(int af, const char* src, void* dest,
inline int gethostname(char* name, int namelen, asio::error_code& ec)
{
clear_error(ec);
return error_wrapper(::gethostname(name, namelen), ec);
int result = error_wrapper(::gethostname(name, namelen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
if (result == 0)
clear_error(ec);
#endif
return result;
}
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
@ -707,6 +898,9 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af,
hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
if (!retval)
return 0;
# if defined(UNDER_CE)
clear_error(ec);
# endif
*result = *retval;
return retval;
#elif defined(__sun) || defined(__QNX__)
@ -755,6 +949,9 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
hostent* retval = error_wrapper(::gethostbyname(name), ec);
if (!retval)
return 0;
# if defined(UNDER_CE)
clear_error(ec);
# endif
*result = *retval;
return result;
#elif defined(__sun) || defined(__QNX__)
@ -1373,7 +1570,7 @@ inline int getaddrinfo_emulation(const char* host, const char* service,
}
inline asio::error_code getnameinfo_emulation(
const socket_addr_type* sa, socket_addr_len_type salen, char* host,
const socket_addr_type* sa, std::size_t salen, char* host,
std::size_t hostlen, char* serv, std::size_t servlen, int flags,
asio::error_code& ec)
{
@ -1526,10 +1723,10 @@ inline asio::error_code translate_addrinfo_error(int error)
default: // Possibly the non-portable EAI_SYSTEM.
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return asio::error_code(
WSAGetLastError(), asio::error::system_category);
WSAGetLastError(), asio::error::get_system_category());
#else
return asio::error_code(
errno, asio::error::system_category);
errno, asio::error::get_system_category());
#endif
}
}
@ -1540,7 +1737,7 @@ inline asio::error_code getaddrinfo(const char* host,
{
clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
// Building for Windows XP, Windows Server 2003, or later.
int error = ::getaddrinfo(host, service, hints, result);
return ec = translate_addrinfo_error(error);
@ -1571,7 +1768,7 @@ inline asio::error_code getaddrinfo(const char* host,
inline void freeaddrinfo(addrinfo_type* ai)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
// Building for Windows XP, Windows Server 2003, or later.
::freeaddrinfo(ai);
# else
@ -1595,11 +1792,11 @@ inline void freeaddrinfo(addrinfo_type* ai)
}
inline asio::error_code getnameinfo(const socket_addr_type* addr,
socket_addr_len_type addrlen, char* host, std::size_t hostlen,
std::size_t addrlen, char* host, std::size_t hostlen,
char* serv, std::size_t servlen, int flags, asio::error_code& ec)
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
// Building for Windows XP, Windows Server 2003, or later.
clear_error(ec);
int error = ::getnameinfo(addr, addrlen, host, static_cast<DWORD>(hostlen),
@ -1608,7 +1805,7 @@ inline asio::error_code getnameinfo(const socket_addr_type* addr,
# else
// Building for Windows 2000 or earlier.
typedef int (WSAAPI *gni_t)(const socket_addr_type*,
socket_addr_len_type, char*, std::size_t, char*, std::size_t, int);
int, char*, std::size_t, char*, std::size_t, int);
if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
{
if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))

View File

@ -52,7 +52,7 @@ public:
using namespace std; // For memset.
sockaddr_in4_type addr;
socket_addr_len_type addr_len = sizeof(addr);
std::size_t addr_len = sizeof(addr);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");

View File

@ -29,12 +29,12 @@
# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER) || defined(__BORLANDC__)
# pragma message("Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately")
# pragma message("Assuming _WIN32_WINNT=0x0500 (i.e. Windows 2000 target)")
# pragma message("Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)")
# else // defined(_MSC_VER) || defined(__BORLANDC__)
# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately
# warning Assuming _WIN32_WINNT=0x0500 (i.e. Windows 2000 target)
# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
# define _WIN32_WINNT 0x0500
# define _WIN32_WINNT 0x0501
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER)
# if defined(_WIN32) && !defined(WIN32)
@ -80,7 +80,9 @@
# undef ASIO_WSPIAPI_H_DEFINED
# endif // defined(ASIO_WSPIAPI_H_DEFINED)
# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
# if defined(_MSC_VER) || defined(__BORLANDC__)
# if defined(UNDER_CE)
# pragma comment(lib, "ws2.lib")
# elif defined(_MSC_VER) || defined(__BORLANDC__)
# pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "mswsock.lib")
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
@ -116,7 +118,6 @@ const int socket_error_retval = SOCKET_ERROR;
const int max_addr_v4_str_len = 256;
const int max_addr_v6_str_len = 256;
typedef sockaddr socket_addr_type;
typedef int socket_addr_len_type;
typedef in_addr in4_addr_type;
typedef ip_mreq in4_mreq_type;
typedef sockaddr_in sockaddr_in4_type;
@ -154,7 +155,6 @@ const int socket_error_retval = -1;
const int max_addr_v4_str_len = INET_ADDRSTRLEN;
const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;
typedef sockaddr socket_addr_type;
typedef socklen_t socket_addr_len_type;
typedef in_addr in4_addr_type;
typedef ip_mreq in4_mreq_type;
typedef sockaddr_in sockaddr_in4_type;

View File

@ -135,9 +135,9 @@ public:
handler_base* last_waiter_;
// Storage for posted handlers.
typedef boost::aligned_storage<64> handler_storage_type;
typedef boost::aligned_storage<128> handler_storage_type;
#if defined(__BORLANDC__)
boost::aligned_storage<64> handler_storage_;
boost::aligned_storage<128> handler_storage_;
#else
handler_storage_type handler_storage_;
#endif
@ -235,7 +235,7 @@ public:
void* do_handler_allocate(std::size_t size)
{
#if defined(__BORLANDC__)
BOOST_ASSERT(size <= boost::aligned_storage<64>::size);
BOOST_ASSERT(size <= boost::aligned_storage<128>::size);
#else
BOOST_ASSERT(size <= strand_impl::handler_storage_type::size);
#endif
@ -276,7 +276,7 @@ public:
if (impl_->first_waiter_ == 0)
impl_->last_waiter_ = 0;
lock.unlock();
service_impl_.io_service().post(
service_impl_.get_io_service().post(
invoke_current_handler(service_impl_, impl_));
}
}
@ -429,7 +429,7 @@ public:
// This handler now has the lock, so can be dispatched immediately.
impl->current_handler_ = ptr.get();
lock.unlock();
this->io_service().dispatch(invoke_current_handler(*this, impl));
this->get_io_service().dispatch(invoke_current_handler(*this, impl));
ptr.release();
}
else
@ -469,7 +469,7 @@ public:
// This handler now has the lock, so can be dispatched immediately.
impl->current_handler_ = ptr.get();
lock.unlock();
this->io_service().post(invoke_current_handler(*this, impl));
this->get_io_service().post(invoke_current_handler(*this, impl));
ptr.release();
}
else

View File

@ -23,6 +23,7 @@
#include "asio/detail/event.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/handler_queue.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/task_io_service_fwd.hpp"
@ -42,12 +43,11 @@ public:
task_(use_service<Task>(io_service)),
task_interrupted_(true),
outstanding_work_(0),
handler_queue_(&task_handler_),
handler_queue_end_(&task_handler_),
stopped_(false),
shutdown_(false),
first_idle_thread_(0)
{
handler_queue_.push(&task_handler_);
}
void init(size_t /*concurrency_hint*/)
@ -62,17 +62,16 @@ public:
lock.unlock();
// Destroy handler objects.
while (handler_queue_)
while (!handler_queue_.empty())
{
handler_base* h = handler_queue_;
handler_queue_ = h->next_;
handler_queue::handler* h = handler_queue_.front();
handler_queue_.pop();
if (h != &task_handler_)
h->destroy();
}
// Reset handler queue to initial state.
handler_queue_ = &task_handler_;
handler_queue_end_ = &task_handler_;
handler_queue_.push(&task_handler_);
}
// Run the event loop until interrupted or no more work.
@ -173,10 +172,7 @@ public:
void post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
typedef handler_wrapper<Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr, handler);
handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
asio::detail::mutex::scoped_lock lock(mutex_);
@ -185,15 +181,7 @@ public:
return;
// Add the handler to the end of the queue.
if (handler_queue_end_)
{
handler_queue_end_->next_ = ptr.get();
handler_queue_end_ = ptr.get();
}
else
{
handler_queue_ = handler_queue_end_ = ptr.get();
}
handler_queue_.push(ptr.get());
ptr.release();
// An undelivered handler is treated as unfinished work.
@ -227,29 +215,28 @@ private:
bool task_has_run = false;
while (!stopped_)
{
if (handler_queue_)
if (!handler_queue_.empty())
{
// Prepare to execute first handler from queue.
handler_base* h = handler_queue_;
handler_queue_ = h->next_;
if (handler_queue_ == 0)
handler_queue_end_ = 0;
h->next_ = 0;
handler_queue::handler* h = handler_queue_.front();
handler_queue_.pop();
if (h == &task_handler_)
{
bool more_handlers = (handler_queue_ != 0);
bool more_handlers = (!handler_queue_.empty());
task_interrupted_ = more_handlers || polling;
lock.unlock();
// If the task has already run and we're polling then we're done.
if (task_has_run && polling)
{
task_interrupted_ = true;
handler_queue_.push(&task_handler_);
ec = asio::error_code();
return 0;
}
task_has_run = true;
lock.unlock();
task_cleanup c(lock, *this);
// Run the task. May throw an exception. Only block if the handler
@ -263,7 +250,7 @@ private:
handler_cleanup c(lock, *this);
// Invoke the handler. May throw an exception.
h->call(); // call() deletes the handler object
h->invoke(); // invoke() deletes the handler object
ec = asio::error_code();
return 1;
@ -330,94 +317,9 @@ private:
}
}
// Helper class to perform task-related operations on block exit.
class task_cleanup;
friend class task_cleanup;
// The base class for all handler wrappers. A function pointer is used
// instead of virtual functions to avoid the associated overhead.
class handler_base
{
public:
typedef void (*call_func_type)(handler_base*);
typedef void (*destroy_func_type)(handler_base*);
handler_base(call_func_type call_func, destroy_func_type destroy_func)
: next_(0),
call_func_(call_func),
destroy_func_(destroy_func)
{
}
void call()
{
call_func_(this);
}
void destroy()
{
destroy_func_(this);
}
protected:
// Prevent deletion through this type.
~handler_base()
{
}
private:
friend class task_io_service<Task>;
friend class task_cleanup;
handler_base* next_;
call_func_type call_func_;
destroy_func_type destroy_func_;
};
// Template wrapper for handlers.
template <typename Handler>
class handler_wrapper
: public handler_base
{
public:
handler_wrapper(Handler handler)
: handler_base(&handler_wrapper<Handler>::do_call,
&handler_wrapper<Handler>::do_destroy),
handler_(handler)
{
}
static void do_call(handler_base* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made.
Handler handler(h->handler_);
// Free the memory associated with the handler.
ptr.reset();
// Make the upcall.
asio_handler_invoke_helpers::invoke(handler, &handler);
}
static void do_destroy(handler_base* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
}
private:
Handler handler_;
};
// Helper class to perform task-related operations on block exit.
class task_cleanup
{
public:
@ -433,20 +335,7 @@ private:
// Reinsert the task at the end of the handler queue.
lock_.lock();
task_io_service_.task_interrupted_ = true;
task_io_service_.task_handler_.next_ = 0;
if (task_io_service_.handler_queue_end_)
{
task_io_service_.handler_queue_end_->next_
= &task_io_service_.task_handler_;
task_io_service_.handler_queue_end_
= &task_io_service_.task_handler_;
}
else
{
task_io_service_.handler_queue_
= task_io_service_.handler_queue_end_
= &task_io_service_.task_handler_;
}
task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
}
private:
@ -487,11 +376,11 @@ private:
// Handler object to represent the position of the task in the queue.
class task_handler
: public handler_base
: public handler_queue::handler
{
public:
task_handler()
: handler_base(0, 0)
: handler_queue::handler(0, 0)
{
}
} task_handler_;
@ -502,11 +391,8 @@ private:
// The count of unfinished work.
int outstanding_work_;
// The start of a linked list of handlers that are ready to be delivered.
handler_base* handler_queue_;
// The end of a linked list of handlers that are ready to be delivered.
handler_base* handler_queue_end_;
// The queue of handlers that are ready to be delivered.
handler_queue handler_queue_;
// Flag to indicate that the dispatcher has been stopped.
bool stopped_;

View File

@ -24,7 +24,11 @@
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_thread.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_thread.hpp"
# if defined(UNDER_CE)
# include "asio/detail/wince_thread.hpp"
# else
# include "asio/detail/win_thread.hpp"
# endif
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_thread.hpp"
#else
@ -37,7 +41,11 @@ namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_thread thread;
#elif defined(BOOST_WINDOWS)
# if defined(UNDER_CE)
typedef wince_thread thread;
# else
typedef win_thread thread;
# endif
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_thread thread;
#endif

View File

@ -162,13 +162,7 @@ public:
// Destroy timers that are waiting to be cleaned up.
virtual void cleanup_timers()
{
while (cleanup_timers_)
{
timer_base* next_timer = cleanup_timers_->next_;
cleanup_timers_->next_ = 0;
cleanup_timers_->destroy();
cleanup_timers_ = next_timer;
}
destroy_timer_list(cleanup_timers_);
}
// Destroy all timers.
@ -181,11 +175,12 @@ public:
timer_base* t = i->second;
typename hash_map<void*, timer_base*>::iterator old_i = i++;
timers_.erase(old_i);
t->destroy();
destroy_timer_list(t);
}
heap_.clear();
timers_.clear();
cleanup_timers();
destroy_timer_list(cancelled_timers_);
destroy_timer_list(cleanup_timers_);
}
private:
@ -367,6 +362,18 @@ private:
}
}
// Destroy all timers in a linked list.
void destroy_timer_list(timer_base*& t)
{
while (t)
{
timer_base* next = t->next_;
t->next_ = 0;
t->destroy();
t = next;
}
}
// A hash of timer token to linked lists of timers.
hash_map<void*, timer_base*> timers_;

View File

@ -49,7 +49,7 @@ public:
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::system_category),
asio::error::get_system_category()),
"event");
boost::throw_exception(e);
}

View File

@ -33,7 +33,9 @@
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
#include "asio/detail/win_iocp_operation.hpp"
#include "asio/detail/mutex.hpp"
namespace asio {
namespace detail {
@ -51,7 +53,9 @@ public:
iocp_(),
outstanding_work_(0),
stopped_(0),
shutdown_(0)
shutdown_(0),
timer_thread_(0),
timer_interrupt_issued_(false)
{
}
@ -64,7 +68,7 @@ public:
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::system_category),
asio::error::get_system_category()),
"iocp");
boost::throw_exception(e);
}
@ -93,6 +97,10 @@ public:
if (overlapped)
static_cast<operation*>(overlapped)->destroy();
}
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a handle with the IO completion port.
@ -175,7 +183,7 @@ public:
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::system_category),
asio::error::get_system_category()),
"pqcs");
boost::throw_exception(e);
}
@ -231,7 +239,7 @@ public:
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::system_category),
asio::error::get_system_category()),
"pqcs");
boost::throw_exception(e);
}
@ -251,20 +259,102 @@ public:
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::system_category),
asio::error::get_system_category()),
"pqcs");
boost::throw_exception(e);
}
}
// Add a new timer queue to the service.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(timer_mutex_);
timer_queues_.push_back(&timer_queue);
}
// Remove a timer queue from the service.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(timer_mutex_);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
if (timer_queues_[i] == &timer_queue)
{
timer_queues_.erase(timer_queues_.begin() + i);
return;
}
}
}
// Schedule a timer in the given timer queue to expire at the specified
// absolute time. The handler object will be invoked when the timer expires.
template <typename Time_Traits, typename Handler>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
// If the service has been shut down we silently discard the timer.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return;
asio::detail::mutex::scoped_lock lock(timer_mutex_);
if (timer_queue.enqueue_timer(time, handler, token))
{
if (!timer_interrupt_issued_)
{
timer_interrupt_issued_ = true;
lock.unlock();
::PostQueuedCompletionStatus(iocp_.handle,
0, steal_timer_dispatching, 0);
}
}
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
// If the service has been shut down we silently ignore the cancellation.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return 0;
asio::detail::mutex::scoped_lock lock(timer_mutex_);
std::size_t n = timer_queue.cancel_timer(token);
if (n > 0 && !timer_interrupt_issued_)
{
timer_interrupt_issued_ = true;
lock.unlock();
::PostQueuedCompletionStatus(iocp_.handle,
0, steal_timer_dispatching, 0);
}
return n;
}
private:
// Dequeues at most one operation from the I/O completion port, and then
// executes it. Returns the number of operations that were dequeued (i.e.
// either 0 or 1).
size_t do_one(bool block, asio::error_code& ec)
{
long this_thread_id = static_cast<long>(::GetCurrentThreadId());
for (;;)
{
// Try to acquire responsibility for dispatching timers.
bool dispatching_timers = (::InterlockedCompareExchange(
&timer_thread_, this_thread_id, 0) == 0);
// Calculate timeout for GetQueuedCompletionStatus call.
DWORD timeout = max_timeout;
if (dispatching_timers)
{
asio::detail::mutex::scoped_lock lock(timer_mutex_);
timer_interrupt_issued_ = false;
timeout = get_timeout();
}
// Get the next operation from the queue.
DWORD bytes_transferred = 0;
#if (WINVER < 0x0500)
@ -275,18 +365,47 @@ private:
LPOVERLAPPED overlapped = 0;
::SetLastError(0);
BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
&completion_key, &overlapped, block ? 1000 : 0);
&completion_key, &overlapped, block ? timeout : 0);
DWORD last_error = ::GetLastError();
// Dispatch any pending timers.
if (dispatching_timers)
{
asio::detail::mutex::scoped_lock lock(timer_mutex_);
timer_queues_copy_ = timer_queues_;
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
timer_queues_[i]->dispatch_timers();
timer_queues_[i]->dispatch_cancellations();
timer_queues_[i]->cleanup_timers();
}
}
if (!ok && overlapped == 0)
{
if (block && last_error == WAIT_TIMEOUT)
{
// Relinquish responsibility for dispatching timers.
if (dispatching_timers)
{
::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
}
continue;
}
// Transfer responsibility for dispatching timers to another thread.
if (dispatching_timers && ::InterlockedCompareExchange(
&timer_thread_, 0, this_thread_id) == this_thread_id)
{
::PostQueuedCompletionStatus(iocp_.handle,
0, transfer_timer_dispatching, 0);
}
ec = asio::error_code();
return 0;
}
if (overlapped)
else if (overlapped)
{
// We may have been passed a last_error value in the completion_key.
if (last_error == 0)
@ -294,6 +413,14 @@ private:
last_error = completion_key;
}
// Transfer responsibility for dispatching timers to another thread.
if (dispatching_timers && ::InterlockedCompareExchange(
&timer_thread_, 0, this_thread_id) == this_thread_id)
{
::PostQueuedCompletionStatus(iocp_.handle,
0, transfer_timer_dispatching, 0);
}
// Ensure that the io_service does not exit due to running out of work
// while we make the upcall.
auto_work work(*this);
@ -305,18 +432,34 @@ private:
ec = asio::error_code();
return 1;
}
else if (completion_key == transfer_timer_dispatching)
{
// Woken up to try to acquire responsibility for dispatching timers.
::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
}
else if (completion_key == steal_timer_dispatching)
{
// Woken up to steal responsibility for dispatching timers.
::InterlockedExchange(&timer_thread_, 0);
}
else
{
// The stopped_ flag is always checked to ensure that any leftover
// interrupts from a previous run invocation are ignored.
if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
{
// Relinquish responsibility for dispatching timers.
if (dispatching_timers)
{
::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
}
// Wake up next thread that is blocked on GetQueuedCompletionStatus.
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::system_category);
asio::error::get_system_category());
return 0;
}
@ -327,6 +470,45 @@ private:
}
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the GetQueuedCompletionStatus call. The timeout
// value is returned as a number of milliseconds. We will wait no longer than
// 1000 milliseconds.
DWORD get_timeout()
{
if (all_timer_queues_are_empty())
return max_timeout;
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::milliseconds(max_timeout);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
int milliseconds = minimum_wait_duration.total_milliseconds();
return static_cast<DWORD>(milliseconds > 0 ? milliseconds : 1);
}
else
{
return 0;
}
}
struct auto_work
{
auto_work(win_iocp_io_service& io_service)
@ -416,6 +598,37 @@ private:
// Flag to indicate whether the service has been shut down.
long shutdown_;
enum
{
// Maximum GetQueuedCompletionStatus timeout, in milliseconds.
max_timeout = 1000,
// Completion key value to indicate that responsibility for dispatching
// timers is being cooperatively transferred from one thread to another.
transfer_timer_dispatching = 1,
// Completion key value to indicate that responsibility for dispatching
// timers should be stolen from another thread.
steal_timer_dispatching = 2
};
// The thread that's currently in charge of dispatching timers.
long timer_thread_;
// Mutex for protecting access to the timer queues.
mutex timer_mutex_;
// Whether a thread has been interrupted to process a new timeout.
bool timer_interrupt_issued_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// A copy of the timer queues, used when dispatching, cancelling and cleaning
// up timers. The copy is stored as a class data member to avoid unnecessary
// memory allocation.
std::vector<timer_queue_base*> timer_queues_copy_;
};
} // namespace detail

View File

@ -27,6 +27,7 @@
#if !defined(ASIO_DISABLE_IOCP)
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
#if !defined(UNDER_CE)
// Define this to indicate that IOCP is supported on the target platform.
#define ASIO_HAS_IOCP 1
@ -39,6 +40,7 @@ class win_iocp_io_service;
} // namespace detail
} // namespace asio
#endif // !defined(UNDER_CE)
#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#endif // !defined(ASIO_DISABLE_IOCP)

View File

@ -327,7 +327,7 @@ public:
ec = asio::error::bad_descriptor;
}
else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
::GetModuleHandle("KERNEL32"), "CancelIoEx"))
::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
{
// The version of Windows supports cancellation from any thread.
typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
@ -338,7 +338,7 @@ public:
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::system_category);
asio::error::get_system_category());
}
else
{
@ -360,7 +360,7 @@ public:
{
DWORD last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::system_category);
asio::error::get_system_category());
}
else
{
@ -561,7 +561,7 @@ public:
}
endpoint_type endpoint;
socket_addr_len_type addr_len = endpoint.capacity();
std::size_t addr_len = endpoint.capacity();
if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
return endpoint_type();
endpoint.resize(addr_len);
@ -600,7 +600,7 @@ public:
else
{
endpoint_type endpoint;
socket_addr_len_type addr_len = endpoint.capacity();
std::size_t addr_len = endpoint.capacity();
if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
return endpoint_type();
endpoint.resize(addr_len);
@ -667,7 +667,7 @@ public:
else if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
ec = asio::error_code(last_error,
asio::error::system_category);
asio::error::get_system_category());
return 0;
}
@ -719,7 +719,7 @@ public:
// Map non-portable errors to their portable counterparts.
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
if (ec.value() == ERROR_NETNAME_DELETED)
{
if (handler_op->cancel_token_.expired())
@ -767,7 +767,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
return;
}
@ -783,7 +783,7 @@ public:
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr,
this->io_service(), impl.cancel_token_, buffers, handler);
this->get_io_service(), impl.cancel_token_, buffers, handler);
// Copy buffers into WSABUF array.
::WSABUF bufs[max_buffers];
@ -803,7 +803,7 @@ public:
// A request to receive 0 bytes on a stream socket is a no-op.
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
{
asio::io_service::work work(this->io_service());
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code error;
iocp_service_.post(bind_handler(handler, error, 0));
@ -819,10 +819,10 @@ public:
// Check if the operation completed immediately.
if (result != 0 && last_error != WSA_IO_PENDING)
{
asio::io_service::work work(this->io_service());
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
@ -867,7 +867,7 @@ public:
if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
ec = asio::error_code(last_error,
asio::error::system_category);
asio::error::get_system_category());
return 0;
}
@ -917,7 +917,7 @@ public:
// Map non-portable errors to their portable counterparts.
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
if (ec.value() == ERROR_PORT_UNREACHABLE)
{
ec = asio::error::connection_refused;
@ -958,7 +958,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
return;
}
@ -974,7 +974,7 @@ public:
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr,
this->io_service(), buffers, handler);
this->get_io_service(), buffers, handler);
// Copy buffers into WSABUF array.
::WSABUF bufs[max_buffers];
@ -998,10 +998,10 @@ public:
// Check if the operation completed immediately.
if (result != 0 && last_error != WSA_IO_PENDING)
{
asio::io_service::work work(this->io_service());
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
@ -1056,7 +1056,7 @@ public:
else if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
ec = asio::error_code(last_error,
asio::error::system_category);
asio::error::get_system_category());
return 0;
}
if (bytes_transferred == 0)
@ -1115,7 +1115,7 @@ public:
// Map non-portable errors to their portable counterparts.
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
if (ec.value() == ERROR_NETNAME_DELETED)
{
if (handler_op->cancel_token_.expired())
@ -1170,7 +1170,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
return;
}
@ -1186,7 +1186,7 @@ public:
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr,
this->io_service(), impl.cancel_token_, buffers, handler);
this->get_io_service(), impl.cancel_token_, buffers, handler);
// Copy buffers into WSABUF array.
::WSABUF bufs[max_buffers];
@ -1205,7 +1205,7 @@ public:
// A request to receive 0 bytes on a stream socket is a no-op.
if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
{
asio::io_service::work work(this->io_service());
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code error;
iocp_service_.post(bind_handler(handler, error, 0));
@ -1220,10 +1220,10 @@ public:
DWORD last_error = ::WSAGetLastError();
if (result != 0 && last_error != WSA_IO_PENDING)
{
asio::io_service::work work(this->io_service());
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
@ -1261,7 +1261,7 @@ public:
// Receive some data.
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int endpoint_size = sender_endpoint.capacity();
int endpoint_size = static_cast<int>(sender_endpoint.capacity());
int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred,
&recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0);
if (result != 0)
@ -1270,7 +1270,7 @@ public:
if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
ec = asio::error_code(last_error,
asio::error::system_category);
asio::error::get_system_category());
return 0;
}
if (bytes_transferred == 0)
@ -1279,7 +1279,7 @@ public:
return 0;
}
sender_endpoint.resize(endpoint_size);
sender_endpoint.resize(static_cast<std::size_t>(endpoint_size));
ec = asio::error_code();
return bytes_transferred;
@ -1299,7 +1299,7 @@ public:
&receive_from_operation<
MutableBufferSequence, Handler>::destroy_impl),
endpoint_(endpoint),
endpoint_size_(endpoint.capacity()),
endpoint_size_(static_cast<int>(endpoint.capacity())),
work_(io_service),
buffers_(buffers),
handler_(handler)
@ -1337,7 +1337,7 @@ public:
// Map non-portable errors to their portable counterparts.
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
if (ec.value() == ERROR_PORT_UNREACHABLE)
{
ec = asio::error::connection_refused;
@ -1390,7 +1390,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor, 0));
return;
}
@ -1406,7 +1406,7 @@ public:
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr,
this->io_service(), sender_endp, buffers, handler);
this->get_io_service(), sender_endp, buffers, handler);
// Copy buffers into WSABUF array.
::WSABUF bufs[max_buffers];
@ -1429,10 +1429,10 @@ public:
DWORD last_error = ::WSAGetLastError();
if (result != 0 && last_error != WSA_IO_PENDING)
{
asio::io_service::work work(this->io_service());
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
}
else
@ -1463,7 +1463,7 @@ public:
{
asio::error_code ec;
socket_holder new_socket;
socket_addr_len_type addr_len = 0;
std::size_t addr_len = 0;
if (peer_endpoint)
{
addr_len = peer_endpoint->capacity();
@ -1517,7 +1517,7 @@ public:
peer_(peer),
protocol_(protocol),
peer_endpoint_(peer_endpoint),
work_(io_service.io_service()),
work_(io_service.get_io_service()),
enable_connection_aborted_(enable_connection_aborted),
handler_(handler)
{
@ -1618,7 +1618,8 @@ public:
GetAcceptExSockaddrs(handler_op->output_buffer(), 0,
handler_op->address_length(), handler_op->address_length(),
&local_addr, &local_addr_length, &remote_addr, &remote_addr_length);
if (remote_addr_length > peer_endpoint.capacity())
if (static_cast<std::size_t>(remote_addr_length)
> peer_endpoint.capacity())
{
last_error = WSAEINVAL;
}
@ -1626,7 +1627,7 @@ public:
{
using namespace std; // For memcpy.
memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
peer_endpoint.resize(remote_addr_length);
peer_endpoint.resize(static_cast<std::size_t>(remote_addr_length));
}
}
@ -1670,7 +1671,7 @@ public:
// Call the handler.
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
asio_handler_invoke_helpers::invoke(
detail::bind_handler(handler, ec), &handler);
}
@ -1705,7 +1706,7 @@ public:
// Check whether acceptor has been initialised.
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor));
return;
}
@ -1713,7 +1714,7 @@ public:
// Check that peer socket has not already been opened.
if (peer.is_open())
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::already_open));
return;
}
@ -1730,7 +1731,7 @@ public:
impl.protocol_.type(), impl.protocol_.protocol(), ec));
if (sock.get() == invalid_socket)
{
this->io_service().post(bind_handler(handler, ec));
this->get_io_service().post(bind_handler(handler, ec));
return;
}
@ -1768,10 +1769,10 @@ public:
}
else
{
asio::io_service::work work(this->io_service());
asio::io_service::work work(this->get_io_service());
ptr.reset();
asio::error_code ec(last_error,
asio::error::system_category);
asio::error::get_system_category());
iocp_service_.post(bind_handler(handler, ec));
}
}
@ -1848,7 +1849,7 @@ public:
if (connect_error)
{
ec = asio::error_code(connect_error,
asio::error::system_category);
asio::error::get_system_category());
io_service_.post(bind_handler(handler_, ec));
return true;
}
@ -1887,7 +1888,7 @@ public:
{
if (!is_open(impl))
{
this->io_service().post(bind_handler(handler,
this->get_io_service().post(bind_handler(handler,
asio::error::bad_descriptor));
return;
}
@ -1904,7 +1905,8 @@ public:
reinterpret_cast<void**>(&reactor_), 0, 0));
if (!reactor)
{
reactor = &(asio::use_service<reactor_type>(this->io_service()));
reactor = &(asio::use_service<reactor_type>(
this->get_io_service()));
interlocked_exchange_pointer(
reinterpret_cast<void**>(&reactor_), reactor);
}
@ -1915,7 +1917,7 @@ public:
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{
this->io_service().post(bind_handler(handler, ec));
this->get_io_service().post(bind_handler(handler, ec));
return;
}
@ -1932,7 +1934,7 @@ public:
// The connect operation has finished successfully so we need to post the
// handler immediately.
this->io_service().post(bind_handler(handler, ec));
this->get_io_service().post(bind_handler(handler, ec));
}
else if (ec == asio::error::in_progress
|| ec == asio::error::would_block)
@ -1944,7 +1946,7 @@ public:
connect_handler<Handler>(
impl.socket_,
(impl.flags_ & implementation_type::user_set_non_blocking) != 0,
completed, this->io_service(), *reactor, handler));
completed, this->get_io_service(), *reactor, handler));
}
else
{
@ -1957,7 +1959,7 @@ public:
}
// The connect operation has failed, so post the handler immediately.
this->io_service().post(bind_handler(handler, ec));
this->get_io_service().post(bind_handler(handler, ec));
}
}

View File

@ -0,0 +1,59 @@
//
// win_local_free_on_block_exit.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2006 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_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#define ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class win_local_free_on_block_exit
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
explicit win_local_free_on_block_exit(void* p)
: p_(p)
{
}
// Destructor restores the previous signal mask.
~win_local_free_on_block_exit()
{
::LocalFree(p_);
}
private:
void* p_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP

View File

@ -49,7 +49,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}
@ -68,7 +69,8 @@ public:
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::error::system_category),
asio::error_code(error,
asio::error::get_system_category()),
"mutex");
boost::throw_exception(e);
}

View File

@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS)
#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
#include "asio/error.hpp"
#include "asio/system_error.hpp"
@ -56,7 +56,7 @@ public:
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::system_category),
asio::error::get_system_category()),
"thread");
boost::throw_exception(e);
}
@ -118,7 +118,7 @@ inline unsigned int __stdcall win_thread_function(void* arg)
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS)
#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
#include "asio/detail/pop_options.hpp"

View File

@ -40,16 +40,22 @@ class win_tss_ptr
: private noncopyable
{
public:
#if defined(UNDER_CE)
enum { out_of_indexes = 0xFFFFFFFF };
#else
enum { out_of_indexes = TLS_OUT_OF_INDEXES };
#endif
// Constructor.
win_tss_ptr()
{
tss_key_ = ::TlsAlloc();
if (tss_key_ == TLS_OUT_OF_INDEXES)
if (tss_key_ == out_of_indexes)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::system_category),
asio::error::get_system_category()),
"tss");
boost::throw_exception(e);
}

View File

@ -0,0 +1,124 @@
//
// wince_thread.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 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_WINCE_THREAD_HPP
#define ASIO_DETAIL_WINCE_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <memory>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
DWORD WINAPI wince_thread_function(LPVOID arg);
class wince_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
wince_thread(Function f)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
DWORD thread_id = 0;
thread_ = ::CreateThread(0, 0, wince_thread_function,
arg.get(), 0, &thread_id);
if (!thread_)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error,
asio::error::get_system_category()),
"thread");
boost::throw_exception(e);
}
arg.release();
}
// Destructor.
~wince_thread()
{
::CloseHandle(thread_);
}
// Wait for the thread to exit.
void join()
{
::WaitForSingleObject(thread_, INFINITE);
}
private:
friend DWORD WINAPI wince_thread_function(LPVOID arg);
class func_base
{
public:
virtual ~func_base() {}
virtual void run() = 0;
};
template <typename Function>
class func
: public func_base
{
public:
func(Function f)
: f_(f)
{
}
virtual void run()
{
f_();
}
private:
Function f_;
};
::HANDLE thread_;
};
inline DWORD WINAPI wince_thread_function(LPVOID arg)
{
std::auto_ptr<wince_thread::func_base> func(
static_cast<wince_thread::func_base*>(arg));
func->run();
return 0;
}
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WINCE_THREAD_HPP

View File

@ -28,6 +28,7 @@
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
@ -86,7 +87,7 @@ public:
{
asio::system_error e(
asio::error_code(ref_->result(),
asio::error::system_category),
asio::error::get_system_category()),
"winsock");
boost::throw_exception(e);
}

View File

@ -197,26 +197,40 @@ enum misc_errors
not_found
};
enum ssl_errors
{
};
// boostify: error category definitions go here.
inline asio::error_code make_error_code(basic_errors e)
{
return asio::error_code(static_cast<int>(e), system_category);
return asio::error_code(
static_cast<int>(e), get_system_category());
}
inline asio::error_code make_error_code(netdb_errors e)
{
return asio::error_code(static_cast<int>(e), netdb_category);
return asio::error_code(
static_cast<int>(e), get_netdb_category());
}
inline asio::error_code make_error_code(addrinfo_errors e)
{
return asio::error_code(static_cast<int>(e), addrinfo_category);
return asio::error_code(
static_cast<int>(e), get_addrinfo_category());
}
inline asio::error_code make_error_code(misc_errors e)
{
return asio::error_code(static_cast<int>(e), misc_category);
return asio::error_code(
static_cast<int>(e), get_misc_category());
}
inline asio::error_code make_error_code(ssl_errors e)
{
return asio::error_code(
static_cast<int>(e), get_ssl_category());
}
} // namespace error

View File

@ -41,10 +41,10 @@ namespace error
system_category = ASIO_WIN_OR_POSIX(0, 0),
/// Error codes from NetDB functions.
netdb_category = ASIO_WIN_OR_POSIX(system_category, 1),
netdb_category = ASIO_WIN_OR_POSIX(_system_category, 1),
/// Error codes from getaddrinfo.
addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2),
addrinfo_category = ASIO_WIN_OR_POSIX(_system_category, 2),
/// Miscellaneous error codes.
misc_category = ASIO_WIN_OR_POSIX(3, 3),
@ -52,8 +52,19 @@ namespace error
/// SSL error codes.
ssl_category = ASIO_WIN_OR_POSIX(4, 4)
};
// Category getters.
inline error_category get_system_category() { return system_category; }
inline error_category get_netdb_category() { return netdb_category; }
inline error_category get_addrinfo_category() { return addrinfo_category; }
inline error_category get_misc_category() { return misc_category; }
inline error_category get_ssl_category() { return ssl_category; }
} // namespace error
/// Bring error category type into the asio namespace.
typedef asio::error::error_category error_category;
/// Class to represent an error code value.
class error_code
{
@ -69,7 +80,7 @@ public:
}
/// Construct with specific error code and category.
error_code(value_type v, error::error_category c)
error_code(value_type v, error_category c)
: value_(v),
category_(c)
{
@ -89,7 +100,7 @@ public:
}
/// Get the error category.
error::error_category category() const
error_category category() const
{
return category_;
}
@ -135,7 +146,7 @@ private:
value_type value_;
// The category associated with the error code.
error::error_category category_;
error_category category_;
};
} // namespace asio

View File

@ -0,0 +1,120 @@
//
// error_handler.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2006 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_ERROR_HANDLER_HPP
#define ASIO_ERROR_HANDLER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class ignore_error_t
{
public:
typedef void result_type;
template <typename Error>
void operator()(const Error&) const
{
}
};
class throw_error_t
{
public:
typedef void result_type;
template <typename Error>
void operator()(const Error& err) const
{
if (err)
boost::throw_exception(err);
}
};
template <typename Target>
class assign_error_t
{
public:
typedef void result_type;
assign_error_t(Target& target)
: target_(&target)
{
}
template <typename Error>
void operator()(const Error& err) const
{
*target_ = err;
}
private:
Target* target_;
};
} // namespace detail
/**
* @defgroup error_handler Error Handler Function Objects
*
* Function objects for custom error handling.
*/
/*@{*/
/// Return a function object that always ignores the error.
#if defined(GENERATING_DOCUMENTATION)
unspecified ignore_error();
#else
inline detail::ignore_error_t ignore_error()
{
return detail::ignore_error_t();
}
#endif
/// Return a function object that always throws the error.
#if defined(GENERATING_DOCUMENTATION)
unspecified throw_error();
#else
inline detail::throw_error_t throw_error()
{
return detail::throw_error_t();
}
#endif
/// Return a function object that assigns the error to a variable.
#if defined(GENERATING_DOCUMENTATION)
template <typename Target>
unspecified assign_error(Target& target);
#else
template <typename Target>
inline detail::assign_error_t<Target> assign_error(Target& target)
{
return detail::assign_error_t<Target>(target);
}
#endif
/*@}*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ERROR_HANDLER_HPP

View File

@ -35,11 +35,11 @@ inline std::string error_code::message() const
return "Already open.";
if (*this == error::not_found)
return "Not found.";
if (category_ == error::ssl_category)
if (category_ == error::get_ssl_category())
return "SSL error.";
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
value_type value = value_;
if (category() != error::system_category && *this != error::eof)
if (category() != error::get_system_category() && *this != error::eof)
return "asio error";
if (*this == error::eof)
value = ERROR_HANDLE_EOF;
@ -78,13 +78,13 @@ inline std::string error_code::message() const
return "Service not found.";
if (*this == error::socket_type_not_supported)
return "Socket type not supported.";
if (category() != error::system_category)
if (category() != error::get_system_category())
return "asio error";
#if defined(__sun) || defined(__QNX__)
return strerror(value_);
#elif defined(__MACH__) && defined(__APPLE__) \
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
|| defined(_AIX)
|| defined(_AIX) || defined(__hpux) || defined(__osf__)
char buf[256] = "";
strerror_r(value_, buf, sizeof(buf));
return buf;

View File

@ -21,6 +21,7 @@
#include <limits>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/dev_poll_reactor.hpp"
#include "asio/detail/epoll_reactor.hpp"
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/select_reactor.hpp"
@ -157,6 +158,11 @@ inline asio::io_service& io_service::work::io_service()
return io_service_;
}
inline asio::io_service& io_service::work::get_io_service()
{
return io_service_;
}
inline io_service::service::service(asio::io_service& owner)
: owner_(owner),
type_info_(0),
@ -173,6 +179,11 @@ inline asio::io_service& io_service::service::io_service()
return owner_;
}
inline asio::io_service& io_service::service::get_io_service()
{
return owner_;
}
template <typename Service>
inline Service& use_service(io_service& ios)
{

View File

@ -26,6 +26,7 @@
#include "asio/detail/pop_options.hpp"
#include "asio/error_code.hpp"
#include "asio/detail/dev_poll_reactor_fwd.hpp"
#include "asio/detail/epoll_reactor_fwd.hpp"
#include "asio/detail/kqueue_reactor_fwd.hpp"
#include "asio/detail/noncopyable.hpp"
@ -39,6 +40,11 @@
namespace asio {
class io_service;
template <typename Service> Service& use_service(io_service& ios);
template <typename Service> void add_service(io_service& ios, Service* svc);
template <typename Service> bool has_service(io_service& ios);
/// Provides core I/O functionality.
/**
* The io_service class provides the core I/O functionality for users of the
@ -106,6 +112,8 @@ private:
typedef detail::task_io_service<detail::epoll_reactor<false> > impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::task_io_service<detail::kqueue_reactor<false> > impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::task_io_service<detail::dev_poll_reactor<false> > impl_type;
#else
typedef detail::task_io_service<detail::select_reactor<false> > impl_type;
#endif
@ -373,7 +381,8 @@ public:
private:
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
detail::winsock_init<> init_;
#elif defined(__sun) || defined(__QNX__)
#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
|| defined(__osf__)
detail::signal_init<> init_;
#endif
@ -421,9 +430,13 @@ public:
*/
~work();
/// Get the io_service associated with the work.
/// (Deprecated: use get_io_service().) Get the io_service associated with the
/// work.
asio::io_service& io_service();
/// Get the io_service associated with the work.
asio::io_service& get_io_service();
private:
// Prevent assignment.
void operator=(const work& other);
@ -446,9 +459,13 @@ class io_service::service
: private noncopyable
{
public:
/// Get the io_service object that owns the service.
/// (Deprecated: use get_io_service().) Get the io_service object that owns
/// the service.
asio::io_service& io_service();
/// Get the io_service object that owns the service.
asio::io_service& get_io_service();
protected:
/// Constructor.
/**

View File

@ -268,7 +268,12 @@ std::basic_ostream<Elem, Traits>& operator<<(
asio::error_code ec;
std::string s = addr.to_string(ec);
if (ec)
os.setstate(std::ios_base::failbit);
{
if (os.exceptions() & std::ios::failbit)
asio::detail::throw_error(ec);
else
os.setstate(std::ios_base::failbit);
}
else
for (std::string::iterator i = s.begin(); i != s.end(); ++i)
os << os.widen(*i);

View File

@ -300,7 +300,7 @@ public:
{
using namespace std; // For memcmp.
int memcmp_result = memcmp(&a1.addr_, &a2.addr_,
sizeof(asio::detail::in6_addr_type)) < 0;
sizeof(asio::detail::in6_addr_type));
if (memcmp_result < 0)
return true;
if (memcmp_result > 0)
@ -386,7 +386,12 @@ std::basic_ostream<Elem, Traits>& operator<<(
asio::error_code ec;
std::string s = addr.to_string(ec);
if (ec)
os.setstate(std::ios_base::failbit);
{
if (os.exceptions() & std::ios::failbit)
asio::detail::throw_error(ec);
else
os.setstate(std::ios_base::failbit);
}
else
for (std::string::iterator i = s.begin(); i != s.end(); ++i)
os << os.widen(*i);

View File

@ -61,14 +61,6 @@ public:
typedef asio::detail::socket_addr_type data_type;
#endif
/// The type for the size of the endpoint structure. This type is dependent on
/// the underlying implementation of the socket layer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined size_type;
#else
typedef asio::detail::socket_addr_len_type size_type;
#endif
/// Default constructor.
basic_endpoint()
: data_()
@ -190,7 +182,7 @@ public:
}
/// Get the underlying size of the endpoint in the native type.
size_type size() const
std::size_t size() const
{
if (is_v4(data_))
return sizeof(asio::detail::sockaddr_in4_type);
@ -199,9 +191,9 @@ public:
}
/// Set the underlying size of the endpoint in the native type.
void resize(size_type size)
void resize(std::size_t size)
{
if (size > size_type(sizeof(data_)))
if (size > sizeof(data_))
{
asio::system_error e(asio::error::invalid_argument);
boost::throw_exception(e);
@ -209,7 +201,7 @@ public:
}
/// Get the capacity of the endpoint in the native type.
size_type capacity() const
std::size_t capacity() const
{
return sizeof(data_);
}
@ -349,11 +341,23 @@ std::ostream& operator<<(std::ostream& os,
const basic_endpoint<InternetProtocol>& endpoint)
{
const address& addr = endpoint.address();
if (addr.is_v4())
os << addr.to_string();
asio::error_code ec;
std::string a = addr.to_string(ec);
if (ec)
{
if (os.exceptions() & std::ios::failbit)
asio::detail::throw_error(ec);
else
os.setstate(std::ios_base::failbit);
}
else
os << '[' << addr.to_string() << ']';
os << ':' << endpoint.port();
{
if (addr.is_v4())
os << a;
else
os << '[' << a << ']';
os << ':' << endpoint.port();
}
return os;
}
#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
@ -363,11 +367,23 @@ std::basic_ostream<Elem, Traits>& operator<<(
const basic_endpoint<InternetProtocol>& endpoint)
{
const address& addr = endpoint.address();
if (addr.is_v4())
os << addr.to_string();
asio::error_code ec;
std::string a = addr.to_string(ec);
if (ec)
{
if (os.exceptions() & std::ios::failbit)
asio::detail::throw_error(ec);
else
os.setstate(std::ios_base::failbit);
}
else
os << '[' << addr.to_string() << ']';
os << ':' << endpoint.port();
{
if (addr.is_v4())
os << a;
else
os << '[' << a << ']';
os << ':' << endpoint.port();
}
return os;
}
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))

View File

@ -80,9 +80,7 @@ public:
{
using namespace std; // For memcpy.
typename InternetProtocol::endpoint endpoint;
endpoint.resize(
static_cast<asio::detail::socket_addr_len_type>(
address_info->ai_addrlen));
endpoint.resize(static_cast<std::size_t>(address_info->ai_addrlen));
memcpy(endpoint.data(), address_info->ai_addr,
address_info->ai_addrlen);
iter.values_->push_back(

View File

@ -32,52 +32,60 @@ namespace ip {
namespace detail {
namespace socket_option {
// Helper template for implementing boolean-based options.
// Helper template for implementing multicast enable loopback options.
template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
class boolean
class multicast_enable_loopback
{
public:
#if defined(__sun)
typedef unsigned char value_type;
#if defined(__sun) || defined(__osf__)
typedef unsigned char ipv4_value_type;
typedef unsigned char ipv6_value_type;
#elif defined(_AIX) || defined(__hpux)
typedef unsigned char ipv4_value_type;
typedef unsigned int ipv6_value_type;
#else
typedef int value_type;
typedef int ipv4_value_type;
typedef int ipv6_value_type;
#endif
// Default constructor.
boolean()
: value_(0)
multicast_enable_loopback()
: ipv4_value_(0),
ipv6_value_(0)
{
}
// Construct with a specific option value.
explicit boolean(bool v)
: value_(v ? 1 : 0)
explicit multicast_enable_loopback(bool v)
: ipv4_value_(v ? 1 : 0),
ipv6_value_(v ? 1 : 0)
{
}
// Set the value of the boolean.
boolean& operator=(bool v)
multicast_enable_loopback& operator=(bool v)
{
value_ = v ? 1 : 0;
ipv4_value_ = v ? 1 : 0;
ipv6_value_ = v ? 1 : 0;
return *this;
}
// Get the current value of the boolean.
bool value() const
{
return !!value_;
return !!ipv4_value_;
}
// Convert to bool.
operator bool() const
{
return !!value_;
return !!ipv4_value_;
}
// Test for false.
bool operator!() const
{
return !value_;
return !ipv4_value_;
}
// Get the level of the socket option.
@ -100,35 +108,58 @@ public:
// Get the address of the boolean data.
template <typename Protocol>
value_type* data(const Protocol&)
void* data(const Protocol& protocol)
{
return &value_;
if (protocol.family() == PF_INET6)
return &ipv6_value_;
return &ipv4_value_;
}
// Get the address of the boolean data.
template <typename Protocol>
const value_type* data(const Protocol&) const
const void* data(const Protocol& protocol) const
{
return &value_;
if (protocol.family() == PF_INET6)
return &ipv6_value_;
return &ipv4_value_;
}
// Get the size of the boolean data.
template <typename Protocol>
std::size_t size(const Protocol&) const
std::size_t size(const Protocol& protocol) const
{
return sizeof(value_);
if (protocol.family() == PF_INET6)
return sizeof(ipv6_value_);
return sizeof(ipv4_value_);
}
// Set the size of the boolean data.
template <typename Protocol>
void resize(const Protocol&, std::size_t s)
void resize(const Protocol& protocol, std::size_t s)
{
if (s != sizeof(value_))
throw std::length_error("boolean socket option resize");
if (protocol.family() == PF_INET6)
{
if (s != sizeof(ipv6_value_))
{
throw std::length_error(
"multicast_enable_loopback socket option resize");
}
ipv4_value_ = ipv6_value_ ? 1 : 0;
}
else
{
if (s != sizeof(ipv4_value_))
{
throw std::length_error(
"multicast_enable_loopback socket option resize");
}
ipv6_value_ = ipv4_value_ ? 1 : 0;
}
}
private:
value_type value_;
ipv4_value_type ipv4_value_;
ipv6_value_type ipv6_value_;
};
// Helper template for implementing unicast hops options.
@ -206,6 +237,10 @@ public:
{
if (s != sizeof(value_))
throw std::length_error("unicast hops socket option resize");
#if defined(__hpux)
if (value_ < 0)
value_ = value_ & 0xFF;
#endif
}
private:
@ -217,6 +252,13 @@ template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
class multicast_hops
{
public:
#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
typedef int ipv4_value_type;
#else
typedef unsigned char ipv4_value_type;
#endif
typedef int ipv6_value_type;
// Default constructor.
multicast_hops()
: ipv4_value_(0),
@ -229,7 +271,7 @@ public:
{
if (v < 0 || v > 255)
throw std::out_of_range("multicast hops value out of range");
ipv4_value_ = static_cast<unsigned char>(v);
ipv4_value_ = (ipv4_value_type)v;
ipv6_value_ = v;
}
@ -238,7 +280,7 @@ public:
{
if (v < 0 || v > 255)
throw std::out_of_range("multicast hops value out of range");
ipv4_value_ = static_cast<unsigned char>(v);
ipv4_value_ = (ipv4_value_type)v;
ipv6_value_ = v;
return *this;
}
@ -307,7 +349,7 @@ public:
else if (ipv6_value_ > 255)
ipv4_value_ = 255;
else
ipv4_value_ = static_cast<unsigned char>(ipv6_value_);
ipv4_value_ = (ipv4_value_type)ipv6_value_;
}
else
{
@ -318,8 +360,8 @@ public:
}
private:
unsigned char ipv4_value_;
int ipv6_value_;
ipv4_value_type ipv4_value_;
ipv6_value_type ipv6_value_;
};
// Helper template for implementing ip_mreq-based options.
@ -477,7 +519,7 @@ public:
}
// Construct with IPv6 interface.
explicit network_interface(unsigned long ipv6_interface)
explicit network_interface(unsigned int ipv6_interface)
{
ipv4_value_.s_addr =
asio::detail::socket_ops::host_to_network_long(
@ -523,7 +565,7 @@ public:
private:
asio::detail::in4_addr_type ipv4_value_;
unsigned long ipv6_value_;
unsigned int ipv6_value_;
};
} // namespace socket_option

View File

@ -167,7 +167,7 @@ typedef asio::ip::detail::socket_option::multicast_hops<
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined enable_loopback;
#else
typedef asio::ip::detail::socket_option::boolean<
typedef asio::ip::detail::socket_option::multicast_enable_loopback<
IPPROTO_IP, IP_MULTICAST_LOOP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP>
enable_loopback;
#endif

View File

@ -27,17 +27,17 @@ namespace placeholders {
#if defined(GENERATING_DOCUMENTATION)
/// An argument placeholder, for use with @ref boost_bind, that corresponds to
/// An argument placeholder, for use with boost::bind(), that corresponds to
/// the error argument of a handler for any of the asynchronous functions.
unspecified error;
/// An argument placeholder, for use with @ref boost_bind, that corresponds to
/// An argument placeholder, for use with boost::bind(), that corresponds to
/// the bytes_transferred argument of a handler for asynchronous functions such
/// as asio::basic_stream_socket::async_write_some or
/// asio::async_write.
unspecified bytes_transferred;
/// An argument placeholder, for use with @ref boost_bind, that corresponds to
/// An argument placeholder, for use with boost::bind(), that corresponds to
/// the iterator argument of a handler for asynchronous functions such as
/// asio::basic_resolver::resolve.
unspecified iterator;

View File

@ -0,0 +1,126 @@
//
// resolver_service.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2006 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_RESOLVER_SERVICE_HPP
#define ASIO_RESOLVER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/resolver_service.hpp"
namespace asio {
/// Default service implementation for a resolver.
template <typename Protocol>
class resolver_service
: public asio::io_service::service
{
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The query type.
typedef typename Protocol::resolver_query query_type;
/// The iterator type.
typedef typename Protocol::resolver_iterator iterator_type;
private:
// The type of the platform-specific implementation.
typedef detail::resolver_service<Protocol> service_impl_type;
public:
/// The type of a resolver implementation.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef typename service_impl_type::implementation_type implementation_type;
#endif
/// Construct a new resolver service for the specified io_service.
explicit resolver_service(asio::io_service& io_service)
: asio::io_service::service(io_service),
service_impl_(asio::use_service<service_impl_type>(io_service))
{
}
/// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
/// Construct a new resolver implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a resolver implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
/// Cancel pending asynchronous operations.
void cancel(implementation_type& impl)
{
service_impl_.cancel(impl);
}
/// Resolve a query to a list of entries.
template <typename Error_Handler>
iterator_type resolve(implementation_type& impl, const query_type& query,
Error_Handler error_handler)
{
return service_impl_.resolve(impl, query, error_handler);
}
/// Asynchronously resolve a query to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const query_type& query,
Handler handler)
{
service_impl_.async_resolve(impl, query, handler);
}
/// Resolve an endpoint to a list of entries.
template <typename Error_Handler>
iterator_type resolve(implementation_type& impl,
const endpoint_type& endpoint, Error_Handler error_handler)
{
return service_impl_.resolve(impl, endpoint, error_handler);
}
/// Asynchronously resolve an endpoint to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
Handler handler)
{
return service_impl_.async_resolve(impl, endpoint, handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_RESOLVER_SERVICE_HPP

View File

@ -60,6 +60,9 @@ private:
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::reactive_socket_service<
Protocol, detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::reactive_socket_service<
Protocol, detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::reactive_socket_service<
Protocol, detail::select_reactor<false> > service_impl_type;

View File

@ -179,7 +179,7 @@ public:
else
{
return handler_(asio::error_code(
error_code, asio::error::ssl_category), rc);
error_code, asio::error::get_ssl_category()), rc);
}
}

View File

@ -238,7 +238,7 @@ public:
typedef handshake_handler<Stream, Handler> connect_handler;
connect_handler* local_handler =
new connect_handler(handler, io_service());
new connect_handler(handler, get_io_service());
openssl_operation<Stream>* op = new openssl_operation<Stream>
(
@ -259,7 +259,7 @@ public:
);
local_handler->set_operation(op);
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
get_io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
}
// Shut down SSL on the stream.
@ -294,7 +294,7 @@ public:
typedef shutdown_handler<Stream, Handler> disconnect_handler;
disconnect_handler* local_handler =
new disconnect_handler(handler, io_service());
new disconnect_handler(handler, get_io_service());
openssl_operation<Stream>* op = new openssl_operation<Stream>
(
@ -313,7 +313,7 @@ public:
);
local_handler->set_operation(op);
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
get_io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
}
// Write some data to the stream.
@ -354,7 +354,7 @@ public:
{
typedef io_handler<Stream, Handler> send_handler;
send_handler* local_handler = new send_handler(handler, io_service());
send_handler* local_handler = new send_handler(handler, get_io_service());
boost::function<int (SSL*)> send_func =
boost::bind(&::SSL_write, boost::arg<1>(),
@ -378,7 +378,7 @@ public:
);
local_handler->set_operation(op);
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
get_io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
}
// Read some data from the stream.
@ -419,7 +419,7 @@ public:
{
typedef io_handler<Stream, Handler> recv_handler;
recv_handler* local_handler = new recv_handler(handler, io_service());
recv_handler* local_handler = new recv_handler(handler, get_io_service());
boost::function<int (SSL*)> recv_func =
boost::bind(&::SSL_read, boost::arg<1>(),
@ -443,7 +443,7 @@ public:
);
local_handler->set_operation(op);
io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
get_io_service().post(boost::bind(&openssl_operation<Stream>::start, op));
}
// Peek at the incoming data on the stream.

View File

@ -85,7 +85,7 @@ public:
template <typename Arg, typename Context_Service>
explicit stream(Arg& arg, basic_context<Context_Service>& context)
: next_layer_(arg),
service_(asio::use_service<Service>(next_layer_.io_service())),
service_(asio::use_service<Service>(next_layer_.get_io_service())),
impl_(service_.null())
{
service_.create(impl_, next_layer_, context);
@ -97,7 +97,8 @@ public:
service_.destroy(impl_, next_layer_);
}
/// Get the io_service associated with the object.
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object.
/**
* This function may be used to obtain the io_service object that the stream
* uses to dispatch handlers for asynchronous operations.
@ -107,7 +108,20 @@ public:
*/
asio::io_service& io_service()
{
return next_layer_.io_service();
return next_layer_.get_io_service();
}
/// Get the io_service associated with the object.
/**
* This function may be used to obtain the io_service object that the stream
* uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_service object that stream will use to
* dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_service& get_io_service()
{
return next_layer_.get_io_service();
}
/// Get a reference to the next layer.

View File

@ -65,7 +65,8 @@ public:
service_.destroy(impl_);
}
/// Get the io_service associated with the strand.
/// (Deprecated: use get_io_service().) Get the io_service associated with
/// the strand.
/**
* This function may be used to obtain the io_service object that the strand
* uses to dispatch handlers for asynchronous operations.
@ -75,7 +76,20 @@ public:
*/
asio::io_service& io_service()
{
return service_.io_service();
return service_.get_io_service();
}
/// Get the io_service associated with the strand.
/**
* This function may be used to obtain the io_service object that the strand
* uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_service object that the strand will use to
* dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_service& get_io_service()
{
return service_.get_io_service();
}
/// Request the strand to invoke the given handler.

View File

@ -64,6 +64,9 @@ private:
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::reactive_socket_service<
Protocol, detail::kqueue_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_DEV_POLL)
typedef detail::reactive_socket_service<
Protocol, detail::dev_poll_reactor<false> > service_impl_type;
#else
typedef detail::reactive_socket_service<
Protocol, detail::select_reactor<false> > service_impl_type;

View File

@ -0,0 +1,198 @@
//
// error.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2006 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_SYSTEM_EXCEPTION_HPP
#define ASIO_SYSTEM_EXCEPTION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <boost/scoped_ptr.hpp>
#include <cerrno>
#include <cstring>
#include <exception>
#include <string>
#include <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
# include <iostream>
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
#include "asio/detail/pop_options.hpp"
#include "asio/detail/win_local_free_on_block_exit.hpp"
namespace asio {
/// The system_exception class is used to represent system conditions that
/// prevent the library from operating correctly.
class system_exception
: public std::exception
{
public:
/// Construct with a specific context and error code.
system_exception(const std::string& context, int code)
: context_(context),
code_(code)
{
}
/// Copy constructor.
system_exception(const system_exception& e)
: std::exception(e),
context_(e.context_),
code_(e.code_)
{
}
/// Destructor.
virtual ~system_exception() throw ()
{
}
/// Assignment operator.
system_exception& operator=(const system_exception& e)
{
context_ = e.context_;
code_ = e.code_;
what_.reset();
return *this;
}
/// Get a string representation of the exception.
virtual const char* what() const throw ()
{
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
try
{
if (!what_)
{
char* msg = 0;
DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS, 0, code_,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);
detail::win_local_free_on_block_exit local_free_obj(msg);
if (length && msg[length - 1] == '\n')
msg[--length] = '\0';
if (length && msg[length - 1] == '\r')
msg[--length] = '\0';
if (length)
{
std::string tmp(context_);
tmp += ": ";
tmp += msg;
what_.reset(new std::string(tmp));
}
else
{
return "asio system_exception";
}
}
return what_->c_str();
}
catch (std::exception&)
{
return "asio system_exception";
}
#elif defined(__sun) || defined(__QNX__)
return strerror(code_);
#elif defined(__MACH__) && defined(__APPLE__) \
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
try
{
char buf[256] = "";
strerror_r(code_, buf, sizeof(buf));
std::string tmp(context_);
tmp += ": ";
tmp += buf;
what_.reset(new std::string(tmp));
return what_->c_str();
}
catch (std::exception&)
{
return "asio system_exception";
}
#else
try
{
char buf[256] = "";
std::string tmp(context_);
tmp += ": ";
tmp += strerror_r(code_, buf, sizeof(buf));
what_.reset(new std::string(tmp));
return what_->c_str();
}
catch (std::exception&)
{
return "asio system_exception";
}
#endif
}
/// Get the implementation-defined context associated with the exception.
const std::string& context() const
{
return context_;
}
/// Get the implementation-defined code associated with the exception.
int code() const
{
return code_;
}
private:
// The context associated with the error.
std::string context_;
// The code associated with the error.
int code_;
// The string representation of the error.
mutable boost::scoped_ptr<std::string> what_;
};
/// Output the string associated with a system exception.
/**
* Used to output a human-readable string that is associated with a system
* exception.
*
* @param os The output stream to which the string will be written.
*
* @param e The exception to be written.
*
* @return The output stream.
*
* @relates asio::system_exception
*/
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
std::ostream& operator<<(std::ostream& os, const system_exception& e)
{
os << e.what();
return os;
}
#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
template <typename Ostream>
Ostream& operator<<(Ostream& os, const system_exception& e)
{
os << e.what();
return os;
}
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_SYSTEM_EXCEPTION_HPP