summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2010-05-06 17:44:27 (GMT)
committerRemko Tronçon <git@el-tramo.be>2010-05-06 17:44:27 (GMT)
commitd76ada0ab59634e3333f9eb5a92d0e850f60d7bf (patch)
tree5eaae441173fad2ec19ba67d6589f28ecd740991 /3rdParty/Boost/src/boost/asio/detail
parent6f49e5abee37d37b351d68c01374232eccdac458 (diff)
downloadswift-d76ada0ab59634e3333f9eb5a92d0e850f60d7bf.zip
swift-d76ada0ab59634e3333f9eb5a92d0e850f60d7bf.tar.bz2
Updated Boost to 1.43.0.
Diffstat (limited to '3rdParty/Boost/src/boost/asio/detail')
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/base_from_completion_cond.hpp67
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/buffer_sequence_adapter.hpp254
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/completion_handler.hpp73
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp54
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp63
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp412
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp1
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp747
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp1
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/event.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/fenced_block.hpp72
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/gcc_fenced_block.hpp65
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/gcc_x86_fenced_block.hpp63
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/handler_base_from_member.hpp78
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/handler_queue.hpp231
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/hash_map.hpp93
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/indirect_handler_queue.hpp293
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp710
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp1
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/macos_fenced_block.hpp59
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/mutex.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/null_buffers_op.hpp79
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/null_event.hpp10
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/null_fenced_block.hpp45
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/null_thread.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/op_queue.hpp158
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/operation.hpp45
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/posix_event.hpp10
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp22
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp510
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp23
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp1195
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/reactor.hpp34
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/reactor_fwd.hpp48
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/reactor_op.hpp62
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp383
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp247
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp447
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/service_registry.hpp175
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/socket_types.hpp8
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/solaris_fenced_block.hpp59
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/strand_service.hpp445
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp287
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/task_io_service_2lock.hpp475
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/task_io_service_operation.hpp71
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/thread.hpp4
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/timer_op.hpp46
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp334
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp32
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/timer_queue_fwd.hpp33
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/timer_queue_set.hpp117
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/timer_scheduler.hpp36
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/timer_scheduler_fwd.hpp48
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp6
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_event.hpp9
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_fenced_block.hpp77
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp429
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp545
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_iocp_operation.hpp91
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp124
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp10
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp1693
-rw-r--r--3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp46
67 files changed, 5277 insertions, 6606 deletions
diff --git a/3rdParty/Boost/src/boost/asio/detail/base_from_completion_cond.hpp b/3rdParty/Boost/src/boost/asio/detail/base_from_completion_cond.hpp
new file mode 100644
index 0000000..1b1f142
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/base_from_completion_cond.hpp
@@ -0,0 +1,67 @@
+//
+// base_from_completion_cond.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
+#define BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/completion_condition.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename CompletionCondition>
+class base_from_completion_cond
+{
+protected:
+ explicit base_from_completion_cond(CompletionCondition completion_condition)
+ : completion_condition_(completion_condition)
+ {
+ }
+
+ std::size_t check(const boost::system::error_code& ec,
+ std::size_t total_transferred)
+ {
+ return detail::adapt_completion_condition_result(
+ completion_condition_(ec, total_transferred));
+ }
+
+private:
+ CompletionCondition completion_condition_;
+};
+
+template <>
+class base_from_completion_cond<transfer_all_t>
+{
+protected:
+ explicit base_from_completion_cond(transfer_all_t)
+ {
+ }
+
+ static std::size_t check(const boost::system::error_code& ec,
+ std::size_t total_transferred)
+ {
+ return transfer_all_t()(ec, total_transferred);
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/buffer_sequence_adapter.hpp b/3rdParty/Boost/src/boost/asio/detail/buffer_sequence_adapter.hpp
new file mode 100644
index 0000000..ce9652e
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/buffer_sequence_adapter.hpp
@@ -0,0 +1,254 @@
+//
+// buffer_sequence_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
+#define BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class buffer_sequence_adapter_base
+{
+protected:
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ typedef WSABUF native_buffer_type;
+
+ static void init_native_buffer(WSABUF& buf,
+ const boost::asio::mutable_buffer& buffer)
+ {
+ buf.buf = boost::asio::buffer_cast<char*>(buffer);
+ buf.len = boost::asio::buffer_size(buffer);
+ }
+
+ static void init_native_buffer(WSABUF& buf,
+ const boost::asio::const_buffer& buffer)
+ {
+ buf.buf = const_cast<char*>(boost::asio::buffer_cast<const char*>(buffer));
+ buf.len = boost::asio::buffer_size(buffer);
+ }
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ typedef iovec native_buffer_type;
+
+ static void init_iov_base(void*& base, void* addr)
+ {
+ base = addr;
+ }
+
+ template <typename T>
+ static void init_iov_base(T& base, void* addr)
+ {
+ base = static_cast<T>(addr);
+ }
+
+ static void init_native_buffer(iovec& iov,
+ const boost::asio::mutable_buffer& buffer)
+ {
+ init_iov_base(iov.iov_base, boost::asio::buffer_cast<void*>(buffer));
+ iov.iov_len = boost::asio::buffer_size(buffer);
+ }
+
+ static void init_native_buffer(iovec& iov,
+ const boost::asio::const_buffer& buffer)
+ {
+ init_iov_base(iov.iov_base, const_cast<void*>(
+ boost::asio::buffer_cast<const void*>(buffer)));
+ iov.iov_len = boost::asio::buffer_size(buffer);
+ }
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+};
+
+// Helper class to translate buffers into the native buffer representation.
+template <typename Buffer, typename Buffers>
+class buffer_sequence_adapter
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(const Buffers& buffers)
+ : count_(0), total_buffer_size_(0)
+ {
+ typename Buffers::const_iterator iter = buffers.begin();
+ typename Buffers::const_iterator end = buffers.end();
+ for (; iter != end && count_ < max_buffers; ++iter, ++count_)
+ {
+ Buffer buffer(*iter);
+ init_native_buffer(buffers_[count_], buffer);
+ total_buffer_size_ += boost::asio::buffer_size(buffer);
+ }
+ }
+
+ native_buffer_type* buffers()
+ {
+ return buffers_;
+ }
+
+ std::size_t count() const
+ {
+ return count_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const Buffers& buffers)
+ {
+ typename Buffers::const_iterator iter = buffers.begin();
+ typename Buffers::const_iterator end = buffers.end();
+ std::size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ if (boost::asio::buffer_size(Buffer(*iter)) > 0)
+ return false;
+ return true;
+ }
+
+ static void validate(const Buffers& buffers)
+ {
+ typename Buffers::const_iterator iter = buffers.begin();
+ typename Buffers::const_iterator end = buffers.end();
+ for (; iter != end; ++iter)
+ {
+ Buffer buffer(*iter);
+ boost::asio::buffer_cast<const void*>(buffer);
+ }
+ }
+
+ static Buffer first(const Buffers& buffers)
+ {
+ typename Buffers::const_iterator iter = buffers.begin();
+ typename Buffers::const_iterator end = buffers.end();
+ for (; iter != end; ++iter)
+ {
+ Buffer buffer(*iter);
+ if (boost::asio::buffer_size(buffer) != 0)
+ return buffer;
+ }
+ return Buffer();
+ }
+
+private:
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+ native_buffer_type buffers_[max_buffers];
+ std::size_t count_;
+ std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const boost::asio::mutable_buffers_1& buffers)
+ {
+ init_native_buffer(buffer_, buffers);
+ total_buffer_size_ = boost::asio::buffer_size(buffers);
+ }
+
+ native_buffer_type* buffers()
+ {
+ return &buffer_;
+ }
+
+ std::size_t count() const
+ {
+ return 1;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const boost::asio::mutable_buffers_1& buffers)
+ {
+ return boost::asio::buffer_size(buffers) == 0;
+ }
+
+ static void validate(const boost::asio::mutable_buffers_1& buffers)
+ {
+ boost::asio::buffer_cast<const void*>(buffers);
+ }
+
+ static Buffer first(const boost::asio::mutable_buffers_1& buffers)
+ {
+ return Buffer(buffers);
+ }
+
+private:
+ native_buffer_type buffer_;
+ std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const boost::asio::const_buffers_1& buffers)
+ {
+ init_native_buffer(buffer_, buffers);
+ total_buffer_size_ = boost::asio::buffer_size(buffers);
+ }
+
+ native_buffer_type* buffers()
+ {
+ return &buffer_;
+ }
+
+ std::size_t count() const
+ {
+ return 1;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const boost::asio::const_buffers_1& buffers)
+ {
+ return boost::asio::buffer_size(buffers) == 0;
+ }
+
+ static void validate(const boost::asio::const_buffers_1& buffers)
+ {
+ boost::asio::buffer_cast<const void*>(buffers);
+ }
+
+ static Buffer first(const boost::asio::const_buffers_1& buffers)
+ {
+ return Buffer(buffers);
+ }
+
+private:
+ native_buffer_type buffer_;
+ std::size_t total_buffer_size_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/completion_handler.hpp b/3rdParty/Boost/src/boost/asio/detail/completion_handler.hpp
new file mode 100644
index 0000000..d78e6c8
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/completion_handler.hpp
@@ -0,0 +1,73 @@
+//
+// completion_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP
+#define BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/operation.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class completion_handler : public operation
+{
+public:
+ completion_handler(Handler h)
+ : operation(&completion_handler::do_complete),
+ handler_(h)
+ {
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ completion_handler* h(static_cast<completion_handler*>(base));
+ typedef handler_alloc_traits<Handler, completion_handler> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ Handler handler(h->handler_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp b/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp
index bf04b1b..3604cba 100644
--- a/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/consuming_buffers.hpp
@@ -21,12 +21,11 @@
#include <algorithm>
#include <cstddef>
#include <boost/config.hpp>
-#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator.hpp>
#include <boost/limits.hpp>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/buffer.hpp>
-#include <boost/asio/completion_condition.hpp>
namespace boost {
namespace asio {
@@ -35,9 +34,7 @@ namespace detail {
// A proxy iterator for a sub-range in a list of buffers.
template <typename Buffer, typename Buffer_Iterator>
class consuming_buffers_iterator
- : public boost::iterator_facade<
- consuming_buffers_iterator<Buffer, Buffer_Iterator>,
- const Buffer, boost::forward_traversal_tag>
+ : public boost::iterator<std::forward_iterator_tag, const Buffer>
{
public:
// Default constructor creates an end iterator.
@@ -60,9 +57,48 @@ public:
{
}
-private:
- friend class boost::iterator_core_access;
+ // Dereference an iterator.
+ const Buffer& operator*() const
+ {
+ return dereference();
+ }
+
+ // Dereference an iterator.
+ const Buffer* operator->() const
+ {
+ return &dereference();
+ }
+
+ // Increment operator (prefix).
+ consuming_buffers_iterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+ // Increment operator (postfix).
+ consuming_buffers_iterator operator++(int)
+ {
+ consuming_buffers_iterator tmp(*this);
+ ++*this;
+ return tmp;
+ }
+
+ // Test two iterators for equality.
+ friend bool operator==(const consuming_buffers_iterator& a,
+ const consuming_buffers_iterator& b)
+ {
+ return a.equal(b);
+ }
+
+ // Test two iterators for inequality.
+ friend bool operator!=(const consuming_buffers_iterator& a,
+ const consuming_buffers_iterator& b)
+ {
+ return !a.equal(b);
+ }
+
+private:
void increment()
{
if (!at_end_)
@@ -170,7 +206,7 @@ public:
}
// Set the maximum size for a single transfer.
- void set_max_size(std::size_t max_size)
+ void prepare(std::size_t max_size)
{
max_size_ = max_size;
}
@@ -226,7 +262,7 @@ public:
// No-op.
}
- void set_max_size(std::size_t)
+ void prepare(std::size_t)
{
// No-op.
}
diff --git a/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp b/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp
index 7885c9a..5ba21b1 100644
--- a/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/deadline_timer_service.hpp
@@ -26,21 +26,20 @@
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/bind_handler.hpp>
-#include <boost/asio/detail/handler_base_from_member.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/noncopyable.hpp>
-#include <boost/asio/detail/service_base.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_op.hpp>
#include <boost/asio/detail/timer_queue.hpp>
+#include <boost/asio/detail/timer_scheduler.hpp>
namespace boost {
namespace asio {
namespace detail {
-template <typename Time_Traits, typename Timer_Scheduler>
+template <typename Time_Traits>
class deadline_timer_service
- : public boost::asio::detail::service_base<
- deadline_timer_service<Time_Traits, Timer_Scheduler> >
{
public:
// The time type.
@@ -60,9 +59,7 @@ public:
// Constructor.
deadline_timer_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
- scheduler_(boost::asio::use_service<Timer_Scheduler>(io_service))
+ : scheduler_(boost::asio::use_service<timer_scheduler>(io_service))
{
scheduler_.init_task();
scheduler_.add_timer_queue(timer_queue_);
@@ -156,34 +153,58 @@ public:
}
template <typename Handler>
- class wait_handler :
- public handler_base_from_member<Handler>
+ class wait_handler : public timer_op
{
public:
- wait_handler(boost::asio::io_service& io_service, Handler handler)
- : handler_base_from_member<Handler>(handler),
- io_service_(io_service),
- work_(io_service)
+ wait_handler(Handler handler)
+ : timer_op(&wait_handler::do_complete),
+ handler_(handler)
{
}
- void operator()(const boost::system::error_code& result)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- io_service_.post(detail::bind_handler(this->handler_, result));
+ // Take ownership of the handler object.
+ wait_handler* h(static_cast<wait_handler*>(base));
+ typedef handler_alloc_traits<Handler, wait_handler> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder1<Handler, boost::system::error_code>
+ handler(h->handler_, h->ec_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
private:
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
+ Handler handler_;
};
// Start an asynchronous wait on the timer.
template <typename Handler>
void async_wait(implementation_type& impl, Handler handler)
{
+ // Allocate and construct an operation to wrap the handler.
+ typedef wait_handler<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);
+
impl.might_have_pending_waits = true;
- scheduler_.schedule_timer(timer_queue_, impl.expiry,
- wait_handler<Handler>(this->get_io_service(), handler), &impl);
+
+ scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl);
+ ptr.release();
}
private:
@@ -191,7 +212,7 @@ private:
timer_queue<Time_Traits> timer_queue_;
// The object that schedules and executes timers. Usually a reactor.
- Timer_Scheduler& scheduler_;
+ timer_scheduler& scheduler_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp
index 7315384..e00f501 100644
--- a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor.hpp
@@ -33,27 +33,30 @@
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/hash_map.hpp>
#include <boost/asio/detail/mutex.hpp>
-#include <boost/asio/detail/task_io_service.hpp>
-#include <boost/asio/detail/thread.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/reactor_op_queue.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/service_base.hpp>
-#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/timer_queue.hpp>
+#include <boost/asio/detail/timer_op.hpp>
+#include <boost/asio/detail/timer_queue_base.hpp>
+#include <boost/asio/detail/timer_queue_fwd.hpp>
+#include <boost/asio/detail/timer_queue_set.hpp>
namespace boost {
namespace asio {
namespace detail {
-template <bool Own_Thread>
class dev_poll_reactor
- : public boost::asio::detail::service_base<dev_poll_reactor<Own_Thread> >
+ : public boost::asio::detail::service_base<dev_poll_reactor>
{
public:
+ enum { read_op = 0, write_op = 1,
+ connect_op = 1, except_op = 2, max_ops = 3 };
+
// Per-descriptor data.
struct per_descriptor_data
{
@@ -61,28 +64,13 @@ public:
// Constructor.
dev_poll_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- dev_poll_reactor<Own_Thread> >(io_service),
+ : boost::asio::detail::service_base<dev_poll_reactor>(io_service),
+ io_service_(use_service<io_service_impl>(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)
- {
- boost::asio::detail::signal_blocker sb;
- thread_ = new boost::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();
@@ -103,35 +91,20 @@ public:
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
- stop_thread_ = true;
lock.unlock();
- if (thread_)
- {
- interrupter_.interrupt();
- thread_->join();
- delete thread_;
- thread_ = 0;
- }
+ op_queue<operation> ops;
- read_op_queue_.destroy_operations();
- write_op_queue_.destroy_operations();
- except_op_queue_.destroy_operations();
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].get_all_operations(ops);
- for (std::size_t i = 0; i < timer_queues_.size(); ++i)
- timer_queues_[i]->destroy_timers();
- timer_queues_.clear();
+ timer_queues_.get_all_timers(ops);
}
- // Initialise the task, but only if the reactor is not in its own thread.
+ // Initialise the task.
void init_task()
{
- if (!Own_Thread)
- {
- typedef task_io_service<dev_poll_reactor<Own_Thread> >
- task_io_service_type;
- use_service<task_io_service_type>(this->get_io_service()).init_task();
- }
+ io_service_.init_task();
}
// Register a socket with the reactor. Returns 0 on success, system error
@@ -141,121 +114,46 @@ public:
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, per_descriptor_data&,
- Handler handler, bool allow_speculative_read = true)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (shutdown_)
- return;
-
- if (allow_speculative_read)
- {
- if (!read_op_queue_.has_operation(descriptor))
- {
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
- {
- handler.complete(ec, bytes_transferred);
- 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, per_descriptor_data&,
- Handler handler, bool allow_speculative_write = true)
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data&, reactor_op* op, bool allow_speculative)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
- if (allow_speculative_write)
+ if (allow_speculative)
{
- if (!write_op_queue_.has_operation(descriptor))
+ if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
{
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
+ if (!op_queue_[op_type].has_operation(descriptor))
{
- handler.complete(ec, bytes_transferred);
- return;
+ if (op->perform())
+ {
+ lock.unlock();
+ io_service_.post_immediate_completion(op);
+ return;
+ }
}
}
}
- if (write_op_queue_.enqueue_operation(descriptor, handler))
+ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+ io_service_.work_started();
+ if (first)
{
::pollfd& ev = add_pending_event_change(descriptor);
- ev.events = POLLOUT | POLLERR | POLLHUP;
- if (read_op_queue_.has_operation(descriptor))
+ ev.events = POLLERR | POLLHUP;
+ if (op_type == read_op
+ || op_queue_[read_op].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,
- per_descriptor_data&, Handler handler)
- {
- boost::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))
+ if (op_type == write_op
+ || op_queue_[write_op].has_operation(descriptor))
ev.events |= POLLOUT;
- interrupter_.interrupt();
- }
- }
-
- // Start a new write operation. The handler object will be invoked when the
- // information available, or an error has occurred.
- template <typename Handler>
- void start_connect_op(socket_type descriptor,
- per_descriptor_data&, Handler handler)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (shutdown_)
- 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))
+ if (op_type == except_op
+ || op_queue_[except_op].has_operation(descriptor))
ev.events |= POLLPRI;
interrupter_.interrupt();
}
@@ -267,7 +165,7 @@ public:
void cancel_ops(socket_type descriptor, per_descriptor_data&)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- cancel_ops_unlocked(descriptor);
+ cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
// Cancel any operations that are running against the descriptor and remove
@@ -282,7 +180,7 @@ public:
interrupter_.interrupt();
// Cancel any outstanding operations associated with the descriptor.
- cancel_ops_unlocked(descriptor);
+ cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
// Add a new timer queue to the reactor.
@@ -290,7 +188,7 @@ public:
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.push_back(&timer_queue);
+ timer_queues_.insert(&timer_queue);
}
// Remove a timer queue from the reactor.
@@ -298,71 +196,48 @@ public:
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
boost::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;
- }
- }
+ timer_queues_.erase(&timer_queue);
}
- // 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>
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, Handler handler, void* token)
+ const typename Time_Traits::time_type& time, timer_op* op, void* token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (timer_queue.enqueue_timer(time, handler, token))
+ {
+ bool earliest = timer_queue.enqueue_timer(time, op, token);
+ io_service_.work_started();
+ if (earliest)
interrupter_.interrupt();
+ }
}
- // Cancel the timer associated with the given token. Returns the number of
- // handlers that have been posted or dispatched.
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- std::size_t n = timer_queue.cancel_timer(token);
- if (n > 0)
- interrupter_.interrupt();
+ op_queue<operation> ops;
+ std::size_t n = timer_queue.cancel_timer(token, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
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)
+ void run(bool block, op_queue<operation>& ops)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- // Dispatch any operation cancellations that were made while the select
- // loop was not running.
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
- except_op_queue_.perform_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_)
- {
- complete_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())
- {
- complete_operations_and_timers(lock);
+ if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty()
+ && op_queue_[except_op].empty() && timer_queues_.all_empty())
return;
- }
// Write the pending event registration changes to the /dev/poll descriptor.
std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
@@ -373,14 +248,13 @@ private:
&pending_event_changes_[0], events_size);
if (result != static_cast<int>(events_size))
{
+ boost::system::error_code ec = boost::system::error_code(
+ errno, boost::asio::error::get_system_category());
for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
{
int descriptor = pending_event_changes_[i].fd;
- boost::system::error_code ec = boost::system::error_code(
- errno, boost::asio::error::get_system_category());
- read_op_queue_.perform_all_operations(descriptor, ec);
- write_op_queue_.perform_all_operations(descriptor, ec);
- except_op_queue_.perform_all_operations(descriptor, ec);
+ for (int j = 0; j < max_ops; ++j)
+ op_queue_[j].cancel_operations(descriptor, ops, ec);
}
}
pending_event_changes_.clear();
@@ -388,7 +262,6 @@ private:
}
int timeout = block ? get_timeout() : 0;
- wait_in_progress_ = true;
lock.unlock();
// Block on the /dev/poll descriptor.
@@ -400,7 +273,6 @@ private:
int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
lock.lock();
- wait_in_progress_ = false;
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
@@ -415,24 +287,24 @@ private:
bool more_reads = false;
bool more_writes = false;
bool more_except = false;
- boost::system::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_.perform_operation(descriptor, ec);
+ more_except =
+ op_queue_[except_op].perform_operations(descriptor, ops);
else
- more_except = except_op_queue_.has_operation(descriptor);
+ more_except = op_queue_[except_op].has_operation(descriptor);
if (events[i].events & (POLLIN | POLLERR | POLLHUP))
- more_reads = read_op_queue_.perform_operation(descriptor, ec);
+ more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
else
- more_reads = read_op_queue_.has_operation(descriptor);
+ more_reads = op_queue_[read_op].has_operation(descriptor);
if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
- more_writes = write_op_queue_.perform_operation(descriptor, ec);
+ more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
else
- more_writes = write_op_queue_.has_operation(descriptor);
+ more_writes = op_queue_[write_op].has_operation(descriptor);
if ((events[i].events & (POLLERR | POLLHUP)) != 0
&& !more_except && !more_reads && !more_writes)
@@ -463,48 +335,15 @@ private:
int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
if (result != sizeof(ev))
{
- ec = boost::system::error_code(errno,
+ boost::system::error_code ec(errno,
boost::asio::error::get_system_category());
- read_op_queue_.perform_all_operations(descriptor, ec);
- write_op_queue_.perform_all_operations(descriptor, ec);
- except_op_queue_.perform_all_operations(descriptor, ec);
+ for (int j = 0; j < max_ops; ++j)
+ op_queue_[j].cancel_operations(descriptor, ops, ec);
}
}
}
}
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
- except_op_queue_.perform_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();
-
- complete_operations_and_timers(lock);
- }
-
- // Run the select loop in the thread.
- void run_thread()
- {
- boost::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();
+ timer_queues_.get_ready_timers(ops);
}
// Interrupt the select loop.
@@ -513,6 +352,7 @@ private:
interrupter_.interrupt();
}
+private:
// Create the /dev/poll file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_dev_poll_create()
@@ -529,75 +369,32 @@ private:
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;
- }
+ return timer_queues_.wait_duration_msec(5 * 60 * 1000);
}
// 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)
+ void cancel_ops_unlocked(socket_type descriptor,
+ const boost::system::error_code& ec)
{
- 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)
+ bool need_interrupt = false;
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ need_interrupt = op_queue_[i].cancel_operations(
+ descriptor, ops, ec) || need_interrupt;
+ io_service_.post_deferred_completions(ops);
+ if (need_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 complete_operations_and_timers(
- boost::asio::detail::mutex::scoped_lock& lock)
- {
- timer_queues_for_cleanup_ = timer_queues_;
- lock.unlock();
- read_op_queue_.complete_operations();
- write_op_queue_.complete_operations();
- except_op_queue_.complete_operations();
- for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->complete_timers();
- }
-
// Add a pending event entry for the given descriptor.
::pollfd& add_pending_event_change(int descriptor)
{
@@ -619,6 +416,9 @@ private:
}
}
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_;
+
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
@@ -631,36 +431,14 @@ private:
// 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 queues of read, write and except operations.
+ reactor_op_queue<socket_type> op_queue_[max_ops];
// 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.
- boost::asio::detail::thread* thread_;
+ timer_queue_set timer_queues_;
// Whether the service has been shut down.
bool shutdown_;
diff --git a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp
index d890fa8..238cee5 100644
--- a/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/dev_poll_reactor_fwd.hpp
@@ -27,7 +27,6 @@ namespace boost {
namespace asio {
namespace detail {
-template <bool Own_Thread>
class dev_poll_reactor;
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp
index 6c6bfe3..4684944 100644
--- a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor.hpp
@@ -23,115 +23,126 @@
#include <boost/asio/detail/push_options.hpp>
#include <cstddef>
-#include <vector>
#include <sys/epoll.h>
#include <boost/config.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/hash_map.hpp>
#include <boost/asio/detail/mutex.hpp>
-#include <boost/asio/detail/task_io_service.hpp>
-#include <boost/asio/detail/thread.hpp>
-#include <boost/asio/detail/reactor_op_queue.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/service_base.hpp>
-#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/timer_queue.hpp>
+#include <boost/asio/detail/timer_op.hpp>
+#include <boost/asio/detail/timer_queue_base.hpp>
+#include <boost/asio/detail/timer_queue_fwd.hpp>
+#include <boost/asio/detail/timer_queue_set.hpp>
+
+#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+# define BOOST_ASIO_HAS_TIMERFD 1
+#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+# include <boost/asio/detail/push_options.hpp>
+# include <sys/timerfd.h>
+# include <boost/asio/detail/pop_options.hpp>
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
namespace boost {
namespace asio {
namespace detail {
-template <bool Own_Thread>
class epoll_reactor
- : public boost::asio::detail::service_base<epoll_reactor<Own_Thread> >
+ : public boost::asio::detail::service_base<epoll_reactor>
{
public:
- // Per-descriptor data.
- struct per_descriptor_data
+ enum { read_op = 0, write_op = 1,
+ connect_op = 1, except_op = 2, max_ops = 3 };
+
+ // Per-descriptor queues.
+ struct descriptor_state
{
- bool allow_speculative_read;
- bool allow_speculative_write;
+ descriptor_state() {}
+ descriptor_state(const descriptor_state&) {}
+ void operator=(const descriptor_state&) {}
+
+ mutex mutex_;
+ op_queue<reactor_op> op_queue_[max_ops];
+ bool shutdown_;
};
+ // Per-descriptor data.
+ typedef descriptor_state* per_descriptor_data;
+
// Constructor.
epoll_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<epoll_reactor<Own_Thread> >(io_service),
+ : boost::asio::detail::service_base<epoll_reactor>(io_service),
+ io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
epoll_fd_(do_epoll_create()),
- wait_in_progress_(false),
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+ timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
+#else // defined(BOOST_ASIO_HAS_TIMERFD)
+ timer_fd_(-1),
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
interrupter_(),
- read_op_queue_(),
- write_op_queue_(),
- except_op_queue_(),
- pending_cancellations_(),
- stop_thread_(false),
- thread_(0),
- shutdown_(false),
- need_epoll_wait_(true)
+ shutdown_(false)
{
- // Start the reactor's internal thread only if needed.
- if (Own_Thread)
- {
- boost::asio::detail::signal_blocker sb;
- thread_ = new boost::asio::detail::thread(
- bind_handler(&epoll_reactor::call_run_thread, this));
- }
-
// Add the interrupter's descriptor to epoll.
epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLIN | EPOLLERR;
- ev.data.fd = interrupter_.read_descriptor();
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+ interrupter_.interrupt();
+
+ // Add the timer descriptor to epoll.
+ if (timer_fd_ != -1)
+ {
+ ev.events = EPOLLIN | EPOLLERR;
+ ev.data.ptr = &timer_fd_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+ }
}
// Destructor.
~epoll_reactor()
{
- shutdown_service();
close(epoll_fd_);
+ if (timer_fd_ != -1)
+ close(timer_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock lock(mutex_);
shutdown_ = true;
- stop_thread_ = true;
lock.unlock();
- if (thread_)
+ op_queue<operation> ops;
+
+ descriptor_map::iterator iter = registered_descriptors_.begin();
+ descriptor_map::iterator end = registered_descriptors_.end();
+ while (iter != end)
{
- interrupter_.interrupt();
- thread_->join();
- delete thread_;
- thread_ = 0;
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(iter->second.op_queue_[i]);
+ iter->second.shutdown_ = true;
+ ++iter;
}
- 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();
+ timer_queues_.get_all_timers(ops);
}
- // Initialise the task, but only if the reactor is not in its own thread.
+ // Initialise the task.
void init_task()
{
- if (!Own_Thread)
- {
- typedef task_io_service<epoll_reactor<Own_Thread> > task_io_service_type;
- use_service<task_io_service_type>(this->get_io_service()).init_task();
- }
+ io_service_.init_task();
}
// Register a socket with the reactor. Returns 0 on success, system error
@@ -139,454 +150,274 @@ public:
int register_descriptor(socket_type descriptor,
per_descriptor_data& descriptor_data)
{
- // No need to lock according to epoll documentation.
+ mutex::scoped_lock lock(registered_descriptors_mutex_);
- descriptor_data.allow_speculative_read = true;
- descriptor_data.allow_speculative_write = true;
+ descriptor_map::iterator new_entry = registered_descriptors_.insert(
+ std::make_pair(descriptor, descriptor_state())).first;
+ descriptor_data = &new_entry->second;
epoll_event ev = { 0, { 0 } };
- ev.events = 0;
- ev.data.fd = descriptor;
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
+ ev.data.ptr = descriptor_data;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
return errno;
+
+ descriptor_data->shutdown_ = false;
+
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,
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data,
- Handler handler, bool allow_speculative_read = true)
+ reactor_op* op, bool allow_speculative)
{
- if (allow_speculative_read && descriptor_data.allow_speculative_read)
- {
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
- {
- handler.complete(ec, bytes_transferred);
- return;
- }
-
- // We only get one shot at a speculative read in this function.
- allow_speculative_read = false;
- }
-
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (shutdown_)
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ if (descriptor_data->shutdown_)
return;
- if (!allow_speculative_read)
- need_epoll_wait_ = true;
- else if (!read_op_queue_.has_operation(descriptor))
+ if (descriptor_data->op_queue_[op_type].empty())
{
- // Speculative reads are ok as there are no queued read operations.
- descriptor_data.allow_speculative_read = true;
-
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
+ if (allow_speculative
+ && (op_type != read_op
+ || descriptor_data->op_queue_[except_op].empty()))
{
- handler.complete(ec, bytes_transferred);
- return;
+ if (op->perform())
+ {
+ descriptor_lock.unlock();
+ io_service_.post_immediate_completion(op);
+ return;
+ }
}
- }
-
- // Speculative reads are not ok as there will be queued read operations.
- descriptor_data.allow_speculative_read = false;
-
- if (read_op_queue_.enqueue_operation(descriptor, handler))
- {
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;
- if (write_op_queue_.has_operation(descriptor))
- ev.events |= EPOLLOUT;
- if (except_op_queue_.has_operation(descriptor))
- 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)
+ else
{
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- read_op_queue_.perform_all_operations(descriptor, ec);
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP
+ | EPOLLOUT | EPOLLPRI | EPOLLET;
+ ev.data.ptr = descriptor_data;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
}
}
+
+ descriptor_data->op_queue_[op_type].push(op);
+ io_service_.work_started();
}
- // 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,
- per_descriptor_data& descriptor_data,
- Handler handler, bool allow_speculative_write = true)
+ // 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, per_descriptor_data& descriptor_data)
{
- if (allow_speculative_write && descriptor_data.allow_speculative_write)
- {
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
- {
- handler.complete(ec, bytes_transferred);
- return;
- }
-
- // We only get one shot at a speculative write in this function.
- allow_speculative_write = false;
- }
-
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- if (shutdown_)
- return;
-
- if (!allow_speculative_write)
- need_epoll_wait_ = true;
- else if (!write_op_queue_.has_operation(descriptor))
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
{
- // Speculative writes are ok as there are no queued write operations.
- descriptor_data.allow_speculative_write = true;
-
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
- handler.complete(ec, bytes_transferred);
- return;
+ op->ec_ = boost::asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
}
}
- // Speculative writes are not ok as there will be queued write operations.
- descriptor_data.allow_speculative_write = false;
+ descriptor_lock.unlock();
- if (write_op_queue_.enqueue_operation(descriptor, handler))
- {
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
- if (read_op_queue_.has_operation(descriptor))
- ev.events |= EPOLLIN;
- if (except_op_queue_.has_operation(descriptor))
- 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)
- {
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- write_op_queue_.perform_all_operations(descriptor, ec);
- }
- }
+ io_service_.post_deferred_completions(ops);
}
- // 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,
- per_descriptor_data&, Handler handler)
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
- if (shutdown_)
- return;
+ // Remove the descriptor from the set of known descriptors. The descriptor
+ // will be automatically removed from the epoll set when it is closed.
+ descriptor_data->shutdown_ = true;
- if (except_op_queue_.enqueue_operation(descriptor, handler))
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
{
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP;
- if (read_op_queue_.has_operation(descriptor))
- ev.events |= EPOLLIN;
- if (write_op_queue_.has_operation(descriptor))
- ev.events |= EPOLLOUT;
- 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)
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- except_op_queue_.perform_all_operations(descriptor, ec);
+ op->ec_ = boost::asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
}
}
- }
- // Start a new write operation. The handler object will be invoked when the
- // given descriptor is ready for writing or an error has occurred. Speculative
- // writes are not allowed.
- template <typename Handler>
- void start_connect_op(socket_type descriptor,
- per_descriptor_data& descriptor_data, Handler handler)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ descriptor_lock.unlock();
- if (shutdown_)
- return;
+ registered_descriptors_.erase(descriptor);
- // Speculative writes are not ok as there will be queued write operations.
- descriptor_data.allow_speculative_write = false;
-
- if (write_op_queue_.enqueue_operation(descriptor, handler))
- {
- epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
- if (read_op_queue_.has_operation(descriptor))
- ev.events |= EPOLLIN;
- if (except_op_queue_.has_operation(descriptor))
- 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)
- {
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- write_op_queue_.perform_all_operations(descriptor, ec);
- }
- }
- }
+ descriptors_lock.unlock();
- // 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, per_descriptor_data&)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- cancel_ops_unlocked(descriptor);
- }
-
- // Cancel any operations that are running against the descriptor and remove
- // its registration from the reactor.
- void close_descriptor(socket_type descriptor, per_descriptor_data&)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- // Remove the descriptor from epoll.
- epoll_event ev = { 0, { 0 } };
- epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
-
- // Cancel any outstanding operations associated with the descriptor.
- cancel_ops_unlocked(descriptor);
+ io_service_.post_deferred_completions(ops);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.push_back(&timer_queue);
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&timer_queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
- boost::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;
- }
- }
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&timer_queue);
}
- // 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>
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, Handler handler, void* token)
+ const typename Time_Traits::time_type& time, timer_op* op, void* token)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (timer_queue.enqueue_timer(time, handler, token))
+ {
+ bool earliest = timer_queue.enqueue_timer(time, op, token);
+ io_service_.work_started();
+ if (earliest)
+ {
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+ if (timer_fd_ != -1)
+ {
+ itimerspec new_timeout;
+ itimerspec old_timeout;
+ int flags = get_timeout(new_timeout);
+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+ return;
+ }
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
interrupter_.interrupt();
+ }
+ }
}
- // Cancel the timer associated with the given token. Returns the number of
- // handlers that have been posted or dispatched.
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- std::size_t n = timer_queue.cancel_timer(token);
- if (n > 0)
- interrupter_.interrupt();
+ mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = timer_queue.cancel_timer(token, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
return n;
}
-private:
- friend class task_io_service<epoll_reactor<Own_Thread> >;
-
// Run epoll once until interrupted or events are ready to be dispatched.
- void run(bool block)
+ void run(bool block, op_queue<operation>& ops)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- // Dispatch any operation cancellations that were made while the select
- // loop was not running.
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
- except_op_queue_.perform_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_)
- {
- complete_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())
+ // Calculate a timeout only if timerfd is not used.
+ int timeout;
+ if (timer_fd_ != -1)
+ timeout = block ? -1 : 0;
+ else
{
- complete_operations_and_timers(lock);
- return;
+ mutex::scoped_lock lock(mutex_);
+ timeout = block ? get_timeout() : 0;
}
- int timeout = block ? get_timeout() : 0;
- wait_in_progress_ = true;
- lock.unlock();
-
// Block on the epoll descriptor.
epoll_event events[128];
- int num_events = (block || need_epoll_wait_)
- ? epoll_wait(epoll_fd_, events, 128, timeout)
- : 0;
+ int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
- lock.lock();
- wait_in_progress_ = false;
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+ bool check_timers = (timer_fd_ == -1);
+#else // defined(BOOST_ASIO_HAS_TIMERFD)
+ bool check_timers = true;
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
- int descriptor = events[i].data.fd;
- if (descriptor == interrupter_.read_descriptor())
+ void* ptr = events[i].data.ptr;
+ if (ptr == &interrupter_)
{
- interrupter_.reset();
+ // No need to reset the interrupter since we're leaving the descriptor
+ // in a ready-to-read state and relying on edge-triggered notifications
+ // to make it so that we only get woken up when the descriptor's epoll
+ // registration is updated.
+
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+ if (timer_fd_ == -1)
+ check_timers = true;
+#else // defined(BOOST_ASIO_HAS_TIMERFD)
+ check_timers = true;
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
}
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+ else if (ptr == &timer_fd_)
+ {
+ check_timers = true;
+ }
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
else
{
- bool more_reads = false;
- bool more_writes = false;
- bool more_except = false;
- boost::system::error_code ec;
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
- if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP))
- more_except = except_op_queue_.perform_operation(descriptor, ec);
- else
- more_except = except_op_queue_.has_operation(descriptor);
-
- if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))
- more_reads = read_op_queue_.perform_operation(descriptor, ec);
- else
- more_reads = read_op_queue_.has_operation(descriptor);
-
- if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
- more_writes = write_op_queue_.perform_operation(descriptor, ec);
- else
- more_writes = write_op_queue_.has_operation(descriptor);
-
- if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0
- && (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0
- && !more_except && !more_reads && !more_writes)
+ static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
+ for (int j = max_ops - 1; j >= 0; --j)
{
- // If we have an event and no operations associated with the
- // descriptor then we need to delete the descriptor from epoll. The
- // epoll_wait system call can produce EPOLLHUP or EPOLLERR events
- // when there is no operation pending, 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)
+ if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
{
- ec = boost::system::error_code(errno,
- boost::asio::error::get_system_category());
- read_op_queue_.perform_all_operations(descriptor, ec);
- write_op_queue_.perform_all_operations(descriptor, ec);
- except_op_queue_.perform_all_operations(descriptor, ec);
+ while (reactor_op* op = descriptor_data->op_queue_[j].front())
+ {
+ if (op->perform())
+ {
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ else
+ break;
+ }
}
}
}
}
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
- except_op_queue_.perform_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();
-
- // Determine whether epoll_wait should be called when the reactor next runs.
- need_epoll_wait_ = !read_op_queue_.empty()
- || !write_op_queue_.empty() || !except_op_queue_.empty();
-
- complete_operations_and_timers(lock);
- }
- // Run the select loop in the thread.
- void run_thread()
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- while (!stop_thread_)
+ if (check_timers)
{
- lock.unlock();
- run(true);
- lock.lock();
- }
- }
+ mutex::scoped_lock common_lock(mutex_);
+ timer_queues_.get_ready_timers(ops);
- // Entry point for the select loop thread.
- static void call_run_thread(epoll_reactor* reactor)
- {
- reactor->run_thread();
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+ if (timer_fd_ != -1)
+ {
+ itimerspec new_timeout;
+ itimerspec old_timeout;
+ int flags = get_timeout(new_timeout);
+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+ }
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
+ }
}
// Interrupt the select loop.
void interrupt()
{
- interrupter_.interrupt();
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
}
+private:
// The hint to pass to epoll_create to size its data structures.
enum { epoll_size = 20000 };
@@ -606,117 +437,65 @@ private:
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 epoll_wait call. The timeout value is
// returned as a number of milliseconds. A return value of -1 indicates
// that epoll_wait 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;
- }
+ return timer_queues_.wait_duration_msec(5 * 60 * 1000);
}
- // 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 epoll_reactor's mutex.
- void cancel_ops_unlocked(socket_type descriptor)
+#if defined(BOOST_ASIO_HAS_TIMERFD)
+ // Get the timeout value for the timer descriptor. The return value is the
+ // flag argument to be used when calling timerfd_settime.
+ int get_timeout(itimerspec& ts)
{
- 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();
- }
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
- // 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 complete_operations_and_timers(
- boost::asio::detail::mutex::scoped_lock& lock)
- {
- timer_queues_for_cleanup_ = timer_queues_;
- lock.unlock();
- read_op_queue_.complete_operations();
- write_op_queue_.complete_operations();
- except_op_queue_.complete_operations();
- for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->complete_timers();
+ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ ts.it_value.tv_sec = usec / 1000000;
+ ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
+
+ return usec ? 0 : TFD_TIMER_ABSTIME;
}
+#endif // defined(BOOST_ASIO_HAS_TIMERFD)
+
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_;
// Mutex to protect access to internal data.
- boost::asio::detail::mutex mutex_;
+ mutex mutex_;
// The epoll file descriptor.
int epoll_fd_;
- // Whether the epoll_wait call is currently in progress
- bool wait_in_progress_;
+ // The timer file descriptor.
+ int timer_fd_;
// The interrupter is used to break a blocking epoll_wait call.
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.
- boost::asio::detail::thread* thread_;
+ timer_queue_set timer_queues_;
// Whether the service has been shut down.
bool shutdown_;
- // Whether we need to call epoll_wait the next time the reactor is run.
- bool need_epoll_wait_;
+ // Mutex to protect access to the registered descriptors.
+ mutex registered_descriptors_mutex_;
+
+ // Keep track of all registered descriptors. This code relies on the fact that
+ // the hash_map implementation pools deleted nodes, meaning that we can assume
+ // our descriptor_state pointer remains valid even after the entry is removed.
+ // Technically this is not true for C++98, as that standard says that spliced
+ // elements in a list are invalidated. However, C++0x fixes this shortcoming
+ // so we'll just assume that C++98 std::list implementations will do the right
+ // thing anyway.
+ typedef detail::hash_map<socket_type, descriptor_state> descriptor_map;
+ descriptor_map registered_descriptors_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp
index 9659dd4..214cee5 100644
--- a/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/epoll_reactor_fwd.hpp
@@ -33,7 +33,6 @@ namespace boost {
namespace asio {
namespace detail {
-template <bool Own_Thread>
class epoll_reactor;
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/event.hpp b/3rdParty/Boost/src/boost/asio/detail/event.hpp
index 89f9896..e8d185f 100644
--- a/3rdParty/Boost/src/boost/asio/detail/event.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/event.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
# include <boost/asio/detail/null_event.hpp>
#elif defined(BOOST_WINDOWS)
# include <boost/asio/detail/win_event.hpp>
@@ -35,7 +35,7 @@ namespace boost {
namespace asio {
namespace detail {
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
typedef null_event event;
#elif defined(BOOST_WINDOWS)
typedef win_event event;
diff --git a/3rdParty/Boost/src/boost/asio/detail/fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/fenced_block.hpp
new file mode 100644
index 0000000..c80161f
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/fenced_block.hpp
@@ -0,0 +1,72 @@
+//
+// fenced_block.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP
+#define BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
+# include <boost/asio/detail/null_fenced_block.hpp>
+#elif defined(__MACH__) && defined(__APPLE__)
+# include <boost/asio/detail/macos_fenced_block.hpp>
+#elif defined(__sun)
+# include <boost/asio/detail/solaris_fenced_block.hpp>
+#elif defined(__GNUC__) \
+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+# include <boost/asio/detail/gcc_fenced_block.hpp>
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+# include <boost/asio/detail/gcc_x86_fenced_block.hpp>
+#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+# include <boost/asio/detail/win_fenced_block.hpp>
+#else
+# include <boost/asio/detail/null_fenced_block.hpp>
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
+typedef null_fenced_block fenced_block;
+#elif defined(__MACH__) && defined(__APPLE__)
+typedef macos_fenced_block fenced_block;
+#elif defined(__sun)
+typedef solaris_fenced_block fenced_block;
+#elif defined(__GNUC__) \
+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+typedef gcc_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+typedef gcc_x86_fenced_block fenced_block;
+#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+typedef win_fenced_block fenced_block;
+#else
+typedef null_fenced_block fenced_block;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/gcc_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/gcc_fenced_block.hpp
new file mode 100644
index 0000000..0c086a6
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/gcc_fenced_block.hpp
@@ -0,0 +1,65 @@
+//
+// gcc_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP
+#define BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(__GNUC__) \
+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class gcc_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ gcc_fenced_block()
+ : value_(0)
+ {
+ __sync_lock_test_and_set(&value_, 1);
+ }
+
+ // Destructor.
+ ~gcc_fenced_block()
+ {
+ __sync_lock_release(&value_);
+ }
+
+private:
+ int value_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(__GNUC__)
+ // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4))
+ // && !defined(__INTEL_COMPILER) && !defined(__ICL)
+ // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/gcc_x86_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/gcc_x86_fenced_block.hpp
new file mode 100644
index 0000000..fc23d66
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/gcc_x86_fenced_block.hpp
@@ -0,0 +1,63 @@
+//
+// gcc_x86_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
+#define BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class gcc_x86_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ gcc_x86_fenced_block()
+ {
+ barrier();
+ }
+
+ // Destructor.
+ ~gcc_x86_fenced_block()
+ {
+ barrier();
+ }
+
+private:
+ static int barrier()
+ {
+ int r = 0;
+ __asm__ __volatile__ ("xchgl %%eax, %0" : "=m" (r) : : "memory", "cc");
+ return r;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/handler_base_from_member.hpp b/3rdParty/Boost/src/boost/asio/detail/handler_base_from_member.hpp
deleted file mode 100644
index 4e471e3..0000000
--- a/3rdParty/Boost/src/boost/asio/detail/handler_base_from_member.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// handler_base_from_member.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP
-#define BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/push_options.hpp>
-
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
-#include <boost/asio/detail/handler_invoke_helpers.hpp>
-
-namespace boost {
-namespace asio {
-namespace detail {
-
-// Base class for classes that need a handler data member. Forwards the custom
-// allocation and invocation hooks to the contained handler.
-template <typename Handler>
-class handler_base_from_member
-{
-public:
- handler_base_from_member(Handler handler)
- : handler_(handler)
- {
- }
-
-//protected:
- Handler handler_;
-
-protected:
- // Protected destructor to prevent deletion through this type.
- ~handler_base_from_member()
- {
- }
-};
-
-template <typename Handler>
-inline void* asio_handler_allocate(std::size_t size,
- handler_base_from_member<Handler>* this_handler)
-{
- return boost_asio_handler_alloc_helpers::allocate(
- size, this_handler->handler_);
-}
-
-template <typename Handler>
-inline void asio_handler_deallocate(void* pointer, std::size_t size,
- handler_base_from_member<Handler>* this_handler)
-{
- boost_asio_handler_alloc_helpers::deallocate(
- pointer, size, this_handler->handler_);
-}
-
-template <typename Function, typename Handler>
-inline void asio_handler_invoke(const Function& function,
- handler_base_from_member<Handler>* this_handler)
-{
- boost_asio_handler_invoke_helpers::invoke(
- function, this_handler->handler_);
-}
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#include <boost/asio/detail/pop_options.hpp>
-
-#endif // BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/handler_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/handler_queue.hpp
deleted file mode 100644
index c1fb988..0000000
--- a/3rdParty/Boost/src/boost/asio/detail/handler_queue.hpp
+++ /dev/null
@@ -1,231 +0,0 @@
-//
-// handler_queue.hpp
-// ~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
-#define BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/push_options.hpp>
-
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
-#include <boost/asio/detail/handler_invoke_helpers.hpp>
-#include <boost/asio/detail/noncopyable.hpp>
-
-namespace boost {
-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.
- boost_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);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(h->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
- }
-
- private:
- Handler handler_;
- };
-
- // The front of the queue.
- handler* front_;
-
- // The back of the queue.
- handler* back_;
-};
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#include <boost/asio/detail/pop_options.hpp>
-
-#endif // BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp b/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp
index c620da7..36c9a99 100644
--- a/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/hash_map.hpp
@@ -21,7 +21,6 @@
#include <cassert>
#include <list>
#include <utility>
-#include <vector>
#include <boost/functional/hash.hpp>
#include <boost/asio/detail/pop_options.hpp>
@@ -62,9 +61,16 @@ public:
// Constructor.
hash_map()
- : size_(0)
+ : size_(0),
+ buckets_(0),
+ num_buckets_(0)
{
- rehash(hash_size(0));
+ }
+
+ // Destructor.
+ ~hash_map()
+ {
+ delete[] buckets_;
}
// Get an iterator for the beginning of the map.
@@ -100,17 +106,20 @@ public:
// Find an entry in the map.
iterator find(const K& k)
{
- size_t bucket = calculate_hash_value(k) % buckets_.size();
- iterator it = buckets_[bucket].first;
- if (it == values_.end())
- return values_.end();
- iterator end = buckets_[bucket].last;
- ++end;
- while (it != end)
+ if (num_buckets_)
{
- if (it->first == k)
- return it;
- ++it;
+ size_t bucket = calculate_hash_value(k) % num_buckets_;
+ iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ return values_.end();
+ iterator end = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ if (it->first == k)
+ return it;
+ ++it;
+ }
}
return values_.end();
}
@@ -118,17 +127,20 @@ public:
// Find an entry in the map.
const_iterator find(const K& k) const
{
- size_t bucket = calculate_hash_value(k) % buckets_.size();
- const_iterator it = buckets_[bucket].first;
- if (it == values_.end())
- return it;
- const_iterator end = buckets_[bucket].last;
- ++end;
- while (it != end)
+ if (num_buckets_)
{
- if (it->first == k)
+ size_t bucket = calculate_hash_value(k) % num_buckets_;
+ const_iterator it = buckets_[bucket].first;
+ if (it == values_.end())
return it;
- ++it;
+ const_iterator end = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ if (it->first == k)
+ return it;
+ ++it;
+ }
}
return values_.end();
}
@@ -136,9 +148,9 @@ public:
// Insert a new entry into the map.
std::pair<iterator, bool> insert(const value_type& v)
{
- if (size_ + 1 >= buckets_.size())
+ if (size_ + 1 >= num_buckets_)
rehash(hash_size(size_ + 1));
- size_t bucket = calculate_hash_value(v.first) % buckets_.size();
+ size_t bucket = calculate_hash_value(v.first) % num_buckets_;
iterator it = buckets_[bucket].first;
if (it == values_.end())
{
@@ -165,7 +177,7 @@ public:
{
assert(it != values_.end());
- size_t bucket = calculate_hash_value(it->first) % buckets_.size();
+ size_t bucket = calculate_hash_value(it->first) % num_buckets_;
bool is_first = (it == buckets_[bucket].first);
bool is_last = (it == buckets_[bucket].last);
if (is_first && is_last)
@@ -179,6 +191,14 @@ public:
--size_;
}
+ // Erase a key from the map.
+ void erase(const K& k)
+ {
+ iterator it = find(k);
+ if (it != values_.end())
+ erase(it);
+ }
+
// Remove all entries from the map.
void clear()
{
@@ -187,8 +207,9 @@ public:
size_ = 0;
// Initialise all buckets to empty.
- for (size_t i = 0; i < buckets_.size(); ++i)
- buckets_[i].first = buckets_[i].last = values_.end();
+ iterator end = values_.end();
+ for (size_t i = 0; i < num_buckets_; ++i)
+ buckets_[i].first = buckets_[i].last = end;
}
private:
@@ -215,21 +236,24 @@ private:
// Re-initialise the hash from the values already contained in the list.
void rehash(std::size_t num_buckets)
{
- if (num_buckets == buckets_.size())
+ if (num_buckets == num_buckets_)
return;
+ num_buckets_ = num_buckets;
iterator end = values_.end();
// Update number of buckets and initialise all buckets to empty.
- buckets_.resize(num_buckets);
- for (std::size_t i = 0; i < buckets_.size(); ++i)
+ bucket_type* tmp = new bucket_type[num_buckets_];
+ delete[] buckets_;
+ buckets_ = tmp;
+ for (std::size_t i = 0; i < num_buckets_; ++i)
buckets_[i].first = buckets_[i].last = end;
// Put all values back into the hash.
iterator iter = values_.begin();
while (iter != end)
{
- std::size_t bucket = calculate_hash_value(iter->first) % buckets_.size();
+ std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_;
if (buckets_[bucket].last == end)
{
buckets_[bucket].first = buckets_[bucket].last = iter++;
@@ -282,14 +306,15 @@ private:
// The type for a bucket in the hash table.
struct bucket_type
{
- bucket_type() {}
- bucket_type(const bucket_type&) { /* noop */ }
iterator first;
iterator last;
};
// The buckets in the hash.
- std::vector<bucket_type> buckets_;
+ bucket_type* buckets_;
+
+ // The number of buckets in the hash.
+ std::size_t num_buckets_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/indirect_handler_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/indirect_handler_queue.hpp
deleted file mode 100644
index 72b1030..0000000
--- a/3rdParty/Boost/src/boost/asio/detail/indirect_handler_queue.hpp
+++ /dev/null
@@ -1,293 +0,0 @@
-//
-// indirect_handler_queue.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP
-#define BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/push_options.hpp>
-
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
-#include <boost/asio/detail/handler_invoke_helpers.hpp>
-#include <boost/asio/detail/noncopyable.hpp>
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1310)
-extern "C" void _ReadWriteBarrier();
-# pragma intrinsic(_ReadWriteBarrier)
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1310)
-
-namespace boost {
-namespace asio {
-namespace detail {
-
-class indirect_handler_queue
- : private noncopyable
-{
-public:
- class handler;
-
- // Element for a node in the queue.
- class node
- {
- public:
- node()
- : version_(0),
- handler_(0),
- next_(0)
- {
- }
-
- private:
- friend class indirect_handler_queue;
- unsigned long version_;
- handler* handler_;
- node* next_;
- };
-
- // 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)
- : node_(new node),
- invoke_func_(invoke_func),
- destroy_func_(destroy_func)
- {
- }
-
- ~handler()
- {
- if (node_)
- delete node_;
- }
-
- private:
- friend class indirect_handler_queue;
- node* node_;
- 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.
- indirect_handler_queue()
- : front_(new node),
- back_(front_),
- next_version_(1)
- {
- }
-
- // Destructor.
- ~indirect_handler_queue()
- {
- while (front_)
- {
- node* tmp = front_;
- front_ = front_->next_;
- delete tmp;
- }
- }
-
- // 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();
- }
-
- // Determine whether the queue has something ready to pop.
- bool poppable()
- {
- return front_->next_ != 0;
- }
-
- // The version number at the front of the queue.
- unsigned long front_version()
- {
- return front_->version_;
- }
-
- // The version number at the back of the queue.
- unsigned long back_version()
- {
- return back_->version_;
- }
-
- // Pop a handler from the front of the queue.
- handler* pop()
- {
- node* n = front_;
- node* new_front = n->next_;
- if (new_front)
- {
- handler* h = new_front->handler_;
- h->node_ = n;
- new_front->handler_ = 0;
- front_ = new_front;
- return h;
- }
- return 0;
- }
-
- // Push a handler on to the back of the queue.
- void push(handler* h)
- {
- node* n = h->node_;
- h->node_ = 0;
- n->version_ = next_version_;
- next_version_ += 2;
- n->handler_ = h;
- n->next_ = 0;
- memory_barrier();
- back_->next_ = n;
- back_ = n;
- }
-
-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.
- boost_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);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(h->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
- }
-
- private:
- Handler handler_;
- };
-
- // Helper function to create a memory barrier.
- static void memory_barrier()
- {
-#if defined(_GLIBCXX_WRITE_MEM_BARRIER)
- _GLIBCXX_WRITE_MEM_BARRIER;
-#elif defined(_MSC_VER) && (_MSC_VER >= 1310)
- _ReadWriteBarrier();
-#else
-# error memory barrier required
-#endif
- }
-
- // The front of the queue.
- node* front_;
-
- // The back of the queue.
- node* back_;
-
- // The next version counter to be assigned to a node.
- unsigned long next_version_;
-};
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#include <boost/asio/detail/pop_options.hpp>
-
-#endif // BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp
index ea8e285..c1a6705 100644
--- a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor.hpp
@@ -24,28 +24,27 @@
#include <boost/asio/detail/push_options.hpp>
#include <cstddef>
-#include <vector>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <boost/config.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/hash_map.hpp>
#include <boost/asio/detail/mutex.hpp>
-#include <boost/asio/detail/task_io_service.hpp>
-#include <boost/asio/detail/thread.hpp>
-#include <boost/asio/detail/reactor_op_queue.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/service_base.hpp>
-#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/timer_queue.hpp>
+#include <boost/asio/detail/timer_op.hpp>
+#include <boost/asio/detail/timer_queue_base.hpp>
+#include <boost/asio/detail/timer_queue_fwd.hpp>
+#include <boost/asio/detail/timer_queue_set.hpp>
// Older versions of Mac OS X may not define EV_OOBAND.
#if !defined(EV_OOBAND)
@@ -56,520 +55,368 @@ namespace boost {
namespace asio {
namespace detail {
-template <bool Own_Thread>
class kqueue_reactor
- : public boost::asio::detail::service_base<kqueue_reactor<Own_Thread> >
+ : public boost::asio::detail::service_base<kqueue_reactor>
{
public:
- // Per-descriptor data.
- struct per_descriptor_data
+ enum op_types { read_op = 0, write_op = 1,
+ connect_op = 1, except_op = 2, max_ops = 3 };
+
+ // Per-descriptor queues.
+ struct descriptor_state
{
- bool allow_speculative_read;
- bool allow_speculative_write;
+ descriptor_state() {}
+ descriptor_state(const descriptor_state&) {}
+ void operator=(const descriptor_state&) {}
+
+ mutex mutex_;
+ op_queue<reactor_op> op_queue_[max_ops];
+ bool shutdown_;
};
+ // Per-descriptor data.
+ typedef descriptor_state* per_descriptor_data;
+
// Constructor.
kqueue_reactor(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- kqueue_reactor<Own_Thread> >(io_service),
+ : boost::asio::detail::service_base<kqueue_reactor>(io_service),
+ io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
kqueue_fd_(do_kqueue_create()),
- wait_in_progress_(false),
interrupter_(),
- read_op_queue_(),
- write_op_queue_(),
- except_op_queue_(),
- pending_cancellations_(),
- stop_thread_(false),
- thread_(0),
- shutdown_(false),
- need_kqueue_wait_(true)
+ shutdown_(false)
{
- // Start the reactor's internal thread only if needed.
- if (Own_Thread)
- {
- boost::asio::detail::signal_blocker sb;
- thread_ = new boost::asio::detail::thread(
- bind_handler(&kqueue_reactor::call_run_thread, this));
- }
-
- // Add the interrupter's descriptor to the kqueue.
- struct kevent event;
- EV_SET(&event, interrupter_.read_descriptor(),
- EVFILT_READ, EV_ADD, 0, 0, 0);
- ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
+ // The interrupter is put into a permanently readable state. Whenever we
+ // want to interrupt the blocked kevent call we register a one-shot read
+ // operation against the descriptor.
+ interrupter_.interrupt();
}
// Destructor.
~kqueue_reactor()
{
- shutdown_service();
close(kqueue_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock lock(mutex_);
shutdown_ = true;
- stop_thread_ = true;
lock.unlock();
- if (thread_)
+ op_queue<operation> ops;
+
+ descriptor_map::iterator iter = registered_descriptors_.begin();
+ descriptor_map::iterator end = registered_descriptors_.end();
+ while (iter != end)
{
- interrupter_.interrupt();
- thread_->join();
- delete thread_;
- thread_ = 0;
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(iter->second.op_queue_[i]);
+ iter->second.shutdown_ = true;
+ ++iter;
}
- 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();
+ timer_queues_.get_all_timers(ops);
}
- // Initialise the task, but only if the reactor is not in its own thread.
+ // Initialise the task.
void init_task()
{
- if (!Own_Thread)
- {
- typedef task_io_service<kqueue_reactor<Own_Thread> > task_io_service_type;
- use_service<task_io_service_type>(this->get_io_service()).init_task();
- }
+ io_service_.init_task();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
- int register_descriptor(socket_type, per_descriptor_data& descriptor_data)
+ int register_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data)
{
- descriptor_data.allow_speculative_read = true;
- descriptor_data.allow_speculative_write = true;
+ mutex::scoped_lock lock(registered_descriptors_mutex_);
+
+ descriptor_map::iterator new_entry = registered_descriptors_.insert(
+ std::make_pair(descriptor, descriptor_state())).first;
+ descriptor_data = &new_entry->second;
+
+ descriptor_data->shutdown_ = false;
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,
- per_descriptor_data& descriptor_data, Handler handler,
- bool allow_speculative_read = true)
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data& descriptor_data,
+ reactor_op* op, bool allow_speculative)
{
- if (allow_speculative_read && descriptor_data.allow_speculative_read)
- {
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
- {
- handler.complete(ec, bytes_transferred);
- return;
- }
-
- // We only get one shot at a speculative read in this function.
- allow_speculative_read = false;
- }
-
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (shutdown_)
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ if (descriptor_data->shutdown_)
return;
- if (!allow_speculative_read)
- need_kqueue_wait_ = true;
- else if (!read_op_queue_.has_operation(descriptor))
+ bool first = descriptor_data->op_queue_[op_type].empty();
+ if (first)
{
- // Speculative reads are ok as there are no queued read operations.
- descriptor_data.allow_speculative_read = true;
-
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
+ if (allow_speculative)
{
- handler.complete(ec, bytes_transferred);
- return;
+ if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
+ {
+ if (op->perform())
+ {
+ descriptor_lock.unlock();
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+ }
}
}
- // Speculative reads are not ok as there will be queued read operations.
- descriptor_data.allow_speculative_read = false;
+ descriptor_data->op_queue_[op_type].push(op);
+ io_service_.work_started();
- if (read_op_queue_.enqueue_operation(descriptor, handler))
+ if (first)
{
struct kevent event;
- EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ switch (op_type)
+ {
+ case read_op:
+ EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ break;
+ case write_op:
+ EV_SET(&event, descriptor, EVFILT_WRITE,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ break;
+ case except_op:
+ if (!descriptor_data->op_queue_[read_op].empty())
+ return; // Already registered for read events.
+ EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+ break;
+ }
+
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
- boost::system::error_code ec(errno,
+ op->ec_ = boost::system::error_code(errno,
boost::asio::error::get_system_category());
- read_op_queue_.perform_all_operations(descriptor, ec);
+ descriptor_data->op_queue_[op_type].pop();
+ io_service_.post_deferred_completion(op);
}
}
}
- // 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,
- per_descriptor_data& descriptor_data, Handler handler,
- bool allow_speculative_write = true)
+ // 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, per_descriptor_data& descriptor_data)
{
- if (allow_speculative_write && descriptor_data.allow_speculative_write)
- {
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
- {
- handler.complete(ec, bytes_transferred);
- return;
- }
-
- // We only get one shot at a speculative write in this function.
- allow_speculative_write = false;
- }
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (shutdown_)
- return;
-
- if (!allow_speculative_write)
- need_kqueue_wait_ = true;
- else if (!write_op_queue_.has_operation(descriptor))
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
{
- // Speculative writes are ok as there are no queued write operations.
- descriptor_data.allow_speculative_write = true;
-
- boost::system::error_code ec;
- std::size_t bytes_transferred = 0;
- if (handler.perform(ec, bytes_transferred))
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
- handler.complete(ec, bytes_transferred);
- return;
+ op->ec_ = boost::asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
}
}
- // Speculative writes are not ok as there will be queued write operations.
- descriptor_data.allow_speculative_write = false;
+ descriptor_lock.unlock();
- if (write_op_queue_.enqueue_operation(descriptor, handler))
- {
- struct kevent event;
- EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
- if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
- {
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- write_op_queue_.perform_all_operations(descriptor, ec);
- }
- }
+ io_service_.post_deferred_completions(ops);
}
- // 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,
- per_descriptor_data&, Handler handler)
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
- if (shutdown_)
- return;
+ // Remove the descriptor from the set of known descriptors. The descriptor
+ // will be automatically removed from the kqueue set when it is closed.
+ descriptor_data->shutdown_ = true;
- if (except_op_queue_.enqueue_operation(descriptor, handler))
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
{
- struct kevent event;
- if (read_op_queue_.has_operation(descriptor))
- EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
- else
- EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
- if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
{
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- except_op_queue_.perform_all_operations(descriptor, ec);
+ op->ec_ = boost::asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
}
}
- }
-
- // 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_connect_op(socket_type descriptor,
- per_descriptor_data& descriptor_data, Handler handler)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- if (shutdown_)
- return;
- // Speculative writes are not ok as there will be queued write operations.
- descriptor_data.allow_speculative_write = false;
+ descriptor_lock.unlock();
- if (write_op_queue_.enqueue_operation(descriptor, handler))
- {
- struct kevent event;
- EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
- if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
- {
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- write_op_queue_.perform_all_operations(descriptor, ec);
- }
- }
- }
+ registered_descriptors_.erase(descriptor);
- // 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, per_descriptor_data&)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- cancel_ops_unlocked(descriptor);
- }
+ descriptors_lock.unlock();
- // Cancel any operations that are running against the descriptor and remove
- // its registration from the reactor.
- void close_descriptor(socket_type descriptor, per_descriptor_data&)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- // Remove the descriptor from kqueue.
- struct kevent event[2];
- EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
- EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
- ::kevent(kqueue_fd_, event, 2, 0, 0, 0);
-
- // Cancel any outstanding operations associated with the descriptor.
- cancel_ops_unlocked(descriptor);
+ io_service_.post_deferred_completions(ops);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.push_back(&timer_queue);
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&timer_queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
- boost::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;
- }
- }
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&timer_queue);
}
- // 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>
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, Handler handler, void* token)
+ const typename Time_Traits::time_type& time, timer_op* op, void* token)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (timer_queue.enqueue_timer(time, handler, token))
- interrupter_.interrupt();
+ {
+ bool earliest = timer_queue.enqueue_timer(time, op, token);
+ io_service_.work_started();
+ if (earliest)
+ interrupt();
+ }
}
- // Cancel the timer associated with the given token. Returns the number of
- // handlers that have been posted or dispatched.
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- std::size_t n = timer_queue.cancel_timer(token);
- if (n > 0)
- interrupter_.interrupt();
+ mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = timer_queue.cancel_timer(token, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
return n;
}
-private:
- friend class task_io_service<kqueue_reactor<Own_Thread> >;
-
// Run the kqueue loop.
- void run(bool block)
+ void run(bool block, op_queue<operation>& ops)
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- // Dispatch any operation cancellations that were made while the select
- // loop was not running.
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
- except_op_queue_.perform_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_)
- {
- complete_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())
- {
- complete_operations_and_timers(lock);
- return;
- }
+ mutex::scoped_lock lock(mutex_);
// Determine how long to block while waiting for events.
timespec timeout_buf = { 0, 0 };
timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
- wait_in_progress_ = true;
lock.unlock();
// Block on the kqueue descriptor.
struct kevent events[128];
- int num_events = (block || need_kqueue_wait_)
- ? kevent(kqueue_fd_, 0, 0, events, 128, timeout)
- : 0;
-
- lock.lock();
- wait_in_progress_ = false;
+ int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].ident;
- if (descriptor == interrupter_.read_descriptor())
+ void* ptr = events[i].udata;
+ if (ptr == &interrupter_)
{
- interrupter_.reset();
+ // No need to reset the interrupter since we're leaving the descriptor
+ // in a ready-to-read state and relying on one-shot notifications.
}
- else if (events[i].filter == EVFILT_READ)
+ else
{
- // Dispatch operations associated with the descriptor.
- bool more_reads = false;
- bool more_except = false;
- if (events[i].flags & EV_ERROR)
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ static const int filter[max_ops] =
+ { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
+ for (int j = max_ops - 1; j >= 0; --j)
{
- boost::system::error_code error(
- events[i].data, boost::asio::error::get_system_category());
- except_op_queue_.perform_all_operations(descriptor, error);
- read_op_queue_.perform_all_operations(descriptor, error);
- }
- else if (events[i].flags & EV_OOBAND)
- {
- boost::system::error_code error;
- more_except = except_op_queue_.perform_operation(descriptor, error);
- if (events[i].data > 0)
- more_reads = read_op_queue_.perform_operation(descriptor, error);
- else
- more_reads = read_op_queue_.has_operation(descriptor);
- }
- else
- {
- boost::system::error_code error;
- more_reads = read_op_queue_.perform_operation(descriptor, error);
- more_except = except_op_queue_.has_operation(descriptor);
+ if (events[i].filter == filter[j])
+ {
+ if (j != except_op || events[i].flags & EV_OOBAND)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[j].front())
+ {
+ if (events[i].flags & EV_ERROR)
+ {
+ op->ec_ = boost::system::error_code(events[i].data,
+ boost::asio::error::get_system_category());
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ if (op->perform())
+ {
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ else
+ break;
+ }
+ }
+ }
}
- // Update the descriptor in the kqueue.
+ // Renew registration for event notifications.
struct kevent event;
- if (more_reads)
- EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
- else if (more_except)
- EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
- else
- EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
- if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
- {
- boost::system::error_code error(errno,
- boost::asio::error::get_system_category());
- except_op_queue_.perform_all_operations(descriptor, error);
- read_op_queue_.perform_all_operations(descriptor, error);
- }
- }
- else if (events[i].filter == EVFILT_WRITE)
- {
- // Dispatch operations associated with the descriptor.
- bool more_writes = false;
- if (events[i].flags & EV_ERROR)
- {
- boost::system::error_code error(
- events[i].data, boost::asio::error::get_system_category());
- write_op_queue_.perform_all_operations(descriptor, error);
- }
- else
+ switch (events[i].filter)
{
- boost::system::error_code error;
- more_writes = write_op_queue_.perform_operation(descriptor, error);
+ case EVFILT_READ:
+ if (!descriptor_data->op_queue_[read_op].empty())
+ EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ else if (!descriptor_data->op_queue_[except_op].empty())
+ EV_SET(&event, descriptor, EVFILT_READ,
+ EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+ else
+ continue;
+ case EVFILT_WRITE:
+ if (!descriptor_data->op_queue_[write_op].empty())
+ EV_SET(&event, descriptor, EVFILT_WRITE,
+ EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ else
+ continue;
+ default:
+ break;
}
-
- // Update the descriptor in the kqueue.
- struct kevent event;
- if (more_writes)
- EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
- else
- EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
boost::system::error_code error(errno,
boost::asio::error::get_system_category());
- write_op_queue_.perform_all_operations(descriptor, error);
+ for (int j = 0; j < max_ops; ++j)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[j].front())
+ {
+ op->ec_ = error;
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ }
}
}
}
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
- except_op_queue_.perform_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 (std::size_t i = 0; i < pending_cancellations_.size(); ++i)
- cancel_ops_unlocked(pending_cancellations_[i]);
- pending_cancellations_.clear();
-
- // Determine whether kqueue needs to be called next time the reactor is run.
- need_kqueue_wait_ = !read_op_queue_.empty()
- || !write_op_queue_.empty() || !except_op_queue_.empty();
-
- complete_operations_and_timers(lock);
- }
-
- // Run the select loop in the thread.
- void run_thread()
- {
- boost::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(kqueue_reactor* reactor)
- {
- reactor->run_thread();
+ lock.lock();
+ timer_queues_.get_ready_timers(ops);
}
- // Interrupt the select loop.
+ // Interrupt the kqueue loop.
void interrupt()
{
- interrupter_.interrupt();
+ struct kevent event;
+ EV_SET(&event, interrupter_.read_descriptor(),
+ EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_);
+ ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
}
+private:
// Create the kqueue file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_kqueue_create()
@@ -586,118 +433,47 @@ private:
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 kevent call.
timespec* get_timeout(timespec& ts)
{
- if (all_timer_queues_are_empty())
- return 0;
-
// 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())
- {
- ts.tv_sec = minimum_wait_duration.total_seconds();
- ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000;
- }
- else
- {
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
- }
-
+ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
return &ts;
}
- // 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 kqueue_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 complete_operations_and_timers(
- boost::asio::detail::mutex::scoped_lock& lock)
- {
- timer_queues_for_cleanup_ = timer_queues_;
- lock.unlock();
- read_op_queue_.complete_operations();
- write_op_queue_.complete_operations();
- except_op_queue_.complete_operations();
- for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->complete_timers();
- }
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_;
// Mutex to protect access to internal data.
- boost::asio::detail::mutex mutex_;
+ mutex mutex_;
// The kqueue file descriptor.
int kqueue_fd_;
- // Whether the kqueue wait call is currently in progress
- bool wait_in_progress_;
-
// The interrupter is used to break a blocking kevent call.
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.
- boost::asio::detail::thread* thread_;
+ timer_queue_set timer_queues_;
// Whether the service has been shut down.
bool shutdown_;
- // Whether we need to call kqueue the next time the reactor is run.
- bool need_kqueue_wait_;
+ // Mutex to protect access to the registered descriptors.
+ mutex registered_descriptors_mutex_;
+
+ // Keep track of all registered descriptors. This code relies on the fact that
+ // the hash_map implementation pools deleted nodes, meaning that we can assume
+ // our descriptor_state pointer remains valid even after the entry is removed.
+ // Technically this is not true for C++98, as that standard says that spliced
+ // elements in a list are invalidated. However, C++0x fixes this shortcoming
+ // so we'll just assume that C++98 std::list implementations will do the right
+ // thing anyway.
+ typedef detail::hash_map<socket_type, descriptor_state> descriptor_map;
+ descriptor_map registered_descriptors_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp
index b2751bf..0471c39 100644
--- a/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/kqueue_reactor_fwd.hpp
@@ -30,7 +30,6 @@ namespace boost {
namespace asio {
namespace detail {
-template <bool Own_Thread>
class kqueue_reactor;
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/macos_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/macos_fenced_block.hpp
new file mode 100644
index 0000000..496d7f0
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/macos_fenced_block.hpp
@@ -0,0 +1,59 @@
+//
+// macos_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
+#define BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <libkern/OSAtomic.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class macos_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ macos_fenced_block()
+ {
+ OSMemoryBarrier();
+ }
+
+ // Destructor.
+ ~macos_fenced_block()
+ {
+ OSMemoryBarrier();
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(__MACH__) && defined(__APPLE__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/mutex.hpp
index fc7ed83..e804ec2 100644
--- a/3rdParty/Boost/src/boost/asio/detail/mutex.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/mutex.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
# include <boost/asio/detail/null_mutex.hpp>
#elif defined(BOOST_WINDOWS)
# include <boost/asio/detail/win_mutex.hpp>
@@ -35,7 +35,7 @@ namespace boost {
namespace asio {
namespace detail {
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
typedef null_mutex mutex;
#elif defined(BOOST_WINDOWS)
typedef win_mutex mutex;
diff --git a/3rdParty/Boost/src/boost/asio/detail/null_buffers_op.hpp b/3rdParty/Boost/src/boost/asio/detail/null_buffers_op.hpp
new file mode 100644
index 0000000..02160af
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/null_buffers_op.hpp
@@ -0,0 +1,79 @@
+//
+// null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP
+#define BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class null_buffers_op : public reactor_op
+{
+public:
+ null_buffers_op(Handler handler)
+ : reactor_op(&null_buffers_op::do_perform, &null_buffers_op::do_complete),
+ handler_(handler)
+ {
+ }
+
+ static bool do_perform(reactor_op*)
+ {
+ return true;
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ null_buffers_op* o(static_cast<null_buffers_op*>(base));
+ typedef handler_alloc_traits<Handler, null_buffers_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an upcall,
+ // a sub-object of the handler may be the true owner of the memory
+ // associated with the handler. Consequently, a local copy of the handler
+ // is required to ensure that any owning sub-object remains valid until
+ // after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/null_event.hpp b/3rdParty/Boost/src/boost/asio/detail/null_event.hpp
index 184f753..2dc0bf6 100644
--- a/3rdParty/Boost/src/boost/asio/detail/null_event.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/null_event.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/noncopyable.hpp>
@@ -49,6 +49,12 @@ public:
{
}
+ // Signal the event and unlock the mutex.
+ template <typename Lock>
+ void signal_and_unlock(Lock&)
+ {
+ }
+
// Reset the event.
template <typename Lock>
void clear(Lock&)
@@ -66,7 +72,7 @@ public:
} // namespace asio
} // namespace boost
-#endif // !defined(BOOST_HAS_THREADS)
+#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/pop_options.hpp>
diff --git a/3rdParty/Boost/src/boost/asio/detail/null_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/null_fenced_block.hpp
new file mode 100644
index 0000000..ea8e0fc
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/null_fenced_block.hpp
@@ -0,0 +1,45 @@
+//
+// null_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
+#define BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class null_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ null_fenced_block()
+ {
+ }
+
+ // Destructor.
+ ~null_fenced_block()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp
index bdf5617..edc1358 100644
--- a/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/null_mutex.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/scoped_lock.hpp>
@@ -61,7 +61,7 @@ public:
} // namespace asio
} // namespace boost
-#endif // !defined(BOOST_HAS_THREADS)
+#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/pop_options.hpp>
diff --git a/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp b/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp
index 7fe5c10..65b55e9 100644
--- a/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/null_signal_blocker.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/noncopyable.hpp>
@@ -58,7 +58,7 @@ public:
} // namespace asio
} // namespace boost
-#endif // !defined(BOOST_HAS_THREADS)
+#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/pop_options.hpp>
diff --git a/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp b/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp
index 0a508f3..ba16311 100644
--- a/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/null_thread.hpp
@@ -22,7 +22,7 @@
#include <boost/system/system_error.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/push_options.hpp>
#include <boost/throw_exception.hpp>
@@ -63,7 +63,7 @@ public:
} // namespace asio
} // namespace boost
-#endif // !defined(BOOST_HAS_THREADS)
+#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/pop_options.hpp>
diff --git a/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp b/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp
index 7c35b15..bd83e7e 100644
--- a/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/null_tss_ptr.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/noncopyable.hpp>
@@ -65,7 +65,7 @@ private:
} // namespace asio
} // namespace boost
-#endif // !defined(BOOST_HAS_THREADS)
+#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
#include <boost/asio/detail/pop_options.hpp>
diff --git a/3rdParty/Boost/src/boost/asio/detail/op_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/op_queue.hpp
new file mode 100644
index 0000000..ddf3e18
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/op_queue.hpp
@@ -0,0 +1,158 @@
+//
+// op_queue.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_OP_QUEUE_HPP
+#define BOOST_ASIO_DETAIL_OP_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Operation>
+class op_queue;
+
+class op_queue_access
+{
+public:
+ template <typename Operation>
+ static Operation* next(Operation* o)
+ {
+ return static_cast<Operation*>(o->next_);
+ }
+
+ template <typename Operation1, typename Operation2>
+ static void next(Operation1*& o1, Operation2* o2)
+ {
+ o1->next_ = o2;
+ }
+
+ template <typename Operation>
+ static void destroy(Operation* o)
+ {
+ o->destroy();
+ }
+
+ template <typename Operation>
+ static Operation*& front(op_queue<Operation>& q)
+ {
+ return q.front_;
+ }
+
+ template <typename Operation>
+ static Operation*& back(op_queue<Operation>& q)
+ {
+ return q.back_;
+ }
+};
+
+template <typename Operation>
+class op_queue
+ : private noncopyable
+{
+public:
+ // Constructor.
+ op_queue()
+ : front_(0),
+ back_(0)
+ {
+ }
+
+ // Destructor destroys all operations.
+ ~op_queue()
+ {
+ while (Operation* op = front_)
+ {
+ pop();
+ op_queue_access::destroy(op);
+ }
+ }
+
+ // Get the operation at the front of the queue.
+ Operation* front()
+ {
+ return front_;
+ }
+
+ // Pop an operation from the front of the queue.
+ void pop()
+ {
+ if (front_)
+ {
+ Operation* tmp = front_;
+ front_ = op_queue_access::next(front_);
+ if (front_ == 0)
+ back_ = 0;
+ op_queue_access::next(tmp, static_cast<Operation*>(0));
+ }
+ }
+
+ // Push an operation on to the back of the queue.
+ void push(Operation* h)
+ {
+ op_queue_access::next(h, static_cast<Operation*>(0));
+ if (back_)
+ {
+ op_queue_access::next(back_, h);
+ back_ = h;
+ }
+ else
+ {
+ front_ = back_ = h;
+ }
+ }
+
+ // Push all operations from another queue on to the back of the queue. The
+ // source queue may contain operations of a derived type.
+ template <typename OtherOperation>
+ void push(op_queue<OtherOperation>& q)
+ {
+ if (Operation* other_front = op_queue_access::front(q))
+ {
+ if (back_)
+ op_queue_access::next(back_, other_front);
+ else
+ front_ = other_front;
+ back_ = op_queue_access::back(q);
+ op_queue_access::front(q) = 0;
+ op_queue_access::back(q) = 0;
+ }
+ }
+
+ // Whether the queue is empty.
+ bool empty() const
+ {
+ return front_ == 0;
+ }
+
+private:
+ friend class op_queue_access;
+
+ // The front of the queue.
+ Operation* front_;
+
+ // The back of the queue.
+ Operation* back_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_OP_QUEUE_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/operation.hpp b/3rdParty/Boost/src/boost/asio/detail/operation.hpp
new file mode 100644
index 0000000..579b6b5
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/operation.hpp
@@ -0,0 +1,45 @@
+//
+// operation.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_OPERATION_HPP
+#define BOOST_ASIO_DETAIL_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+# include <boost/asio/detail/win_iocp_operation.hpp>
+#else
+# include <boost/asio/detail/reactor_fwd.hpp>
+# include <boost/asio/detail/task_io_service_operation.hpp>
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+typedef win_iocp_operation operation;
+#else
+typedef task_io_service_operation<reactor> operation;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_OPERATION_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp b/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp
index 20c0fe3..b2938cf 100644
--- a/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/posix_event.hpp
@@ -72,6 +72,16 @@ public:
::pthread_cond_signal(&cond_); // Ignore EINVAL.
}
+ // Signal the event and unlock the mutex.
+ template <typename Lock>
+ void signal_and_unlock(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ signalled_ = true;
+ lock.unlock();
+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+ }
+
// Reset the event.
template <typename Lock>
void clear(Lock& lock)
diff --git a/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp
index e7209c1..6d9a44f 100644
--- a/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/posix_mutex.hpp
@@ -62,35 +62,19 @@ public:
// Destructor.
~posix_mutex()
{
- ::pthread_mutex_destroy(&mutex_);
+ ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY.
}
// Lock the mutex.
void lock()
{
- int error = ::pthread_mutex_lock(&mutex_);
- if (error != 0)
- {
- boost::system::system_error e(
- boost::system::error_code(error,
- boost::asio::error::get_system_category()),
- "mutex");
- boost::throw_exception(e);
- }
+ (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.
}
// Unlock the mutex.
void unlock()
{
- int error = ::pthread_mutex_unlock(&mutex_);
- if (error != 0)
- {
- boost::system::system_error e(
- boost::system::error_code(error,
- boost::asio::error::get_system_category()),
- "mutex");
- boost::throw_exception(e);
- }
+ (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.
}
private:
diff --git a/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp b/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp
index 61f676b..536b96a 100644
--- a/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/reactive_descriptor_service.hpp
@@ -21,10 +21,13 @@
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/bind_handler.hpp>
-#include <boost/asio/detail/handler_base_from_member.hpp>
-#include <boost/asio/detail/noncopyable.hpp>
-#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/descriptor_ops.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/null_buffers_op.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
@@ -32,10 +35,7 @@ namespace boost {
namespace asio {
namespace detail {
-template <typename Reactor>
class reactive_descriptor_service
- : public boost::asio::detail::service_base<
- reactive_descriptor_service<Reactor> >
{
public:
// The native type of a descriptor.
@@ -55,22 +55,28 @@ public:
private:
// Only this service will have access to the internal values.
- friend class reactive_descriptor_service<Reactor>;
+ friend class reactive_descriptor_service;
// The native descriptor representation.
int descriptor_;
enum
{
- user_set_non_blocking = 1, // The user wants a non-blocking descriptor.
- internal_non_blocking = 2 // The descriptor has been set non-blocking.
+ // The user wants a non-blocking descriptor.
+ user_set_non_blocking = 1,
+
+ // The descriptor has been set non-blocking.
+ internal_non_blocking = 2,
+
+ // Helper "flag" used to determine whether the descriptor is non-blocking.
+ non_blocking = user_set_non_blocking | internal_non_blocking
};
// Flags indicating the current state of the descriptor.
unsigned char flags_;
// Per-descriptor data used by the reactor.
- typename Reactor::per_descriptor_data reactor_data_;
+ reactor::per_descriptor_data reactor_data_;
};
// The maximum number of buffers to support in a single operation.
@@ -78,9 +84,8 @@ public:
// Constructor.
reactive_descriptor_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- reactive_descriptor_service<Reactor> >(io_service),
- reactor_(boost::asio::use_service<Reactor>(io_service))
+ : io_service_impl_(boost::asio::use_service<io_service_impl>(io_service)),
+ reactor_(boost::asio::use_service<reactor>(io_service))
{
reactor_.init_task();
}
@@ -209,19 +214,31 @@ public:
return ec;
}
- if (command.name() == static_cast<int>(FIONBIO))
+ descriptor_ops::ioctl(impl.descriptor_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+
+ // When updating the non-blocking mode we always perform the ioctl syscall,
+ // even if the flags would otherwise indicate that the descriptor is
+ // already in the correct state. This ensures that the underlying
+ // descriptor is put into the state that has been requested by the user. If
+ // the ioctl syscall was successful then we need to update the flags to
+ // match.
+ if (!ec && command.name() == static_cast<int>(FIONBIO))
{
- if (command.get())
+ if (*static_cast<ioctl_arg_type*>(command.data()))
+ {
impl.flags_ |= implementation_type::user_set_non_blocking;
+ }
else
- impl.flags_ &= ~implementation_type::user_set_non_blocking;
- ec = boost::system::error_code();
- }
- else
- {
- descriptor_ops::ioctl(impl.descriptor_, command.name(),
- static_cast<ioctl_arg_type*>(command.data()), ec);
+ {
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ impl.flags_ &= ~(implementation_type::user_set_non_blocking
+ | implementation_type::internal_non_blocking);
+ }
}
+
return ec;
}
@@ -236,47 +253,22 @@ public:
return 0;
}
- // Copy buffers into array.
- descriptor_ops::buf bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- descriptor_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<const void*>(buffer),
- boost::asio::buffer_size(buffer));
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
// A request to read_some 0 bytes on a stream is a no-op.
- if (total_buffer_size == 0)
+ if (bufs.all_empty())
{
ec = boost::system::error_code();
return 0;
}
- // Make descriptor non-blocking if user wants non-blocking.
- if (impl.flags_ & implementation_type::user_set_non_blocking)
- {
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- if (descriptor_ops::ioctl(impl.descriptor_,
- FIONBIO, &non_blocking, ec))
- return 0;
- impl.flags_ |= implementation_type::internal_non_blocking;
- }
- }
-
// Send the data.
for (;;)
{
// Try to complete the operation without blocking.
int bytes_sent = descriptor_ops::gather_write(
- impl.descriptor_, bufs, i, ec);
+ impl.descriptor_, bufs.buffers(), bufs.count(), ec);
// Check if operation succeeded.
if (bytes_sent >= 0)
@@ -310,48 +302,31 @@ public:
return 0;
}
- template <typename ConstBufferSequence, typename Handler>
- class write_operation :
- public handler_base_from_member<Handler>
+ template <typename ConstBufferSequence>
+ class write_op_base : public reactor_op
{
public:
- write_operation(int descriptor, boost::asio::io_service& io_service,
- const ConstBufferSequence& buffers, Handler handler)
- : handler_base_from_member<Handler>(handler),
+ write_op_base(int descriptor,
+ const ConstBufferSequence& buffers, func_type complete_func)
+ : reactor_op(&write_op_base::do_perform, complete_func),
descriptor_(descriptor),
- io_service_(io_service),
- work_(io_service),
buffers_(buffers)
{
}
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- {
- bytes_transferred = 0;
- return true;
- }
+ write_op_base* o(static_cast<write_op_base*>(base));
- // Copy buffers into array.
- descriptor_ops::buf bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers_.begin();
- typename ConstBufferSequence::const_iterator end = buffers_.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- descriptor_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<const void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
for (;;)
{
// Write the data.
- int bytes = descriptor_ops::gather_write(descriptor_, bufs, i, ec);
+ boost::system::error_code ec;
+ int bytes = descriptor_ops::gather_write(
+ o->descriptor_, bufs.buffers(), bufs.count(), ec);
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
@@ -362,120 +337,89 @@ public:
|| ec == boost::asio::error::try_again)
return false;
- bytes_transferred = (bytes < 0 ? 0 : bytes);
+ o->ec_ = ec;
+ o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
return true;
}
}
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
- }
-
private:
int descriptor_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
ConstBufferSequence buffers_;
};
- // Start an asynchronous write. The data being sent must be valid for the
- // lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
- void async_write_some(implementation_type& impl,
- const ConstBufferSequence& buffers, Handler handler)
- {
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- // Determine total size of buffers.
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
-
- // A request to read_some 0 bytes on a stream is a no-op.
- if (total_buffer_size == 0)
- {
- this->get_io_service().post(bind_handler(handler,
- boost::system::error_code(), 0));
- return;
- }
-
- // Make descriptor non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
- {
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
- }
- impl.flags_ |= implementation_type::internal_non_blocking;
- }
-
- reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
- write_operation<ConstBufferSequence, Handler>(
- impl.descriptor_, this->get_io_service(), buffers, handler));
- }
- }
-
- template <typename Handler>
- class null_buffers_operation :
- public handler_base_from_member<Handler>
+ class write_op : public write_op_base<ConstBufferSequence>
{
public:
- null_buffers_operation(boost::asio::io_service& io_service, Handler handler)
- : handler_base_from_member<Handler>(handler),
- work_(io_service)
+ write_op(int descriptor,
+ const ConstBufferSequence& buffers, Handler handler)
+ : write_op_base<ConstBufferSequence>(
+ descriptor, buffers, &write_op::do_complete),
+ handler_(handler)
{
}
- bool perform(boost::system::error_code&,
- std::size_t& bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- bytes_transferred = 0;
- return true;
- }
+ // Take ownership of the handler object.
+ write_op* o(static_cast<write_op*>(base));
+ typedef handler_alloc_traits<Handler, write_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- work_.get_io_service().post(bind_handler(
- this->handler_, ec, bytes_transferred));
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
private:
- boost::asio::io_service::work work_;
+ Handler handler_;
};
+ // Start an asynchronous write. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef write_op<ConstBufferSequence, 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, impl.descriptor_, buffers, handler);
+
+ start_op(impl, reactor::write_op, ptr.get(), true,
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers));
+ ptr.release();
+ }
+
// Start an asynchronous wait until data can be written without blocking.
template <typename Handler>
void async_write_some(implementation_type& impl,
const null_buffers&, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
+
+ start_op(impl, reactor::write_op, ptr.get(), false, false);
+ ptr.release();
}
// Read some data from the stream. Returns the number of bytes read.
@@ -489,46 +433,22 @@ public:
return 0;
}
- // Copy buffers into array.
- descriptor_ops::buf bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- descriptor_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<void*>(buffer),
- boost::asio::buffer_size(buffer));
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
// A request to read_some 0 bytes on a stream is a no-op.
- if (total_buffer_size == 0)
+ if (bufs.all_empty())
{
ec = boost::system::error_code();
return 0;
}
- // Make descriptor non-blocking if user wants non-blocking.
- if (impl.flags_ & implementation_type::user_set_non_blocking)
- {
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
- return 0;
- impl.flags_ |= implementation_type::internal_non_blocking;
- }
- }
-
// Read some data.
for (;;)
{
// Try to complete the operation without blocking.
int bytes_read = descriptor_ops::scatter_read(
- impl.descriptor_, bufs, i, ec);
+ impl.descriptor_, bufs.buffers(), bufs.count(), ec);
// Check if operation succeeded.
if (bytes_read > 0)
@@ -569,48 +489,31 @@ public:
return 0;
}
- template <typename MutableBufferSequence, typename Handler>
- class read_operation :
- public handler_base_from_member<Handler>
+ template <typename MutableBufferSequence>
+ class read_op_base : public reactor_op
{
public:
- read_operation(int descriptor, boost::asio::io_service& io_service,
- const MutableBufferSequence& buffers, Handler handler)
- : handler_base_from_member<Handler>(handler),
+ read_op_base(int descriptor,
+ const MutableBufferSequence& buffers, func_type complete_func)
+ : reactor_op(&read_op_base::do_perform, complete_func),
descriptor_(descriptor),
- io_service_(io_service),
- work_(io_service),
buffers_(buffers)
{
}
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- {
- bytes_transferred = 0;
- return true;
- }
+ read_op_base* o(static_cast<read_op_base*>(base));
- // Copy buffers into array.
- descriptor_ops::buf bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers_.begin();
- typename MutableBufferSequence::const_iterator end = buffers_.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- descriptor_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
for (;;)
{
// Read some data.
- int bytes = descriptor_ops::scatter_read(descriptor_, bufs, i, ec);
+ boost::system::error_code ec;
+ int bytes = descriptor_ops::scatter_read(
+ o->descriptor_, bufs.buffers(), bufs.count(), ec);
if (bytes == 0)
ec = boost::asio::error::eof;
@@ -623,73 +526,75 @@ public:
|| ec == boost::asio::error::try_again)
return false;
- bytes_transferred = (bytes < 0 ? 0 : bytes);
+ o->ec_ = ec;
+ o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
return true;
}
}
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
- }
-
private:
int descriptor_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
MutableBufferSequence buffers_;
};
- // Start an asynchronous read. The buffer for the data being read must be
- // valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
- void async_read_some(implementation_type& impl,
- const MutableBufferSequence& buffers, Handler handler)
+ class read_op : public read_op_base<MutableBufferSequence>
{
- if (!is_open(impl))
+ public:
+ read_op(int descriptor,
+ const MutableBufferSequence& buffers, Handler handler)
+ : read_op_base<MutableBufferSequence>(
+ descriptor, buffers, &read_op::do_complete),
+ handler_(handler)
{
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
}
- else
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- // Determine total size of buffers.
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ // Take ownership of the handler object.
+ read_op* o(static_cast<read_op*>(base));
+ typedef handler_alloc_traits<Handler, read_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
- // A request to read_some 0 bytes on a stream is a no-op.
- if (total_buffer_size == 0)
+ // Make the upcall if required.
+ if (owner)
{
- this->get_io_service().post(bind_handler(handler,
- boost::system::error_code(), 0));
- return;
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
}
+ }
- // Make descriptor non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
- {
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
- }
- impl.flags_ |= implementation_type::internal_non_blocking;
- }
+ private:
+ Handler handler_;
+ };
- reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
- read_operation<MutableBufferSequence, Handler>(
- impl.descriptor_, this->get_io_service(), buffers, handler));
- }
+ // Start an asynchronous read. The buffer for the data being read must be
+ // valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef read_op<MutableBufferSequence, 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,
+ impl.descriptor_, buffers, handler);
+
+ start_op(impl, reactor::read_op, ptr.get(), true,
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers));
+ ptr.release();
}
// Wait until data can be read without blocking.
@@ -697,22 +602,61 @@ public:
void async_read_some(implementation_type& impl,
const null_buffers&, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
+
+ start_op(impl, reactor::read_op, ptr.get(), false, false);
+ ptr.release();
+ }
+
+private:
+ // Start the asynchronous operation.
+ void start_op(implementation_type& impl, int op_type,
+ reactor_op* op, bool non_blocking, bool noop)
+ {
+ if (!noop)
{
- reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
+ if (is_open(impl))
+ {
+ if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.descriptor_,
+ impl.reactor_data_, op, non_blocking);
+ return;
+ }
+ }
+ else
+ op->ec_ = boost::asio::error::bad_descriptor;
}
+
+ io_service_impl_.post_immediate_completion(op);
}
-private:
+ // Determine whether the descriptor has been set non-blocking.
+ bool is_non_blocking(implementation_type& impl) const
+ {
+ return (impl.flags_ & implementation_type::non_blocking);
+ }
+
+ // Set the internal non-blocking flag.
+ bool set_non_blocking(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
+ return false;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ return true;
+ }
+
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_impl_;
+
// The selector that performs event demultiplexing for the service.
- Reactor& reactor_;
+ reactor& reactor_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp b/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp
index cd163e9..faa2149 100644
--- a/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/reactive_serial_port_service.hpp
@@ -38,31 +38,24 @@ namespace asio {
namespace detail {
// Extend reactive_descriptor_service to provide serial port support.
-template <typename Reactor>
class reactive_serial_port_service
- : public boost::asio::detail::service_base<
- reactive_serial_port_service<Reactor> >
{
public:
- // The native type of a stream handle.
- typedef typename reactive_descriptor_service<Reactor>::native_type
- native_type;
+ // The native type of a serial port.
+ typedef reactive_descriptor_service::native_type native_type;
- // The implementation type of the stream handle.
- typedef typename reactive_descriptor_service<Reactor>::implementation_type
- implementation_type;
+ // The implementation type of the serial port.
+ typedef reactive_descriptor_service::implementation_type implementation_type;
reactive_serial_port_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- reactive_serial_port_service>(io_service),
- descriptor_service_(boost::asio::use_service<
- reactive_descriptor_service<Reactor> >(io_service))
+ : descriptor_service_(io_service)
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
+ descriptor_service_.shutdown_service();
}
// Construct a new handle implementation.
@@ -254,8 +247,8 @@ public:
}
private:
- // The handle service used for initiating asynchronous operations.
- reactive_descriptor_service<Reactor>& descriptor_service_;
+ // The implementation used for initiating asynchronous operations.
+ reactive_descriptor_service descriptor_service_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp b/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp
index 95d39dd..5f7bbf5 100644
--- a/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/reactive_socket_service.hpp
@@ -17,18 +17,17 @@
#include <boost/asio/detail/push_options.hpp>
-#include <boost/asio/detail/push_options.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/asio/detail/pop_options.hpp>
-
#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/socket_base.hpp>
#include <boost/asio/detail/bind_handler.hpp>
-#include <boost/asio/detail/handler_base_from_member.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/noncopyable.hpp>
-#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/null_buffers_op.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_holder.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
@@ -37,10 +36,8 @@ namespace boost {
namespace asio {
namespace detail {
-template <typename Protocol, typename Reactor>
+template <typename Protocol>
class reactive_socket_service
- : public boost::asio::detail::service_base<
- reactive_socket_service<Protocol, Reactor> >
{
public:
// The protocol type.
@@ -67,7 +64,7 @@ public:
private:
// Only this service will have access to the internal values.
- friend class reactive_socket_service<Protocol, Reactor>;
+ friend class reactive_socket_service<Protocol>;
// The native socket representation.
socket_type socket_;
@@ -87,7 +84,7 @@ public:
// User wants connection_aborted errors, which are disabled by default.
enable_connection_aborted = 4,
- // The user set the linger option. Needs to be checked when closing.
+ // The user set the linger option. Needs to be checked when closing.
user_set_linger = 8
};
@@ -98,17 +95,13 @@ public:
protocol_type protocol_;
// Per-descriptor data used by the reactor.
- typename Reactor::per_descriptor_data reactor_data_;
+ reactor::per_descriptor_data reactor_data_;
};
- // The maximum number of buffers to support in a single operation.
- enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
-
// Constructor.
reactive_socket_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- reactive_socket_service<Protocol, Reactor> >(io_service),
- reactor_(boost::asio::use_service<Reactor>(io_service))
+ : io_service_impl_(use_service<io_service_impl>(io_service)),
+ reactor_(use_service<reactor>(io_service))
{
reactor_.init_task();
}
@@ -452,43 +445,30 @@ public:
return ec;
}
- if (command.name() == static_cast<int>(FIONBIO))
+ socket_ops::ioctl(impl.socket_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+
+ // When updating the non-blocking mode we always perform the ioctl
+ // syscall, even if the flags would otherwise indicate that the socket is
+ // already in the correct state. This ensures that the underlying socket
+ // is put into the state that has been requested by the user. If the ioctl
+ // syscall was successful then we need to update the flags to match.
+ if (!ec && command.name() == static_cast<int>(FIONBIO))
{
- // Flags are manipulated in a temporary variable so that the socket
- // implementation is not updated unless the ioctl operation succeeds.
- unsigned char new_flags = impl.flags_;
if (*static_cast<ioctl_arg_type*>(command.data()))
- new_flags |= implementation_type::user_set_non_blocking;
- else
- new_flags &= ~implementation_type::user_set_non_blocking;
-
- // Perform ioctl on socket if the non-blocking state has changed.
- if (!(impl.flags_ & implementation_type::non_blocking)
- && (new_flags & implementation_type::non_blocking))
{
- ioctl_arg_type non_blocking = 1;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
- }
- else if ((impl.flags_ & implementation_type::non_blocking)
- && !(new_flags & implementation_type::non_blocking))
- {
- ioctl_arg_type non_blocking = 0;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ impl.flags_ |= implementation_type::user_set_non_blocking;
}
else
{
- ec = boost::system::error_code();
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ impl.flags_ &= ~(implementation_type::user_set_non_blocking
+ | implementation_type::internal_non_blocking);
}
-
- // Update socket implementation's flags only if successful.
- if (!ec)
- impl.flags_ = new_flags;
- }
- else
- {
- socket_ops::ioctl(impl.socket_, command.name(),
- static_cast<ioctl_arg_type*>(command.data()), ec);
}
+
return ec;
}
@@ -553,23 +533,11 @@ public:
return 0;
}
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<const void*>(buffer),
- boost::asio::buffer_size(buffer));
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
// A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
{
ec = boost::system::error_code();
return 0;
@@ -579,7 +547,8 @@ public:
for (;;)
{
// Try to complete the operation without blocking.
- int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec);
+ int bytes_sent = socket_ops::send(impl.socket_,
+ bufs.buffers(), bufs.count(), flags, ec);
// Check if operation succeeded.
if (bytes_sent >= 0)
@@ -613,50 +582,32 @@ public:
return 0;
}
- template <typename ConstBufferSequence, typename Handler>
- class send_operation :
- public handler_base_from_member<Handler>
+ template <typename ConstBufferSequence>
+ class send_op_base : public reactor_op
{
public:
- send_operation(socket_type socket, boost::asio::io_service& io_service,
- const ConstBufferSequence& buffers, socket_base::message_flags flags,
- Handler handler)
- : handler_base_from_member<Handler>(handler),
+ send_op_base(socket_type socket, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&send_op_base::do_perform, complete_func),
socket_(socket),
- io_service_(io_service),
- work_(io_service),
buffers_(buffers),
flags_(flags)
{
}
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- {
- bytes_transferred = 0;
- return true;
- }
+ send_op_base* o(static_cast<send_op_base*>(base));
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers_.begin();
- typename ConstBufferSequence::const_iterator end = buffers_.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<const void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
for (;;)
{
// Send the data.
- int bytes = socket_ops::send(socket_, bufs, i, flags_, ec);
+ boost::system::error_code ec;
+ int bytes = socket_ops::send(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_, ec);
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
@@ -667,127 +618,92 @@ public:
|| ec == boost::asio::error::try_again)
return false;
- bytes_transferred = (bytes < 0 ? 0 : bytes);
+ o->ec_ = ec;
+ o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
return true;
}
}
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
- }
-
private:
socket_type socket_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
ConstBufferSequence buffers_;
socket_base::message_flags flags_;
};
- // Start an asynchronous send. The data being sent must be valid for the
- // lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
- void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
- {
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- if (impl.protocol_.type() == SOCK_STREAM)
- {
- // Determine total size of buffers.
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
-
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (total_buffer_size == 0)
- {
- this->get_io_service().post(bind_handler(handler,
- boost::system::error_code(), 0));
- return;
- }
- }
-
- // Make socket non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
- {
- if (!(impl.flags_ & implementation_type::non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
- {
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
- }
- }
- impl.flags_ |= implementation_type::internal_non_blocking;
- }
-
- reactor_.start_write_op(impl.socket_, impl.reactor_data_,
- send_operation<ConstBufferSequence, Handler>(
- impl.socket_, this->get_io_service(), buffers, flags, handler));
- }
- }
-
- template <typename Handler>
- class null_buffers_operation :
- public handler_base_from_member<Handler>
+ class send_op : public send_op_base<ConstBufferSequence>
{
public:
- null_buffers_operation(boost::asio::io_service& io_service, Handler handler)
- : handler_base_from_member<Handler>(handler),
- work_(io_service)
+ send_op(socket_type socket, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ : send_op_base<ConstBufferSequence>(socket,
+ buffers, flags, &send_op::do_complete),
+ handler_(handler)
{
}
- bool perform(boost::system::error_code&,
- std::size_t& bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- bytes_transferred = 0;
- return true;
- }
+ // Take ownership of the handler object.
+ send_op* o(static_cast<send_op*>(base));
+ typedef handler_alloc_traits<Handler, send_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- work_.get_io_service().post(bind_handler(
- this->handler_, ec, bytes_transferred));
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
private:
- boost::asio::io_service::work work_;
+ Handler handler_;
};
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef send_op<ConstBufferSequence, 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,
+ impl.socket_, buffers, flags, handler);
+
+ start_op(impl, reactor::write_op, ptr.get(), true,
+ (impl.protocol_.type() == SOCK_STREAM
+ && buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers)));
+ ptr.release();
+ }
+
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send(implementation_type& impl, const null_buffers&,
socket_base::message_flags, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- reactor_.start_write_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
+
+ start_op(impl, reactor::write_op, ptr.get(), false, false);
+ ptr.release();
}
// Send a datagram to the specified endpoint. Returns the number of bytes
@@ -803,25 +719,15 @@ public:
return 0;
}
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<const void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
// Send the data.
for (;;)
{
// Try to complete the operation without blocking.
- int bytes_sent = socket_ops::sendto(impl.socket_, bufs, i, flags,
- destination.data(), destination.size(), ec);
+ int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(),
+ bufs.count(), flags, destination.data(), destination.size(), ec);
// Check if operation succeeded.
if (bytes_sent >= 0)
@@ -856,52 +762,34 @@ public:
return 0;
}
- template <typename ConstBufferSequence, typename Handler>
- class send_to_operation :
- public handler_base_from_member<Handler>
+ template <typename ConstBufferSequence>
+ class send_to_op_base : public reactor_op
{
public:
- send_to_operation(socket_type socket, boost::asio::io_service& io_service,
- const ConstBufferSequence& buffers, const endpoint_type& endpoint,
- socket_base::message_flags flags, Handler handler)
- : handler_base_from_member<Handler>(handler),
+ send_to_op_base(socket_type socket, const ConstBufferSequence& buffers,
+ const endpoint_type& endpoint, socket_base::message_flags flags,
+ func_type complete_func)
+ : reactor_op(&send_to_op_base::do_perform, complete_func),
socket_(socket),
- io_service_(io_service),
- work_(io_service),
buffers_(buffers),
destination_(endpoint),
flags_(flags)
{
}
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- {
- bytes_transferred = 0;
- return true;
- }
+ send_to_op_base* o(static_cast<send_to_op_base*>(base));
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers_.begin();
- typename ConstBufferSequence::const_iterator end = buffers_.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<const void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
for (;;)
{
// Send the data.
- int bytes = socket_ops::sendto(socket_, bufs, i, flags_,
- destination_.data(), destination_.size(), ec);
+ boost::system::error_code ec;
+ int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(),
+ o->flags_, o->destination_.data(), o->destination_.size(), ec);
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
@@ -912,62 +800,78 @@ public:
|| ec == boost::asio::error::try_again)
return false;
- bytes_transferred = (bytes < 0 ? 0 : bytes);
+ o->ec_ = ec;
+ o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
return true;
}
}
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
- }
-
private:
socket_type socket_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
ConstBufferSequence buffers_;
endpoint_type destination_;
socket_base::message_flags flags_;
};
- // Start an asynchronous send. The data being sent must be valid for the
- // lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename Handler>
- void async_send_to(implementation_type& impl,
- const ConstBufferSequence& buffers,
- const endpoint_type& destination, socket_base::message_flags flags,
- Handler handler)
+ class send_to_op : public send_to_op_base<ConstBufferSequence>
{
- if (!is_open(impl))
+ public:
+ send_to_op(socket_type socket, const ConstBufferSequence& buffers,
+ const endpoint_type& endpoint, socket_base::message_flags flags,
+ Handler handler)
+ : send_to_op_base<ConstBufferSequence>(socket,
+ buffers, endpoint, flags, &send_to_op::do_complete),
+ handler_(handler)
{
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
}
- else
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- // Make socket non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ // Take ownership of the handler object.
+ send_to_op* o(static_cast<send_to_op*>(base));
+ typedef handler_alloc_traits<Handler, send_to_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ // Make the upcall if required.
+ if (owner)
{
- if (!(impl.flags_ & implementation_type::non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
- {
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
- }
- }
- impl.flags_ |= implementation_type::internal_non_blocking;
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
}
-
- reactor_.start_write_op(impl.socket_, impl.reactor_data_,
- send_to_operation<ConstBufferSequence, Handler>(
- impl.socket_, this->get_io_service(), buffers,
- destination, flags, handler));
}
+
+ private:
+ Handler handler_;
+ };
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef send_to_op<ConstBufferSequence, 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, impl.socket_,
+ buffers, destination, flags, handler);
+
+ start_op(impl, reactor::write_op, ptr.get(), true, false);
+ ptr.release();
}
// Start an asynchronous wait until data can be sent without blocking.
@@ -975,17 +879,14 @@ public:
void async_send_to(implementation_type& impl, const null_buffers&,
socket_base::message_flags, const endpoint_type&, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- reactor_.start_write_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
+
+ start_op(impl, reactor::write_op, ptr.get(), false, false);
+ ptr.release();
}
// Receive some data from the peer. Returns the number of bytes received.
@@ -1000,23 +901,11 @@ public:
return 0;
}
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<void*>(buffer),
- boost::asio::buffer_size(buffer));
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
// A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
{
ec = boost::system::error_code();
return 0;
@@ -1026,7 +915,8 @@ public:
for (;;)
{
// Try to complete the operation without blocking.
- int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags, ec);
+ int bytes_recvd = socket_ops::recv(impl.socket_,
+ bufs.buffers(), bufs.count(), flags, ec);
// Check if operation succeeded.
if (bytes_recvd > 0)
@@ -1067,53 +957,35 @@ public:
return 0;
}
- template <typename MutableBufferSequence, typename Handler>
- class receive_operation :
- public handler_base_from_member<Handler>
+ template <typename MutableBufferSequence>
+ class receive_op_base : public reactor_op
{
public:
- receive_operation(socket_type socket, int protocol_type,
- boost::asio::io_service& io_service,
+ receive_op_base(socket_type socket, int protocol_type,
const MutableBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
- : handler_base_from_member<Handler>(handler),
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&receive_op_base::do_perform, complete_func),
socket_(socket),
protocol_type_(protocol_type),
- io_service_(io_service),
- work_(io_service),
buffers_(buffers),
flags_(flags)
{
}
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- {
- bytes_transferred = 0;
- return true;
- }
+ receive_op_base* o(static_cast<receive_op_base*>(base));
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers_.begin();
- typename MutableBufferSequence::const_iterator end = buffers_.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
for (;;)
{
// Receive some data.
- int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec);
- if (bytes == 0 && protocol_type_ == SOCK_STREAM)
+ boost::system::error_code ec;
+ int bytes = socket_ops::recv(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_, ec);
+ if (bytes == 0 && o->protocol_type_ == SOCK_STREAM)
ec = boost::asio::error::eof;
// Retry operation if interrupted by signal.
@@ -1125,93 +997,84 @@ public:
|| ec == boost::asio::error::try_again)
return false;
- bytes_transferred = (bytes < 0 ? 0 : bytes);
+ o->ec_ = ec;
+ o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
return true;
}
}
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
- }
-
private:
socket_type socket_;
int protocol_type_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
MutableBufferSequence buffers_;
socket_base::message_flags flags_;
};
- // Start an asynchronous receive. The buffer for the data being received
- // must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
- void async_receive(implementation_type& impl,
- const MutableBufferSequence& buffers,
- socket_base::message_flags flags, Handler handler)
+ class receive_op : public receive_op_base<MutableBufferSequence>
{
- if (!is_open(impl))
+ public:
+ receive_op(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ : receive_op_base<MutableBufferSequence>(socket,
+ protocol_type, buffers, flags, &receive_op::do_complete),
+ handler_(handler)
{
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
}
- else
- {
- if (impl.protocol_.type() == SOCK_STREAM)
- {
- // Determine total size of buffers.
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
-
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (total_buffer_size == 0)
- {
- this->get_io_service().post(bind_handler(handler,
- boost::system::error_code(), 0));
- return;
- }
- }
- // Make socket non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
- {
- if (!(impl.flags_ & implementation_type::non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
- {
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
- }
- }
- impl.flags_ |= implementation_type::internal_non_blocking;
- }
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ receive_op* o(static_cast<receive_op*>(base));
+ typedef handler_alloc_traits<Handler, receive_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
- if (flags & socket_base::message_out_of_band)
+ // Make the upcall if required.
+ if (owner)
{
- reactor_.start_except_op(impl.socket_, impl.reactor_data_,
- receive_operation<MutableBufferSequence, Handler>(
- impl.socket_, impl.protocol_.type(),
- this->get_io_service(), buffers, flags, handler));
- }
- else
- {
- reactor_.start_read_op(impl.socket_, impl.reactor_data_,
- receive_operation<MutableBufferSequence, Handler>(
- impl.socket_, impl.protocol_.type(),
- this->get_io_service(), buffers, flags, handler));
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
}
}
+
+ private:
+ Handler handler_;
+ };
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_op<MutableBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ int protocol_type = impl.protocol_.type();
+ handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
+ protocol_type, buffers, flags, handler);
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ ptr.get(), (flags & socket_base::message_out_of_band) == 0,
+ (impl.protocol_.type() == SOCK_STREAM
+ && buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers)));
+ ptr.release();
}
// Wait until data can be received without blocking.
@@ -1219,22 +1082,17 @@ public:
void async_receive(implementation_type& impl, const null_buffers&,
socket_base::message_flags flags, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else if (flags & socket_base::message_out_of_band)
- {
- reactor_.start_except_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler));
- }
- else
- {
- reactor_.start_read_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ ptr.get(), false, false);
+ ptr.release();
}
// Receive a datagram with the endpoint of the sender. Returns the number of
@@ -1251,26 +1109,16 @@ public:
return 0;
}
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
// Receive some data.
for (;;)
{
// Try to complete the operation without blocking.
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);
+ int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(),
+ bufs.count(), flags, sender_endpoint.data(), &addr_len, ec);
// Check if operation succeeded.
if (bytes_recvd > 0)
@@ -1318,56 +1166,37 @@ public:
return 0;
}
- template <typename MutableBufferSequence, typename Handler>
- class receive_from_operation :
- public handler_base_from_member<Handler>
+ template <typename MutableBufferSequence>
+ class receive_from_op_base : public reactor_op
{
public:
- receive_from_operation(socket_type socket, int protocol_type,
- boost::asio::io_service& io_service,
+ receive_from_op_base(socket_type socket, int protocol_type,
const MutableBufferSequence& buffers, endpoint_type& endpoint,
- socket_base::message_flags flags, Handler handler)
- : handler_base_from_member<Handler>(handler),
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&receive_from_op_base::do_perform, complete_func),
socket_(socket),
protocol_type_(protocol_type),
- io_service_(io_service),
- work_(io_service),
buffers_(buffers),
sender_endpoint_(endpoint),
flags_(flags)
{
}
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- {
- bytes_transferred = 0;
- return true;
- }
+ receive_from_op_base* o(static_cast<receive_from_op_base*>(base));
- // Copy buffers into array.
- socket_ops::buf bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers_.begin();
- typename MutableBufferSequence::const_iterator end = buffers_.end();
- size_t i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- socket_ops::init_buf(bufs[i],
- boost::asio::buffer_cast<void*>(buffer),
- boost::asio::buffer_size(buffer));
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
for (;;)
{
// Receive some data.
- std::size_t addr_len = sender_endpoint_.capacity();
- int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_,
- sender_endpoint_.data(), &addr_len, ec);
- if (bytes == 0 && protocol_type_ == SOCK_STREAM)
+ boost::system::error_code ec;
+ std::size_t addr_len = o->sender_endpoint_.capacity();
+ int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(),
+ bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec);
+ if (bytes == 0 && o->protocol_type_ == SOCK_STREAM)
ec = boost::asio::error::eof;
// Retry operation if interrupted by signal.
@@ -1379,64 +1208,84 @@ public:
|| ec == boost::asio::error::try_again)
return false;
- sender_endpoint_.resize(addr_len);
- bytes_transferred = (bytes < 0 ? 0 : bytes);
+ o->sender_endpoint_.resize(addr_len);
+ o->ec_ = ec;
+ o->bytes_transferred_ = (bytes < 0 ? 0 : bytes);
return true;
}
}
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
- }
-
private:
socket_type socket_;
int protocol_type_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
MutableBufferSequence buffers_;
endpoint_type& sender_endpoint_;
socket_base::message_flags flags_;
};
- // Start an asynchronous receive. The buffer for the data being received and
- // the sender_endpoint object must both be valid for the lifetime of the
- // asynchronous operation.
template <typename MutableBufferSequence, typename Handler>
- void async_receive_from(implementation_type& impl,
- const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
- socket_base::message_flags flags, Handler handler)
+ class receive_from_op : public receive_from_op_base<MutableBufferSequence>
{
- if (!is_open(impl))
+ public:
+ receive_from_op(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, endpoint_type& endpoint,
+ socket_base::message_flags flags, Handler handler)
+ : receive_from_op_base<MutableBufferSequence>(socket, protocol_type,
+ buffers, endpoint, flags, &receive_from_op::do_complete),
+ handler_(handler)
{
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
}
- else
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- // Make socket non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ // Take ownership of the handler object.
+ receive_from_op* o(static_cast<receive_from_op*>(base));
+ typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ // Make the upcall if required.
+ if (owner)
{
- if (!(impl.flags_ & implementation_type::non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
- {
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
- }
- }
- impl.flags_ |= implementation_type::internal_non_blocking;
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
}
-
- reactor_.start_read_op(impl.socket_, impl.reactor_data_,
- receive_from_operation<MutableBufferSequence, Handler>(
- impl.socket_, impl.protocol_.type(), this->get_io_service(),
- buffers, sender_endpoint, flags, handler));
}
+
+ private:
+ Handler handler_;
+ };
+
+ // Start an asynchronous receive. The buffer for the data being received and
+ // the sender_endpoint object must both be valid for the lifetime of the
+ // asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_from_op<MutableBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ int protocol_type = impl.protocol_.type();
+ handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_,
+ protocol_type, buffers, sender_endpoint, flags, handler);
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ ptr.get(), true, false);
+ ptr.release();
}
// Wait until data can be received without blocking.
@@ -1445,28 +1294,20 @@ public:
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags flags, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- // Reset endpoint since it can be given no sensible value at this time.
- sender_endpoint = endpoint_type();
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
- if (flags & socket_base::message_out_of_band)
- {
- reactor_.start_except_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler));
- }
- else
- {
- reactor_.start_read_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
- }
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ ptr.get(), false, false);
+ ptr.release();
}
// Accept a new connection.
@@ -1546,19 +1387,15 @@ public:
}
}
- template <typename Socket, typename Handler>
- class accept_operation :
- public handler_base_from_member<Handler>
+ template <typename Socket>
+ class accept_op_base : public reactor_op
{
public:
- accept_operation(socket_type socket, boost::asio::io_service& io_service,
- Socket& peer, const protocol_type& protocol,
- endpoint_type* peer_endpoint, bool enable_connection_aborted,
- Handler handler)
- : handler_base_from_member<Handler>(handler),
+ accept_op_base(socket_type socket, Socket& peer,
+ const protocol_type& protocol, endpoint_type* peer_endpoint,
+ bool enable_connection_aborted, func_type complete_func)
+ : reactor_op(&accept_op_base::do_perform, complete_func),
socket_(socket),
- io_service_(io_service),
- work_(io_service),
peer_(peer),
protocol_(protocol),
peer_endpoint_(peer_endpoint),
@@ -1566,27 +1403,25 @@ public:
{
}
- bool perform(boost::system::error_code& ec, std::size_t&)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- return true;
+ accept_op_base* o(static_cast<accept_op_base*>(base));
for (;;)
{
// Accept the waiting connection.
+ boost::system::error_code ec;
socket_holder new_socket;
std::size_t addr_len = 0;
- if (peer_endpoint_)
- {
- addr_len = peer_endpoint_->capacity();
- new_socket.reset(socket_ops::accept(socket_,
- peer_endpoint_->data(), &addr_len, ec));
- }
- else
+ std::size_t* addr_len_p = 0;
+ socket_addr_type* addr = 0;
+ if (o->peer_endpoint_)
{
- new_socket.reset(socket_ops::accept(socket_, 0, 0, ec));
+ addr_len = o->peer_endpoint_->capacity();
+ addr_len_p = &addr_len;
+ addr = o->peer_endpoint_->data();
}
+ new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec));
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
@@ -1597,83 +1432,95 @@ public:
|| ec == boost::asio::error::try_again)
return false;
if (ec == boost::asio::error::connection_aborted
- && !enable_connection_aborted_)
+ && !o->enable_connection_aborted_)
return false;
#if defined(EPROTO)
- if (ec.value() == EPROTO && !enable_connection_aborted_)
+ if (ec.value() == EPROTO && !o->enable_connection_aborted_)
return false;
#endif // defined(EPROTO)
// Transfer ownership of the new socket to the peer object.
if (!ec)
{
- if (peer_endpoint_)
- peer_endpoint_->resize(addr_len);
- peer_.assign(protocol_, new_socket.get(), ec);
+ if (o->peer_endpoint_)
+ o->peer_endpoint_->resize(addr_len);
+ o->peer_.assign(o->protocol_, new_socket.get(), ec);
if (!ec)
new_socket.release();
}
+ o->ec_ = ec;
return true;
}
}
- void complete(const boost::system::error_code& ec, std::size_t)
- {
- io_service_.post(bind_handler(this->handler_, ec));
- }
-
private:
socket_type socket_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
Socket& peer_;
protocol_type protocol_;
endpoint_type* peer_endpoint_;
bool enable_connection_aborted_;
};
- // Start an asynchronous accept. The peer and peer_endpoint objects
- // must be valid until the accept's handler is invoked.
template <typename Socket, typename Handler>
- void async_accept(implementation_type& impl, Socket& peer,
- endpoint_type* peer_endpoint, Handler handler)
+ class accept_op : public accept_op_base<Socket>
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor));
- }
- else if (peer.is_open())
+ public:
+ accept_op(socket_type socket, Socket& peer, const protocol_type& protocol,
+ endpoint_type* peer_endpoint, bool enable_connection_aborted,
+ Handler handler)
+ : accept_op_base<Socket>(socket, peer, protocol, peer_endpoint,
+ enable_connection_aborted, &accept_op::do_complete),
+ handler_(handler)
{
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::already_open));
}
- else
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- // Make socket non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ // Take ownership of the handler object.
+ accept_op* o(static_cast<accept_op*>(base));
+ typedef handler_alloc_traits<Handler, accept_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ // Make the upcall if required.
+ if (owner)
{
- if (!(impl.flags_ & implementation_type::non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
- {
- this->get_io_service().post(bind_handler(handler, ec));
- return;
- }
- }
- impl.flags_ |= implementation_type::internal_non_blocking;
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder1<Handler, boost::system::error_code>
+ handler(o->handler_, o->ec_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
}
-
- reactor_.start_read_op(impl.socket_, impl.reactor_data_,
- accept_operation<Socket, Handler>(
- impl.socket_, this->get_io_service(),
- peer, impl.protocol_, peer_endpoint,
- (impl.flags_ & implementation_type::enable_connection_aborted) != 0,
- handler));
}
+
+ private:
+ Handler handler_;
+ };
+
+ // Start an asynchronous accept. The peer and peer_endpoint objects
+ // must be valid until the accept's handler is invoked.
+ template <typename Socket, typename Handler>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef accept_op<Socket, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ bool enable_connection_aborted =
+ (impl.flags_ & implementation_type::enable_connection_aborted) != 0;
+ handler_ptr<alloc_traits> ptr(raw_ptr, impl.socket_, peer,
+ impl.protocol_, peer_endpoint, enable_connection_aborted, handler);
+
+ start_accept_op(impl, ptr.get(), peer.is_open());
+ ptr.release();
}
// Connect the socket to the specified endpoint.
@@ -1713,53 +1560,77 @@ public:
return ec;
}
- template <typename Handler>
- class connect_operation :
- public handler_base_from_member<Handler>
+ class connect_op_base : public reactor_op
{
public:
- connect_operation(socket_type socket,
- boost::asio::io_service& io_service, Handler handler)
- : handler_base_from_member<Handler>(handler),
- socket_(socket),
- io_service_(io_service),
- work_(io_service)
+ connect_op_base(socket_type socket, func_type complete_func)
+ : reactor_op(&connect_op_base::do_perform, complete_func),
+ socket_(socket)
{
}
- bool perform(boost::system::error_code& ec, std::size_t&)
+ static bool do_perform(reactor_op* base)
{
- // Check whether the operation was successful.
- if (ec)
- return true;
+ connect_op_base* o(static_cast<connect_op_base*>(base));
// Get the error code from the connect operation.
int connect_error = 0;
size_t connect_error_len = sizeof(connect_error);
- if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
- &connect_error, &connect_error_len, ec) == socket_error_retval)
+ if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, o->ec_) == socket_error_retval)
return true;
// The connection failed so the handler will be posted with an error code.
if (connect_error)
{
- ec = boost::system::error_code(connect_error,
+ o->ec_ = boost::system::error_code(connect_error,
boost::asio::error::get_system_category());
- return true;
}
return true;
}
- void complete(const boost::system::error_code& ec, std::size_t)
+ private:
+ socket_type socket_;
+ };
+
+ template <typename Handler>
+ class connect_op : public connect_op_base
+ {
+ public:
+ connect_op(socket_type socket, Handler handler)
+ : connect_op_base(socket, &connect_op::do_complete),
+ handler_(handler)
{
- io_service_.post(bind_handler(this->handler_, ec));
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ connect_op* o(static_cast<connect_op*>(base));
+ typedef handler_alloc_traits<Handler, connect_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder1<Handler, boost::system::error_code>
+ handler(o->handler_, o->ec_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
private:
- socket_type socket_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
+ Handler handler_;
};
// Start an asynchronous connect.
@@ -1767,59 +1638,103 @@ public:
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor));
- return;
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef connect_op<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, impl.socket_, handler);
+
+ start_connect_op(impl, ptr.get(), peer_endpoint);
+ ptr.release();
+ }
- // Make socket non-blocking.
- if (!(impl.flags_ & implementation_type::internal_non_blocking))
+private:
+ // Start the asynchronous read or write operation.
+ void start_op(implementation_type& impl, int op_type,
+ reactor_op* op, bool non_blocking, bool noop)
+ {
+ if (!noop)
{
- if (!(impl.flags_ & implementation_type::non_blocking))
+ if (is_open(impl))
{
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ if (!non_blocking || is_non_blocking(impl)
+ || set_non_blocking(impl, op->ec_))
{
- this->get_io_service().post(bind_handler(handler, ec));
+ reactor_.start_op(op_type, impl.socket_,
+ impl.reactor_data_, op, non_blocking);
return;
}
}
- impl.flags_ |= implementation_type::internal_non_blocking;
+ else
+ op->ec_ = boost::asio::error::bad_descriptor;
}
- // Start the connect operation. The socket is already marked as non-blocking
- // so the connection will take place asynchronously.
- boost::system::error_code ec;
- if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
- peer_endpoint.size(), ec) == 0)
+ io_service_impl_.post_immediate_completion(op);
+ }
+
+ // Start the asynchronous accept operation.
+ void start_accept_op(implementation_type& impl,
+ reactor_op* op, bool peer_is_open)
+ {
+ if (!peer_is_open)
+ start_op(impl, reactor::read_op, op, true, false);
+ else
{
- // The connect operation has finished successfully so we need to post the
- // handler immediately.
- this->get_io_service().post(bind_handler(handler,
- boost::system::error_code()));
+ op->ec_ = boost::asio::error::already_open;
+ io_service_impl_.post_immediate_completion(op);
}
- else if (ec == boost::asio::error::in_progress
- || ec == boost::asio::error::would_block)
+ }
+
+ // Start the asynchronous connect operation.
+ void start_connect_op(implementation_type& impl,
+ reactor_op* op, const endpoint_type& peer_endpoint)
+ {
+ if (is_open(impl))
{
- // The connection is happening in the background, and we need to wait
- // until the socket becomes writeable.
- reactor_.start_connect_op(impl.socket_, impl.reactor_data_,
- connect_operation<Handler>(impl.socket_,
- this->get_io_service(), handler));
+ if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_))
+ {
+ if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
+ peer_endpoint.size(), op->ec_) != 0)
+ {
+ if (op->ec_ == boost::asio::error::in_progress
+ || op->ec_ == boost::asio::error::would_block)
+ {
+ op->ec_ = boost::system::error_code();
+ reactor_.start_op(reactor::connect_op,
+ impl.socket_, impl.reactor_data_, op, false);
+ return;
+ }
+ }
+ }
}
else
- {
- // The connect operation has failed, so post the handler immediately.
- this->get_io_service().post(bind_handler(handler, ec));
- }
+ op->ec_ = boost::asio::error::bad_descriptor;
+
+ io_service_impl_.post_immediate_completion(op);
}
-private:
+ // Determine whether the socket has been set non-blocking.
+ bool is_non_blocking(implementation_type& impl) const
+ {
+ return (impl.flags_ & implementation_type::non_blocking);
+ }
+
+ // Set the internal non-blocking flag.
+ bool set_non_blocking(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return false;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ return true;
+ }
+
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_impl_;
+
// The selector that performs event demultiplexing for the service.
- Reactor& reactor_;
+ reactor& reactor_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor.hpp
new file mode 100644
index 0000000..43e432b
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/reactor.hpp
@@ -0,0 +1,34 @@
+//
+// reactor.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTOR_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/reactor_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_EPOLL)
+# include <boost/asio/detail/epoll_reactor.hpp>
+#elif defined(BOOST_ASIO_HAS_KQUEUE)
+# include <boost/asio/detail/kqueue_reactor.hpp>
+#elif defined(BOOST_ASIO_HAS_DEV_POLL)
+# include <boost/asio/detail/dev_poll_reactor.hpp>
+#else
+# include <boost/asio/detail/select_reactor.hpp>
+#endif
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor_fwd.hpp
new file mode 100644
index 0000000..9ff05eb
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/reactor_fwd.hpp
@@ -0,0 +1,48 @@
+//
+// reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTOR_FWD_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/dev_poll_reactor_fwd.hpp>
+#include <boost/asio/detail/epoll_reactor_fwd.hpp>
+#include <boost/asio/detail/kqueue_reactor_fwd.hpp>
+#include <boost/asio/detail/select_reactor_fwd.hpp>
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+typedef select_reactor<true> reactor;
+#elif defined(BOOST_ASIO_HAS_EPOLL)
+typedef epoll_reactor reactor;
+#elif defined(BOOST_ASIO_HAS_KQUEUE)
+typedef kqueue_reactor reactor;
+#elif defined(BOOST_ASIO_HAS_DEV_POLL)
+typedef dev_poll_reactor reactor;
+#else
+typedef select_reactor<false> reactor;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_FWD_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor_op.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor_op.hpp
new file mode 100644
index 0000000..40647ec
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/reactor_op.hpp
@@ -0,0 +1,62 @@
+//
+// reactor_op.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/operation.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactor_op
+ : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ boost::system::error_code ec_;
+
+ // The number of bytes transferred, to be passed to the completion handler.
+ std::size_t bytes_transferred_;
+
+ // Perform the operation. Returns true if it is finished.
+ bool perform()
+ {
+ return perform_func_(this);
+ }
+
+protected:
+ typedef bool (*perform_func_type)(reactor_op*);
+
+ reactor_op(perform_func_type perform_func, func_type complete_func)
+ : operation(complete_func),
+ bytes_transferred_(0),
+ perform_func_(perform_func)
+ {
+ }
+
+private:
+ perform_func_type perform_func_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_OP_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp
index 46f0c10..0dd5654 100644
--- a/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/reactor_op_queue.hpp
@@ -17,14 +17,11 @@
#include <boost/asio/detail/push_options.hpp>
-#include <boost/asio/detail/push_options.hpp>
-#include <memory>
-#include <boost/asio/detail/pop_options.hpp>
-
#include <boost/asio/error.hpp>
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/hash_map.hpp>
#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
namespace boost {
namespace asio {
@@ -37,39 +34,21 @@ class reactor_op_queue
public:
// Constructor.
reactor_op_queue()
- : operations_(),
- cancelled_operations_(0),
- complete_operations_(0)
+ : operations_()
{
}
// Add a new operation to the queue. Returns true if this is the only
// operation for the given descriptor, in which case the reactor's event
// demultiplexing function call may need to be interrupted and restarted.
- template <typename Operation>
- bool enqueue_operation(Descriptor descriptor, Operation operation)
+ bool enqueue_operation(Descriptor descriptor, reactor_op* op)
{
- // Allocate and construct an object to wrap the handler.
- typedef handler_alloc_traits<Operation, op<Operation> > alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(operation);
- handler_ptr<alloc_traits> ptr(raw_ptr, descriptor, operation);
-
- typedef typename operation_map::iterator iterator;
- typedef typename operation_map::value_type value_type;
+ typedef typename operations_map::iterator iterator;
+ typedef typename operations_map::value_type value_type;
std::pair<iterator, bool> entry =
- operations_.insert(value_type(descriptor, ptr.get()));
- if (entry.second)
- {
- ptr.release();
- return true;
- }
-
- op_base* current_op = entry.first->second;
- while (current_op->next_)
- current_op = current_op->next_;
- current_op->next_ = ptr.release();
-
- return false;
+ operations_.insert(value_type(descriptor, operations()));
+ entry.first->second.op_queue_.push(op);
+ return entry.second;
}
// Cancel all operations associated with the descriptor. Any operations
@@ -77,16 +56,19 @@ public:
// next time perform_cancellations is called. Returns true if any operations
// were cancelled, in which case the reactor's event demultiplexing function
// may need to be interrupted and restarted.
- bool cancel_operations(Descriptor descriptor)
+ bool cancel_operations(Descriptor descriptor, op_queue<operation>& ops,
+ const boost::system::error_code& ec =
+ boost::asio::error::operation_aborted)
{
- typename operation_map::iterator i = operations_.find(descriptor);
+ typename operations_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
- op_base* last_op = i->second;
- while (last_op->next_)
- last_op = last_op->next_;
- last_op->next_ = cancelled_operations_;
- cancelled_operations_ = i->second;
+ while (reactor_op* op = i->second.op_queue_.front())
+ {
+ op->ec_ = ec;
+ i->second.op_queue_.pop();
+ ops.push(op);
+ }
operations_.erase(i);
return true;
}
@@ -106,79 +88,37 @@ public:
return operations_.find(descriptor) != operations_.end();
}
- // Perform the first operation corresponding to the descriptor. Returns true
- // if there are more operations queued for the descriptor.
- bool perform_operation(Descriptor descriptor,
- const boost::system::error_code& result)
+ // Perform the operations corresponding to the descriptor. Returns true if
+ // there are still unfinished operations queued for the descriptor.
+ bool perform_operations(Descriptor descriptor, op_queue<operation>& ops)
{
- typename operation_map::iterator i = operations_.find(descriptor);
+ typename operations_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
- op_base* this_op = i->second;
- i->second = this_op->next_;
- this_op->next_ = complete_operations_;
- complete_operations_ = this_op;
- bool done = this_op->perform(result);
- if (done)
+ while (reactor_op* op = i->second.op_queue_.front())
{
- // Operation has finished.
- if (i->second)
+ if (op->perform())
{
- return true;
+ i->second.op_queue_.pop();
+ ops.push(op);
}
else
{
- operations_.erase(i);
- return false;
- }
- }
- else
- {
- // Operation wants to be called again. Leave it at the front of the
- // queue for this descriptor, and remove from the completed list.
- complete_operations_ = this_op->next_;
- this_op->next_ = i->second;
- i->second = this_op;
- return true;
- }
- }
- return false;
- }
-
- // Perform all operations corresponding to the descriptor.
- void perform_all_operations(Descriptor descriptor,
- const boost::system::error_code& result)
- {
- typename operation_map::iterator i = operations_.find(descriptor);
- if (i != operations_.end())
- {
- while (i->second)
- {
- op_base* this_op = i->second;
- i->second = this_op->next_;
- this_op->next_ = complete_operations_;
- complete_operations_ = this_op;
- bool done = this_op->perform(result);
- if (!done)
- {
- // Operation has not finished yet, so leave at front of queue, and
- // remove from the completed list.
- complete_operations_ = this_op->next_;
- this_op->next_ = i->second;
- i->second = this_op;
- return;
+ return true;
}
}
operations_.erase(i);
}
+ return false;
}
// Fill a descriptor set with the descriptors corresponding to each active
- // operation.
+ // operation. The op_queue is used only when descriptors fail to be added to
+ // the descriptor set.
template <typename Descriptor_Set>
- void get_descriptors(Descriptor_Set& descriptors)
+ void get_descriptors(Descriptor_Set& descriptors, op_queue<operation>& ops)
{
- typename operation_map::iterator i = operations_.begin();
+ typename operations_map::iterator i = operations_.begin();
while (i != operations_.end())
{
Descriptor descriptor = i->first;
@@ -186,7 +126,7 @@ public:
if (!descriptors.set(descriptor))
{
boost::system::error_code ec(error::fd_set_failure);
- perform_all_operations(descriptor, ec);
+ cancel_operations(descriptor, ops, ec);
}
}
}
@@ -194,257 +134,62 @@ public:
// Perform the operations corresponding to the ready file descriptors
// contained in the given descriptor set.
template <typename Descriptor_Set>
- void perform_operations_for_descriptors(const Descriptor_Set& descriptors,
- const boost::system::error_code& result)
+ void perform_operations_for_descriptors(
+ const Descriptor_Set& descriptors, op_queue<operation>& ops)
{
- typename operation_map::iterator i = operations_.begin();
+ typename operations_map::iterator i = operations_.begin();
while (i != operations_.end())
{
- typename operation_map::iterator op_iter = i++;
+ typename operations_map::iterator op_iter = i++;
if (descriptors.is_set(op_iter->first))
{
- op_base* this_op = op_iter->second;
- op_iter->second = this_op->next_;
- this_op->next_ = complete_operations_;
- complete_operations_ = this_op;
- bool done = this_op->perform(result);
- if (done)
- {
- if (!op_iter->second)
- operations_.erase(op_iter);
- }
- else
+ while (reactor_op* op = op_iter->second.op_queue_.front())
{
- // Operation has not finished yet, so leave at front of queue, and
- // remove from the completed list.
- complete_operations_ = this_op->next_;
- this_op->next_ = op_iter->second;
- op_iter->second = this_op;
+ if (op->perform())
+ {
+ op_iter->second.op_queue_.pop();
+ ops.push(op);
+ }
+ else
+ {
+ break;
+ }
}
- }
- }
- }
-
- // Perform any pending cancels for operations.
- void perform_cancellations()
- {
- while (cancelled_operations_)
- {
- op_base* this_op = cancelled_operations_;
- cancelled_operations_ = this_op->next_;
- this_op->next_ = complete_operations_;
- complete_operations_ = this_op;
- this_op->perform(boost::asio::error::operation_aborted);
- }
- }
- // Complete all operations that are waiting to be completed.
- void complete_operations()
- {
- while (complete_operations_)
- {
- op_base* next_op = complete_operations_->next_;
- complete_operations_->next_ = 0;
- complete_operations_->complete();
- complete_operations_ = next_op;
+ if (op_iter->second.op_queue_.empty())
+ operations_.erase(op_iter);
+ }
}
}
- // Destroy all operations owned by the queue.
- void destroy_operations()
+ // Get all operations owned by the queue.
+ void get_all_operations(op_queue<operation>& ops)
{
- while (cancelled_operations_)
- {
- op_base* next_op = cancelled_operations_->next_;
- cancelled_operations_->next_ = 0;
- cancelled_operations_->destroy();
- cancelled_operations_ = next_op;
- }
-
- while (complete_operations_)
- {
- op_base* next_op = complete_operations_->next_;
- complete_operations_->next_ = 0;
- complete_operations_->destroy();
- complete_operations_ = next_op;
- }
-
- typename operation_map::iterator i = operations_.begin();
+ typename operations_map::iterator i = operations_.begin();
while (i != operations_.end())
{
- typename operation_map::iterator op_iter = i++;
- op_base* curr_op = op_iter->second;
+ typename operations_map::iterator op_iter = i++;
+ ops.push(op_iter->second.op_queue_);
operations_.erase(op_iter);
- while (curr_op)
- {
- op_base* next_op = curr_op->next_;
- curr_op->next_ = 0;
- curr_op->destroy();
- curr_op = next_op;
- }
}
}
private:
- // Base class for reactor operations. A function pointer is used instead of
- // virtual functions to avoid the associated overhead.
- class op_base
- {
- public:
- // Get the descriptor associated with the operation.
- Descriptor descriptor() const
- {
- return descriptor_;
- }
-
- // Perform the operation.
- bool perform(const boost::system::error_code& result)
- {
- result_ = result;
- return perform_func_(this, result_, bytes_transferred_);
- }
-
- // Destroy the operation and post the handler.
- void complete()
- {
- complete_func_(this, result_, bytes_transferred_);
- }
-
- // Destroy the operation.
- void destroy()
- {
- destroy_func_(this);
- }
-
- protected:
- typedef bool (*perform_func_type)(op_base*,
- boost::system::error_code&, std::size_t&);
- typedef void (*complete_func_type)(op_base*,
- const boost::system::error_code&, std::size_t);
- typedef void (*destroy_func_type)(op_base*);
-
- // Construct an operation for the given descriptor.
- op_base(perform_func_type perform_func, complete_func_type complete_func,
- destroy_func_type destroy_func, Descriptor descriptor)
- : perform_func_(perform_func),
- complete_func_(complete_func),
- destroy_func_(destroy_func),
- descriptor_(descriptor),
- result_(),
- bytes_transferred_(0),
- next_(0)
- {
- }
-
- // Prevent deletion through this type.
- ~op_base()
- {
- }
-
- private:
- friend class reactor_op_queue<Descriptor>;
-
- // The function to be called to perform the operation.
- perform_func_type perform_func_;
-
- // The function to be called to delete the operation and post the handler.
- complete_func_type complete_func_;
-
- // The function to be called to delete the operation.
- destroy_func_type destroy_func_;
-
- // The descriptor associated with the operation.
- Descriptor descriptor_;
-
- // The result of the operation.
- boost::system::error_code result_;
-
- // The number of bytes transferred in the operation.
- std::size_t bytes_transferred_;
-
- // The next operation for the same file descriptor.
- op_base* next_;
- };
-
- // Adaptor class template for operations.
- template <typename Operation>
- class op
- : public op_base
+ struct operations
{
- public:
- // Constructor.
- op(Descriptor descriptor, Operation operation)
- : op_base(&op<Operation>::do_perform, &op<Operation>::do_complete,
- &op<Operation>::do_destroy, descriptor),
- operation_(operation)
- {
- }
-
- // Perform the operation.
- static bool do_perform(op_base* base,
- boost::system::error_code& result, std::size_t& bytes_transferred)
- {
- return static_cast<op<Operation>*>(base)->operation_.perform(
- result, bytes_transferred);
- }
-
- // Destroy the operation and post the handler.
- static void do_complete(op_base* base,
- const boost::system::error_code& result, std::size_t bytes_transferred)
- {
- // Take ownership of the operation object.
- typedef op<Operation> this_type;
- this_type* this_op(static_cast<this_type*>(base));
- typedef handler_alloc_traits<Operation, this_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(this_op->operation_, this_op);
-
- // Make a copy of the error_code and the operation so that the memory can
- // be deallocated before the upcall is made.
- boost::system::error_code ec(result);
- Operation operation(this_op->operation_);
-
- // Free the memory associated with the operation.
- ptr.reset();
-
- // Make the upcall.
- operation.complete(ec, bytes_transferred);
- }
-
- // Destroy the operation.
- static void do_destroy(op_base* base)
- {
- // Take ownership of the operation object.
- typedef op<Operation> this_type;
- this_type* this_op(static_cast<this_type*>(base));
- typedef handler_alloc_traits<Operation, this_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(this_op->operation_, this_op);
-
- // A sub-object of the operation may be the true owner of the memory
- // associated with the operation. Consequently, a local copy of the
- // operation is required to ensure that any owning sub-object remains
- // valid until after we have deallocated the memory here.
- Operation operation(this_op->operation_);
- (void)operation;
-
- // Free the memory associated with the operation.
- ptr.reset();
- }
+ operations() {}
+ operations(const operations&) {}
+ void operator=(const operations&) {}
- private:
- Operation operation_;
+ // The operations waiting on the desccriptor.
+ op_queue<reactor_op> op_queue_;
};
// The type for a map of operations.
- typedef hash_map<Descriptor, op_base*> operation_map;
+ typedef hash_map<Descriptor, operations> operations_map;
// The operations that are currently executing asynchronously.
- operation_map operations_;
-
- // The list of operations that have been cancelled.
- op_base* cancelled_operations_;
-
- // The list of operations waiting to be completed.
- op_base* complete_operations_;
+ operations_map operations_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp b/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp
index 3270cd6..f9b7a98 100644
--- a/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/resolver_service.hpp
@@ -26,9 +26,13 @@
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
+#include <boost/asio/ip/basic_resolver_iterator.hpp>
+#include <boost/asio/ip/basic_resolver_query.hpp>
#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/service_base.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
@@ -79,17 +83,20 @@ public:
typedef typename Protocol::endpoint endpoint_type;
// The query type.
- typedef typename Protocol::resolver_query query_type;
+ typedef boost::asio::ip::basic_resolver_query<Protocol> query_type;
// The iterator type.
- typedef typename Protocol::resolver_iterator iterator_type;
+ typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type;
// Constructor.
resolver_service(boost::asio::io_service& io_service)
: boost::asio::detail::service_base<
resolver_service<Protocol> >(io_service),
mutex_(),
+ io_service_impl_(boost::asio::use_service<io_service_impl>(io_service)),
work_io_service_(new boost::asio::io_service),
+ work_io_service_impl_(boost::asio::use_service<
+ io_service_impl>(*work_io_service_)),
work_(new boost::asio::io_service::work(*work_io_service_)),
work_thread_(0)
{
@@ -143,7 +150,7 @@ public:
std::string service_name = query.service_name();
boost::asio::detail::addrinfo_type hints = query.hints();
- socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
+ socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0,
service_name.c_str(), &hints, &address_info, ec);
auto_addrinfo auto_address_info(address_info);
@@ -154,54 +161,84 @@ public:
}
template <typename Handler>
- class resolve_query_handler
+ class resolve_op
+ : public operation
{
public:
- resolve_query_handler(implementation_type impl, const query_type& query,
- boost::asio::io_service& io_service, Handler handler)
- : impl_(impl),
+ resolve_op(implementation_type impl, const query_type& query,
+ io_service_impl& io_service_impl, Handler handler)
+ : operation(&resolve_op::do_complete),
+ impl_(impl),
query_(query),
- io_service_(io_service),
- work_(io_service),
+ io_service_impl_(io_service_impl),
handler_(handler)
{
}
- void operator()()
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- // Check if the operation has been cancelled.
- if (impl_.expired())
+ // Take ownership of the operation object.
+ resolve_op* o(static_cast<resolve_op*>(base));
+ typedef handler_alloc_traits<Handler, resolve_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ if (owner)
{
- iterator_type iterator;
- io_service_.post(boost::asio::detail::bind_handler(handler_,
- boost::asio::error::operation_aborted, iterator));
- return;
+ if (owner != &o->io_service_impl_)
+ {
+ // The operation is being run on the worker io_service. Time to
+ // perform the resolver operation.
+
+ if (o->impl_.expired())
+ {
+ // THe operation has been cancelled.
+ o->ec_ = boost::asio::error::operation_aborted;
+ }
+ else
+ {
+ // Perform the blocking host resolution operation.
+ boost::asio::detail::addrinfo_type* address_info = 0;
+ std::string host_name = o->query_.host_name();
+ std::string service_name = o->query_.service_name();
+ boost::asio::detail::addrinfo_type hints = o->query_.hints();
+ socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0,
+ service_name.c_str(), &hints, &address_info, o->ec_);
+ auto_addrinfo auto_address_info(address_info);
+ o->iter_ = iterator_type::create(
+ address_info, host_name, service_name);
+ }
+
+ o->io_service_impl_.post_deferred_completion(o);
+ ptr.release();
+ }
+ else
+ {
+ // The operation has been returned to the main io_serice. The
+ // completion handler is ready to be delivered.
+
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object
+ // remains valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, iterator_type>
+ handler(o->handler_, o->ec_, o->iter_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
-
- // Perform the blocking host resolution operation.
- boost::asio::detail::addrinfo_type* address_info = 0;
- std::string host_name = query_.host_name();
- std::string service_name = query_.service_name();
- boost::asio::detail::addrinfo_type hints = query_.hints();
- boost::system::error_code ec;
- socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
- service_name.c_str(), &hints, &address_info, ec);
- auto_addrinfo auto_address_info(address_info);
-
- // Invoke the handler and pass the result.
- iterator_type iterator;
- if (!ec)
- iterator = iterator_type::create(address_info, host_name, service_name);
- io_service_.post(boost::asio::detail::bind_handler(
- handler_, ec, iterator));
}
private:
boost::weak_ptr<void> impl_;
query_type query_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
+ io_service_impl& io_service_impl_;
Handler handler_;
+ boost::system::error_code ec_;
+ iterator_type iter_;
};
// Asynchronously resolve a query to a list of entries.
@@ -209,12 +246,19 @@ public:
void async_resolve(implementation_type& impl, const query_type& query,
Handler handler)
{
+ // Allocate and construct an operation to wrap the handler.
+ typedef resolve_op<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,
+ impl, query, io_service_impl_, handler);
+
if (work_io_service_)
{
start_work_thread();
- work_io_service_->post(
- resolve_query_handler<Handler>(
- impl, query, this->get_io_service(), handler));
+ io_service_impl_.work_started();
+ work_io_service_impl_.post_immediate_completion(ptr.get());
+ ptr.release();
}
}
@@ -243,61 +287,89 @@ public:
}
template <typename Handler>
- class resolve_endpoint_handler
+ class resolve_endpoint_op
+ : public operation
{
public:
- resolve_endpoint_handler(implementation_type impl,
- const endpoint_type& endpoint, boost::asio::io_service& io_service,
- Handler handler)
- : impl_(impl),
- endpoint_(endpoint),
- io_service_(io_service),
- work_(io_service),
+ resolve_endpoint_op(implementation_type impl, const endpoint_type& ep,
+ io_service_impl& io_service_impl, Handler handler)
+ : operation(&resolve_endpoint_op::do_complete),
+ impl_(impl),
+ ep_(ep),
+ io_service_impl_(io_service_impl),
handler_(handler)
{
}
- void operator()()
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
{
- // Check if the operation has been cancelled.
- if (impl_.expired())
- {
- iterator_type iterator;
- io_service_.post(boost::asio::detail::bind_handler(handler_,
- boost::asio::error::operation_aborted, iterator));
- return;
- }
-
+ // Take ownership of the operation object.
+ resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
+ typedef handler_alloc_traits<Handler, resolve_endpoint_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
- // First try resolving with the service name. If that fails try resolving
- // but allow the service to be returned as a number.
- char host_name[NI_MAXHOST];
- char service_name[NI_MAXSERV];
- int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
- boost::system::error_code ec;
- socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
- host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
- if (ec)
+ if (owner)
{
- flags |= NI_NUMERICSERV;
- socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
- host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ if (owner != &o->io_service_impl_)
+ {
+ // The operation is being run on the worker io_service. Time to
+ // perform the resolver operation.
+
+ if (o->impl_.expired())
+ {
+ // THe operation has been cancelled.
+ o->ec_ = boost::asio::error::operation_aborted;
+ }
+ else
+ {
+ // Perform the blocking endoint resolution operation.
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
+ socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(),
+ host_name, NI_MAXHOST, service_name,
+ NI_MAXSERV, flags, o->ec_);
+ if (o->ec_)
+ {
+ flags |= NI_NUMERICSERV;
+ socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(),
+ host_name, NI_MAXHOST, service_name,
+ NI_MAXSERV, flags, o->ec_);
+ }
+ o->iter_ = iterator_type::create(o->ep_, host_name, service_name);
+ }
+
+ o->io_service_impl_.post_deferred_completion(o);
+ ptr.release();
+ }
+ else
+ {
+ // The operation has been returned to the main io_serice. The
+ // completion handler is ready to be delivered.
+
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object
+ // remains valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, iterator_type>
+ handler(o->handler_, o->ec_, o->iter_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
-
- // Invoke the handler and pass the result.
- iterator_type iterator;
- if (!ec)
- iterator = iterator_type::create(endpoint_, host_name, service_name);
- io_service_.post(boost::asio::detail::bind_handler(
- handler_, ec, iterator));
}
private:
boost::weak_ptr<void> impl_;
- endpoint_type endpoint_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
+ endpoint_type ep_;
+ io_service_impl& io_service_impl_;
Handler handler_;
+ boost::system::error_code ec_;
+ iterator_type iter_;
};
// Asynchronously resolve an endpoint to a list of entries.
@@ -305,12 +377,19 @@ public:
void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
Handler handler)
{
+ // Allocate and construct an operation to wrap the handler.
+ typedef resolve_endpoint_op<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,
+ impl, endpoint, io_service_impl_, handler);
+
if (work_io_service_)
{
start_work_thread();
- work_io_service_->post(
- resolve_endpoint_handler<Handler>(
- impl, endpoint, this->get_io_service(), handler));
+ io_service_impl_.work_started();
+ work_io_service_impl_.post_immediate_completion(ptr.get());
+ ptr.release();
}
}
@@ -340,9 +419,15 @@ private:
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_impl_;
+
// Private io_service used for performing asynchronous host resolution.
boost::scoped_ptr<boost::asio::io_service> work_io_service_;
+ // The work io_service implementation used to post completions.
+ io_service_impl& work_io_service_impl_;
+
// Work for the private io_service to perform.
boost::scoped_ptr<boost::asio::io_service::work> work_;
diff --git a/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp b/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp
index ba8b5d3..91030e9 100644
--- a/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/select_reactor.hpp
@@ -22,9 +22,6 @@
#include <boost/asio/detail/push_options.hpp>
#include <cstddef>
#include <boost/config.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/shared_ptr.hpp>
-#include <vector>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/io_service.hpp>
@@ -32,6 +29,8 @@
#include <boost/asio/detail/fd_set_adapter.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/reactor_op_queue.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/select_reactor_fwd.hpp>
@@ -39,9 +38,11 @@
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/task_io_service.hpp>
#include <boost/asio/detail/thread.hpp>
-#include <boost/asio/detail/timer_queue.hpp>
+#include <boost/asio/detail/timer_op.hpp>
+#include <boost/asio/detail/timer_queue_base.hpp>
+#include <boost/asio/detail/timer_queue_fwd.hpp>
+#include <boost/asio/detail/timer_queue_set.hpp>
namespace boost {
namespace asio {
@@ -52,6 +53,14 @@ class select_reactor
: public boost::asio::detail::service_base<select_reactor<Own_Thread> >
{
public:
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ enum { read_op = 0, write_op = 1, except_op = 2,
+ max_select_ops = 3, connect_op = 3, max_ops = 4 };
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ enum { read_op = 0, write_op = 1, except_op = 2,
+ max_select_ops = 3, connect_op = 1, max_ops = 3 };
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
// Per-descriptor data.
struct per_descriptor_data
{
@@ -61,13 +70,9 @@ public:
select_reactor(boost::asio::io_service& io_service)
: boost::asio::detail::service_base<
select_reactor<Own_Thread> >(io_service),
+ io_service_(use_service<io_service_impl>(io_service)),
mutex_(),
- select_in_progress_(false),
interrupter_(),
- read_op_queue_(),
- write_op_queue_(),
- except_op_queue_(),
- pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false)
@@ -94,31 +99,29 @@ public:
stop_thread_ = true;
lock.unlock();
- if (thread_)
+ if (Own_Thread)
{
- interrupter_.interrupt();
- thread_->join();
- delete thread_;
- thread_ = 0;
+ 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();
+ op_queue<operation> ops;
- for (std::size_t i = 0; i < timer_queues_.size(); ++i)
- timer_queues_[i]->destroy_timers();
- timer_queues_.clear();
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].get_all_operations(ops);
+
+ timer_queues_.get_all_timers(ops);
}
// Initialise the task, but only if the reactor is not in its own thread.
void init_task()
{
- if (!Own_Thread)
- {
- typedef task_io_service<select_reactor<Own_Thread> > task_io_service_type;
- use_service<task_io_service_type>(this->get_io_service()).init_task();
- }
+ io_service_.init_task();
}
// Register a socket with the reactor. Returns 0 on success, system error
@@ -128,111 +131,17 @@ public:
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, per_descriptor_data&,
- Handler handler, bool /*allow_speculative_read*/ = true)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- if (read_op_queue_.enqueue_operation(descriptor, handler))
- 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, per_descriptor_data&,
- Handler handler, bool /*allow_speculative_write*/ = true)
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data&, reactor_op* op, bool)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (write_op_queue_.enqueue_operation(descriptor, handler))
- 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,
- per_descriptor_data&, Handler handler)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- if (except_op_queue_.enqueue_operation(descriptor, handler))
- interrupter_.interrupt();
- }
-
- // Wrapper for connect handlers to enable the handler object to be placed
- // in both the write and the except operation queues, but ensure that only
- // one of the handlers is called.
- template <typename Handler>
- class connect_handler_wrapper
- {
- public:
- connect_handler_wrapper(socket_type descriptor,
- boost::shared_ptr<bool> completed,
- select_reactor<Own_Thread>& reactor, Handler handler)
- : descriptor_(descriptor),
- completed_(completed),
- reactor_(reactor),
- handler_(handler)
{
- }
-
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
- {
- // Check whether one of the handlers has already been called. If it has,
- // then we don't want to do anything in this handler.
- if (*completed_)
- {
- completed_.reset(); // Indicate that this handler should not complete.
- return true;
- }
-
- // Cancel the other reactor operation for the connection.
- *completed_ = true;
- reactor_.enqueue_cancel_ops_unlocked(descriptor_);
-
- // Call the contained handler.
- return handler_.perform(ec, bytes_transferred);
- }
-
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- if (completed_.get())
- handler_.complete(ec, bytes_transferred);
- }
-
- private:
- socket_type descriptor_;
- boost::shared_ptr<bool> completed_;
- select_reactor<Own_Thread>& reactor_;
- Handler handler_;
- };
-
- // 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. The handler will be called
- // only once.
- template <typename Handler>
- void start_connect_op(socket_type descriptor,
- per_descriptor_data&, Handler handler)
- {
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- if (!shutdown_)
- {
- boost::shared_ptr<bool> completed(new bool(false));
- connect_handler_wrapper<Handler> wrapped_handler(
- descriptor, completed, *this, handler);
- bool interrupt = write_op_queue_.enqueue_operation(
- descriptor, wrapped_handler);
- interrupt = except_op_queue_.enqueue_operation(
- descriptor, wrapped_handler) || interrupt;
- if (interrupt)
+ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+ io_service_.work_started();
+ if (first)
interrupter_.interrupt();
}
}
@@ -243,17 +152,7 @@ public:
void cancel_ops(socket_type descriptor, per_descriptor_data&)
{
boost::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
- // select_reactor's mutex, and so should only be used when the reactor lock is
- // already held.
- void enqueue_cancel_ops_unlocked(socket_type descriptor)
- {
- pending_cancellations_.push_back(descriptor);
+ cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
// Cancel any operations that are running against the descriptor and remove
@@ -261,7 +160,7 @@ public:
void close_descriptor(socket_type descriptor, per_descriptor_data&)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- cancel_ops_unlocked(descriptor);
+ cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
// Add a new timer queue to the reactor.
@@ -269,7 +168,7 @@ public:
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- timer_queues_.push_back(&timer_queue);
+ timer_queues_.insert(&timer_queue);
}
// Remove a timer queue from the reactor.
@@ -277,252 +176,186 @@ public:
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
boost::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;
- }
- }
+ timer_queues_.erase(&timer_queue);
}
- // 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>
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, Handler handler, void* token)
+ const typename Time_Traits::time_type& time, timer_op* op, void* token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (timer_queue.enqueue_timer(time, handler, token))
+ {
+ bool earliest = timer_queue.enqueue_timer(time, op, token);
+ io_service_.work_started();
+ if (earliest)
interrupter_.interrupt();
+ }
}
- // Cancel the timer associated with the given token. Returns the number of
- // handlers that have been posted or dispatched.
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- std::size_t n = timer_queue.cancel_timer(token);
- if (n > 0)
- interrupter_.interrupt();
+ op_queue<operation> ops;
+ std::size_t n = timer_queue.cancel_timer(token, ops);
+ lock.unlock();
+ io_service_.post_deferred_completions(ops);
return n;
}
-private:
- friend class task_io_service<select_reactor<Own_Thread> >;
-
// Run select once until interrupted or events are ready to be dispatched.
- void run(bool block)
+ void run(bool block, op_queue<operation>& ops)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- // Dispatch any operation cancellations that were made while the select
- // loop was not running.
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
- except_op_queue_.perform_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_)
+ if (Own_Thread)
+ if (stop_thread_)
+ return;
+
+ // Set up the descriptor sets.
+ fd_set_adapter fds[max_select_ops];
+ fds[read_op].set(interrupter_.read_descriptor());
+ socket_type max_fd = 0;
+ bool have_work_to_do = !timer_queues_.all_empty();
+ for (int i = 0; i < max_select_ops; ++i)
{
- complete_operations_and_timers(lock);
- return;
+ have_work_to_do = have_work_to_do || !op_queue_[i].empty();
+ op_queue_[i].get_descriptors(fds[i], ops);
+ if (fds[i].max_descriptor() > max_fd)
+ max_fd = fds[i].max_descriptor();
}
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Connection operations on Windows use both except and write fd_sets.
+ have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
+ op_queue_[connect_op].get_descriptors(fds[write_op], ops);
+ if (fds[write_op].max_descriptor() > max_fd)
+ max_fd = fds[write_op].max_descriptor();
+ op_queue_[connect_op].get_descriptors(fds[except_op], ops);
+ if (fds[except_op].max_descriptor() > max_fd)
+ max_fd = fds[except_op].max_descriptor();
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
// 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())
- {
- complete_operations_and_timers(lock);
+ if (!block && !have_work_to_do)
return;
- }
- // Set up the descriptor sets.
- fd_set_adapter read_fds;
- read_fds.set(interrupter_.read_descriptor());
- read_op_queue_.get_descriptors(read_fds);
- fd_set_adapter write_fds;
- write_op_queue_.get_descriptors(write_fds);
- fd_set_adapter except_fds;
- except_op_queue_.get_descriptors(except_fds);
- socket_type max_fd = read_fds.max_descriptor();
- if (write_fds.max_descriptor() > max_fd)
- max_fd = write_fds.max_descriptor();
- if (except_fds.max_descriptor() > max_fd)
- max_fd = except_fds.max_descriptor();
-
- // Block on the select call without holding the lock so that new
- // operations can be started while the call is executing.
+ // Determine how long to block while waiting for events.
timeval tv_buf = { 0, 0 };
timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
- select_in_progress_ = true;
+
lock.unlock();
+
+ // Block on the select call until descriptors become ready.
boost::system::error_code ec;
int retval = socket_ops::select(static_cast<int>(max_fd + 1),
- read_fds, write_fds, except_fds, tv, ec);
- lock.lock();
- select_in_progress_ = false;
+ fds[read_op], fds[write_op], fds[except_op], tv, ec);
// Reset the interrupter.
- if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor()))
+ if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor()))
interrupter_.reset();
+ lock.lock();
+
// Dispatch all ready operations.
if (retval > 0)
{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // Connection operations on Windows use both except and write fd_sets.
+ op_queue_[connect_op].perform_operations_for_descriptors(
+ fds[except_op], ops);
+ op_queue_[connect_op].perform_operations_for_descriptors(
+ fds[write_op], ops);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
- except_op_queue_.perform_operations_for_descriptors(
- except_fds, boost::system::error_code());
- read_op_queue_.perform_operations_for_descriptors(
- read_fds, boost::system::error_code());
- write_op_queue_.perform_operations_for_descriptors(
- write_fds, boost::system::error_code());
- except_op_queue_.perform_cancellations();
- read_op_queue_.perform_cancellations();
- write_op_queue_.perform_cancellations();
+ for (int i = max_select_ops - 1; i >= 0; --i)
+ op_queue_[i].perform_operations_for_descriptors(fds[i], ops);
}
- 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();
+ timer_queues_.get_ready_timers(ops);
+ }
- complete_operations_and_timers(lock);
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
}
+private:
// Run the select loop in the thread.
void run_thread()
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
- while (!stop_thread_)
+ if (Own_Thread)
{
- lock.unlock();
- run(true);
- lock.lock();
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ op_queue<operation> ops;
+ run(true, ops);
+ io_service_.post_deferred_completions(ops);
+ lock.lock();
+ }
}
}
// Entry point for the select loop thread.
static void call_run_thread(select_reactor* reactor)
{
- reactor->run_thread();
- }
-
- // Interrupt the select loop.
- void interrupt()
- {
- interrupter_.interrupt();
- }
-
- // 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;
+ if (Own_Thread)
+ {
+ reactor->run_thread();
+ }
}
// Get the timeout value for the select call.
timeval* get_timeout(timeval& tv)
{
- if (all_timer_queues_are_empty())
- return 0;
-
// 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())
- {
- tv.tv_sec = minimum_wait_duration.total_seconds();
- tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000;
- }
- else
- {
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- }
-
+ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ tv.tv_sec = usec / 1000000;
+ tv.tv_usec = usec % 1000000;
return &tv;
}
- // 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 select_reactor's mutex.
- void cancel_ops_unlocked(socket_type descriptor)
+ // Cancel all operations associated with the given descriptor. This function
+ // does not acquire the select_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor,
+ const boost::system::error_code& ec)
{
- 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)
+ bool need_interrupt = false;
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ need_interrupt = op_queue_[i].cancel_operations(
+ descriptor, ops, ec) || need_interrupt;
+ io_service_.post_deferred_completions(ops);
+ if (need_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 complete_operations_and_timers(
- boost::asio::detail::mutex::scoped_lock& lock)
- {
- timer_queues_for_cleanup_ = timer_queues_;
- lock.unlock();
- read_op_queue_.complete_operations();
- write_op_queue_.complete_operations();
- except_op_queue_.complete_operations();
- for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
- timer_queues_for_cleanup_[i]->complete_timers();
- }
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_;
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
- // Whether the select loop is currently running or not.
- bool select_in_progress_;
-
// The interrupter is used to break a blocking select call.
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 exception operations.
- reactor_op_queue<socket_type> except_op_queue_;
+ // The queues of read, write and except operations.
+ reactor_op_queue<socket_type> op_queue_[max_ops];
// 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_;
+ timer_queue_set timer_queues_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
diff --git a/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp b/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp
index b648939..e640ec8 100644
--- a/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/service_registry.hpp
@@ -18,7 +18,6 @@
#include <boost/asio/detail/push_options.hpp>
#include <boost/asio/detail/push_options.hpp>
-#include <memory>
#include <typeinfo>
#include <boost/asio/detail/pop_options.hpp>
@@ -80,7 +79,7 @@ public:
while (first_service_)
{
boost::asio::io_service::service* next_service = first_service_->next_;
- delete first_service_;
+ destroy(first_service_);
first_service_ = next_service;
}
}
@@ -91,14 +90,105 @@ public:
template <typename Service>
Service& use_service()
{
+ boost::asio::io_service::service::key key;
+ init_key(key, Service::id);
+ factory_type factory = &service_registry::create<Service>;
+ return *static_cast<Service*>(do_use_service(key, factory));
+ }
+
+ // Add a service object. Returns false on error, in which case ownership of
+ // the object is retained by the caller.
+ template <typename Service>
+ bool add_service(Service* new_service)
+ {
+ boost::asio::io_service::service::key key;
+ init_key(key, Service::id);
+ return do_add_service(key, new_service);
+ }
+
+ // Check whether a service object of the specified type already exists.
+ template <typename Service>
+ bool has_service() const
+ {
+ boost::asio::io_service::service::key key;
+ init_key(key, Service::id);
+ return do_has_service(key);
+ }
+
+private:
+ // Initialise a service's key based on its id.
+ void init_key(boost::asio::io_service::service::key& key,
+ const boost::asio::io_service::id& id)
+ {
+ key.type_info_ = 0;
+ key.id_ = &id;
+ }
+
+#if !defined(BOOST_ASIO_NO_TYPEID)
+ // Initialise a service's key based on its id.
+ template <typename Service>
+ void init_key(boost::asio::io_service::service::key& key,
+ const boost::asio::detail::service_id<Service>& /*id*/)
+ {
+ key.type_info_ = &typeid(typeid_wrapper<Service>);
+ key.id_ = 0;
+ }
+#endif // !defined(BOOST_ASIO_NO_TYPEID)
+
+ // Check if a service matches the given id.
+ static bool keys_match(
+ const boost::asio::io_service::service::key& key1,
+ const boost::asio::io_service::service::key& key2)
+ {
+ if (key1.id_ && key2.id_)
+ if (key1.id_ == key2.id_)
+ return true;
+ if (key1.type_info_ && key2.type_info_)
+ if (*key1.type_info_ == *key2.type_info_)
+ return true;
+ return false;
+ }
+
+ // The type of a factory function used for creating a service instance.
+ typedef boost::asio::io_service::service*
+ (*factory_type)(boost::asio::io_service&);
+
+ // Factory function for creating a service instance.
+ template <typename Service>
+ static boost::asio::io_service::service* create(
+ boost::asio::io_service& owner)
+ {
+ return new Service(owner);
+ }
+
+ // Destroy a service instance.
+ static void destroy(boost::asio::io_service::service* service)
+ {
+ delete service;
+ }
+
+ // Helper class to manage service pointers.
+ struct auto_service_ptr
+ {
+ boost::asio::io_service::service* ptr_;
+ ~auto_service_ptr() { destroy(ptr_); }
+ };
+
+ // Get the service object corresponding to the specified service key. Will
+ // create a new service object automatically if no such object already
+ // exists. Ownership of the service object is not transferred to the caller.
+ boost::asio::io_service::service* do_use_service(
+ const boost::asio::io_service::service::key& key,
+ factory_type factory)
+ {
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- // First see if there is an existing service object for the given type.
+ // First see if there is an existing service object with the given key.
boost::asio::io_service::service* service = first_service_;
while (service)
{
- if (service_id_matches(*service, Service::id))
- return *static_cast<Service*>(service);
+ if (keys_match(service->key_, key))
+ return service;
service = service->next_;
}
@@ -106,9 +196,8 @@ public:
// at this time to allow for nested calls into this function from the new
// service's constructor.
lock.unlock();
- std::auto_ptr<Service> new_service(new Service(owner_));
- init_service_id(*new_service, Service::id);
- Service& new_service_ref = *new_service;
+ auto_service_ptr new_service = { factory(owner_) };
+ new_service.ptr_->key_ = key;
lock.lock();
// Check that nobody else created another service object of the same type
@@ -116,52 +205,52 @@ public:
service = first_service_;
while (service)
{
- if (service_id_matches(*service, Service::id))
- return *static_cast<Service*>(service);
+ if (keys_match(service->key_, key))
+ return service;
service = service->next_;
}
// Service was successfully initialised, pass ownership to registry.
- new_service->next_ = first_service_;
- first_service_ = new_service.release();
-
- return new_service_ref;
+ new_service.ptr_->next_ = first_service_;
+ first_service_ = new_service.ptr_;
+ new_service.ptr_ = 0;
+ return first_service_;
}
// Add a service object. Returns false on error, in which case ownership of
// the object is retained by the caller.
- template <typename Service>
- bool add_service(Service* new_service)
+ bool do_add_service(
+ const boost::asio::io_service::service::key& key,
+ boost::asio::io_service::service* new_service)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- // Check if there is an existing service object for the given type.
+ // Check if there is an existing service object with the given key.
boost::asio::io_service::service* service = first_service_;
while (service)
{
- if (service_id_matches(*service, Service::id))
+ if (keys_match(service->key_, key))
return false;
service = service->next_;
}
// Take ownership of the service object.
- init_service_id(*new_service, Service::id);
+ new_service->key_ = key;
new_service->next_ = first_service_;
first_service_ = new_service;
return true;
}
- // Check whether a service object of the specified type already exists.
- template <typename Service>
- bool has_service() const
+ // Check whether a service object with the specified key already exists.
+ bool do_has_service(const boost::asio::io_service::service::key& key) const
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
boost::asio::io_service::service* service = first_service_;
while (service)
{
- if (service_id_matches(*service, Service::id))
+ if (keys_match(service->key_, key))
return true;
service = service->next_;
}
@@ -169,46 +258,6 @@ public:
return false;
}
-private:
- // Set a service's id.
- void init_service_id(boost::asio::io_service::service& service,
- const boost::asio::io_service::id& id)
- {
- service.type_info_ = 0;
- service.id_ = &id;
- }
-
-#if !defined(BOOST_ASIO_NO_TYPEID)
- // Set a service's id.
- template <typename Service>
- void init_service_id(boost::asio::io_service::service& service,
- const boost::asio::detail::service_id<Service>& /*id*/)
- {
- service.type_info_ = &typeid(typeid_wrapper<Service>);
- service.id_ = 0;
- }
-#endif // !defined(BOOST_ASIO_NO_TYPEID)
-
- // Check if a service matches the given id.
- static bool service_id_matches(
- const boost::asio::io_service::service& service,
- const boost::asio::io_service::id& id)
- {
- return service.id_ == &id;
- }
-
-#if !defined(BOOST_ASIO_NO_TYPEID)
- // Check if a service matches the given id.
- template <typename Service>
- static bool service_id_matches(
- const boost::asio::io_service::service& service,
- const boost::asio::detail::service_id<Service>& /*id*/)
- {
- return service.type_info_ != 0
- && *service.type_info_ == typeid(typeid_wrapper<Service>);
- }
-#endif // !defined(BOOST_ASIO_NO_TYPEID)
-
// Mutex to protect access to internal data.
mutable boost::asio::detail::mutex mutex_;
diff --git a/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp b/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp
index db11fe4..0197e04 100644
--- a/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/signal_blocker.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
# include <boost/asio/detail/null_signal_blocker.hpp>
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# include <boost/asio/detail/win_signal_blocker.hpp>
@@ -35,7 +35,7 @@ namespace boost {
namespace asio {
namespace detail {
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
typedef null_signal_blocker signal_blocker;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef win_signal_blocker signal_blocker;
diff --git a/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp b/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp
index 7395ee4..1009164 100644
--- a/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/socket_types.hpp
@@ -68,13 +68,15 @@
# define WIN32_LEAN_AND_MEAN
# endif // !defined(WIN32_LEAN_AND_MEAN)
# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN)
+# if !defined(BOOST_ASIO_NO_NOMINMAX)
+# if !defined(NOMINMAX)
+# define NOMINMAX 1
+# endif // !defined(NOMINMAX)
+# endif // !defined(BOOST_ASIO_NO_NOMINMAX)
# if defined(__CYGWIN__)
# if !defined(__USE_W32_SOCKETS)
# error You must add -D__USE_W32_SOCKETS to your compiler options.
# endif // !defined(__USE_W32_SOCKETS)
-# if !defined(NOMINMAX)
-# define NOMINMAX 1
-# endif // !defined(NOMINMAX)
# endif // defined(__CYGWIN__)
# include <winsock2.h>
# include <ws2tcpip.h>
diff --git a/3rdParty/Boost/src/boost/asio/detail/solaris_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/solaris_fenced_block.hpp
new file mode 100644
index 0000000..be9803e
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/solaris_fenced_block.hpp
@@ -0,0 +1,59 @@
+//
+// solaris_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
+#define BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(__sun)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <atomic.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class solaris_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ solaris_fenced_block()
+ {
+ membar_consumer();
+ }
+
+ // Destructor.
+ ~solaris_fenced_block()
+ {
+ membar_producer();
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(__sun)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp b/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp
index b228cec..d6b45b1 100644
--- a/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/strand_service.hpp
@@ -18,19 +18,19 @@
#include <boost/asio/detail/push_options.hpp>
#include <boost/asio/detail/push_options.hpp>
-#include <boost/aligned_storage.hpp>
-#include <boost/assert.hpp>
#include <boost/functional/hash.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/completion_handler.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/mutex.hpp>
-#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/service_base.hpp>
namespace boost {
@@ -41,252 +41,45 @@ namespace detail {
class strand_service
: public boost::asio::detail::service_base<strand_service>
{
+private:
+ struct on_do_complete_exit;
+ struct on_dispatch_exit;
+
public:
- class handler_base;
- class invoke_current_handler;
- class post_next_waiter_on_exit;
// The underlying implementation of a strand.
class strand_impl
+ : public operation
{
public:
strand_impl()
- : current_handler_(0),
- first_waiter_(0),
- last_waiter_(0)
+ : operation(&strand_service::do_complete),
+ count_(0)
{
}
private:
// Only this service will have access to the internal values.
friend class strand_service;
- friend class post_next_waiter_on_exit;
- friend class invoke_current_handler;
+ friend struct on_do_complete_exit;
+ friend struct on_dispatch_exit;
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
- // The handler that is ready to execute. If this pointer is non-null then it
- // indicates that a handler holds the lock.
- handler_base* current_handler_;
-
- // The start of the list of waiting handlers for the strand.
- handler_base* first_waiter_;
-
- // The end of the list of waiting handlers for the strand.
- handler_base* last_waiter_;
-
- // Storage for posted handlers.
- typedef boost::aligned_storage<128> handler_storage_type;
-#if defined(__BORLANDC__)
- boost::aligned_storage<128> handler_storage_;
-#else
- handler_storage_type handler_storage_;
-#endif
- };
-
- friend class strand_impl;
-
- typedef strand_impl* implementation_type;
-
- // Base class for all handler types.
- class handler_base
- {
- public:
- typedef void (*invoke_func_type)(handler_base*,
- strand_service&, implementation_type&);
- typedef void (*destroy_func_type)(handler_base*);
-
- handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func)
- : next_(0),
- invoke_func_(invoke_func),
- destroy_func_(destroy_func)
- {
- }
-
- void invoke(strand_service& service_impl, implementation_type& impl)
- {
- invoke_func_(this, service_impl, impl);
- }
-
- void destroy()
- {
- destroy_func_(this);
- }
-
- protected:
- ~handler_base()
- {
- }
-
- private:
- friend class strand_service;
- friend class strand_impl;
- friend class post_next_waiter_on_exit;
- handler_base* next_;
- invoke_func_type invoke_func_;
- destroy_func_type destroy_func_;
- };
-
- // Helper class to allow handlers to be dispatched.
- class invoke_current_handler
- {
- public:
- invoke_current_handler(strand_service& service_impl,
- const implementation_type& impl)
- : service_impl_(service_impl),
- impl_(impl)
- {
- }
-
- void operator()()
- {
- impl_->current_handler_->invoke(service_impl_, impl_);
- }
-
- friend void* asio_handler_allocate(std::size_t size,
- invoke_current_handler* this_handler)
- {
- return this_handler->do_handler_allocate(size);
- }
-
- friend void asio_handler_deallocate(void*, std::size_t,
- invoke_current_handler*)
- {
- }
-
- void* do_handler_allocate(std::size_t size)
- {
-#if defined(__BORLANDC__)
- BOOST_ASSERT(size <= boost::aligned_storage<128>::size);
-#else
- BOOST_ASSERT(size <= strand_impl::handler_storage_type::size);
-#endif
- (void)size;
- return impl_->handler_storage_.address();
- }
-
- // The asio_handler_invoke hook is not defined here since the default one
- // provides the correct behaviour, and including it here breaks MSVC 7.1
- // in some situations.
-
- private:
- strand_service& service_impl_;
- implementation_type impl_;
- };
-
- // Helper class to automatically enqueue next waiter on block exit.
- class post_next_waiter_on_exit
- {
- public:
- post_next_waiter_on_exit(strand_service& service_impl,
- implementation_type& impl)
- : service_impl_(service_impl),
- impl_(impl),
- cancelled_(false)
- {
- }
-
- ~post_next_waiter_on_exit()
- {
- if (!cancelled_)
- {
- boost::asio::detail::mutex::scoped_lock lock(impl_->mutex_);
- impl_->current_handler_ = impl_->first_waiter_;
- if (impl_->current_handler_)
- {
- impl_->first_waiter_ = impl_->first_waiter_->next_;
- if (impl_->first_waiter_ == 0)
- impl_->last_waiter_ = 0;
- lock.unlock();
- service_impl_.get_io_service().post(
- invoke_current_handler(service_impl_, impl_));
- }
- }
- }
-
- void cancel()
- {
- cancelled_ = true;
- }
+ // The count of handlers in the strand, including the upcall (if any).
+ std::size_t count_;
- private:
- strand_service& service_impl_;
- implementation_type& impl_;
- bool cancelled_;
+ // The handlers waiting on the strand.
+ op_queue<operation> queue_;
};
- // Class template for a waiter.
- template <typename Handler>
- class handler_wrapper
- : public handler_base
- {
- public:
- handler_wrapper(Handler handler)
- : handler_base(&handler_wrapper<Handler>::do_invoke,
- &handler_wrapper<Handler>::do_destroy),
- handler_(handler)
- {
- }
-
- static void do_invoke(handler_base* base,
- strand_service& service_impl, implementation_type& impl)
- {
- // 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);
-
- post_next_waiter_on_exit p1(service_impl, impl);
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(h->handler_);
-
- // A handler object must still be valid when the next waiter is posted
- // since destroying the last handler might cause the strand object to be
- // destroyed. Therefore we create a second post_next_waiter_on_exit object
- // that will be destroyed before the handler object.
- p1.cancel();
- post_next_waiter_on_exit p2(service_impl, impl);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Indicate that this strand is executing on the current thread.
- call_stack<strand_impl>::context ctx(impl);
-
- // Make the upcall.
- boost_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);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(h->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
- }
-
- private:
- Handler handler_;
- };
+ typedef strand_impl* implementation_type;
// Construct a new strand service for the specified io_service.
explicit strand_service(boost::asio::io_service& io_service)
: boost::asio::detail::service_base<strand_service>(io_service),
+ io_service_(boost::asio::use_service<io_service_impl>(io_service)),
mutex_(),
salt_(0)
{
@@ -295,37 +88,13 @@ public:
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
- // Construct a list of all handlers to be destroyed.
+ op_queue<operation> ops;
+
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- handler_base* first_handler = 0;
+
for (std::size_t i = 0; i < num_implementations; ++i)
- {
if (strand_impl* impl = implementations_[i].get())
- {
- if (impl->current_handler_)
- {
- impl->current_handler_->next_ = first_handler;
- first_handler = impl->current_handler_;
- impl->current_handler_ = 0;
- }
- if (impl->first_waiter_)
- {
- impl->last_waiter_->next_ = first_handler;
- first_handler = impl->first_waiter_;
- impl->first_waiter_ = 0;
- impl->last_waiter_ = 0;
- }
- }
- }
-
- // Destroy all handlers without holding the lock.
- lock.unlock();
- while (first_handler)
- {
- handler_base* next = first_handler->next_;
- first_handler->destroy();
- first_handler = next;
- }
+ ops.push(impl->queue_);
}
// Construct a new strand implementation.
@@ -352,45 +121,54 @@ public:
template <typename Handler>
void dispatch(implementation_type& impl, Handler handler)
{
+ // If we are already in the strand then the handler can run immediately.
if (call_stack<strand_impl>::contains(impl))
{
+ boost::asio::detail::fenced_block b;
boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ return;
}
- else
+
+ // Allocate and construct an object to wrap the handler.
+ typedef completion_handler<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);
+
+ // If we are running inside the io_service, and no other handler is queued
+ // or running, then the handler can run immediately.
+ bool can_dispatch = call_stack<io_service_impl>::contains(&io_service_);
+ impl->mutex_.lock();
+ bool first = (++impl->count_ == 1);
+ if (can_dispatch && first)
{
- // 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(handler);
- handler_ptr<alloc_traits> ptr(raw_ptr, handler);
-
- boost::asio::detail::mutex::scoped_lock lock(impl->mutex_);
-
- if (impl->current_handler_ == 0)
- {
- // This handler now has the lock, so can be dispatched immediately.
- impl->current_handler_ = ptr.release();
- lock.unlock();
- this->get_io_service().dispatch(invoke_current_handler(*this, impl));
- }
- else
- {
- // Another handler already holds the lock, so this handler must join
- // the list of waiters. The handler will be posted automatically when
- // its turn comes.
- if (impl->last_waiter_)
- {
- impl->last_waiter_->next_ = ptr.get();
- impl->last_waiter_ = impl->last_waiter_->next_;
- }
- else
- {
- impl->first_waiter_ = ptr.get();
- impl->last_waiter_ = ptr.get();
- }
- ptr.release();
- }
+ // Immediate invocation is allowed.
+ impl->mutex_.unlock();
+
+ // Memory must be releaesed before any upcall is made.
+ ptr.reset();
+
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl);
+
+ // Ensure the next handler, if any, is scheduled on block exit.
+ on_dispatch_exit on_exit = { &io_service_, impl };
+ (void)on_exit;
+
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ return;
}
+
+ // Immediate invocation is not allowed, so enqueue for later.
+ impl->queue_.push(ptr.get());
+ impl->mutex_.unlock();
+ ptr.release();
+
+ // The first handler to be enqueued is responsible for scheduling the
+ // strand.
+ if (first)
+ io_service_.post_immediate_completion(impl);
}
// Request the io_service to invoke the given handler and return immediately.
@@ -398,40 +176,85 @@ public:
void post(implementation_type& impl, Handler handler)
{
// Allocate and construct an object to wrap the handler.
- typedef handler_wrapper<Handler> value_type;
+ typedef completion_handler<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);
- boost::asio::detail::mutex::scoped_lock lock(impl->mutex_);
+ // Add the handler to the queue.
+ impl->mutex_.lock();
+ bool first = (++impl->count_ == 1);
+ impl->queue_.push(ptr.get());
+ impl->mutex_.unlock();
+ ptr.release();
+
+ // The first handler to be enqueue is responsible for scheduling the strand.
+ if (first)
+ io_service_.post_immediate_completion(impl);
+ }
+
+private:
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ if (owner)
+ {
+ strand_impl* impl = static_cast<strand_impl*>(base);
+
+ // Get the next handler to be executed.
+ impl->mutex_.lock();
+ operation* o = impl->queue_.front();
+ impl->queue_.pop();
+ impl->mutex_.unlock();
+
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl);
+
+ // Ensure the next handler, if any, is scheduled on block exit.
+ on_do_complete_exit on_exit = { owner, impl };
+ (void)on_exit;
+
+ o->complete(*owner);
+ }
+ }
+
+ // Helper class to re-post the strand on exit.
+ struct on_do_complete_exit
+ {
+ io_service_impl* owner_;
+ strand_impl* impl_;
- if (impl->current_handler_ == 0)
+ ~on_do_complete_exit()
{
- // This handler now has the lock, so can be dispatched immediately.
- impl->current_handler_ = ptr.release();
- lock.unlock();
- this->get_io_service().post(invoke_current_handler(*this, impl));
+ impl_->mutex_.lock();
+ bool more_handlers = (--impl_->count_ > 0);
+ impl_->mutex_.unlock();
+
+ if (more_handlers)
+ owner_->post_immediate_completion(impl_);
}
- else
+ };
+
+ // Helper class to re-post the strand on exit.
+ struct on_dispatch_exit
+ {
+ io_service_impl* io_service_;
+ strand_impl* impl_;
+
+ ~on_dispatch_exit()
{
- // Another handler already holds the lock, so this handler must join the
- // list of waiters. The handler will be posted automatically when its turn
- // comes.
- if (impl->last_waiter_)
- {
- impl->last_waiter_->next_ = ptr.get();
- impl->last_waiter_ = impl->last_waiter_->next_;
- }
- else
- {
- impl->first_waiter_ = ptr.get();
- impl->last_waiter_ = ptr.get();
- }
- ptr.release();
+ impl_->mutex_.lock();
+ bool more_handlers = (--impl_->count_ > 0);
+ impl_->mutex_.unlock();
+
+ if (more_handlers)
+ io_service_->post_immediate_completion(impl_);
}
- }
+ };
+
+ // The io_service implementation used to post completions.
+ io_service_impl& io_service_;
-private:
// Mutex to protect access to the array of implementations.
boost::asio::detail::mutex mutex_;
diff --git a/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp b/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp
index ddfea72..f6de370 100644
--- a/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/task_io_service.hpp
@@ -15,21 +15,25 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-#if defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE)
-#include <boost/asio/detail/task_io_service_2lock.hpp>
-#else // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE)
-
#include <boost/asio/detail/push_options.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/completion_handler.hpp>
#include <boost/asio/detail/event.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
-#include <boost/asio/detail/handler_queue.hpp>
#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/service_base.hpp>
#include <boost/asio/detail/task_io_service_fwd.hpp>
+#include <boost/asio/detail/task_io_service_operation.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/asio/detail/pop_options.hpp>
namespace boost {
namespace asio {
@@ -40,6 +44,8 @@ class task_io_service
: public boost::asio::detail::service_base<task_io_service<Task> >
{
public:
+ typedef task_io_service_operation<Task> operation;
+
// Constructor.
task_io_service(boost::asio::io_service& io_service)
: boost::asio::detail::service_base<task_io_service<Task> >(io_service),
@@ -65,12 +71,12 @@ public:
lock.unlock();
// Destroy handler objects.
- while (!handler_queue_.empty())
+ while (!op_queue_.empty())
{
- handler_queue::handler* h = handler_queue_.front();
- handler_queue_.pop();
- if (h != &task_handler_)
- h->destroy();
+ operation* o = op_queue_.front();
+ op_queue_.pop();
+ if (o != &task_operation_)
+ o->destroy();
}
// Reset to initial state.
@@ -84,14 +90,21 @@ public:
if (!shutdown_ && !task_)
{
task_ = &use_service<Task>(this->get_io_service());
- handler_queue_.push(&task_handler_);
- interrupt_one_idle_thread(lock);
+ op_queue_.push(&task_operation_);
+ wake_one_thread_and_unlock(lock);
}
}
// Run the event loop until interrupted or no more work.
size_t run(boost::system::error_code& ec)
{
+ ec = boost::system::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
@@ -100,7 +113,7 @@ public:
boost::asio::detail::mutex::scoped_lock lock(mutex_);
size_t n = 0;
- while (do_one(lock, &this_idle_thread, ec))
+ for (; do_one(lock, &this_idle_thread); lock.lock())
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
@@ -109,6 +122,13 @@ public:
// Run until interrupted or one operation is performed.
size_t run_one(boost::system::error_code& ec)
{
+ ec = boost::system::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
@@ -116,18 +136,25 @@ public:
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- return do_one(lock, &this_idle_thread, ec);
+ return do_one(lock, &this_idle_thread);
}
// Poll for operations without blocking.
size_t poll(boost::system::error_code& ec)
{
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ ec = boost::system::error_code();
+ return 0;
+ }
+
typename call_stack<task_io_service>::context ctx(this);
boost::asio::detail::mutex::scoped_lock lock(mutex_);
size_t n = 0;
- while (do_one(lock, 0, ec))
+ for (; do_one(lock, 0); lock.lock())
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
@@ -136,11 +163,18 @@ public:
// Poll for one operation without blocking.
size_t poll_one(boost::system::error_code& ec)
{
+ ec = boost::system::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
typename call_stack<task_io_service>::context ctx(this);
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- return do_one(lock, 0, ec);
+ return do_one(lock, 0);
}
// Interrupt the event processing loop.
@@ -160,16 +194,14 @@ public:
// Notify that some work has started.
void work_started()
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
++outstanding_work_;
}
// Notify that some work has finished.
void work_finished()
{
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (--outstanding_work_ == 0)
- stop_all_threads(lock);
+ stop();
}
// Request invocation of the given handler.
@@ -177,7 +209,10 @@ public:
void dispatch(Handler handler)
{
if (call_stack<task_io_service>::contains(this))
+ {
+ boost::asio::detail::fenced_block b;
boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
else
post(handler);
}
@@ -187,29 +222,41 @@ public:
void post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
- handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
-
- boost::asio::detail::mutex::scoped_lock lock(mutex_);
-
- // If the service has been shut down we silently discard the handler.
- if (shutdown_)
- return;
+ typedef completion_handler<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);
- // Add the handler to the end of the queue.
- handler_queue_.push(ptr.get());
+ post_immediate_completion(ptr.get());
ptr.release();
+ }
- // An undelivered handler is treated as unfinished work.
- ++outstanding_work_;
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() has not yet been called for the operation.
+ void post_immediate_completion(operation* op)
+ {
+ work_started();
+ post_deferred_completion(op);
+ }
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() was previously called for the operation.
+ void post_deferred_completion(operation* op)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue_.push(op);
+ wake_one_thread_and_unlock(lock);
+ }
- // Wake up a thread to execute the handler.
- if (!interrupt_one_idle_thread(lock))
+ // Request invocation of the given operations and return immediately. Assumes
+ // that work_started() was previously called for each operation.
+ void post_deferred_completions(op_queue<operation>& ops)
+ {
+ if (!ops.empty())
{
- if (!task_interrupted_ && task_)
- {
- task_interrupted_ = true;
- task_->interrupt();
- }
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue_.push(ops);
+ wake_one_thread_and_unlock(lock);
}
}
@@ -217,57 +264,58 @@ private:
struct idle_thread_info;
size_t do_one(boost::asio::detail::mutex::scoped_lock& lock,
- idle_thread_info* this_idle_thread, boost::system::error_code& ec)
+ idle_thread_info* this_idle_thread)
{
- if (outstanding_work_ == 0 && !stopped_)
- {
- stop_all_threads(lock);
- ec = boost::system::error_code();
- return 0;
- }
-
bool polling = !this_idle_thread;
bool task_has_run = false;
while (!stopped_)
{
- if (!handler_queue_.empty())
+ if (!op_queue_.empty())
{
// Prepare to execute first handler from queue.
- handler_queue::handler* h = handler_queue_.front();
- handler_queue_.pop();
+ operation* o = op_queue_.front();
+ op_queue_.pop();
+ bool more_handlers = (!op_queue_.empty());
- if (h == &task_handler_)
+ if (o == &task_operation_)
{
- bool more_handlers = (!handler_queue_.empty());
task_interrupted_ = more_handlers || polling;
// 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 = boost::system::error_code();
+ op_queue_.push(&task_operation_);
return 0;
}
task_has_run = true;
- lock.unlock();
- task_cleanup c(lock, *this);
+ if (!more_handlers || !wake_one_idle_thread_and_unlock(lock))
+ lock.unlock();
- // Run the task. May throw an exception. Only block if the handler
- // queue is empty and we have an idle_thread_info object, otherwise
- // we want to return as soon as possible.
- task_->run(!more_handlers && !polling);
+ op_queue<operation> completed_ops;
+ task_cleanup c = { this, &lock, &completed_ops };
+ (void)c;
+
+ // Run the task. May throw an exception. Only block if the operation
+ // queue is empty and we're not polling, otherwise we want to return
+ // as soon as possible.
+ task_->run(!more_handlers && !polling, completed_ops);
}
else
{
- lock.unlock();
- handler_cleanup c(lock, *this);
+ if (more_handlers)
+ wake_one_thread_and_unlock(lock);
+ else
+ lock.unlock();
+
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_finished_on_block_exit on_exit = { this };
+ (void)on_exit;
- // Invoke the handler. May throw an exception.
- h->invoke(); // invoke() deletes the handler object
+ // Complete the operation. May throw an exception.
+ o->complete(*this); // deletes the operation object
- ec = boost::system::error_code();
return 1;
}
}
@@ -281,12 +329,10 @@ private:
}
else
{
- ec = boost::system::error_code();
return 0;
}
}
- ec = boost::system::error_code();
return 0;
}
@@ -295,7 +341,15 @@ private:
boost::asio::detail::mutex::scoped_lock& lock)
{
stopped_ = true;
- interrupt_all_idle_threads(lock);
+
+ while (first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = first_idle_thread_;
+ first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(lock);
+ }
+
if (!task_interrupted_ && task_)
{
task_interrupted_ = true;
@@ -303,9 +357,10 @@ private:
}
}
- // Interrupt a single idle thread. Returns true if a thread was interrupted,
- // false if no running thread could be found to interrupt.
- bool interrupt_one_idle_thread(
+ // Wakes a single idle thread and unlocks the mutex. Returns true if an idle
+ // thread was found. If there is no idle thread, returns false and leaves the
+ // mutex locked.
+ bool wake_one_idle_thread_and_unlock(
boost::asio::detail::mutex::scoped_lock& lock)
{
if (first_idle_thread_)
@@ -313,74 +368,56 @@ private:
idle_thread_info* idle_thread = first_idle_thread_;
first_idle_thread_ = idle_thread->next;
idle_thread->next = 0;
- idle_thread->wakeup_event.signal(lock);
+ idle_thread->wakeup_event.signal_and_unlock(lock);
return true;
}
return false;
}
- // Interrupt all idle threads.
- void interrupt_all_idle_threads(
+ // Wake a single idle thread, or the task, and always unlock the mutex.
+ void wake_one_thread_and_unlock(
boost::asio::detail::mutex::scoped_lock& lock)
{
- while (first_idle_thread_)
+ if (!wake_one_idle_thread_and_unlock(lock))
{
- idle_thread_info* idle_thread = first_idle_thread_;
- first_idle_thread_ = idle_thread->next;
- idle_thread->next = 0;
- idle_thread->wakeup_event.signal(lock);
+ if (!task_interrupted_ && task_)
+ {
+ task_interrupted_ = true;
+ task_->interrupt();
+ }
+ lock.unlock();
}
}
// Helper class to perform task-related operations on block exit.
- class task_cleanup;
- friend class task_cleanup;
- class task_cleanup
+ struct task_cleanup;
+ friend struct task_cleanup;
+ struct task_cleanup
{
- public:
- task_cleanup(boost::asio::detail::mutex::scoped_lock& lock,
- task_io_service& task_io_svc)
- : lock_(lock),
- task_io_service_(task_io_svc)
- {
- }
-
~task_cleanup()
{
- // Reinsert the task at the end of the handler queue.
- lock_.lock();
- task_io_service_.task_interrupted_ = true;
- task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
+ // Enqueue the completed operations and reinsert the task at the end of
+ // the operation queue.
+ lock_->lock();
+ task_io_service_->task_interrupted_ = true;
+ task_io_service_->op_queue_.push(*ops_);
+ task_io_service_->op_queue_.push(&task_io_service_->task_operation_);
}
- private:
- boost::asio::detail::mutex::scoped_lock& lock_;
- task_io_service& task_io_service_;
+ task_io_service* task_io_service_;
+ boost::asio::detail::mutex::scoped_lock* lock_;
+ op_queue<operation>* ops_;
};
- // Helper class to perform handler-related operations on block exit.
- class handler_cleanup;
- friend class handler_cleanup;
- class handler_cleanup
+ // Helper class to call work_finished() on block exit.
+ struct work_finished_on_block_exit
{
- public:
- handler_cleanup(boost::asio::detail::mutex::scoped_lock& lock,
- task_io_service& task_io_svc)
- : lock_(lock),
- task_io_service_(task_io_svc)
- {
- }
-
- ~handler_cleanup()
+ ~work_finished_on_block_exit()
{
- lock_.lock();
- if (--task_io_service_.outstanding_work_ == 0)
- task_io_service_.stop_all_threads(lock_);
+ task_io_service_->work_finished();
}
- private:
- boost::asio::detail::mutex::scoped_lock& lock_;
- task_io_service& task_io_service_;
+ task_io_service* task_io_service_;
};
// Mutex to protect access to internal data.
@@ -389,25 +426,20 @@ private:
// The task to be run by this service.
Task* task_;
- // Handler object to represent the position of the task in the queue.
- class task_handler
- : public handler_queue::handler
+ // Operation object to represent the position of the task in the queue.
+ struct task_operation : public operation
{
- public:
- task_handler()
- : handler_queue::handler(0, 0)
- {
- }
- } task_handler_;
+ task_operation() : operation(0) {}
+ } task_operation_;
// Whether the task has been interrupted.
bool task_interrupted_;
// The count of unfinished work.
- int outstanding_work_;
+ boost::detail::atomic_count outstanding_work_;
// The queue of handlers that are ready to be delivered.
- handler_queue handler_queue_;
+ op_queue<operation> op_queue_;
// Flag to indicate that the dispatcher has been stopped.
bool stopped_;
@@ -422,7 +454,7 @@ private:
idle_thread_info* next;
};
- // The number of threads that are currently idle.
+ // The threads that are currently idle.
idle_thread_info* first_idle_thread_;
};
@@ -430,9 +462,6 @@ private:
} // namespace asio
} // namespace boost
-#include <boost/system/error_code.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#endif // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE)
-
#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/task_io_service_2lock.hpp b/3rdParty/Boost/src/boost/asio/detail/task_io_service_2lock.hpp
deleted file mode 100644
index 71bceef..0000000
--- a/3rdParty/Boost/src/boost/asio/detail/task_io_service_2lock.hpp
+++ /dev/null
@@ -1,475 +0,0 @@
-//
-// task_io_service_2lock.hpp
-// ~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP
-#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1200)
-# pragma once
-#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
-
-#include <boost/asio/detail/push_options.hpp>
-
-#include <boost/asio/io_service.hpp>
-#include <boost/asio/detail/call_stack.hpp>
-#include <boost/asio/detail/event.hpp>
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
-#include <boost/asio/detail/handler_invoke_helpers.hpp>
-#include <boost/asio/detail/indirect_handler_queue.hpp>
-#include <boost/asio/detail/mutex.hpp>
-#include <boost/asio/detail/service_base.hpp>
-#include <boost/asio/detail/task_io_service_fwd.hpp>
-
-#include <boost/asio/detail/push_options.hpp>
-#include <boost/detail/atomic_count.hpp>
-#include <boost/system/error_code.hpp>
-#include <boost/asio/detail/pop_options.hpp>
-
-namespace boost {
-namespace asio {
-namespace detail {
-
-// An alternative task_io_service implementation based on a two-lock queue.
-
-template <typename Task>
-class task_io_service
- : public boost::asio::detail::service_base<task_io_service<Task> >
-{
-public:
- typedef indirect_handler_queue handler_queue;
-
- // Constructor.
- task_io_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<task_io_service<Task> >(io_service),
- front_mutex_(),
- back_mutex_(),
- task_(0),
- outstanding_work_(0),
- front_stopped_(false),
- back_stopped_(false),
- back_shutdown_(false),
- back_first_idle_thread_(0),
- back_task_thread_(0)
- {
- }
-
- void init(size_t /*concurrency_hint*/)
- {
- }
-
- // Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
- back_shutdown_ = true;
- back_lock.unlock();
-
- // Destroy handler objects.
- while (handler_queue::handler* h = handler_queue_.pop())
- if (h != &task_handler_)
- h->destroy();
-
- // Reset to initial state.
- task_ = 0;
- }
-
- // Initialise the task, if required.
- void init_task()
- {
- boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
- if (!back_shutdown_ && !task_)
- {
- task_ = &use_service<Task>(this->get_io_service());
- handler_queue_.push(&task_handler_);
- interrupt_one_idle_thread(back_lock);
- }
- }
-
- // Run the event loop until interrupted or no more work.
- size_t run(boost::system::error_code& ec)
- {
- if (outstanding_work_ == 0)
- {
- stop();
- ec = boost::system::error_code();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- idle_thread_info this_idle_thread;
- this_idle_thread.next = 0;
-
- size_t n = 0;
- while (do_one(&this_idle_thread, ec))
- if (n != (std::numeric_limits<size_t>::max)())
- ++n;
- return n;
- }
-
- // Run until interrupted or one operation is performed.
- size_t run_one(boost::system::error_code& ec)
- {
- if (outstanding_work_ == 0)
- {
- stop();
- ec = boost::system::error_code();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- idle_thread_info this_idle_thread;
- this_idle_thread.next = 0;
-
- return do_one(&this_idle_thread, ec);
- }
-
- // Poll for operations without blocking.
- size_t poll(boost::system::error_code& ec)
- {
- if (outstanding_work_ == 0)
- {
- stop();
- ec = boost::system::error_code();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- size_t n = 0;
- while (do_one(0, ec))
- if (n != (std::numeric_limits<size_t>::max)())
- ++n;
- return n;
- }
-
- // Poll for one operation without blocking.
- size_t poll_one(boost::system::error_code& ec)
- {
- if (outstanding_work_ == 0)
- {
- stop();
- ec = boost::system::error_code();
- return 0;
- }
-
- typename call_stack<task_io_service>::context ctx(this);
-
- return do_one(0, ec);
- }
-
- // Interrupt the event processing loop.
- void stop()
- {
- boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_);
- front_stopped_ = true;
- front_lock.unlock();
-
- boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
- back_stopped_ = true;
- interrupt_all_idle_threads(back_lock);
- }
-
- // Reset in preparation for a subsequent run invocation.
- void reset()
- {
- boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_);
- front_stopped_ = false;
- front_lock.unlock();
-
- boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
- back_stopped_ = false;
- }
-
- // Notify that some work has started.
- void work_started()
- {
- ++outstanding_work_;
- }
-
- // Notify that some work has finished.
- void work_finished()
- {
- if (--outstanding_work_ == 0)
- stop();
- }
-
- // Request invocation of the given handler.
- template <typename Handler>
- void dispatch(Handler handler)
- {
- if (call_stack<task_io_service>::contains(this))
- boost_asio_handler_invoke_helpers::invoke(handler, handler);
- else
- post(handler);
- }
-
- // Request invocation of the given handler and return immediately.
- template <typename Handler>
- void post(Handler handler)
- {
- // Allocate and construct an operation to wrap the handler.
- handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
-
- boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
-
- // If the service has been shut down we silently discard the handler.
- if (back_shutdown_)
- return;
-
- // Add the handler to the end of the queue.
- handler_queue_.push(ptr.get());
- ptr.release();
-
- // An undelivered handler is treated as unfinished work.
- ++outstanding_work_;
-
- // Wake up a thread to execute the handler.
- interrupt_one_idle_thread(back_lock);
- }
-
-private:
- struct idle_thread_info;
-
- size_t do_one(idle_thread_info* this_idle_thread,
- boost::system::error_code& ec)
- {
- bool task_has_run = false;
- for (;;)
- {
- // The front lock must be held before we can pop items from the queue.
- boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_);
- if (front_stopped_)
- {
- ec = boost::system::error_code();
- return 0;
- }
-
- if (handler_queue::handler* h = handler_queue_.pop())
- {
- if (h == &task_handler_)
- {
- bool more_handlers = handler_queue_.poppable();
- unsigned long front_version = handler_queue_.front_version();
- front_lock.unlock();
-
- // The task is always added to the back of the queue when we exit
- // this block.
- task_cleanup c(*this);
-
- // If we're polling and the task has already run then we're done.
- bool polling = !this_idle_thread;
- if (task_has_run && polling)
- {
- ec = boost::system::error_code();
- return 0;
- }
-
- // If we're considering going idle we need to check whether the queue
- // is still empty. If it is, add the thread to the list of idle
- // threads.
- if (!more_handlers && !polling)
- {
- boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
- if (back_stopped_)
- {
- ec = boost::system::error_code();
- return 0;
- }
- else if (front_version == handler_queue_.back_version())
- {
- back_task_thread_ = this_idle_thread;
- }
- else
- {
- more_handlers = true;
- }
- }
-
- // Run the task. May throw an exception. Only block if the handler
- // queue is empty and we're not polling, otherwise we want to return
- // as soon as possible.
- task_has_run = true;
- task_->run(!more_handlers && !polling);
- }
- else
- {
- front_lock.unlock();
- handler_cleanup c(*this);
-
- // Invoke the handler. May throw an exception.
- h->invoke(); // invoke() deletes the handler object
-
- ec = boost::system::error_code();
- return 1;
- }
- }
- else if (this_idle_thread)
- {
- unsigned long front_version = handler_queue_.front_version();
- front_lock.unlock();
-
- // If we're considering going idle we need to check whether the queue
- // is still empty. If it is, add the thread to the list of idle
- // threads.
- boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
- if (back_stopped_)
- {
- ec = boost::system::error_code();
- return 0;
- }
- else if (front_version == handler_queue_.back_version())
- {
- this_idle_thread->next = back_first_idle_thread_;
- back_first_idle_thread_ = this_idle_thread;
- this_idle_thread->wakeup_event.clear(back_lock);
- this_idle_thread->wakeup_event.wait(back_lock);
- }
- }
- else
- {
- ec = boost::system::error_code();
- return 0;
- }
- }
- }
-
- // Interrupt a single idle thread.
- void interrupt_one_idle_thread(
- boost::asio::detail::mutex::scoped_lock& back_lock)
- {
- if (back_first_idle_thread_)
- {
- idle_thread_info* idle_thread = back_first_idle_thread_;
- back_first_idle_thread_ = idle_thread->next;
- idle_thread->next = 0;
- idle_thread->wakeup_event.signal(back_lock);
- }
- else if (back_task_thread_ && task_)
- {
- back_task_thread_ = 0;
- task_->interrupt();
- }
- }
-
- // Interrupt all idle threads.
- void interrupt_all_idle_threads(
- boost::asio::detail::mutex::scoped_lock& back_lock)
- {
- while (back_first_idle_thread_)
- {
- idle_thread_info* idle_thread = back_first_idle_thread_;
- back_first_idle_thread_ = idle_thread->next;
- idle_thread->next = 0;
- idle_thread->wakeup_event.signal(back_lock);
- }
-
- if (back_task_thread_ && task_)
- {
- back_task_thread_ = 0;
- task_->interrupt();
- }
- }
-
- // Helper class to perform task-related operations on block exit.
- class task_cleanup;
- friend class task_cleanup;
- class task_cleanup
- {
- public:
- task_cleanup(task_io_service& task_io_svc)
- : task_io_service_(task_io_svc)
- {
- }
-
- ~task_cleanup()
- {
- // Reinsert the task at the end of the handler queue.
- boost::asio::detail::mutex::scoped_lock back_lock(
- task_io_service_.back_mutex_);
- task_io_service_.back_task_thread_ = 0;
- task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
- }
-
- private:
- task_io_service& task_io_service_;
- };
-
- // Helper class to perform handler-related operations on block exit.
- class handler_cleanup
- {
- public:
- handler_cleanup(task_io_service& task_io_svc)
- : task_io_service_(task_io_svc)
- {
- }
-
- ~handler_cleanup()
- {
- task_io_service_.work_finished();
- }
-
- private:
- task_io_service& task_io_service_;
- };
-
- // Mutexes to protect access to internal data.
- boost::asio::detail::mutex front_mutex_;
- boost::asio::detail::mutex back_mutex_;
-
- // The task to be run by this service.
- Task* task_;
-
- // Handler object to represent the position of the task in the queue.
- class task_handler
- : public handler_queue::handler
- {
- public:
- task_handler()
- : handler_queue::handler(0, 0)
- {
- }
- } task_handler_;
-
- // The count of unfinished work.
- boost::detail::atomic_count outstanding_work_;
-
- // The queue of handlers that are ready to be delivered.
- handler_queue handler_queue_;
-
- // Flag to indicate that the dispatcher has been stopped.
- bool front_stopped_;
- bool back_stopped_;
-
- // Flag to indicate that the dispatcher has been shut down.
- bool back_shutdown_;
-
- // Structure containing information about an idle thread.
- struct idle_thread_info
- {
- event wakeup_event;
- idle_thread_info* next;
- };
-
- // The number of threads that are currently idle.
- idle_thread_info* back_first_idle_thread_;
-
- // The thread that is currently blocked on the task.
- idle_thread_info* back_task_thread_;
-};
-
-} // namespace detail
-} // namespace asio
-} // namespace boost
-
-#include <boost/asio/detail/pop_options.hpp>
-
-#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/task_io_service_operation.hpp b/3rdParty/Boost/src/boost/asio/detail/task_io_service_operation.hpp
new file mode 100644
index 0000000..557f673
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/task_io_service_operation.hpp
@@ -0,0 +1,71 @@
+//
+// task_io_service_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP
+#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/task_io_service_fwd.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Base class for all operations. A function pointer is used instead of virtual
+// functions to avoid the associated overhead.
+template <typename Task>
+class task_io_service_operation
+{
+public:
+ void complete(task_io_service<Task>& owner)
+ {
+ func_(&owner, this, boost::system::error_code(), 0);
+ }
+
+ void destroy()
+ {
+ func_(0, this, boost::system::error_code(), 0);
+ }
+
+protected:
+ typedef void (*func_type)(task_io_service<Task>*,
+ task_io_service_operation*, boost::system::error_code, std::size_t);
+
+ task_io_service_operation(func_type func)
+ : next_(0),
+ func_(func)
+ {
+ }
+
+ // Prevents deletion through this type.
+ ~task_io_service_operation()
+ {
+ }
+
+private:
+ friend class op_queue_access;
+ task_io_service_operation* next_;
+ func_type func_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/system/error_code.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/thread.hpp b/3rdParty/Boost/src/boost/asio/detail/thread.hpp
index 24a7a8c..3e2e215 100644
--- a/3rdParty/Boost/src/boost/asio/detail/thread.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/thread.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
# include <boost/asio/detail/null_thread.hpp>
#elif defined(BOOST_WINDOWS)
# if defined(UNDER_CE)
@@ -39,7 +39,7 @@ namespace boost {
namespace asio {
namespace detail {
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
typedef null_thread thread;
#elif defined(BOOST_WINDOWS)
# if defined(UNDER_CE)
diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_op.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_op.hpp
new file mode 100644
index 0000000..9973d89
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/timer_op.hpp
@@ -0,0 +1,46 @@
+//
+// timer_op.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_TIMER_OP_HPP
+#define BOOST_ASIO_DETAIL_TIMER_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/operation.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class timer_op
+ : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ boost::system::error_code ec_;
+
+protected:
+ timer_op(func_type func)
+ : operation(func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TIMER_OP_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp
index 35c8a77..164b342 100644
--- a/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue.hpp
@@ -19,7 +19,6 @@
#include <boost/asio/detail/push_options.hpp>
#include <cstddef>
-#include <functional>
#include <memory>
#include <vector>
#include <boost/config.hpp>
@@ -27,9 +26,9 @@
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/error.hpp>
-#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/hash_map.hpp>
-#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/timer_op.hpp>
#include <boost/asio/detail/timer_queue_base.hpp>
namespace boost {
@@ -50,50 +49,36 @@ public:
// Constructor.
timer_queue()
: timers_(),
- heap_(),
- cancelled_timers_(0),
- complete_timers_(0)
+ heap_()
{
}
// Add a new timer to the queue. Returns true if this is the timer that is
// earliest in the queue, in which case the reactor's event demultiplexing
// function call may need to be interrupted and restarted.
- template <typename Handler>
- bool enqueue_timer(const time_type& time, Handler handler, void* token)
+ bool enqueue_timer(const time_type& time, timer_op* op, void* token)
{
// Ensure that there is space for the timer in the heap. We reserve here so
// that the push_back below will not throw due to a reallocation failure.
heap_.reserve(heap_.size() + 1);
- // Create a new timer object.
- typedef timer<Handler> timer_type;
- typedef handler_alloc_traits<Handler, timer_type> alloc_traits;
- raw_handler_ptr<alloc_traits> raw_ptr(handler);
- handler_ptr<alloc_traits> new_timer(raw_ptr, time, handler, token);
-
// Insert the new timer into the hash.
- typedef typename hash_map<void*, timer_base*>::iterator iterator;
- typedef typename hash_map<void*, timer_base*>::value_type value_type;
+ typedef typename hash_map<void*, timer>::iterator iterator;
+ typedef typename hash_map<void*, timer>::value_type value_type;
std::pair<iterator, bool> result =
- timers_.insert(value_type(token, new_timer.get()));
- if (!result.second)
+ timers_.insert(value_type(token, timer()));
+ result.first->second.op_queue_.push(op);
+ if (result.second)
{
- result.first->second->prev_ = new_timer.get();
- new_timer.get()->next_ = result.first->second;
- result.first->second = new_timer.get();
+ // Put the new timer at the correct position in the heap.
+ result.first->second.time_ = time;
+ result.first->second.heap_index_ = heap_.size();
+ result.first->second.token_ = token;
+ heap_.push_back(&result.first->second);
+ up_heap(heap_.size() - 1);
}
- // Put the timer at the correct position in the heap.
- new_timer.get()->heap_index_ = heap_.size();
- heap_.push_back(new_timer.get());
- up_heap(heap_.size() - 1);
- bool is_first = (heap_[0] == new_timer.get());
-
- // Ownership of the timer is transferred to the timer queue.
- new_timer.release();
-
- return is_first;
+ return (heap_[0] == &result.first->second);
}
// Whether there are no timers in the queue.
@@ -103,226 +88,106 @@ public:
}
// Get the time for the timer that is earliest in the queue.
- virtual boost::posix_time::time_duration wait_duration() const
+ virtual long wait_duration_msec(long max_duration) const
{
if (heap_.empty())
- return boost::posix_time::pos_infin;
- return Time_Traits::to_posix_duration(
+ return max_duration;
+
+ boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
- }
- // Dispatch the timers that are earlier than the specified time.
- virtual void dispatch_timers()
- {
- const time_type now = Time_Traits::now();
- while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
- {
- timer_base* t = heap_[0];
- remove_timer(t);
- t->result_ = boost::system::error_code();
- t->prev_ = 0;
- t->next_ = complete_timers_;
- complete_timers_ = t;
- }
- }
+ if (duration > boost::posix_time::milliseconds(max_duration))
+ duration = boost::posix_time::milliseconds(max_duration);
+ else if (duration < boost::posix_time::milliseconds(0))
+ duration = boost::posix_time::milliseconds(0);
- // Cancel the timers with the given token. Any timers pending for the token
- // will be notified that they have been cancelled next time
- // dispatch_cancellations is called. Returns the number of timers that were
- // cancelled.
- std::size_t cancel_timer(void* timer_token)
- {
- std::size_t num_cancelled = 0;
- typedef typename hash_map<void*, timer_base*>::iterator iterator;
- iterator it = timers_.find(timer_token);
- if (it != timers_.end())
- {
- timer_base* t = it->second;
- while (t)
- {
- timer_base* next = t->next_;
- remove_timer(t);
- t->prev_ = 0;
- t->next_ = cancelled_timers_;
- cancelled_timers_ = t;
- t = next;
- ++num_cancelled;
- }
- }
- return num_cancelled;
+ return duration.total_milliseconds();
}
- // Dispatch any pending cancels for timers.
- virtual void dispatch_cancellations()
+ // Get the time for the timer that is earliest in the queue.
+ virtual long wait_duration_usec(long max_duration) const
{
- while (cancelled_timers_)
- {
- timer_base* this_timer = cancelled_timers_;
- this_timer->result_ = boost::asio::error::operation_aborted;
- cancelled_timers_ = this_timer->next_;
- this_timer->next_ = complete_timers_;
- complete_timers_ = this_timer;
- }
+ if (heap_.empty())
+ return max_duration;
+
+ boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
+ Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
+
+ if (duration > boost::posix_time::microseconds(max_duration))
+ duration = boost::posix_time::microseconds(max_duration);
+ else if (duration < boost::posix_time::microseconds(0))
+ duration = boost::posix_time::microseconds(0);
+
+ return duration.total_microseconds();
}
- // Complete any timers that are waiting to be completed.
- virtual void complete_timers()
+ // Dequeue all timers not later than the current time.
+ virtual void get_ready_timers(op_queue<operation>& ops)
{
- while (complete_timers_)
+ const time_type now = Time_Traits::now();
+ while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
{
- timer_base* this_timer = complete_timers_;
- complete_timers_ = this_timer->next_;
- this_timer->next_ = 0;
- this_timer->complete();
+ timer* t = heap_[0];
+ ops.push(t->op_queue_);
+ remove_timer(t);
}
}
- // Destroy all timers.
- virtual void destroy_timers()
+ // Dequeue all timers.
+ virtual void get_all_timers(op_queue<operation>& ops)
{
- typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
- typename hash_map<void*, timer_base*>::iterator end = timers_.end();
+ typename hash_map<void*, timer>::iterator i = timers_.begin();
+ typename hash_map<void*, timer>::iterator end = timers_.end();
while (i != end)
{
- timer_base* t = i->second;
- typename hash_map<void*, timer_base*>::iterator old_i = i++;
+ ops.push(i->second.op_queue_);
+ typename hash_map<void*, timer>::iterator old_i = i++;
timers_.erase(old_i);
- destroy_timer_list(t);
}
+
heap_.clear();
timers_.clear();
- destroy_timer_list(cancelled_timers_);
- destroy_timer_list(complete_timers_);
}
-private:
- // Base class for timer operations. Function pointers are used instead of
- // virtual functions to avoid the associated overhead.
- class timer_base
+ // Cancel and dequeue the timers with the given token.
+ std::size_t cancel_timer(void* timer_token, op_queue<operation>& ops)
{
- public:
- // Delete the timer and post the handler.
- void complete()
- {
- complete_func_(this, result_);
- }
-
- // Delete the timer.
- void destroy()
- {
- destroy_func_(this);
- }
-
- protected:
- typedef void (*complete_func_type)(timer_base*,
- const boost::system::error_code&);
- typedef void (*destroy_func_type)(timer_base*);
-
- // Constructor.
- timer_base(complete_func_type complete_func, destroy_func_type destroy_func,
- const time_type& time, void* token)
- : complete_func_(complete_func),
- destroy_func_(destroy_func),
- time_(time),
- token_(token),
- next_(0),
- prev_(0),
- heap_index_(
- std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
- {
- }
-
- // Prevent deletion through this type.
- ~timer_base()
+ std::size_t num_cancelled = 0;
+ typedef typename hash_map<void*, timer>::iterator iterator;
+ iterator it = timers_.find(timer_token);
+ if (it != timers_.end())
{
+ while (timer_op* op = it->second.op_queue_.front())
+ {
+ op->ec_ = boost::asio::error::operation_aborted;
+ it->second.op_queue_.pop();
+ ops.push(op);
+ ++num_cancelled;
+ }
+ remove_timer(&it->second);
}
+ return num_cancelled;
+ }
- private:
- friend class timer_queue<Time_Traits>;
-
- // The function to be called to delete the timer and post the handler.
- complete_func_type complete_func_;
-
- // The function to be called to delete the timer.
- destroy_func_type destroy_func_;
-
- // The result of the timer operation.
- boost::system::error_code result_;
+private:
+ // Structure representing a single outstanding timer.
+ struct timer
+ {
+ timer() {}
+ timer(const timer&) {}
+ void operator=(const timer&) {}
// The time when the timer should fire.
time_type time_;
- // The token associated with the timer.
- void* token_;
-
- // The next timer known to the queue.
- timer_base* next_;
-
- // The previous timer known to the queue.
- timer_base* prev_;
+ // The operations waiting on the timer.
+ op_queue<timer_op> op_queue_;
// The index of the timer in the heap.
size_t heap_index_;
- };
- // Adaptor class template for using handlers in timers.
- template <typename Handler>
- class timer
- : public timer_base
- {
- public:
- // Constructor.
- timer(const time_type& time, Handler handler, void* token)
- : timer_base(&timer<Handler>::complete_handler,
- &timer<Handler>::destroy_handler, time, token),
- handler_(handler)
- {
- }
-
- // Delete the timer and post the handler.
- static void complete_handler(timer_base* base,
- const boost::system::error_code& result)
- {
- // Take ownership of the timer object.
- typedef timer<Handler> this_type;
- this_type* this_timer(static_cast<this_type*>(base));
- typedef handler_alloc_traits<Handler, this_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
-
- // Make a copy of the error_code and the handler so that the memory can
- // be deallocated before the upcall is made.
- boost::system::error_code ec(result);
- Handler handler(this_timer->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Make the upcall.
- handler(ec);
- }
-
- // Delete the timer.
- static void destroy_handler(timer_base* base)
- {
- // Take ownership of the timer object.
- typedef timer<Handler> this_type;
- this_type* this_timer(static_cast<this_type*>(base));
- typedef handler_alloc_traits<Handler, this_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(this_timer->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
- }
-
- private:
- Handler handler_;
+ // The token associated with the timer.
+ void* token_;
};
// Move the item at the given index up the heap to its correct position.
@@ -359,7 +224,7 @@ private:
// Swap two entries in the heap.
void swap_heap(size_t index1, size_t index2)
{
- timer_base* tmp = heap_[index1];
+ timer* tmp = heap_[index1];
heap_[index1] = heap_[index2];
heap_[index2] = tmp;
heap_[index1]->heap_index_ = index1;
@@ -367,7 +232,7 @@ private:
}
// Remove a timer from the heap and list of timers.
- void remove_timer(timer_base* t)
+ void remove_timer(timer* t)
{
// Remove the timer from the heap.
size_t index = t->heap_index_;
@@ -391,44 +256,17 @@ private:
}
// Remove the timer from the hash.
- typedef typename hash_map<void*, timer_base*>::iterator iterator;
+ typedef typename hash_map<void*, timer>::iterator iterator;
iterator it = timers_.find(t->token_);
if (it != timers_.end())
- {
- if (it->second == t)
- it->second = t->next_;
- if (t->prev_)
- t->prev_->next_ = t->next_;
- if (t->next_)
- t->next_->prev_ = t->prev_;
- if (it->second == 0)
- timers_.erase(it);
- }
- }
-
- // 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;
- }
+ timers_.erase(it);
}
// A hash of timer token to linked lists of timers.
- hash_map<void*, timer_base*> timers_;
+ hash_map<void*, timer> timers_;
// The heap of timers, with the earliest timer at the front.
- std::vector<timer_base*> heap_;
-
- // The list of timers to be cancelled.
- timer_base* cancelled_timers_;
-
- // The list of timers waiting to be completed.
- timer_base* complete_timers_;
+ std::vector<timer*> heap_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp
index cd6a0d3..074c2e1 100644
--- a/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue_base.hpp
@@ -17,13 +17,9 @@
#include <boost/asio/detail/push_options.hpp>
-#include <boost/asio/detail/socket_types.hpp> // Must come before posix_time.
-
-#include <boost/asio/detail/push_options.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/asio/detail/pop_options.hpp>
-
#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/op_queue.hpp>
+#include <boost/asio/detail/operation.hpp>
namespace boost {
namespace asio {
@@ -33,6 +29,9 @@ class timer_queue_base
: private noncopyable
{
public:
+ // Constructor.
+ timer_queue_base() : next_(0) {}
+
// Destructor.
virtual ~timer_queue_base() {}
@@ -40,19 +39,22 @@ public:
virtual bool empty() const = 0;
// Get the time to wait until the next timer.
- virtual boost::posix_time::time_duration wait_duration() const = 0;
+ virtual long wait_duration_msec(long max_duration) const = 0;
+
+ // Get the time to wait until the next timer.
+ virtual long wait_duration_usec(long max_duration) const = 0;
- // Dispatch all ready timers.
- virtual void dispatch_timers() = 0;
+ // Dequeue all ready timers.
+ virtual void get_ready_timers(op_queue<operation>& ops) = 0;
- // Dispatch any pending cancels for timers.
- virtual void dispatch_cancellations() = 0;
+ // Dequeue all timers.
+ virtual void get_all_timers(op_queue<operation>& ops) = 0;
- // Complete all timers that are waiting to be completed.
- virtual void complete_timers() = 0;
+private:
+ friend class timer_queue_set;
- // Destroy all timers.
- virtual void destroy_timers() = 0;
+ // Next timer queue in the set.
+ timer_queue_base* next_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue_fwd.hpp
new file mode 100644
index 0000000..b8bc5f2
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue_fwd.hpp
@@ -0,0 +1,33 @@
+//
+// timer_queue_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP
+#define BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+class timer_queue;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_queue_set.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_queue_set.hpp
new file mode 100644
index 0000000..a92a6b9
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/timer_queue_set.hpp
@@ -0,0 +1,117 @@
+//
+// timer_queue_set.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP
+#define BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/timer_queue_base.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class timer_queue_set
+{
+public:
+ // Constructor.
+ timer_queue_set()
+ : first_(0)
+ {
+ }
+
+ // Add a timer queue to the set.
+ void insert(timer_queue_base* q)
+ {
+ q->next_ = first_;
+ first_ = q;
+ }
+
+ // Remove a timer queue from the set.
+ void erase(timer_queue_base* q)
+ {
+ if (first_)
+ {
+ if (q == first_)
+ {
+ first_ = q->next_;
+ q->next_ = 0;
+ return;
+ }
+
+ for (timer_queue_base* p = first_; p->next_; p = p->next_)
+ {
+ if (p->next_ == q)
+ {
+ p->next_ = q->next_;
+ q->next_ = 0;
+ return;
+ }
+ }
+ }
+ }
+
+ // Determine whether all queues are empty.
+ bool all_empty() const
+ {
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ if (!p->empty())
+ return false;
+ return true;
+ }
+
+ // Get the wait duration in milliseconds.
+ long wait_duration_msec(long max_duration) const
+ {
+ long min_duration = max_duration;
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ min_duration = p->wait_duration_msec(min_duration);
+ return min_duration;
+ }
+
+ // Get the wait duration in microseconds.
+ long wait_duration_usec(long max_duration) const
+ {
+ long min_duration = max_duration;
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ min_duration = p->wait_duration_usec(min_duration);
+ return min_duration;
+ }
+
+ // Dequeue all ready timers.
+ void get_ready_timers(op_queue<operation>& ops)
+ {
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ p->get_ready_timers(ops);
+ }
+
+ // Dequeue all timers.
+ void get_all_timers(op_queue<operation>& ops)
+ {
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ p->get_all_timers(ops);
+ }
+
+private:
+ timer_queue_base* first_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_scheduler.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler.hpp
new file mode 100644
index 0000000..bc837ee
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler.hpp
@@ -0,0 +1,36 @@
+//
+// timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP
+#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/timer_scheduler_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+# include <boost/asio/detail/win_iocp_io_service.hpp>
+#elif defined(BOOST_ASIO_HAS_EPOLL)
+# include <boost/asio/detail/epoll_reactor.hpp>
+#elif defined(BOOST_ASIO_HAS_KQUEUE)
+# include <boost/asio/detail/kqueue_reactor.hpp>
+#elif defined(BOOST_ASIO_HAS_DEV_POLL)
+# include <boost/asio/detail/dev_poll_reactor.hpp>
+#else
+# include <boost/asio/detail/select_reactor.hpp>
+#endif
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/timer_scheduler_fwd.hpp b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler_fwd.hpp
new file mode 100644
index 0000000..9d0b1e6
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/timer_scheduler_fwd.hpp
@@ -0,0 +1,48 @@
+//
+// timer_scheduler_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
+#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/dev_poll_reactor_fwd.hpp>
+#include <boost/asio/detail/epoll_reactor_fwd.hpp>
+#include <boost/asio/detail/kqueue_reactor_fwd.hpp>
+#include <boost/asio/detail/select_reactor_fwd.hpp>
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+typedef win_iocp_io_service timer_scheduler;
+#elif defined(BOOST_ASIO_HAS_EPOLL)
+typedef epoll_reactor timer_scheduler;
+#elif defined(BOOST_ASIO_HAS_KQUEUE)
+typedef kqueue_reactor timer_scheduler;
+#elif defined(BOOST_ASIO_HAS_DEV_POLL)
+typedef dev_poll_reactor timer_scheduler;
+#else
+typedef select_reactor<false> timer_scheduler;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp b/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp
index 9af4965..7ccfcf3 100644
--- a/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/tss_ptr.hpp
@@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
# include <boost/asio/detail/null_tss_ptr.hpp>
#elif defined(BOOST_WINDOWS)
# include <boost/asio/detail/win_tss_ptr.hpp>
@@ -37,7 +37,7 @@ namespace detail {
template <typename T>
class tss_ptr
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
: public null_tss_ptr<T>
#elif defined(BOOST_WINDOWS)
: public win_tss_ptr<T>
@@ -48,7 +48,7 @@ class tss_ptr
public:
void operator=(T* value)
{
-#if !defined(BOOST_HAS_THREADS)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
null_tss_ptr<T>::operator=(value);
#elif defined(BOOST_WINDOWS)
win_tss_ptr<T>::operator=(value);
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_event.hpp b/3rdParty/Boost/src/boost/asio/detail/win_event.hpp
index 637b580..bddf09d 100644
--- a/3rdParty/Boost/src/boost/asio/detail/win_event.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/win_event.hpp
@@ -71,6 +71,15 @@ public:
::SetEvent(event_);
}
+ // Signal the event and unlock the mutex.
+ template <typename Lock>
+ void signal_and_unlock(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ lock.unlock();
+ ::SetEvent(event_);
+ }
+
// Reset the event.
template <typename Lock>
void clear(Lock& lock)
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_fenced_block.hpp b/3rdParty/Boost/src/boost/asio/detail/win_fenced_block.hpp
new file mode 100644
index 0000000..ff4a21c
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/win_fenced_block.hpp
@@ -0,0 +1,77 @@
+//
+// win_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
+#define BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class win_fenced_block
+ : private noncopyable
+{
+public:
+ // Constructor.
+ win_fenced_block()
+ {
+#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+# if defined(_M_IX86)
+# pragma warning(push)
+# pragma warning(disable:4793)
+ LONG barrier;
+ __asm { xchg barrier, eax }
+# pragma warning(pop)
+# endif // defined(_M_IX86)
+#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+ MemoryBarrier();
+#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+ }
+
+ // Destructor.
+ ~win_fenced_block()
+ {
+#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+# if defined(_M_IX86)
+# pragma warning(push)
+# pragma warning(disable:4793)
+ LONG barrier;
+ __asm { xchg barrier, eax }
+# pragma warning(pop)
+# endif // defined(_M_IX86)
+#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+ MemoryBarrier();
+#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400)
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp
index 6998d57..a6d6599 100644
--- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_handle_service.hpp
@@ -26,13 +26,14 @@
#include <boost/cstdint.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/operation.hpp>
#include <boost/asio/detail/win_iocp_io_service.hpp>
namespace boost {
@@ -40,12 +41,8 @@ namespace asio {
namespace detail {
class win_iocp_handle_service
- : public boost::asio::detail::service_base<win_iocp_handle_service>
{
public:
- // Base class for all operations.
- typedef win_iocp_io_service::operation operation;
-
// The native type of a stream handle.
typedef HANDLE native_type;
@@ -81,8 +78,7 @@ public:
};
win_iocp_handle_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<win_iocp_handle_service>(io_service),
- iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
+ : iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
mutex_(),
impl_list_(0)
{
@@ -307,16 +303,9 @@ public:
return 0;
}
- // Find first buffer of non-zero length.
- boost::asio::const_buffer buffer;
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- for (DWORD i = 0; iter != end; ++iter, ++i)
- {
- buffer = boost::asio::const_buffer(*iter);
- if (boost::asio::buffer_size(buffer) != 0)
- break;
- }
+ boost::asio::const_buffer buffer =
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::first(buffers);
// A request to write 0 bytes on a handle is a no-op.
if (boost::asio::buffer_size(buffer) == 0)
@@ -365,79 +354,48 @@ public:
}
template <typename ConstBufferSequence, typename Handler>
- class write_operation
- : public operation
+ class write_op : public operation
{
public:
- write_operation(win_iocp_io_service& io_service,
- const ConstBufferSequence& buffers, Handler handler)
- : operation(io_service,
- &write_operation<ConstBufferSequence, Handler>::do_completion_impl,
- &write_operation<ConstBufferSequence, Handler>::destroy_impl),
- work_(io_service.get_io_service()),
+ write_op(const ConstBufferSequence& buffers, Handler handler)
+ : operation(&write_op::do_complete),
buffers_(buffers),
handler_(handler)
{
}
- private:
- static void do_completion_impl(operation* op,
- DWORD last_error, size_t bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t bytes_transferred)
{
// Take ownership of the operation object.
- typedef write_operation<ConstBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ write_op* o(static_cast<write_op*>(base));
+ typedef handler_alloc_traits<Handler, write_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
-#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- typename ConstBufferSequence::const_iterator iter
- = handler_op->buffers_.begin();
- typename ConstBufferSequence::const_iterator end
- = handler_op->buffers_.end();
- while (iter != end)
+ // Make the upcall if required.
+ if (owner)
{
- boost::asio::const_buffer buffer(*iter);
- boost::asio::buffer_cast<const char*>(buffer);
- ++iter;
- }
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Call the handler.
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- boost_asio_handler_invoke_helpers::invoke(
- bind_handler(handler, ec, bytes_transferred), handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef write_operation<ConstBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
- boost::asio::io_service::work work_;
+ private:
ConstBufferSequence buffers_;
Handler handler_;
};
@@ -457,65 +415,16 @@ public:
void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
const ConstBufferSequence& buffers, Handler handler)
{
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-
// Allocate and construct an operation to wrap the handler.
- typedef write_operation<ConstBufferSequence, Handler> value_type;
+ typedef write_op<ConstBufferSequence, 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, iocp_service_, buffers, handler);
-
- if (!is_open(impl))
- {
- ptr.get()->on_immediate_completion(WSAEBADF, 0);
- ptr.release();
- return;
- }
-
- // Find first buffer of non-zero length.
- boost::asio::const_buffer buffer;
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- for (DWORD i = 0; iter != end; ++iter, ++i)
- {
- buffer = boost::asio::const_buffer(*iter);
- if (boost::asio::buffer_size(buffer) != 0)
- break;
- }
-
- // A request to write 0 bytes on a handle is a no-op.
- if (boost::asio::buffer_size(buffer) == 0)
- {
- ptr.get()->on_immediate_completion(0, 0);
- ptr.release();
- return;
- }
-
- // Write the data.
- DWORD bytes_transferred = 0;
- ptr.get()->Offset = offset & 0xFFFFFFFF;
- ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::WriteFile(impl.handle_,
- boost::asio::buffer_cast<LPCVOID>(buffer),
- static_cast<DWORD>(boost::asio::buffer_size(buffer)),
- &bytes_transferred, ptr.get());
- DWORD last_error = ::GetLastError();
+ handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler);
- // Check if the operation completed immediately.
- if (!ok && last_error != ERROR_IO_PENDING)
- {
- ptr.get()->on_immediate_completion(last_error, bytes_transferred);
- ptr.release();
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ start_write_op(impl, offset,
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::first(buffers), ptr.get());
+ ptr.release();
}
// Read some data. Returns the number of bytes received.
@@ -537,16 +446,9 @@ public:
return 0;
}
- // Find first buffer of non-zero length.
- boost::asio::mutable_buffer buffer;
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- for (DWORD i = 0; iter != end; ++iter, ++i)
- {
- buffer = boost::asio::mutable_buffer(*iter);
- if (boost::asio::buffer_size(buffer) != 0)
- break;
- }
+ boost::asio::mutable_buffer buffer =
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::first(buffers);
// A request to read 0 bytes on a stream handle is a no-op.
if (boost::asio::buffer_size(buffer) == 0)
@@ -609,89 +511,54 @@ public:
}
template <typename MutableBufferSequence, typename Handler>
- class read_operation
- : public operation
+ class read_op : public operation
{
public:
- read_operation(win_iocp_io_service& io_service,
- const MutableBufferSequence& buffers, Handler handler)
- : operation(io_service,
- &read_operation<
- MutableBufferSequence, Handler>::do_completion_impl,
- &read_operation<
- MutableBufferSequence, Handler>::destroy_impl),
- work_(io_service.get_io_service()),
+ read_op(const MutableBufferSequence& buffers, Handler handler)
+ : operation(&read_op::do_complete),
buffers_(buffers),
handler_(handler)
{
}
- private:
- static void do_completion_impl(operation* op,
- DWORD last_error, size_t bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t bytes_transferred)
{
// Take ownership of the operation object.
- typedef read_operation<MutableBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ read_op* o(static_cast<read_op*>(base));
+ typedef handler_alloc_traits<Handler, read_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
-#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- typename MutableBufferSequence::const_iterator iter
- = handler_op->buffers_.begin();
- typename MutableBufferSequence::const_iterator end
- = handler_op->buffers_.end();
- while (iter != end)
+ // Make the upcall if required.
+ if (owner)
{
- boost::asio::mutable_buffer buffer(*iter);
- boost::asio::buffer_cast<char*>(buffer);
- ++iter;
- }
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check for the end-of-file condition.
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF)
- {
- ec = boost::asio::error::eof;
- }
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Call the handler.
- boost_asio_handler_invoke_helpers::invoke(
- bind_handler(handler, ec, bytes_transferred), handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef read_operation<MutableBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef boost::asio::detail::handler_alloc_traits<
- Handler, op_type> alloc_traits;
- boost::asio::detail::handler_ptr<alloc_traits> ptr(
- handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_HANDLE_EOF)
+ {
+ ec = boost::asio::error::eof;
+ }
- // Free the memory associated with the handler.
- ptr.reset();
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
- boost::asio::io_service::work work_;
+ private:
MutableBufferSequence buffers_;
Handler handler_;
};
@@ -712,63 +579,16 @@ public:
void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
const MutableBufferSequence& buffers, Handler handler)
{
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-
// Allocate and construct an operation to wrap the handler.
- typedef read_operation<MutableBufferSequence, Handler> value_type;
+ typedef read_op<MutableBufferSequence, 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, iocp_service_, buffers, handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, buffers, handler);
- if (!is_open(impl))
- {
- ptr.get()->on_immediate_completion(WSAEBADF, 0);
- ptr.release();
- return;
- }
-
- // Find first buffer of non-zero length.
- boost::asio::mutable_buffer buffer;
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- for (DWORD i = 0; iter != end; ++iter, ++i)
- {
- buffer = boost::asio::mutable_buffer(*iter);
- if (boost::asio::buffer_size(buffer) != 0)
- break;
- }
-
- // A request to receive 0 bytes on a stream handle is a no-op.
- if (boost::asio::buffer_size(buffer) == 0)
- {
- ptr.get()->on_immediate_completion(0, 0);
- ptr.release();
- return;
- }
-
- // Read some data.
- DWORD bytes_transferred = 0;
- ptr.get()->Offset = offset & 0xFFFFFFFF;
- ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
- BOOL ok = ::ReadFile(impl.handle_,
- boost::asio::buffer_cast<LPVOID>(buffer),
- static_cast<DWORD>(boost::asio::buffer_size(buffer)),
- &bytes_transferred, ptr.get());
- DWORD last_error = ::GetLastError();
- if (!ok && last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
- {
- ptr.get()->on_immediate_completion(last_error, bytes_transferred);
- ptr.release();
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ start_read_op(impl, offset,
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::first(buffers), ptr.get());
+ ptr.release();
}
private:
@@ -794,6 +614,95 @@ private:
void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
const null_buffers& buffers, Handler handler);
+ // Helper function to start a write operation.
+ void start_write_op(implementation_type& impl, boost::uint64_t offset,
+ const boost::asio::const_buffer& buffer, operation* op)
+ {
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ {
+ iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
+ }
+ else if (boost::asio::buffer_size(buffer) == 0)
+ {
+ // A request to write 0 bytes on a handle is a no-op.
+ iocp_service_.on_completion(op);
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ op->Offset = offset & 0xFFFFFFFF;
+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::WriteFile(impl.handle_,
+ boost::asio::buffer_cast<LPCVOID>(buffer),
+ static_cast<DWORD>(boost::asio::buffer_size(buffer)),
+ &bytes_transferred, op);
+ DWORD last_error = ::GetLastError();
+ if (!ok && last_error != ERROR_IO_PENDING
+ && last_error != ERROR_MORE_DATA)
+ {
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ }
+ else
+ {
+ iocp_service_.on_pending(op);
+ }
+ }
+ }
+
+ // Helper function to start a read operation.
+ void start_read_op(implementation_type& impl, boost::uint64_t offset,
+ const boost::asio::mutable_buffer& buffer, operation* op)
+ {
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ {
+ iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
+ }
+ else if (boost::asio::buffer_size(buffer) == 0)
+ {
+ // A request to read 0 bytes on a handle is a no-op.
+ iocp_service_.on_completion(op);
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ op->Offset = offset & 0xFFFFFFFF;
+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::ReadFile(impl.handle_,
+ boost::asio::buffer_cast<LPVOID>(buffer),
+ static_cast<DWORD>(boost::asio::buffer_size(buffer)),
+ &bytes_transferred, op);
+ DWORD last_error = ::GetLastError();
+ if (!ok && last_error != ERROR_IO_PENDING
+ && last_error != ERROR_MORE_DATA)
+ {
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ }
+ else
+ {
+ iocp_service_.on_pending(op);
+ }
+ }
+ }
+
+ // Update the ID of the thread from which cancellation is safe.
+ void update_cancellation_thread_id(implementation_type& impl)
+ {
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#else // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ (void)impl;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ }
+
// Helper function to close a handle when the associated object is being
// destroyed.
void close_for_destruction(implementation_type& impl)
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp
index 1dfb9a1..83b16bf 100644
--- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_io_service.hpp
@@ -29,122 +29,37 @@
#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/completion_handler.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/op_queue.hpp>
#include <boost/asio/detail/service_base.hpp>
#include <boost/asio/detail/socket_types.hpp>
-#include <boost/asio/detail/timer_queue.hpp>
-#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/timer_op.hpp>
+#include <boost/asio/detail/timer_queue_base.hpp>
+#include <boost/asio/detail/timer_queue_fwd.hpp>
+#include <boost/asio/detail/timer_queue_set.hpp>
+#include <boost/asio/detail/win_iocp_operation.hpp>
namespace boost {
namespace asio {
namespace detail {
+class timer_op;
+
class win_iocp_io_service
: public boost::asio::detail::service_base<win_iocp_io_service>
{
public:
- // Base class for all operations. A function pointer is used instead of
- // virtual functions to avoid the associated overhead.
- //
- // This class inherits from OVERLAPPED so that we can downcast to get back to
- // the operation pointer from the LPOVERLAPPED out parameter of
- // GetQueuedCompletionStatus.
- class operation;
- friend class operation;
- class operation
- : public OVERLAPPED
- {
- public:
- typedef void (*invoke_func_type)(operation*, DWORD, size_t);
- typedef void (*destroy_func_type)(operation*);
-
- operation(win_iocp_io_service& iocp_service,
- invoke_func_type invoke_func, destroy_func_type destroy_func)
- : iocp_service_(iocp_service),
- ready_(0),
- last_error_(~DWORD(0)),
- bytes_transferred_(0),
- invoke_func_(invoke_func),
- destroy_func_(destroy_func)
- {
- Internal = 0;
- InternalHigh = 0;
- Offset = 0;
- OffsetHigh = 0;
- hEvent = 0;
-
- ::InterlockedIncrement(&iocp_service_.outstanding_operations_);
- }
-
- void reset()
- {
- Internal = 0;
- InternalHigh = 0;
- Offset = 0;
- OffsetHigh = 0;
- hEvent = 0;
- ready_ = 0;
- last_error_ = ~DWORD(0);
- bytes_transferred_ = 0;
- }
-
- void on_pending()
- {
- if (::InterlockedCompareExchange(&ready_, 1, 0) == 1)
- iocp_service_.post_completion(this, last_error_, bytes_transferred_);
- }
-
- void on_immediate_completion(DWORD last_error, DWORD bytes_transferred)
- {
- ready_ = 1;
- iocp_service_.post_completion(this, last_error, bytes_transferred);
- }
-
- bool on_completion(DWORD last_error, DWORD bytes_transferred)
- {
- if (last_error_ == ~DWORD(0))
- {
- last_error_ = last_error;
- bytes_transferred_ = bytes_transferred;
- }
-
- if (::InterlockedCompareExchange(&ready_, 1, 0) == 1)
- {
- invoke_func_(this, last_error_, bytes_transferred_);
- return true;
- }
-
- return false;
- }
-
- void destroy()
- {
- destroy_func_(this);
- }
-
- protected:
- // Prevent deletion through this type.
- ~operation()
- {
- ::InterlockedDecrement(&iocp_service_.outstanding_operations_);
- }
-
- private:
- win_iocp_io_service& iocp_service_;
- long ready_;
- DWORD last_error_;
- DWORD bytes_transferred_;
- invoke_func_type invoke_func_;
- destroy_func_type destroy_func_;
- };
+ typedef win_iocp_operation operation;
// Constructor.
win_iocp_io_service(boost::asio::io_service& io_service)
: boost::asio::detail::service_base<win_iocp_io_service>(io_service),
iocp_(),
outstanding_work_(0),
- outstanding_operations_(0),
stopped_(0),
shutdown_(0),
timer_thread_(0),
@@ -172,24 +87,34 @@ public:
{
::InterlockedExchange(&shutdown_, 1);
- while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0)
+ while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
{
- DWORD bytes_transferred = 0;
-#if defined(WINVER) && (WINVER < 0x0500)
- DWORD completion_key = 0;
-#else
- DWORD_PTR completion_key = 0;
-#endif
- LPOVERLAPPED overlapped = 0;
- ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
- &completion_key, &overlapped, INFINITE);
- if (overlapped)
- static_cast<operation*>(overlapped)->destroy();
+ op_queue<operation> ops;
+ timer_queues_.get_all_timers(ops);
+ ops.push(completed_ops_);
+ if (!ops.empty())
+ {
+ while (operation* op = ops.front())
+ {
+ ops.pop();
+ ::InterlockedDecrement(&outstanding_work_);
+ op->destroy();
+ }
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ dword_ptr_t completion_key = 0;
+ LPOVERLAPPED overlapped = 0;
+ ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, max_timeout);
+ if (overlapped)
+ {
+ ::InterlockedDecrement(&outstanding_work_);
+ static_cast<operation*>(overlapped)->destroy();
+ }
+ }
}
-
- for (std::size_t i = 0; i < timer_queues_.size(); ++i)
- timer_queues_[i]->destroy_timers();
- timer_queues_.clear();
}
// Initialise the task. Nothing to do here.
@@ -219,6 +144,7 @@ public:
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
+ stop();
ec = boost::system::error_code();
return 0;
}
@@ -237,6 +163,7 @@ public:
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
+ stop();
ec = boost::system::error_code();
return 0;
}
@@ -251,6 +178,7 @@ public:
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
+ stop();
ec = boost::system::error_code();
return 0;
}
@@ -269,6 +197,7 @@ public:
{
if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
{
+ stop();
ec = boost::system::error_code();
return 0;
}
@@ -319,7 +248,10 @@ public:
void dispatch(Handler handler)
{
if (call_stack<win_iocp_io_service>::contains(this))
+ {
+ boost::asio::detail::fenced_block b;
boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
else
post(handler);
}
@@ -328,37 +260,128 @@ public:
template <typename Handler>
void post(Handler handler)
{
- // If the service has been shut down we silently discard the handler.
- if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
- return;
-
// Allocate and construct an operation to wrap the handler.
- typedef handler_operation<Handler> value_type;
+ typedef completion_handler<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, *this, handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+
+ post_immediate_completion(ptr.get());
+ ptr.release();
+ }
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() has not yet been called for the operation.
+ void post_immediate_completion(operation* op)
+ {
+ work_started();
+ post_deferred_completion(op);
+ }
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() was previously called for the operation.
+ void post_deferred_completion(operation* op)
+ {
+ // Flag the operation as ready.
+ op->ready_ = 1;
// Enqueue the operation on the I/O completion port.
- ptr.get()->on_immediate_completion(0, 0);
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ completed_ops_.push(op);
+ }
+ }
- // Operation has been successfully posted.
- ptr.release();
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() was previously called for the operations.
+ void post_deferred_completions(op_queue<operation>& ops)
+ {
+ while (operation* op = ops.front())
+ {
+ ops.pop();
+
+ // Flag the operation as ready.
+ op->ready_ = 1;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ completed_ops_.push(op);
+ completed_ops_.push(ops);
+ }
+ }
}
- // Request invocation of the given OVERLAPPED-derived operation.
- void post_completion(operation* op, DWORD op_last_error,
- DWORD bytes_transferred)
+ // Called after starting an overlapped I/O operation that did not complete
+ // immediately. The caller must have already called work_started() prior to
+ // starting the operation.
+ void on_pending(operation* op)
{
+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+ {
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ completed_ops_.push(op);
+ }
+ }
+ }
+
+ // Called after starting an overlapped I/O operation that completed
+ // immediately. The caller must have already called work_started() prior to
+ // starting the operation.
+ void on_completion(operation* op,
+ DWORD last_error = 0, DWORD bytes_transferred = 0)
+ {
+ // Flag that the operation is ready for invocation.
+ op->ready_ = 1;
+
+ // Store results in the OVERLAPPED structure.
+ op->Internal = reinterpret_cast<ulong_ptr_t>(
+ &boost::asio::error::get_system_category());
+ op->Offset = last_error;
+ op->OffsetHigh = bytes_transferred;
+
// Enqueue the operation on the I/O completion port.
if (!::PostQueuedCompletionStatus(iocp_.handle,
- bytes_transferred, op_last_error, op))
+ 0, overlapped_contains_result, op))
{
- DWORD last_error = ::GetLastError();
- boost::system::system_error e(
- boost::system::error_code(last_error,
- boost::asio::error::get_system_category()),
- "pqcs");
- boost::throw_exception(e);
+ // Out of resources. Put on completed queue instead.
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ completed_ops_.push(op);
+ }
+ }
+
+ // Called after starting an overlapped I/O operation that completed
+ // immediately. The caller must have already called work_started() prior to
+ // starting the operation.
+ void on_completion(operation* op,
+ const boost::system::error_code& ec, DWORD bytes_transferred = 0)
+ {
+ // Flag that the operation is ready for invocation.
+ op->ready_ = 1;
+
+ // Store results in the OVERLAPPED structure.
+ op->Internal = reinterpret_cast<ulong_ptr_t>(&ec.category());
+ op->Offset = ec.value();
+ op->OffsetHigh = bytes_transferred;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ completed_ops_.push(op);
}
}
@@ -367,7 +390,7 @@ public:
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
- timer_queues_.push_back(&timer_queue);
+ timer_queues_.insert(&timer_queue);
}
// Remove a timer queue from the service.
@@ -375,36 +398,28 @@ public:
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
boost::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;
- }
- }
+ timer_queues_.erase(&timer_queue);
}
- // 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>
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
- const typename Time_Traits::time_type& time, Handler handler, void* token)
+ const typename Time_Traits::time_type& time, timer_op* op, void* token)
{
// If the service has been shut down we silently discard the timer.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return;
boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
- if (timer_queue.enqueue_timer(time, handler, token))
+ bool interrupt = timer_queue.enqueue_timer(time, op, token);
+ work_started();
+ if (interrupt && !timer_interrupt_issued_)
{
- if (!timer_interrupt_issued_)
- {
- timer_interrupt_issued_ = true;
- lock.unlock();
- ::PostQueuedCompletionStatus(iocp_.handle,
- 0, steal_timer_dispatching, 0);
- }
+ timer_interrupt_issued_ = true;
+ lock.unlock();
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, steal_timer_dispatching, 0);
}
}
@@ -418,7 +433,9 @@ public:
return 0;
boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
- std::size_t n = timer_queue.cancel_timer(token);
+ op_queue<operation> ops;
+ std::size_t n = timer_queue.cancel_timer(token, ops);
+ post_deferred_completions(ops);
if (n > 0 && !timer_interrupt_issued_)
{
timer_interrupt_issued_ = true;
@@ -430,6 +447,14 @@ public:
}
private:
+#if defined(WINVER) && (WINVER < 0x0500)
+ typedef DWORD dword_ptr_t;
+ typedef ULONG ulong_ptr_t;
+#else // defined(WINVER) && (WINVER < 0x0500)
+ typedef DWORD_PTR dword_ptr_t;
+ typedef ULONG_PTR ulong_ptr_t;
+#endif // defined(WINVER) && (WINVER < 0x0500)
+
// 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).
@@ -454,11 +479,7 @@ private:
// Get the next operation from the queue.
DWORD bytes_transferred = 0;
-#if defined(WINVER) && (WINVER < 0x0500)
- DWORD completion_key = 0;
-#else
- DWORD_PTR completion_key = 0;
-#endif
+ dword_ptr_t completion_key = 0;
LPOVERLAPPED overlapped = 0;
::SetLastError(0);
BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
@@ -468,32 +489,11 @@ private:
// Dispatch any pending timers.
if (dispatching_timers)
{
- try
- {
- boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
- if (!timer_queues_.empty())
- {
- timer_queues_copy_ = timer_queues_;
- for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i)
- {
- timer_queues_copy_[i]->dispatch_timers();
- timer_queues_copy_[i]->dispatch_cancellations();
- timer_queues_copy_[i]->complete_timers();
- }
- }
- }
- catch (...)
- {
- // Transfer responsibility for dispatching timers to another thread.
- if (::InterlockedCompareExchange(&timer_thread_,
- 0, this_thread_id) == this_thread_id)
- {
- ::PostQueuedCompletionStatus(iocp_.handle,
- 0, transfer_timer_dispatching, 0);
- }
-
- throw;
- }
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ op_queue<operation> ops;
+ ops.push(completed_ops_);
+ timer_queues_.get_ready_timers(ops);
+ post_deferred_completions(ops);
}
if (!ok && overlapped == 0)
@@ -522,11 +522,9 @@ private:
}
else if (overlapped)
{
- // We may have been passed a last_error value in the completion_key.
- if (last_error == 0)
- {
- last_error = completion_key;
- }
+ operation* op = static_cast<operation*>(overlapped);
+ boost::system::error_code result_ec(last_error,
+ boost::asio::error::get_system_category());
// Transfer responsibility for dispatching timers to another thread.
if (dispatching_timers && ::InterlockedCompareExchange(
@@ -536,14 +534,35 @@ private:
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);
+ // We may have been passed the last_error and bytes_transferred in the
+ // OVERLAPPED structure itself.
+ if (completion_key == overlapped_contains_result)
+ {
+ result_ec = boost::system::error_code(static_cast<int>(op->Offset),
+ *reinterpret_cast<boost::system::error_category*>(op->Internal));
+ bytes_transferred = op->OffsetHigh;
+ }
- // Dispatch the operation.
- operation* op = static_cast<operation*>(overlapped);
- if (op->on_completion(last_error, bytes_transferred))
+ // Otherwise ensure any result has been saved into the OVERLAPPED
+ // structure.
+ else
{
+ op->Internal = reinterpret_cast<ulong_ptr_t>(&result_ec.category());
+ op->Offset = result_ec.value();
+ op->OffsetHigh = bytes_transferred;
+ }
+
+ // Dispatch the operation only if ready. The operation may not be ready
+ // if the initiating function (e.g. a call to WSARecv) has not yet
+ // returned. This is because the initiating function still wants access
+ // to the operation's OVERLAPPED structure.
+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+ {
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_finished_on_block_exit on_exit = { this };
+ (void)on_exit;
+
+ op->complete(*this, result_ec, bytes_transferred);
ec = boost::system::error_code();
return 1;
}
@@ -588,126 +607,23 @@ 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;
- }
+ return timer_queues_.wait_duration_msec(max_timeout);
}
- struct auto_work
+ // Helper class to call work_finished() on block exit.
+ struct work_finished_on_block_exit
{
- auto_work(win_iocp_io_service& io_service)
- : io_service_(io_service)
+ ~work_finished_on_block_exit()
{
- io_service_.work_started();
+ io_service_->work_finished();
}
- ~auto_work()
- {
- io_service_.work_finished();
- }
-
- private:
- win_iocp_io_service& io_service_;
- };
-
- template <typename Handler>
- struct handler_operation
- : public operation
- {
- handler_operation(win_iocp_io_service& io_service,
- Handler handler)
- : operation(io_service, &handler_operation<Handler>::do_completion_impl,
- &handler_operation<Handler>::destroy_impl),
- io_service_(io_service),
- handler_(handler)
- {
- io_service_.work_started();
- }
-
- ~handler_operation()
- {
- io_service_.work_finished();
- }
-
- private:
- // Prevent copying and assignment.
- handler_operation(const handler_operation&);
- void operator=(const handler_operation&);
-
- static void do_completion_impl(operation* op, DWORD, size_t)
- {
- // Take ownership of the operation object.
- typedef handler_operation<Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Make the upcall.
- boost_asio_handler_invoke_helpers::invoke(handler, handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef handler_operation<Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
- }
-
- win_iocp_io_service& io_service_;
- Handler handler_;
+ win_iocp_io_service* io_service_;
};
// The IO completion port used for queueing operations.
@@ -721,10 +637,6 @@ private:
// The count of unfinished work.
long outstanding_work_;
- // The count of unfinished operations.
- long outstanding_operations_;
- friend class operation;
-
// Flag to indicate whether the event loop has been stopped.
long stopped_;
@@ -742,7 +654,12 @@ private:
// Completion key value to indicate that responsibility for dispatching
// timers should be stolen from another thread.
- steal_timer_dispatching = 2
+ steal_timer_dispatching = 2,
+
+ // Completion key value to indicate that an operation has posted with the
+ // original last_error and bytes_transferred values stored in the fields of
+ // the OVERLAPPED structure.
+ overlapped_contains_result = 3
};
// The thread that's currently in charge of dispatching timers.
@@ -755,12 +672,10 @@ private:
bool timer_interrupt_issued_;
// The timer queues.
- std::vector<timer_queue_base*> timer_queues_;
+ timer_queue_set 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_;
+ // The operations that are ready to dispatch.
+ op_queue<operation> completed_ops_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_operation.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_operation.hpp
new file mode 100644
index 0000000..d7d5723
--- /dev/null
+++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_operation.hpp
@@ -0,0 +1,91 @@
+//
+// win_iocp_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/op_queue.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Base class for all operations. A function pointer is used instead of virtual
+// functions to avoid the associated overhead.
+class win_iocp_operation
+ : public OVERLAPPED
+{
+public:
+ void complete(win_iocp_io_service& owner,
+ const boost::system::error_code& ec = boost::system::error_code(),
+ std::size_t bytes_transferred = 0)
+ {
+ func_(&owner, this, ec, bytes_transferred);
+ }
+
+ void destroy()
+ {
+ func_(0, this, boost::system::error_code(), 0);
+ }
+
+protected:
+ typedef void (*func_type)(win_iocp_io_service*,
+ win_iocp_operation*, boost::system::error_code, std::size_t);
+
+ win_iocp_operation(func_type func)
+ : next_(0),
+ func_(func)
+ {
+ reset();
+ }
+
+ // Prevents deletion through this type.
+ ~win_iocp_operation()
+ {
+ }
+
+ void reset()
+ {
+ Internal = 0;
+ InternalHigh = 0;
+ Offset = 0;
+ OffsetHigh = 0;
+ hEvent = 0;
+ ready_ = 0;
+ }
+
+private:
+ friend class op_queue_access;
+ friend class win_iocp_io_service;
+ win_iocp_operation* next_;
+ func_type func_;
+ long ready_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/system/error_code.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp
index bb64014..082a5b1 100644
--- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_overlapped_ptr.hpp
@@ -21,8 +21,10 @@
#if defined(BOOST_ASIO_HAS_IOCP)
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/win_iocp_io_service.hpp>
+#include <boost/asio/detail/win_iocp_operation.hpp>
namespace boost {
namespace asio {
@@ -35,7 +37,8 @@ class win_iocp_overlapped_ptr
public:
// Construct an empty win_iocp_overlapped_ptr.
win_iocp_overlapped_ptr()
- : ptr_(0)
+ : ptr_(0),
+ iocp_service_(0)
{
}
@@ -43,7 +46,8 @@ public:
template <typename Handler>
explicit win_iocp_overlapped_ptr(
boost::asio::io_service& io_service, Handler handler)
- : ptr_(0)
+ : ptr_(0),
+ iocp_service_(0)
{
this->reset(io_service, handler);
}
@@ -61,6 +65,8 @@ public:
{
ptr_->destroy();
ptr_ = 0;
+ iocp_service_->work_finished();
+ iocp_service_ = 0;
}
}
@@ -69,12 +75,14 @@ public:
template <typename Handler>
void reset(boost::asio::io_service& io_service, Handler handler)
{
- typedef overlapped_operation<Handler> value_type;
+ typedef overlapped_op<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, io_service.impl_, handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+ io_service.impl_.work_started();
reset();
ptr_ = ptr.release();
+ iocp_service_ = &io_service.impl_;
}
// Get the contained OVERLAPPED object.
@@ -93,10 +101,11 @@ public:
OVERLAPPED* release()
{
if (ptr_)
- ptr_->on_pending();
+ iocp_service_->on_pending(ptr_);
OVERLAPPED* tmp = ptr_;
ptr_ = 0;
+ iocp_service_ = 0;
return tmp;
}
@@ -106,99 +115,54 @@ public:
{
if (ptr_)
{
- ptr_->ec_ = ec;
- ptr_->on_immediate_completion(0, static_cast<DWORD>(bytes_transferred));
+ iocp_service_->on_completion(ptr_, ec,
+ static_cast<DWORD>(bytes_transferred));
ptr_ = 0;
+ iocp_service_ = 0;
}
}
private:
- struct overlapped_operation_base
- : public win_iocp_io_service::operation
- {
- overlapped_operation_base(win_iocp_io_service& io_service,
- invoke_func_type invoke_func, destroy_func_type destroy_func)
- : win_iocp_io_service::operation(io_service, invoke_func, destroy_func),
- io_service_(io_service)
- {
- io_service_.work_started();
- }
-
- ~overlapped_operation_base()
- {
- io_service_.work_finished();
- }
-
- win_iocp_io_service& io_service_;
- boost::system::error_code ec_;
- };
-
template <typename Handler>
- struct overlapped_operation
- : public overlapped_operation_base
+ struct overlapped_op : public win_iocp_operation
{
- overlapped_operation(win_iocp_io_service& io_service,
- Handler handler)
- : overlapped_operation_base(io_service,
- &overlapped_operation<Handler>::do_completion_impl,
- &overlapped_operation<Handler>::destroy_impl),
+ overlapped_op(Handler handler)
+ : win_iocp_operation(&overlapped_op::do_complete),
handler_(handler)
{
}
- private:
- // Prevent copying and assignment.
- overlapped_operation(const overlapped_operation&);
- void operator=(const overlapped_operation&);
-
- static void do_completion_impl(win_iocp_io_service::operation* op,
- DWORD last_error, size_t bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t bytes_transferred)
{
// Take ownership of the operation object.
- typedef overlapped_operation<Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // Make a copy of the handler and error_code so that the memory can be
- // deallocated before the upcall is made.
- Handler handler(handler_op->handler_);
- boost::system::error_code ec(handler_op->ec_);
- if (last_error)
- ec = boost::system::error_code(last_error,
- boost::asio::error::get_system_category());
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Make the upcall.
- boost_asio_handler_invoke_helpers::invoke(
- bind_handler(handler, ec, bytes_transferred), handler);
- }
-
- static void destroy_impl(win_iocp_io_service::operation* op)
- {
- // Take ownership of the operation object.
- typedef overlapped_operation<Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
+ overlapped_op* o(static_cast<overlapped_op*>(base));
+ typedef handler_alloc_traits<Handler, overlapped_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
+ private:
Handler handler_;
};
- overlapped_operation_base* ptr_;
+ win_iocp_operation* ptr_;
+ win_iocp_io_service* iocp_service_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp
index 4d6d2e9..288287c 100644
--- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_serial_port_service.hpp
@@ -37,7 +37,6 @@ namespace detail {
// Extend win_iocp_handle_service to provide serial port support.
class win_iocp_serial_port_service
- : public boost::asio::detail::service_base<win_iocp_serial_port_service>
{
public:
// The native type of a stream handle.
@@ -47,10 +46,7 @@ public:
typedef win_iocp_handle_service::implementation_type implementation_type;
win_iocp_serial_port_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- win_iocp_serial_port_service>(io_service),
- handle_service_(
- boost::asio::use_service<win_iocp_handle_service>(io_service))
+ : handle_service_(io_service)
{
}
@@ -279,8 +275,8 @@ public:
}
private:
- // The handle service used for initiating asynchronous operations.
- win_iocp_handle_service& handle_service_;
+ // The implementation used for initiating asynchronous operations.
+ win_iocp_handle_service handle_service_;
};
} // namespace detail
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp b/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp
index e0c0806..5d545a8 100644
--- a/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/win_iocp_socket_service.hpp
@@ -28,15 +28,19 @@
#include <boost/weak_ptr.hpp>
#include <boost/asio/detail/pop_options.hpp>
-#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/socket_base.hpp>
#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/mutex.hpp>
-#include <boost/asio/detail/select_reactor.hpp>
+#include <boost/asio/detail/null_buffers_op.hpp>
+#include <boost/asio/detail/operation.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/socket_holder.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
@@ -48,7 +52,6 @@ namespace detail {
template <typename Protocol>
class win_iocp_socket_service
- : public boost::asio::detail::service_base<win_iocp_socket_service<Protocol> >
{
public:
// The protocol type.
@@ -57,9 +60,6 @@ public:
// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
- // Base class for all operations.
- typedef win_iocp_io_service::operation operation;
-
struct noop_deleter { void operator()(void*) {} };
typedef boost::shared_ptr<void> shared_cancel_token_type;
typedef boost::weak_ptr<void> weak_cancel_token_type;
@@ -114,9 +114,6 @@ public:
endpoint_type remote_endpoint_;
};
- // The type of the reactor used for connect operations.
- typedef detail::select_reactor<true> reactor_type;
-
// The implementation type of the socket.
class implementation_type
{
@@ -161,7 +158,7 @@ public:
protocol_type protocol_;
// Per-descriptor data used by the reactor.
- reactor_type::per_descriptor_data reactor_data_;
+ reactor::per_descriptor_data reactor_data_;
#if defined(BOOST_ASIO_ENABLE_CANCELIO)
// The ID of the thread from which it is safe to cancel asynchronous
@@ -176,14 +173,10 @@ public:
implementation_type* prev_;
};
- // The maximum number of buffers to support in a single operation.
- enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
-
// Constructor.
win_iocp_socket_service(boost::asio::io_service& io_service)
- : boost::asio::detail::service_base<
- win_iocp_socket_service<Protocol> >(io_service),
- iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
+ : io_service_(io_service),
+ iocp_service_(use_service<win_iocp_io_service>(io_service)),
reactor_(0),
mutex_(),
impl_list_(0)
@@ -304,11 +297,11 @@ public:
// Check if the reactor was created, in which case we need to close the
// socket on the reactor as well to cancel any operations that might be
// running there.
- reactor_type* reactor = static_cast<reactor_type*>(
+ reactor* r = static_cast<reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
- if (reactor)
- reactor->close_descriptor(impl.socket_, impl.reactor_data_);
+ if (r)
+ r->close_descriptor(impl.socket_, impl.reactor_data_);
if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
return ec;
@@ -665,23 +658,11 @@ public:
return 0;
}
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = const_cast<char*>(
- boost::asio::buffer_cast<const char*>(buffer));
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
// A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
{
ec = boost::system::error_code();
return 0;
@@ -689,8 +670,8 @@ public:
// Send the data.
DWORD bytes_transferred = 0;
- int result = ::WSASend(impl.socket_, bufs,
- i, &bytes_transferred, flags, 0, 0);
+ int result = ::WSASend(impl.socket_, bufs.buffers(),
+ bufs.count(), &bytes_transferred, flags, 0, 0);
if (result != 0)
{
DWORD last_error = ::WSAGetLastError();
@@ -724,94 +705,63 @@ public:
}
template <typename ConstBufferSequence, typename Handler>
- class send_operation
- : public operation
+ class send_op : public operation
{
public:
- send_operation(win_iocp_io_service& io_service,
- weak_cancel_token_type cancel_token,
+ send_op(weak_cancel_token_type cancel_token,
const ConstBufferSequence& buffers, Handler handler)
- : operation(io_service,
- &send_operation<ConstBufferSequence, Handler>::do_completion_impl,
- &send_operation<ConstBufferSequence, Handler>::destroy_impl),
- work_(io_service.get_io_service()),
+ : operation(&send_op::do_complete),
cancel_token_(cancel_token),
buffers_(buffers),
handler_(handler)
{
}
- private:
- static void do_completion_impl(operation* op,
- DWORD last_error, size_t bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t bytes_transferred)
{
// Take ownership of the operation object.
- typedef send_operation<ConstBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ send_op* o(static_cast<send_op*>(base));
+ typedef handler_alloc_traits<Handler, send_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
-#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- typename ConstBufferSequence::const_iterator iter
- = handler_op->buffers_.begin();
- typename ConstBufferSequence::const_iterator end
- = handler_op->buffers_.end();
- while (iter != end)
+ // Make the upcall if required.
+ if (owner)
{
- boost::asio::const_buffer buffer(*iter);
- boost::asio::buffer_cast<const char*>(buffer);
- ++iter;
- }
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Map non-portable errors to their portable counterparts.
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (handler_op->cancel_token_.expired())
- ec = boost::asio::error::operation_aborted;
- else
- ec = boost::asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Call the handler.
- boost_asio_handler_invoke_helpers::invoke(
- detail::bind_handler(handler, ec, bytes_transferred), handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef send_operation<ConstBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (o->cancel_token_.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
- // Free the memory associated with the handler.
- ptr.reset();
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
- boost::asio::io_service::work work_;
+ private:
weak_cancel_token_type cancel_token_;
ConstBufferSequence buffers_;
Handler handler_;
@@ -823,127 +773,34 @@ public:
void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler handler)
{
-#if defined(BOOST_ASIO_ENABLE_CANCELIO)
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
-
// Allocate and construct an operation to wrap the handler.
- typedef send_operation<ConstBufferSequence, Handler> value_type;
+ typedef send_op<ConstBufferSequence, 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, iocp_service_,
+ handler_ptr<alloc_traits> ptr(raw_ptr,
impl.cancel_token_, buffers, handler);
- if (!is_open(impl))
- {
- ptr.get()->on_immediate_completion(WSAEBADF, 0);
- ptr.release();
- return;
- }
-
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = const_cast<char*>(
- boost::asio::buffer_cast<const char*>(buffer));
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
-
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
- {
- ptr.get()->on_immediate_completion(0, 0);
- ptr.release();
- return;
- }
-
- // Send the data.
- DWORD bytes_transferred = 0;
- int result = ::WSASend(impl.socket_, bufs, i,
- &bytes_transferred, flags, ptr.get(), 0);
- DWORD last_error = ::WSAGetLastError();
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
- // Check if the operation completed immediately.
- if (result != 0 && last_error != WSA_IO_PENDING)
- {
- ptr.get()->on_immediate_completion(last_error, bytes_transferred);
- ptr.release();
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ start_send_op(impl, bufs.buffers(), bufs.count(), flags,
+ impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get());
+ ptr.release();
}
- template <typename Handler>
- class null_buffers_operation
- {
- public:
- null_buffers_operation(boost::asio::io_service& io_service, Handler handler)
- : work_(io_service),
- handler_(handler)
- {
- }
-
- bool perform(boost::system::error_code&,
- std::size_t& bytes_transferred)
- {
- bytes_transferred = 0;
- return true;
- }
-
- void complete(const boost::system::error_code& ec,
- std::size_t bytes_transferred)
- {
- work_.get_io_service().post(bind_handler(
- handler_, ec, bytes_transferred));
- }
-
- private:
- boost::asio::io_service::work work_;
- Handler handler_;
- };
-
// Start an asynchronous wait until data can be sent without blocking.
template <typename Handler>
void async_send(implementation_type& impl, const null_buffers&,
socket_base::message_flags, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- // Check if the reactor was already obtained from the io_service.
- reactor_type* reactor = static_cast<reactor_type*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (!reactor)
- {
- reactor = &(boost::asio::use_service<reactor_type>(
- this->get_io_service()));
- interlocked_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), reactor);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
- reactor->start_write_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
+ start_reactor_op(impl, reactor::write_op, ptr.get());
+ ptr.release();
}
// Send a datagram to the specified endpoint. Returns the number of bytes
@@ -959,23 +816,14 @@ public:
return 0;
}
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = const_cast<char*>(
- boost::asio::buffer_cast<const char*>(buffer));
- }
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
// Send the data.
DWORD bytes_transferred = 0;
- int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred,
- flags, destination.data(), static_cast<int>(destination.size()), 0, 0);
+ int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(),
+ &bytes_transferred, flags, destination.data(),
+ static_cast<int>(destination.size()), 0, 0);
if (result != 0)
{
DWORD last_error = ::WSAGetLastError();
@@ -1008,85 +856,57 @@ public:
}
template <typename ConstBufferSequence, typename Handler>
- class send_to_operation
- : public operation
+ class send_to_op : public operation
{
public:
- send_to_operation(win_iocp_io_service& io_service,
+ send_to_op(weak_cancel_token_type cancel_token,
const ConstBufferSequence& buffers, Handler handler)
- : operation(io_service,
- &send_to_operation<ConstBufferSequence, Handler>::do_completion_impl,
- &send_to_operation<ConstBufferSequence, Handler>::destroy_impl),
- work_(io_service.get_io_service()),
+ : operation(&send_to_op::do_complete),
+ cancel_token_(cancel_token),
buffers_(buffers),
handler_(handler)
{
}
- private:
- static void do_completion_impl(operation* op,
- DWORD last_error, size_t bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t bytes_transferred)
{
// Take ownership of the operation object.
- typedef send_to_operation<ConstBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ send_to_op* o(static_cast<send_to_op*>(base));
+ typedef handler_alloc_traits<Handler, send_to_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
-#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- typename ConstBufferSequence::const_iterator iter
- = handler_op->buffers_.begin();
- typename ConstBufferSequence::const_iterator end
- = handler_op->buffers_.end();
- while (iter != end)
+ // Make the upcall if required.
+ if (owner)
{
- boost::asio::const_buffer buffer(*iter);
- boost::asio::buffer_cast<const char*>(buffer);
- ++iter;
- }
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Map non-portable errors to their portable counterparts.
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Call the handler.
- boost_asio_handler_invoke_helpers::invoke(
- detail::bind_handler(handler, ec, bytes_transferred), handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef send_to_operation<ConstBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
- // Free the memory associated with the handler.
- ptr.reset();
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
- boost::asio::io_service::work work_;
+ private:
+ weak_cancel_token_type cancel_token_;
ConstBufferSequence buffers_;
Handler handler_;
};
@@ -1098,57 +918,19 @@ public:
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags, Handler handler)
{
-#if defined(BOOST_ASIO_ENABLE_CANCELIO)
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
-
// Allocate and construct an operation to wrap the handler.
- typedef send_to_operation<ConstBufferSequence, Handler> value_type;
+ typedef send_to_op<ConstBufferSequence, 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, iocp_service_, buffers, handler);
-
- if (!is_open(impl))
- {
- ptr.get()->on_immediate_completion(WSAEBADF, 0);
- ptr.release();
- return;
- }
-
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename ConstBufferSequence::const_iterator iter = buffers.begin();
- typename ConstBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::const_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = const_cast<char*>(
- boost::asio::buffer_cast<const char*>(buffer));
- }
+ handler_ptr<alloc_traits> ptr(raw_ptr,
+ impl.cancel_token_, buffers, handler);
- // Send the data.
- DWORD bytes_transferred = 0;
- int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred, flags,
- destination.data(), static_cast<int>(destination.size()), ptr.get(), 0);
- DWORD last_error = ::WSAGetLastError();
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
- // Check if the operation completed immediately.
- if (result != 0 && last_error != WSA_IO_PENDING)
- {
- ptr.get()->on_immediate_completion(last_error, bytes_transferred);
- ptr.release();
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ start_send_to_op(impl, bufs.buffers(),
+ bufs.count(), destination, flags, ptr.get());
+ ptr.release();
}
// Start an asynchronous wait until data can be sent without blocking.
@@ -1156,29 +938,14 @@ public:
void async_send_to(implementation_type& impl, const null_buffers&,
socket_base::message_flags, const endpoint_type&, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- // Check if the reactor was already obtained from the io_service.
- reactor_type* reactor = static_cast<reactor_type*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (!reactor)
- {
- reactor = &(boost::asio::use_service<reactor_type>(
- this->get_io_service()));
- interlocked_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), reactor);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
- reactor->start_write_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
+ start_reactor_op(impl, reactor::write_op, ptr.get());
+ ptr.release();
}
// Receive some data from the peer. Returns the number of bytes received.
@@ -1193,22 +960,11 @@ public:
return 0;
}
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
// A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty())
{
ec = boost::system::error_code();
return 0;
@@ -1217,8 +973,8 @@ public:
// Receive some data.
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
- int result = ::WSARecv(impl.socket_, bufs, i,
- &bytes_transferred, &recv_flags, 0, 0);
+ int result = ::WSARecv(impl.socket_, bufs.buffers(),
+ bufs.count(), &bytes_transferred, &recv_flags, 0, 0);
if (result != 0)
{
DWORD last_error = ::WSAGetLastError();
@@ -1257,106 +1013,75 @@ public:
}
template <typename MutableBufferSequence, typename Handler>
- class receive_operation
- : public operation
+ class receive_op : public operation
{
public:
- receive_operation(int protocol_type, win_iocp_io_service& io_service,
- weak_cancel_token_type cancel_token,
+ receive_op(int protocol_type, weak_cancel_token_type cancel_token,
const MutableBufferSequence& buffers, Handler handler)
- : operation(io_service,
- &receive_operation<
- MutableBufferSequence, Handler>::do_completion_impl,
- &receive_operation<
- MutableBufferSequence, Handler>::destroy_impl),
+ : operation(&receive_op::do_complete),
protocol_type_(protocol_type),
- work_(io_service.get_io_service()),
cancel_token_(cancel_token),
buffers_(buffers),
handler_(handler)
{
}
- private:
- static void do_completion_impl(operation* op,
- DWORD last_error, size_t bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t bytes_transferred)
{
// Take ownership of the operation object.
- typedef receive_operation<MutableBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ receive_op* o(static_cast<receive_op*>(base));
+ typedef handler_alloc_traits<Handler, receive_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
-#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- typename MutableBufferSequence::const_iterator iter
- = handler_op->buffers_.begin();
- typename MutableBufferSequence::const_iterator end
- = handler_op->buffers_.end();
- while (iter != end)
+ // Make the upcall if required.
+ if (owner)
{
- boost::asio::mutable_buffer buffer(*iter);
- boost::asio::buffer_cast<char*>(buffer);
- ++iter;
- }
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Map non-portable errors to their portable counterparts.
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (handler_op->cancel_token_.expired())
- ec = boost::asio::error::operation_aborted;
- else
- ec = boost::asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
-
- // Check for connection closed.
- else if (!ec && bytes_transferred == 0
- && handler_op->protocol_type_ == SOCK_STREAM
- && !boost::is_same<MutableBufferSequence, null_buffers>::value)
- {
- ec = boost::asio::error::eof;
- }
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Call the handler.
- boost_asio_handler_invoke_helpers::invoke(
- detail::bind_handler(handler, ec, bytes_transferred), handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef receive_operation<MutableBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (o->cancel_token_.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
+ // Check for connection closed.
+ else if (!ec && bytes_transferred == 0
+ && o->protocol_type_ == SOCK_STREAM
+ && !buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(o->buffers_)
+ && !boost::is_same<MutableBufferSequence, null_buffers>::value)
+ {
+ ec = boost::asio::error::eof;
+ }
- // Free the memory associated with the handler.
- ptr.reset();
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
+ private:
int protocol_type_;
- boost::asio::io_service::work work_;
weak_cancel_token_type cancel_token_;
MutableBufferSequence buffers_;
Handler handler_;
@@ -1369,67 +1094,20 @@ public:
const MutableBufferSequence& buffers,
socket_base::message_flags flags, Handler handler)
{
-#if defined(BOOST_ASIO_ENABLE_CANCELIO)
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
-
// Allocate and construct an operation to wrap the handler.
- typedef receive_operation<MutableBufferSequence, Handler> value_type;
+ typedef receive_op<MutableBufferSequence, Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
int protocol_type = impl.protocol_.type();
handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
- iocp_service_, impl.cancel_token_, buffers, handler);
-
- if (!is_open(impl))
- {
- ptr.get()->on_immediate_completion(WSAEBADF, 0);
- ptr.release();
- return;
- }
-
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- size_t total_buffer_size = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
- total_buffer_size += boost::asio::buffer_size(buffer);
- }
+ impl.cancel_token_, buffers, handler);
- // A request to receive 0 bytes on a stream socket is a no-op.
- if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
- {
- ptr.get()->on_immediate_completion(0, 0);
- ptr.release();
- return;
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
- // Receive some data.
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int result = ::WSARecv(impl.socket_, bufs, i,
- &bytes_transferred, &recv_flags, ptr.get(), 0);
- DWORD last_error = ::WSAGetLastError();
- if (result != 0 && last_error != WSA_IO_PENDING)
- {
- ptr.get()->on_immediate_completion(last_error, bytes_transferred);
- ptr.release();
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ start_receive_op(impl, bufs.buffers(), bufs.count(), flags,
+ protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get());
+ ptr.release();
}
// Wait until data can be received without blocking.
@@ -1437,75 +1115,36 @@ public:
void async_receive(implementation_type& impl, const null_buffers& buffers,
socket_base::message_flags flags, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else if (impl.protocol_.type() == SOCK_STREAM)
+ if (impl.protocol_.type() == SOCK_STREAM)
{
// For stream sockets on Windows, we may issue a 0-byte overlapped
// WSARecv to wait until there is data available on the socket.
-#if defined(BOOST_ASIO_ENABLE_CANCELIO)
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
-
// Allocate and construct an operation to wrap the handler.
- typedef receive_operation<null_buffers, Handler> value_type;
+ typedef receive_op<null_buffers, Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
int protocol_type = impl.protocol_.type();
handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
- iocp_service_, impl.cancel_token_, buffers, handler);
+ impl.cancel_token_, buffers, handler);
- // Issue a receive operation with an empty buffer.
::WSABUF buf = { 0, 0 };
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int result = ::WSARecv(impl.socket_, &buf, 1,
- &bytes_transferred, &recv_flags, ptr.get(), 0);
- DWORD last_error = ::WSAGetLastError();
- if (result != 0 && last_error != WSA_IO_PENDING)
- {
- ptr.get()->on_immediate_completion(last_error, bytes_transferred);
- ptr.release();
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ start_receive_op(impl, &buf, 1, flags, false, ptr.get());
+ ptr.release();
}
else
{
- // Check if the reactor was already obtained from the io_service.
- reactor_type* reactor = static_cast<reactor_type*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (!reactor)
- {
- reactor = &(boost::asio::use_service<reactor_type>(
- this->get_io_service()));
- interlocked_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), reactor);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
- if (flags & socket_base::message_out_of_band)
- {
- reactor->start_except_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler));
- }
- else
- {
- reactor->start_read_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
+ start_reactor_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ ptr.get());
+ ptr.release();
}
}
@@ -1523,24 +1162,16 @@ public:
return 0;
}
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
// Receive some data.
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
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);
+ int result = ::WSARecvFrom(impl.socket_, bufs.buffers(),
+ bufs.count(), &bytes_transferred, &recv_flags,
+ sender_endpoint.data(), &endpoint_size, 0, 0);
if (result != 0)
{
DWORD last_error = ::WSAGetLastError();
@@ -1583,22 +1214,15 @@ public:
}
template <typename MutableBufferSequence, typename Handler>
- class receive_from_operation
- : public operation
+ class receive_from_op : public operation
{
public:
- receive_from_operation(int protocol_type, win_iocp_io_service& io_service,
- endpoint_type& endpoint, const MutableBufferSequence& buffers,
- Handler handler)
- : operation(io_service,
- &receive_from_operation<
- MutableBufferSequence, Handler>::do_completion_impl,
- &receive_from_operation<
- MutableBufferSequence, Handler>::destroy_impl),
+ receive_from_op(int protocol_type, endpoint_type& endpoint,
+ const MutableBufferSequence& buffers, Handler handler)
+ : operation(&receive_from_op::do_complete),
protocol_type_(protocol_type),
endpoint_(endpoint),
endpoint_size_(static_cast<int>(endpoint.capacity())),
- work_(io_service.get_io_service()),
buffers_(buffers),
handler_(handler)
{
@@ -1609,83 +1233,51 @@ public:
return endpoint_size_;
}
- private:
- static void do_completion_impl(operation* op,
- DWORD last_error, size_t bytes_transferred)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t bytes_transferred)
{
// Take ownership of the operation object.
- typedef receive_from_operation<MutableBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ receive_from_op* o(static_cast<receive_from_op*>(base));
+ typedef handler_alloc_traits<Handler, receive_from_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
-#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Check whether buffers are still valid.
- typename MutableBufferSequence::const_iterator iter
- = handler_op->buffers_.begin();
- typename MutableBufferSequence::const_iterator end
- = handler_op->buffers_.end();
- while (iter != end)
+ // Make the upcall if required.
+ if (owner)
{
- boost::asio::mutable_buffer buffer(*iter);
- boost::asio::buffer_cast<char*>(buffer);
- ++iter;
- }
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
- // Map non-portable errors to their portable counterparts.
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
- // Check for connection closed.
- if (!ec && bytes_transferred == 0
- && handler_op->protocol_type_ == SOCK_STREAM)
- {
- ec = boost::asio::error::eof;
+ // Record the size of the endpoint returned by the operation.
+ o->endpoint_.resize(o->endpoint_size_);
+
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder2<Handler, boost::system::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
}
-
- // Record the size of the endpoint returned by the operation.
- handler_op->endpoint_.resize(handler_op->endpoint_size_);
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Call the handler.
- boost_asio_handler_invoke_helpers::invoke(
- detail::bind_handler(handler, ec, bytes_transferred), handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef receive_from_operation<MutableBufferSequence, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
}
+ private:
int protocol_type_;
endpoint_type& endpoint_;
int endpoint_size_;
- boost::asio::io_service::work work_;
+ weak_cancel_token_type cancel_token_;
MutableBufferSequence buffers_;
Handler handler_;
};
@@ -1698,58 +1290,20 @@ public:
const MutableBufferSequence& buffers, endpoint_type& sender_endp,
socket_base::message_flags flags, Handler handler)
{
-#if defined(BOOST_ASIO_ENABLE_CANCELIO)
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
-
// Allocate and construct an operation to wrap the handler.
- typedef receive_from_operation<MutableBufferSequence, Handler> value_type;
+ typedef receive_from_op<MutableBufferSequence, Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
int protocol_type = impl.protocol_.type();
- handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
- iocp_service_, sender_endp, buffers, handler);
-
- if (!is_open(impl))
- {
- ptr.get()->on_immediate_completion(WSAEBADF, 0);
- ptr.release();
- return;
- }
+ handler_ptr<alloc_traits> ptr(raw_ptr,
+ protocol_type, sender_endp, buffers, handler);
- // Copy buffers into WSABUF array.
- ::WSABUF bufs[max_buffers];
- typename MutableBufferSequence::const_iterator iter = buffers.begin();
- typename MutableBufferSequence::const_iterator end = buffers.end();
- DWORD i = 0;
- for (; iter != end && i < max_buffers; ++iter, ++i)
- {
- boost::asio::mutable_buffer buffer(*iter);
- bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
- bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
- }
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
- // Receive some data.
- DWORD bytes_transferred = 0;
- DWORD recv_flags = flags;
- int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred,
- &recv_flags, sender_endp.data(), &ptr.get()->endpoint_size(),
- ptr.get(), 0);
- DWORD last_error = ::WSAGetLastError();
- if (result != 0 && last_error != WSA_IO_PENDING)
- {
- ptr.get()->on_immediate_completion(last_error, bytes_transferred);
- ptr.release();
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ start_receive_from_op(impl, bufs.buffers(), bufs.count(),
+ sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get());
+ ptr.release();
}
// Wait until data can be received without blocking.
@@ -1758,40 +1312,20 @@ public:
const null_buffers&, endpoint_type& sender_endpoint,
socket_base::message_flags flags, Handler handler)
{
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor, 0));
- }
- else
- {
- // Check if the reactor was already obtained from the io_service.
- reactor_type* reactor = static_cast<reactor_type*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (!reactor)
- {
- reactor = &(boost::asio::use_service<reactor_type>(
- this->get_io_service()));
- interlocked_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), reactor);
- }
+ // Allocate and construct an operation to wrap the handler.
+ typedef null_buffers_op<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);
- // Reset endpoint since it can be given no sensible value at this time.
- sender_endpoint = endpoint_type();
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
- if (flags & socket_base::message_out_of_band)
- {
- reactor->start_except_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler));
- }
- else
- {
- reactor->start_read_op(impl.socket_, impl.reactor_data_,
- null_buffers_operation<Handler>(this->get_io_service(), handler),
- false);
- }
- }
+ start_reactor_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ ptr.get());
+ ptr.release();
}
// Accept a new connection.
@@ -1852,32 +1386,27 @@ public:
}
template <typename Socket, typename Handler>
- class accept_operation
- : public operation
+ class accept_op : public operation
{
public:
- accept_operation(win_iocp_io_service& io_service,
- socket_type socket, socket_type new_socket, Socket& peer,
- const protocol_type& protocol, endpoint_type* peer_endpoint,
- bool enable_connection_aborted, Handler handler)
- : operation(io_service,
- &accept_operation<Socket, Handler>::do_completion_impl,
- &accept_operation<Socket, Handler>::destroy_impl),
- io_service_(io_service),
+ accept_op(win_iocp_io_service& iocp_service, socket_type socket,
+ Socket& peer, const protocol_type& protocol,
+ endpoint_type* peer_endpoint, bool enable_connection_aborted,
+ Handler handler)
+ : operation(&accept_op::do_complete),
+ iocp_service_(iocp_service),
socket_(socket),
- new_socket_(new_socket),
peer_(peer),
protocol_(protocol),
peer_endpoint_(peer_endpoint),
- work_(io_service.get_io_service()),
enable_connection_aborted_(enable_connection_aborted),
handler_(handler)
{
}
- socket_type new_socket()
+ socket_holder& new_socket()
{
- return new_socket_.get();
+ return new_socket_;
}
void* output_buffer()
@@ -1890,166 +1419,145 @@ public:
return sizeof(sockaddr_storage_type) + 16;
}
- private:
- static void do_completion_impl(operation* op, DWORD last_error, size_t)
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code ec, std::size_t /*bytes_transferred*/)
{
- // Take ownership of the operation object.
- typedef accept_operation<Socket, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+ // Take ownership of the handler object.
+ accept_op* o(static_cast<accept_op*>(base));
+ typedef handler_alloc_traits<Handler, accept_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
- // Map Windows error ERROR_NETNAME_DELETED to connection_aborted.
- if (last_error == ERROR_NETNAME_DELETED)
+ // Make the upcall if required.
+ if (owner)
{
- last_error = WSAECONNABORTED;
- }
+ // Map Windows error ERROR_NETNAME_DELETED to connection_aborted.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ ec = boost::asio::error::connection_aborted;
+ }
- // Restart the accept operation if we got the connection_aborted error
- // and the enable_connection_aborted socket option is not set.
- if (last_error == WSAECONNABORTED
- && !ptr.get()->enable_connection_aborted_)
- {
- // Reset OVERLAPPED structure.
- ptr.get()->reset();
-
- // Create a new socket for the next connection, since the AcceptEx call
- // fails with WSAEINVAL if we try to reuse the same socket.
- boost::system::error_code ec;
- ptr.get()->new_socket_.reset();
- ptr.get()->new_socket_.reset(socket_ops::socket(
- ptr.get()->protocol_.family(), ptr.get()->protocol_.type(),
- ptr.get()->protocol_.protocol(), ec));
- if (ptr.get()->new_socket() != invalid_socket)
+ // Restart the accept operation if we got the connection_aborted error
+ // and the enable_connection_aborted socket option is not set.
+ if (ec == boost::asio::error::connection_aborted
+ && !o->enable_connection_aborted_)
{
- // Accept a connection.
- DWORD bytes_read = 0;
- BOOL result = ::AcceptEx(ptr.get()->socket_, ptr.get()->new_socket(),
- ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
- ptr.get()->address_length(), &bytes_read, ptr.get());
- last_error = ::WSAGetLastError();
-
- // Check if the operation completed immediately.
- if (!result && last_error != WSA_IO_PENDING)
+ // Reset OVERLAPPED structure.
+ o->reset();
+
+ // Create a new socket for the next connection, since the AcceptEx
+ // call fails with WSAEINVAL if we try to reuse the same socket.
+ o->new_socket_.reset();
+ o->new_socket_.reset(socket_ops::socket(o->protocol_.family(),
+ o->protocol_.type(), o->protocol_.protocol(), ec));
+ if (o->new_socket_.get() != invalid_socket)
{
- if (last_error == ERROR_NETNAME_DELETED
- || last_error == WSAECONNABORTED)
+ // Accept a connection.
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(),
+ o->output_buffer(), 0, o->address_length(),
+ o->address_length(), &bytes_read, o);
+ DWORD last_error = ::WSAGetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+
+ // Check if the operation completed immediately.
+ if (!result && last_error != WSA_IO_PENDING)
{
- // Post this handler so that operation will be restarted again.
- ptr.get()->on_immediate_completion(last_error, 0);
- ptr.release();
- return;
+ if (last_error == ERROR_NETNAME_DELETED
+ || last_error == WSAECONNABORTED)
+ {
+ // Post this handler so that operation will be restarted again.
+ o->iocp_service_.work_started();
+ o->iocp_service_.on_completion(o, ec);
+ ptr.release();
+ return;
+ }
+ else
+ {
+ // Operation already complete. Continue with rest of this
+ // handler.
+ }
}
else
{
- // Operation already complete. Continue with rest of this handler.
+ // Asynchronous operation has been successfully restarted.
+ o->iocp_service_.work_started();
+ o->iocp_service_.on_pending(o);
+ ptr.release();
+ return;
}
}
+ }
+
+ // Get the address of the peer.
+ endpoint_type peer_endpoint;
+ if (!ec)
+ {
+ LPSOCKADDR local_addr = 0;
+ int local_addr_length = 0;
+ LPSOCKADDR remote_addr = 0;
+ int remote_addr_length = 0;
+ GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(),
+ o->address_length(), &local_addr, &local_addr_length,
+ &remote_addr, &remote_addr_length);
+ if (static_cast<std::size_t>(remote_addr_length)
+ > peer_endpoint.capacity())
+ {
+ ec = boost::asio::error::invalid_argument;
+ }
else
{
- // Asynchronous operation has been successfully restarted.
- ptr.get()->on_pending();
- ptr.release();
- return;
+ using namespace std; // For memcpy.
+ memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
+ peer_endpoint.resize(static_cast<std::size_t>(remote_addr_length));
}
}
- }
- // Get the address of the peer.
- endpoint_type peer_endpoint;
- if (last_error == 0)
- {
- LPSOCKADDR local_addr = 0;
- int local_addr_length = 0;
- LPSOCKADDR remote_addr = 0;
- int remote_addr_length = 0;
- 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 (static_cast<std::size_t>(remote_addr_length)
- > peer_endpoint.capacity())
- {
- last_error = WSAEINVAL;
- }
- else
+ // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
+ // and getpeername will work on the accepted socket.
+ if (!ec)
{
- using namespace std; // For memcpy.
- memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
- peer_endpoint.resize(static_cast<std::size_t>(remote_addr_length));
+ SOCKET update_ctx_param = o->socket_;
+ socket_ops::setsockopt(o->new_socket_.get(),
+ SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ &update_ctx_param, sizeof(SOCKET), ec);
}
- }
- // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
- // and getpeername will work on the accepted socket.
- if (last_error == 0)
- {
- SOCKET update_ctx_param = handler_op->socket_;
- boost::system::error_code ec;
- if (socket_ops::setsockopt(handler_op->new_socket_.get(),
- SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
- &update_ctx_param, sizeof(SOCKET), ec) != 0)
+ // If the socket was successfully accepted, transfer ownership of the
+ // socket to the peer object.
+ if (!ec)
{
- last_error = ec.value();
+ o->peer_.assign(o->protocol_,
+ native_type(o->new_socket_.get(), peer_endpoint), ec);
+ if (!ec)
+ o->new_socket_.release();
}
- }
- // If the socket was successfully accepted, transfer ownership of the
- // socket to the peer object.
- if (last_error == 0)
- {
- boost::system::error_code ec;
- handler_op->peer_.assign(handler_op->protocol_,
- native_type(handler_op->new_socket_.get(), peer_endpoint), ec);
- if (ec)
- last_error = ec.value();
- else
- handler_op->new_socket_.release();
+ // Pass endpoint back to caller.
+ if (o->peer_endpoint_)
+ *o->peer_endpoint_ = peer_endpoint;
+
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder1<Handler, boost::system::error_code>
+ handler(o->handler_, ec);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
}
-
- // Pass endpoint back to caller.
- if (handler_op->peer_endpoint_)
- *handler_op->peer_endpoint_ = peer_endpoint;
-
- // Make a copy of the handler so that the memory can be deallocated before
- // the upcall is made.
- Handler handler(handler_op->handler_);
-
- // Free the memory associated with the handler.
- ptr.reset();
-
- // Call the handler.
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- boost_asio_handler_invoke_helpers::invoke(
- detail::bind_handler(handler, ec), handler);
- }
-
- static void destroy_impl(operation* op)
- {
- // Take ownership of the operation object.
- typedef accept_operation<Socket, Handler> op_type;
- op_type* handler_op(static_cast<op_type*>(op));
- typedef handler_alloc_traits<Handler, op_type> alloc_traits;
- handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
-
- // A sub-object of the handler may be the true owner of the memory
- // associated with the handler. Consequently, a local copy of the handler
- // is required to ensure that any owning sub-object remains valid until
- // after we have deallocated the memory here.
- Handler handler(handler_op->handler_);
- (void)handler;
-
- // Free the memory associated with the handler.
- ptr.reset();
}
- win_iocp_io_service& io_service_;
+ private:
+ win_iocp_io_service& iocp_service_;
socket_type socket_;
socket_holder new_socket_;
Socket& peer_;
protocol_type protocol_;
endpoint_type* peer_endpoint_;
- boost::asio::io_service::work work_;
unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
bool enable_connection_aborted_;
Handler handler_;
@@ -2061,86 +1569,18 @@ public:
void async_accept(implementation_type& impl, Socket& peer,
endpoint_type* peer_endpoint, Handler handler)
{
- // Check whether acceptor has been initialised.
- if (!is_open(impl))
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor));
- return;
- }
-
- // Check that peer socket has not already been opened.
- if (peer.is_open())
- {
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::already_open));
- return;
- }
-
-#if defined(BOOST_ASIO_ENABLE_CANCELIO)
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
-
- // Create a new socket for the connection.
- boost::system::error_code ec;
- socket_holder sock(socket_ops::socket(impl.protocol_.family(),
- impl.protocol_.type(), impl.protocol_.protocol(), ec));
- if (sock.get() == invalid_socket)
- {
- this->get_io_service().post(bind_handler(handler, ec));
- return;
- }
-
// Allocate and construct an operation to wrap the handler.
- typedef accept_operation<Socket, Handler> value_type;
+ typedef accept_op<Socket, Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
- socket_type new_socket = sock.get();
bool enable_connection_aborted =
(impl.flags_ & implementation_type::enable_connection_aborted);
- handler_ptr<alloc_traits> ptr(raw_ptr,
- iocp_service_, impl.socket_, new_socket, peer, impl.protocol_,
- peer_endpoint, enable_connection_aborted, handler);
- sock.release();
-
- // Accept a connection.
- DWORD bytes_read = 0;
- BOOL result = ::AcceptEx(impl.socket_, ptr.get()->new_socket(),
- ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
- ptr.get()->address_length(), &bytes_read, ptr.get());
- DWORD last_error = ::WSAGetLastError();
-
- // Check if the operation completed immediately.
- if (!result && last_error != WSA_IO_PENDING)
- {
- if (!enable_connection_aborted
- && (last_error == ERROR_NETNAME_DELETED
- || last_error == WSAECONNABORTED))
- {
- // Post handler so that operation will be restarted again. We do not
- // perform the AcceptEx again here to avoid the possibility of starving
- // other handlers.
- ptr.get()->on_immediate_completion(last_error, 0);
- ptr.release();
- }
- else
- {
- boost::asio::io_service::work work(this->get_io_service());
- ptr.reset();
- boost::system::error_code ec(last_error,
- boost::asio::error::get_system_category());
- iocp_service_.post(bind_handler(handler, ec));
- }
- }
- else
- {
- ptr.get()->on_pending();
- ptr.release();
- }
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, impl.socket_, peer,
+ impl.protocol_, peer_endpoint, enable_connection_aborted, handler);
+
+ start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(),
+ ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get());
+ ptr.release();
}
// Connect the socket to the specified endpoint.
@@ -2159,67 +1599,76 @@ public:
return ec;
}
- template <typename Handler>
- class connect_operation
+ class connect_op_base : public reactor_op
{
public:
- connect_operation(socket_type socket, bool user_set_non_blocking,
- boost::asio::io_service& io_service, Handler handler)
- : socket_(socket),
- user_set_non_blocking_(user_set_non_blocking),
- io_service_(io_service),
- work_(io_service),
- handler_(handler)
+ connect_op_base(socket_type socket, func_type complete_func)
+ : reactor_op(&connect_op_base::do_perform, complete_func),
+ socket_(socket)
{
}
- bool perform(boost::system::error_code& ec,
- std::size_t& bytes_transferred)
+ static bool do_perform(reactor_op* base)
{
- bytes_transferred = 0;
-
- // Check whether the operation was successful.
- if (ec)
- return true;
+ connect_op_base* o(static_cast<connect_op_base*>(base));
// Get the error code from the connect operation.
int connect_error = 0;
size_t connect_error_len = sizeof(connect_error);
- if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
- &connect_error, &connect_error_len, ec) == socket_error_retval)
+ if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, o->ec_) == socket_error_retval)
return true;
- // If connection failed then post the handler with the error code.
+ // The connection failed so the handler will be posted with an error code.
if (connect_error)
{
- ec = boost::system::error_code(connect_error,
+ o->ec_ = boost::system::error_code(connect_error,
boost::asio::error::get_system_category());
- return true;
}
- // Revert socket to blocking mode unless the user requested otherwise.
- if (!user_set_non_blocking_)
- {
- ioctl_arg_type non_blocking = 0;
- if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec))
- return true;
- }
-
- // Post the result of the successful connection operation.
- ec = boost::system::error_code();
return true;
}
- void complete(const boost::system::error_code& ec, std::size_t)
+ private:
+ socket_type socket_;
+ };
+
+ template <typename Handler>
+ class connect_op : public connect_op_base
+ {
+ public:
+ connect_op(socket_type socket, Handler handler)
+ : connect_op_base(socket, &connect_op::do_complete),
+ handler_(handler)
{
- io_service_.post(bind_handler(handler_, ec));
+ }
+
+ static void do_complete(io_service_impl* owner, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ connect_op* o(static_cast<connect_op*>(base));
+ typedef handler_alloc_traits<Handler, connect_op> alloc_traits;
+ handler_ptr<alloc_traits> ptr(o->handler_, o);
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ // Make a copy of the handler so that the memory can be deallocated
+ // before the upcall is made. Even if we're not about to make an
+ // upcall, a sub-object of the handler may be the true owner of the
+ // memory associated with the handler. Consequently, a local copy of
+ // the handler is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ detail::binder1<Handler, boost::system::error_code>
+ handler(o->handler_, o->ec_);
+ ptr.reset();
+ boost::asio::detail::fenced_block b;
+ boost_asio_handler_invoke_helpers::invoke(handler, handler);
+ }
}
private:
- socket_type socket_;
- bool user_set_non_blocking_;
- boost::asio::io_service& io_service_;
- boost::asio::io_service::work work_;
Handler handler_;
};
@@ -2228,86 +1677,216 @@ public:
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, Handler handler)
{
+ // Allocate and construct an operation to wrap the handler.
+ typedef connect_op<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, impl.socket_, handler);
+
+ start_connect_op(impl, ptr.get(), peer_endpoint);
+ ptr.release();
+ }
+
+private:
+ // Helper function to start an asynchronous send operation.
+ void start_send_op(implementation_type& impl, WSABUF* buffers,
+ std::size_t buffer_count, socket_base::message_flags flags,
+ bool noop, operation* op)
+ {
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (noop)
+ iocp_service_.on_completion(op);
+ else if (!is_open(impl))
+ iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ int result = ::WSASend(impl.socket_, buffers,
+ buffer_count, &bytes_transferred, flags, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+ }
+
+ // Helper function to start an asynchronous send_to operation.
+ void start_send_to_op(implementation_type& impl, WSABUF* buffers,
+ std::size_t buffer_count, const endpoint_type& destination,
+ socket_base::message_flags flags, operation* op)
+ {
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
if (!is_open(impl))
+ iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
+ else
{
- this->get_io_service().post(bind_handler(handler,
- boost::asio::error::bad_descriptor));
- return;
+ DWORD bytes_transferred = 0;
+ int result = ::WSASendTo(impl.socket_, buffers, buffer_count,
+ &bytes_transferred, flags, destination.data(),
+ static_cast<int>(destination.size()), op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
}
+ }
-#if defined(BOOST_ASIO_ENABLE_CANCELIO)
- // Update the ID of the thread from which cancellation is safe.
- if (impl.safe_cancellation_thread_id_ == 0)
- impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
- else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
- impl.safe_cancellation_thread_id_ = ~DWORD(0);
-#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Helper function to start an asynchronous receive operation.
+ void start_receive_op(implementation_type& impl, WSABUF* buffers,
+ std::size_t buffer_count, socket_base::message_flags flags,
+ bool noop, operation* op)
+ {
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
- // Check if the reactor was already obtained from the io_service.
- reactor_type* reactor = static_cast<reactor_type*>(
- interlocked_compare_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), 0, 0));
- if (!reactor)
+ if (noop)
+ iocp_service_.on_completion(op);
+ else if (!is_open(impl))
+ iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
+ else
{
- reactor = &(boost::asio::use_service<reactor_type>(
- this->get_io_service()));
- interlocked_exchange_pointer(
- reinterpret_cast<void**>(&reactor_), reactor);
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, buffers, buffer_count,
+ &bytes_transferred, &recv_flags, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_NETNAME_DELETED)
+ last_error = WSAECONNRESET;
+ else if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
}
+ }
- // Mark the socket as non-blocking so that the connection will take place
- // asynchronously.
- ioctl_arg_type non_blocking = 1;
- boost::system::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ // Helper function to start an asynchronous receive_from operation.
+ void start_receive_from_op(implementation_type& impl, WSABUF* buffers,
+ std::size_t buffer_count, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, int* endpoint_size, operation* op)
+ {
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
+ else
{
- this->get_io_service().post(bind_handler(handler, ec));
- return;
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecvFrom(impl.socket_, buffers,
+ buffer_count, &bytes_transferred, &recv_flags,
+ sender_endpoint.data(), endpoint_size, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
}
+ }
- // Start the connect operation.
- if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
- peer_endpoint.size(), ec) == 0)
+ // Helper function to start an asynchronous receive_from operation.
+ void start_accept_op(implementation_type& impl,
+ bool peer_is_open, socket_holder& new_socket,
+ void* output_buffer, DWORD address_length, operation* op)
+ {
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
+ else if (peer_is_open)
+ iocp_service_.on_completion(op, boost::asio::error::already_open);
+ else
{
- // Revert socket to blocking mode unless the user requested otherwise.
- if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ boost::system::error_code ec;
+ new_socket.reset(socket_ops::socket(impl.protocol_.family(),
+ impl.protocol_.type(), impl.protocol_.protocol(), ec));
+ if (new_socket.get() == invalid_socket)
+ iocp_service_.on_completion(op, ec);
+ else
{
- non_blocking = 0;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
+ 0, address_length, address_length, &bytes_read, op);
+ DWORD last_error = ::WSAGetLastError();
+ if (!result && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error);
+ else
+ iocp_service_.on_pending(op);
}
-
- // The connect operation has finished successfully so we need to post the
- // handler immediately.
- this->get_io_service().post(bind_handler(handler, ec));
}
- else if (ec == boost::asio::error::in_progress
- || ec == boost::asio::error::would_block)
+ }
+
+ // Start an asynchronous read or write operation using the the reactor.
+ void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op)
+ {
+ reactor& r = get_reactor();
+ update_cancellation_thread_id(impl);
+
+ if (is_open(impl))
{
- // The connection is happening in the background, and we need to wait
- // until the socket becomes writeable.
- boost::shared_ptr<bool> completed(new bool(false));
- reactor->start_connect_op(impl.socket_, impl.reactor_data_,
- connect_operation<Handler>(
- impl.socket_,
- (impl.flags_ & implementation_type::user_set_non_blocking) != 0,
- this->get_io_service(), handler));
+ r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false);
+ return;
}
else
+ op->ec_ = boost::asio::error::bad_descriptor;
+
+ iocp_service_.post_immediate_completion(op);
+ }
+
+ // Start the asynchronous connect operation using the reactor.
+ void start_connect_op(implementation_type& impl,
+ reactor_op* op, const endpoint_type& peer_endpoint)
+ {
+ reactor& r = get_reactor();
+ update_cancellation_thread_id(impl);
+
+ if (is_open(impl))
{
- // Revert socket to blocking mode unless the user requested otherwise.
- if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ ioctl_arg_type non_blocking = 1;
+ if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_))
{
- non_blocking = 0;
- boost::system::error_code ignored_ec;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
- }
+ if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
+ peer_endpoint.size(), op->ec_) != 0)
+ {
+ if (!op->ec_
+ && !(impl.flags_ & implementation_type::user_set_non_blocking))
+ {
+ non_blocking = 0;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_);
+ }
- // The connect operation has failed, so post the handler immediately.
- this->get_io_service().post(bind_handler(handler, ec));
+ if (op->ec_ == boost::asio::error::in_progress
+ || op->ec_ == boost::asio::error::would_block)
+ {
+ op->ec_ = boost::system::error_code();
+ r.start_op(reactor::connect_op, impl.socket_,
+ impl.reactor_data_, op, true);
+ return;
+ }
+ }
+ }
}
+ else
+ op->ec_ = boost::asio::error::bad_descriptor;
+
+ iocp_service_.post_immediate_completion(op);
}
-private:
// Helper function to close a socket when the associated object is being
// destroyed.
void close_for_destruction(implementation_type& impl)
@@ -2317,11 +1896,11 @@ private:
// Check if the reactor was created, in which case we need to close the
// socket on the reactor as well to cancel any operations that might be
// running there.
- reactor_type* reactor = static_cast<reactor_type*>(
+ reactor* r = static_cast<reactor*>(
interlocked_compare_exchange_pointer(
reinterpret_cast<void**>(&reactor_), 0, 0));
- if (reactor)
- reactor->close_descriptor(impl.socket_, impl.reactor_data_);
+ if (r)
+ r->close_descriptor(impl.socket_, impl.reactor_data_);
// The socket destructor must not block. If the user has changed the
// linger option to block in the foreground, we will change it back to the
@@ -2347,6 +1926,35 @@ private:
}
}
+ // Update the ID of the thread from which cancellation is safe.
+ void update_cancellation_thread_id(implementation_type& impl)
+ {
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#else // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ (void)impl;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ }
+
+ // Helper function to get the reactor. If no reactor has been created yet, a
+ // new one is obtained from the io_service and a pointer to it is cached in
+ // this service.
+ reactor& get_reactor()
+ {
+ reactor* r = static_cast<reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!r)
+ {
+ r = &(use_service<reactor>(io_service_));
+ interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
+ }
+ return *r;
+ }
+
// Helper function to emulate InterlockedCompareExchangePointer functionality
// for:
// - very old Platform SDKs; and
@@ -2375,13 +1983,16 @@ private:
#endif
}
+ // The io_service used to obtain the reactor, if required.
+ boost::asio::io_service& io_service_;
+
// The IOCP service used for running asynchronous operations and dispatching
// handlers.
win_iocp_io_service& iocp_service_;
// The reactor used for performing connect operations. This object is created
// only if needed.
- reactor_type* reactor_;
+ reactor* reactor_;
// Mutex to protect access to the linked list of implementations.
boost::asio::detail::mutex mutex_;
diff --git a/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp b/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp
index 107d707..176a5fd 100644
--- a/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp
+++ b/3rdParty/Boost/src/boost/asio/detail/win_mutex.hpp
@@ -66,15 +66,7 @@ public:
// Lock the mutex.
void lock()
{
- int error = do_lock();
- if (error != 0)
- {
- boost::system::system_error e(
- boost::system::error_code(error,
- boost::asio::error::get_system_category()),
- "mutex");
- boost::throw_exception(e);
- }
+ ::EnterCriticalSection(&crit_section_);
}
// Unlock the mutex.
@@ -92,12 +84,20 @@ private:
#if defined(__MINGW32__)
// Not sure if MinGW supports structured exception handling, so for now
// we'll just call the Windows API and hope.
+# if defined(UNDER_CE)
::InitializeCriticalSection(&crit_section_);
+# else
+ ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000);
+# endif
return 0;
#else
__try
{
+# if defined(UNDER_CE)
::InitializeCriticalSection(&crit_section_);
+# else
+ ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000);
+# endif
}
__except(GetExceptionCode() == STATUS_NO_MEMORY
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
@@ -109,34 +109,6 @@ private:
#endif
}
- // Locking must be performed in a separate function to lock() since the
- // compiler does not support the use of structured exceptions and C++
- // exceptions in the same function.
- int do_lock()
- {
-#if defined(__MINGW32__)
- // Not sure if MinGW supports structured exception handling, so for now
- // we'll just call the Windows API and hope.
- ::EnterCriticalSection(&crit_section_);
- return 0;
-#else
- __try
- {
- ::EnterCriticalSection(&crit_section_);
- }
- __except(GetExceptionCode() == STATUS_INVALID_HANDLE
- || GetExceptionCode() == STATUS_NO_MEMORY
- ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
- {
- if (GetExceptionCode() == STATUS_NO_MEMORY)
- return ERROR_OUTOFMEMORY;
- return ERROR_INVALID_HANDLE;
- }
-
- return 0;
-#endif
- }
-
::CRITICAL_SECTION crit_section_;
};