Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r74826 - in trunk/boost/asio: . detail detail/impl impl
From: chris_at_[hidden]
Date: 2011-10-08 17:58:15


Author: chris_kohlhoff
Date: 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
New Revision: 74826
URL: http://svn.boost.org/trac/boost/changeset/74826

Log:
Various performance improvements:

* Split the task_io_service's run and poll code.

* Use thread-local operation queues in single-threaded use cases (i.e. concurrency_hint is 1) to eliminate a lock/unlock pair.

* Only fence block exit when a handler is being run directly out of the io_service.

* Prefer x86 mfence-based fenced block when available.

* Use a plain ol' long for the atomic_count when all thread support is disabled.

* Allow some epoll_reactor speculative operations to be performed without holding the lock.

* Improve locality of reference by performing an epoll_reactor's I/O operation immediately before the corresponding handler is called. This also improves scalability across CPUs when multiple threads are running the io_service.

* Pass same error_code variable through to each operation's complete() function.

* Optimise creation of and access to the io_service implementation.

Text files modified:
   trunk/boost/asio/detail/atomic_count.hpp | 8
   trunk/boost/asio/detail/call_stack.hpp | 67 +++++++---
   trunk/boost/asio/detail/completion_handler.hpp | 5
   trunk/boost/asio/detail/descriptor_read_op.hpp | 5
   trunk/boost/asio/detail/descriptor_write_op.hpp | 5
   trunk/boost/asio/detail/epoll_reactor.hpp | 29 ++++
   trunk/boost/asio/detail/fenced_block.hpp | 8
   trunk/boost/asio/detail/gcc_arm_fenced_block.hpp | 12 +
   trunk/boost/asio/detail/gcc_hppa_fenced_block.hpp | 12 +
   trunk/boost/asio/detail/gcc_sync_fenced_block.hpp | 4
   trunk/boost/asio/detail/gcc_x86_fenced_block.hpp | 12 +
   trunk/boost/asio/detail/impl/epoll_reactor.ipp | 214 +++++++++++++++++++++++++++-------
   trunk/boost/asio/detail/impl/kqueue_reactor.ipp | 32 ++++
   trunk/boost/asio/detail/impl/service_registry.hpp | 18 ++
   trunk/boost/asio/detail/impl/service_registry.ipp | 6
   trunk/boost/asio/detail/impl/signal_set_service.ipp | 3
   trunk/boost/asio/detail/impl/strand_service.hpp | 2
   trunk/boost/asio/detail/impl/strand_service.ipp | 6
   trunk/boost/asio/detail/impl/task_io_service.hpp | 5
   trunk/boost/asio/detail/impl/task_io_service.ipp | 241 ++++++++++++++++++++++++++++++---------
   trunk/boost/asio/detail/impl/win_iocp_io_service.hpp | 3
   trunk/boost/asio/detail/impl/win_iocp_io_service.ipp | 6
   trunk/boost/asio/detail/kqueue_reactor.hpp | 8
   trunk/boost/asio/detail/macos_fenced_block.hpp | 12 +
   trunk/boost/asio/detail/null_fenced_block.hpp | 4
   trunk/boost/asio/detail/reactive_null_buffers_op.hpp | 5
   trunk/boost/asio/detail/reactive_socket_accept_op.hpp | 5
   trunk/boost/asio/detail/reactive_socket_connect_op.hpp | 5
   trunk/boost/asio/detail/reactive_socket_recv_op.hpp | 5
   trunk/boost/asio/detail/reactive_socket_recvfrom_op.hpp | 5
   trunk/boost/asio/detail/reactive_socket_recvmsg_op.hpp | 5
   trunk/boost/asio/detail/reactive_socket_send_op.hpp | 5
   trunk/boost/asio/detail/reactive_socket_sendto_op.hpp | 5
   trunk/boost/asio/detail/resolve_endpoint_op.hpp | 5
   trunk/boost/asio/detail/resolve_op.hpp | 5
   trunk/boost/asio/detail/service_registry.hpp | 15 +
   trunk/boost/asio/detail/signal_handler.hpp | 5
   trunk/boost/asio/detail/signal_set_service.hpp | 2
   trunk/boost/asio/detail/solaris_fenced_block.hpp | 12 +
   trunk/boost/asio/detail/strand_service.hpp | 2
   trunk/boost/asio/detail/task_io_service.hpp | 41 ++++-
   trunk/boost/asio/detail/task_io_service_operation.hpp | 13 +
   trunk/boost/asio/detail/wait_handler.hpp | 5
   trunk/boost/asio/detail/win_fenced_block.hpp | 12 +
   trunk/boost/asio/detail/win_iocp_handle_read_op.hpp | 7
   trunk/boost/asio/detail/win_iocp_handle_write_op.hpp | 4
   trunk/boost/asio/detail/win_iocp_io_service.hpp | 14 +
   trunk/boost/asio/detail/win_iocp_null_buffers_op.hpp | 7
   trunk/boost/asio/detail/win_iocp_operation.hpp | 9
   trunk/boost/asio/detail/win_iocp_overlapped_op.hpp | 4
   trunk/boost/asio/detail/win_iocp_socket_accept_op.hpp | 7
   trunk/boost/asio/detail/win_iocp_socket_recv_op.hpp | 7
   trunk/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp | 7
   trunk/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp | 7
   trunk/boost/asio/detail/win_iocp_socket_send_op.hpp | 7
   trunk/boost/asio/impl/io_service.hpp | 19 ++
   trunk/boost/asio/impl/io_service.ipp | 14 +
   trunk/boost/asio/io_service.hpp | 4
   58 files changed, 736 insertions(+), 265 deletions(-)

Modified: trunk/boost/asio/detail/atomic_count.hpp
==============================================================================
--- trunk/boost/asio/detail/atomic_count.hpp (original)
+++ trunk/boost/asio/detail/atomic_count.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -17,7 +17,9 @@
 
 #include <boost/asio/detail/config.hpp>
 
-#if defined(BOOST_ASIO_HAS_STD_ATOMIC)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
+// Nothing to include.
+#elif defined(BOOST_ASIO_HAS_STD_ATOMIC)
 # include <atomic>
 #else // defined(BOOST_ASIO_HAS_STD_ATOMIC)
 # include <boost/detail/atomic_count.hpp>
@@ -27,7 +29,9 @@
 namespace asio {
 namespace detail {
 
-#if defined(BOOST_ASIO_HAS_STD_ATOMIC)
+#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS)
+typedef long atomic_count;
+#elif defined(BOOST_ASIO_HAS_STD_ATOMIC)
 typedef std::atomic<long> atomic_count;
 #else // defined(BOOST_ASIO_HAS_STD_ATOMIC)
 typedef boost::detail::atomic_count atomic_count;

Modified: trunk/boost/asio/detail/call_stack.hpp
==============================================================================
--- trunk/boost/asio/detail/call_stack.hpp (original)
+++ trunk/boost/asio/detail/call_stack.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -27,34 +27,60 @@
 
 // Helper class to determine whether or not the current thread is inside an
 // invocation of io_service::run() for a specified io_service object.
-template <typename Owner>
+template <typename Key, typename Value = unsigned char>
 class call_stack
 {
 public:
- // Context class automatically pushes an owner on to the stack.
+ // Context class automatically pushes the key/value pair on to the stack.
   class context
     : private noncopyable
   {
   public:
- // Push the owner on to the stack.
- explicit context(Owner* d)
- : owner_(d),
- next_(call_stack<Owner>::top_)
+ // Push the key on to the stack.
+ explicit context(Key* k)
+ : key_(k),
+ next_(call_stack<Key, Value>::top_)
     {
- call_stack<Owner>::top_ = this;
+ value_ = reinterpret_cast<unsigned char*>(this);
+ call_stack<Key, Value>::top_ = this;
     }
 
- // Pop the owner from the stack.
+ // Push the key/value pair on to the stack.
+ context(Key* k, Value& v)
+ : key_(k),
+ value_(&v),
+ next_(call_stack<Key, Value>::top_)
+ {
+ call_stack<Key, Value>::top_ = this;
+ }
+
+ // Pop the key/value pair from the stack.
     ~context()
     {
- call_stack<Owner>::top_ = next_;
+ call_stack<Key, Value>::top_ = next_;
+ }
+
+ // Find the next context with the same key.
+ Value* next_by_key() const
+ {
+ context* elem = next_;
+ while (elem)
+ {
+ if (elem->key_ == key_)
+ return elem->value_;
+ elem = elem->next_;
+ }
+ return 0;
     }
 
   private:
- friend class call_stack<Owner>;
+ friend class call_stack<Key, Value>;
+
+ // The key associated with the context.
+ Key* key_;
 
- // The owner associated with the context.
- Owner* owner_;
+ // The value associated with the context.
+ Value* value_;
 
     // The next element in the stack.
     context* next_;
@@ -62,17 +88,18 @@
 
   friend class context;
 
- // Determine whether the specified owner is on the stack.
- static bool contains(Owner* d)
+ // Determine whether the specified owner is on the stack. Returns address of
+ // key if present, 0 otherwise.
+ static Value* contains(Key* k)
   {
     context* elem = top_;
     while (elem)
     {
- if (elem->owner_ == d)
- return true;
+ if (elem->key_ == k)
+ return elem->value_;
       elem = elem->next_;
     }
- return false;
+ return 0;
   }
 
 private:
@@ -80,9 +107,9 @@
   static tss_ptr<context> top_;
 };
 
-template <typename Owner>
-tss_ptr<typename call_stack<Owner>::context>
-call_stack<Owner>::top_;
+template <typename Key, typename Value>
+tss_ptr<typename call_stack<Key, Value>::context>
+call_stack<Key, Value>::top_;
 
 } // namespace detail
 } // namespace asio

Modified: trunk/boost/asio/detail/completion_handler.hpp
==============================================================================
--- trunk/boost/asio/detail/completion_handler.hpp (original)
+++ trunk/boost/asio/detail/completion_handler.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -40,7 +40,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     completion_handler* h(static_cast<completion_handler*>(base));
@@ -61,7 +62,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
       boost_asio_handler_invoke_helpers::invoke(handler, handler);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/descriptor_read_op.hpp
==============================================================================
--- trunk/boost/asio/detail/descriptor_read_op.hpp (original)
+++ trunk/boost/asio/detail/descriptor_read_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -76,7 +76,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
@@ -98,7 +99,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/descriptor_write_op.hpp
==============================================================================
--- trunk/boost/asio/detail/descriptor_write_op.hpp (original)
+++ trunk/boost/asio/detail/descriptor_write_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -76,7 +76,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
@@ -98,7 +99,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/epoll_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/epoll_reactor.hpp (original)
+++ trunk/boost/asio/detail/epoll_reactor.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -21,6 +21,7 @@
 
 #include <boost/limits.hpp>
 #include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/atomic_count.hpp>
 #include <boost/asio/detail/epoll_reactor_fwd.hpp>
 #include <boost/asio/detail/mutex.hpp>
 #include <boost/asio/detail/object_pool.hpp>
@@ -47,16 +48,28 @@
     connect_op = 1, except_op = 2, max_ops = 3 };
 
   // Per-descriptor queues.
- class descriptor_state
+ class descriptor_state : operation
   {
     friend class epoll_reactor;
     friend class object_pool_access;
+
+ descriptor_state* next_;
+ descriptor_state* prev_;
+
+ bool op_queue_is_empty_[max_ops];
+
     mutex mutex_;
+ epoll_reactor* reactor_;
     int descriptor_;
     op_queue<reactor_op> op_queue_[max_ops];
     bool shutdown_;
- descriptor_state* next_;
- descriptor_state* prev_;
+
+ BOOST_ASIO_DECL descriptor_state();
+ void set_ready_events(uint32_t events) { task_result_ = events; }
+ BOOST_ASIO_DECL operation* perform_io(uint32_t events);
+ BOOST_ASIO_DECL static void do_complete(
+ io_service_impl* owner, operation* base,
+ const boost::system::error_code& ec, std::size_t bytes_transferred);
   };
 
   // Per-descriptor data.
@@ -160,6 +173,12 @@
   // Create the timerfd file descriptor. Does not throw.
   BOOST_ASIO_DECL static int do_timerfd_create();
 
+ // Allocate a new descriptor state object.
+ BOOST_ASIO_DECL descriptor_state* allocate_descriptor_state();
+
+ // Free an existing descriptor state object.
+ BOOST_ASIO_DECL void free_descriptor_state(descriptor_state* s);
+
   // Helper function to add a new timer queue.
   BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
 
@@ -206,6 +225,10 @@
 
   // Keep track of all registered descriptors.
   object_pool<descriptor_state> registered_descriptors_;
+
+ // Helper class to do post-perform_io cleanup.
+ struct perform_io_cleanup_on_block_exit;
+ friend struct perform_io_cleanup_on_block_exit;
 };
 
 } // namespace detail

Modified: trunk/boost/asio/detail/fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/fenced_block.hpp (original)
+++ trunk/boost/asio/detail/fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -29,13 +29,13 @@
 # include <boost/asio/detail/gcc_arm_fenced_block.hpp>
 #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
 # include <boost/asio/detail/gcc_hppa_fenced_block.hpp>
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+# include <boost/asio/detail/gcc_x86_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_sync_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
@@ -58,13 +58,13 @@
 typedef gcc_arm_fenced_block fenced_block;
 #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
 typedef gcc_hppa_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+typedef gcc_x86_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_sync_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

Modified: trunk/boost/asio/detail/gcc_arm_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/gcc_arm_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/gcc_arm_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -29,8 +29,16 @@
   : private noncopyable
 {
 public:
- // Constructor.
- gcc_arm_fenced_block()
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit gcc_arm_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit gcc_arm_fenced_block(full_t)
   {
     barrier();
   }

Modified: trunk/boost/asio/detail/gcc_hppa_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/gcc_hppa_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/gcc_hppa_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -29,8 +29,16 @@
   : private noncopyable
 {
 public:
- // Constructor.
- gcc_hppa_fenced_block()
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit gcc_hppa_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit gcc_hppa_fenced_block(full_t)
   {
     barrier();
   }

Modified: trunk/boost/asio/detail/gcc_sync_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/gcc_sync_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/gcc_sync_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -32,8 +32,10 @@
   : private noncopyable
 {
 public:
+ enum half_or_full_t { half, full };
+
   // Constructor.
- gcc_sync_fenced_block()
+ explicit gcc_sync_fenced_block(half_or_full_t)
     : value_(0)
   {
     __sync_lock_test_and_set(&value_, 1);

Modified: trunk/boost/asio/detail/gcc_x86_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/gcc_x86_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/gcc_x86_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -29,8 +29,16 @@
   : private noncopyable
 {
 public:
- // Constructor.
- gcc_x86_fenced_block()
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit gcc_x86_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit gcc_x86_fenced_block(full_t)
   {
     barrier1();
   }

Modified: trunk/boost/asio/detail/impl/epoll_reactor.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/epoll_reactor.ipp (original)
+++ trunk/boost/asio/detail/impl/epoll_reactor.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -148,13 +148,19 @@
 int epoll_reactor::register_descriptor(socket_type descriptor,
     epoll_reactor::per_descriptor_data& descriptor_data)
 {
- mutex::scoped_lock lock(registered_descriptors_mutex_);
+ descriptor_data = allocate_descriptor_state();
 
- descriptor_data = registered_descriptors_.alloc();
- descriptor_data->descriptor_ = descriptor;
- descriptor_data->shutdown_ = false;
+ {
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
 
- lock.unlock();
+ descriptor_data->reactor_ = this;
+ descriptor_data->descriptor_ = descriptor;
+ descriptor_data->shutdown_ = false;
+
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->op_queue_is_empty_[i] =
+ descriptor_data->op_queue_[i].empty();
+ }
 
   epoll_event ev = { 0, { 0 } };
   ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
@@ -170,14 +176,20 @@
     int op_type, socket_type descriptor,
     epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op)
 {
- mutex::scoped_lock lock(registered_descriptors_mutex_);
+ descriptor_data = allocate_descriptor_state();
 
- descriptor_data = registered_descriptors_.alloc();
- descriptor_data->descriptor_ = descriptor;
- descriptor_data->shutdown_ = false;
- descriptor_data->op_queue_[op_type].push(op);
+ {
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
 
- lock.unlock();
+ descriptor_data->reactor_ = this;
+ descriptor_data->descriptor_ = descriptor;
+ descriptor_data->shutdown_ = false;
+ descriptor_data->op_queue_[op_type].push(op);
+
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->op_queue_is_empty_[i] =
+ descriptor_data->op_queue_[i].empty();
+ }
 
   epoll_event ev = { 0, { 0 } };
   ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
@@ -208,6 +220,22 @@
     return;
   }
 
+ bool perform_speculative = allow_speculative;
+ if (perform_speculative)
+ {
+ if (descriptor_data->op_queue_is_empty_[op_type]
+ && (op_type != read_op
+ || descriptor_data->op_queue_is_empty_[except_op]))
+ {
+ if (op->perform())
+ {
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+ perform_speculative = false;
+ }
+ }
+
   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
 
   if (descriptor_data->shutdown_)
@@ -216,17 +244,24 @@
     return;
   }
 
- if (descriptor_data->op_queue_[op_type].empty())
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->op_queue_is_empty_[i] =
+ descriptor_data->op_queue_[i].empty();
+
+ if (descriptor_data->op_queue_is_empty_[op_type])
   {
- if (allow_speculative
- && (op_type != read_op
- || descriptor_data->op_queue_[except_op].empty()))
+ if (allow_speculative)
     {
- if (op->perform())
+ if (perform_speculative
+ && (op_type != read_op
+ || descriptor_data->op_queue_is_empty_[except_op]))
       {
- descriptor_lock.unlock();
- io_service_.post_immediate_completion(op);
- return;
+ if (op->perform())
+ {
+ descriptor_lock.unlock();
+ io_service_.post_immediate_completion(op);
+ return;
+ }
       }
     }
     else
@@ -240,6 +275,7 @@
   }
 
   descriptor_data->op_queue_[op_type].push(op);
+ descriptor_data->op_queue_is_empty_[op_type] = false;
   io_service_.work_started();
 }
 
@@ -274,7 +310,6 @@
     return;
 
   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
 
   if (!descriptor_data->shutdown_)
   {
@@ -305,11 +340,9 @@
 
     descriptor_lock.unlock();
 
- registered_descriptors_.free(descriptor_data);
+ free_descriptor_state(descriptor_data);
     descriptor_data = 0;
 
- descriptors_lock.unlock();
-
     io_service_.post_deferred_completions(ops);
   }
 }
@@ -321,7 +354,6 @@
     return;
 
   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
- mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
 
   if (!descriptor_data->shutdown_)
   {
@@ -337,15 +369,19 @@
 
     descriptor_lock.unlock();
 
- registered_descriptors_.free(descriptor_data);
+ free_descriptor_state(descriptor_data);
     descriptor_data = 0;
-
- descriptors_lock.unlock();
   }
 }
 
 void epoll_reactor::run(bool block, op_queue<operation>& ops)
 {
+ // This code relies on the fact that the task_io_service queues the reactor
+ // task behind all descriptor operations generated by this function. This
+ // means, that by the time we reach this point, any previously returned
+ // descriptor operations have already been dequeued. Therefore it is now safe
+ // for us to reuse and return them for the task_io_service to queue again.
+
   // Calculate a timeout only if timerfd is not used.
   int timeout;
   if (timer_fd_ != -1)
@@ -392,28 +428,12 @@
 #endif // defined(BOOST_ASIO_HAS_TIMERFD)
     else
     {
+ // The descriptor operation doesn't count as work in and of itself, so we
+ // don't call work_started() here. This still allows the io_service to
+ // stop if the only remaining operations are descriptor operations.
       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 flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
- for (int j = max_ops - 1; j >= 0; --j)
- {
- if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP))
- {
- while (reactor_op* op = descriptor_data->op_queue_[j].front())
- {
- if (op->perform())
- {
- descriptor_data->op_queue_[j].pop();
- ops.push(op);
- }
- else
- break;
- }
- }
- }
+ descriptor_data->set_ready_events(events[i].events);
+ ops.push(descriptor_data);
     }
   }
 
@@ -491,6 +511,18 @@
 #endif // defined(BOOST_ASIO_HAS_TIMERFD)
 }
 
+epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state()
+{
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ return registered_descriptors_.alloc();
+}
+
+void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s)
+{
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ registered_descriptors_.free(s);
+}
+
 void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)
 {
   mutex::scoped_lock lock(mutex_);
@@ -539,6 +571,92 @@
 }
 #endif // defined(BOOST_ASIO_HAS_TIMERFD)
 
+struct epoll_reactor::perform_io_cleanup_on_block_exit
+{
+ explicit perform_io_cleanup_on_block_exit(epoll_reactor* r)
+ : reactor_(r), first_op_(0)
+ {
+ }
+
+ ~perform_io_cleanup_on_block_exit()
+ {
+ if (first_op_)
+ {
+ // Post the remaining completed operations for invocation.
+ if (!ops_.empty())
+ reactor_->io_service_.post_deferred_completions(ops_);
+
+ // A user-initiated operation has completed, but there's no need to
+ // explicitly call work_finished() here. Instead, we'll take advantage of
+ // the fact that the task_io_service will call work_finished() once we
+ // return.
+ }
+ else
+ {
+ // No user-initiated operations have completed, so we need to compensate
+ // for the work_finished() call that the task_io_service will make once
+ // this operation returns.
+ reactor_->io_service_.work_started();
+ }
+ }
+
+ epoll_reactor* reactor_;
+ op_queue<operation> ops_;
+ operation* first_op_;
+};
+
+epoll_reactor::descriptor_state::descriptor_state()
+ : operation(&epoll_reactor::descriptor_state::do_complete)
+{
+}
+
+operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
+{
+ perform_io_cleanup_on_block_exit io_cleanup(reactor_);
+ mutex::scoped_lock descriptor_lock(mutex_);
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
+ for (int j = max_ops - 1; j >= 0; --j)
+ {
+ if (events & (flag[j] | EPOLLERR | EPOLLHUP))
+ {
+ while (reactor_op* op = op_queue_[j].front())
+ {
+ if (op->perform())
+ {
+ op_queue_[j].pop();
+ io_cleanup.ops_.push(op);
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ // The first operation will be returned for completion now. The others will
+ // be posted for later by the io_cleanup object's destructor.
+ io_cleanup.first_op_ = io_cleanup.ops_.front();
+ io_cleanup.ops_.pop();
+ return io_cleanup.first_op_;
+}
+
+void epoll_reactor::descriptor_state::do_complete(
+ io_service_impl* owner, operation* base,
+ const boost::system::error_code& ec, std::size_t bytes_transferred)
+{
+ if (owner)
+ {
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(base);
+ uint32_t events = static_cast<uint32_t>(bytes_transferred);
+ if (operation* op = descriptor_data->perform_io(events))
+ {
+ op->complete(*owner, ec, 0);
+ }
+ }
+}
+
 } // namespace detail
 } // namespace asio
 } // namespace boost

Modified: trunk/boost/asio/detail/impl/kqueue_reactor.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/kqueue_reactor.ipp (original)
+++ trunk/boost/asio/detail/impl/kqueue_reactor.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -132,6 +132,10 @@
   descriptor_data->descriptor_ = descriptor;
   descriptor_data->shutdown_ = false;
 
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->op_queue_is_empty_[i] =
+ descriptor_data->op_queue_[i].empty();
+
   return 0;
 }
 
@@ -146,6 +150,10 @@
   descriptor_data->shutdown_ = false;
   descriptor_data->op_queue_[op_type].push(op);
 
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->op_queue_is_empty_[i] =
+ descriptor_data->op_queue_[i].empty();
+
   struct kevent event;
   switch (op_type)
   {
@@ -186,6 +194,21 @@
     return;
   }
 
+ if (allow_speculative)
+ {
+ if (descriptor_data->op_queue_is_empty_[op_type]
+ && (op_type != read_op
+ || descriptor_data->op_queue_is_empty_[except_op]))
+ {
+ if (op->perform())
+ {
+ io_service_.post_immediate_completion(op);
+ return;
+ }
+ allow_speculative = false;
+ }
+ }
+
   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
 
   if (descriptor_data->shutdown_)
@@ -194,12 +217,16 @@
     return;
   }
 
- bool first = descriptor_data->op_queue_[op_type].empty();
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->op_queue_is_empty_[i] =
+ descriptor_data->op_queue_[i].empty();
+
+ bool first = descriptor_data->op_queue_is_empty_[op_type];
   if (first)
   {
     if (allow_speculative)
     {
- if (op_type != read_op || descriptor_data->op_queue_[except_op].empty())
+ if (op_type != read_op || descriptor_data->op_queue_is_empty_[except_op])
       {
         if (op->perform())
         {
@@ -212,6 +239,7 @@
   }
 
   descriptor_data->op_queue_[op_type].push(op);
+ descriptor_data->op_queue_is_empty_[op_type] = false;
   io_service_.work_started();
 
   if (first)

Modified: trunk/boost/asio/detail/impl/service_registry.hpp
==============================================================================
--- trunk/boost/asio/detail/impl/service_registry.hpp (original)
+++ trunk/boost/asio/detail/impl/service_registry.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -21,6 +21,24 @@
 namespace asio {
 namespace detail {
 
+template <typename Service, typename Arg>
+service_registry::service_registry(
+ boost::asio::io_service& o, Service*, Arg arg)
+ : owner_(o),
+ first_service_(new Service(o, arg))
+{
+ boost::asio::io_service::service::key key;
+ init_key(key, Service::id);
+ first_service_->key_ = key;
+ first_service_->next_ = 0;
+}
+
+template <typename Service>
+Service& service_registry::first_service()
+{
+ return *static_cast<Service*>(first_service_);
+}
+
 template <typename Service>
 Service& service_registry::use_service()
 {

Modified: trunk/boost/asio/detail/impl/service_registry.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/service_registry.ipp (original)
+++ trunk/boost/asio/detail/impl/service_registry.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -26,12 +26,6 @@
 namespace asio {
 namespace detail {
 
-service_registry::service_registry(boost::asio::io_service& o)
- : owner_(o),
- first_service_(0)
-{
-}
-
 service_registry::~service_registry()
 {
   // Shutdown all services. This must be done in a separate loop before the

Modified: trunk/boost/asio/detail/impl/signal_set_service.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/signal_set_service.ipp (original)
+++ trunk/boost/asio/detail/impl/signal_set_service.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -98,7 +98,8 @@
   }
 
   static void do_complete(io_service_impl* /*owner*/, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     pipe_read_op* o(static_cast<pipe_read_op*>(base));
     delete o;

Modified: trunk/boost/asio/detail/impl/strand_service.hpp
==============================================================================
--- trunk/boost/asio/detail/impl/strand_service.hpp (original)
+++ trunk/boost/asio/detail/impl/strand_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -61,7 +61,7 @@
   // 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;
+ fenced_block b(fenced_block::full);
     boost_asio_handler_invoke_helpers::invoke(handler, handler);
     return;
   }

Modified: trunk/boost/asio/detail/impl/strand_service.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/strand_service.ipp (original)
+++ trunk/boost/asio/detail/impl/strand_service.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -79,7 +79,7 @@
 {
   // 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_);
+ bool can_dispatch = io_service_.can_dispatch();
   impl->mutex_.lock();
   bool first = (++impl->count_ == 1);
   if (can_dispatch && first)
@@ -115,7 +115,7 @@
 }
 
 void strand_service::do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
 {
   if (owner)
   {
@@ -134,7 +134,7 @@
     on_do_complete_exit on_exit = { owner, impl };
     (void)on_exit;
 
- o->complete(*owner);
+ o->complete(*owner, ec, 0);
   }
 }
 

Modified: trunk/boost/asio/detail/impl/task_io_service.hpp
==============================================================================
--- trunk/boost/asio/detail/impl/task_io_service.hpp (original)
+++ trunk/boost/asio/detail/impl/task_io_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -15,7 +15,6 @@
 # pragma once
 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 
-#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>
@@ -30,9 +29,9 @@
 template <typename Handler>
 void task_io_service::dispatch(Handler handler)
 {
- if (call_stack<task_io_service>::contains(this))
+ if (thread_call_stack::contains(this))
   {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::full);
     boost_asio_handler_invoke_helpers::invoke(handler, handler);
   }
   else

Modified: trunk/boost/asio/detail/impl/task_io_service.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/task_io_service.ipp (original)
+++ trunk/boost/asio/detail/impl/task_io_service.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -20,7 +20,6 @@
 #if !defined(BOOST_ASIO_HAS_IOCP)
 
 #include <boost/limits.hpp>
-#include <boost/asio/detail/call_stack.hpp>
 #include <boost/asio/detail/event.hpp>
 #include <boost/asio/detail/reactor.hpp>
 #include <boost/asio/detail/task_io_service.hpp>
@@ -48,24 +47,37 @@
   op_queue<operation>* ops_;
 };
 
-struct task_io_service::work_finished_on_block_exit
+struct task_io_service::work_cleanup
 {
- ~work_finished_on_block_exit()
+ ~work_cleanup()
   {
     task_io_service_->work_finished();
+
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ if (!ops_->empty())
+ {
+ lock_->lock();
+ task_io_service_->op_queue_.push(*ops_);
+ }
+#endif // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
   }
 
   task_io_service* task_io_service_;
+ mutex::scoped_lock* lock_;
+ op_queue<operation>* ops_;
 };
 
-struct task_io_service::idle_thread_info
+struct task_io_service::thread_info
 {
- event wakeup_event;
- idle_thread_info* next;
+ event* wakeup_event;
+ op_queue<operation>* private_op_queue;
+ thread_info* next;
 };
 
-task_io_service::task_io_service(boost::asio::io_service& io_service)
+task_io_service::task_io_service(
+ boost::asio::io_service& io_service, std::size_t concurrency_hint)
   : boost::asio::detail::service_base<task_io_service>(io_service),
+ one_thread_(concurrency_hint == 1),
     mutex_(),
     task_(0),
     task_interrupted_(true),
@@ -77,10 +89,6 @@
   BOOST_ASIO_HANDLER_TRACKING_INIT;
 }
 
-void task_io_service::init(std::size_t /*concurrency_hint*/)
-{
-}
-
 void task_io_service::shutdown_service()
 {
   mutex::scoped_lock lock(mutex_);
@@ -120,15 +128,22 @@
     return 0;
   }
 
- call_stack<task_io_service>::context ctx(this);
-
- idle_thread_info this_idle_thread;
- this_idle_thread.next = 0;
+ thread_info this_thread;
+ event wakeup_event;
+ this_thread.wakeup_event = &wakeup_event;
+ op_queue<operation> private_op_queue;
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ this_thread.private_op_queue = one_thread_ == 1 ? &private_op_queue : 0;
+#else // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ this_thread.private_op_queue = 0;
+#endif // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ this_thread.next = 0;
+ thread_call_stack::context ctx(this, this_thread);
 
   mutex::scoped_lock lock(mutex_);
 
   std::size_t n = 0;
- for (; do_one(lock, &this_idle_thread); lock.lock())
+ for (; do_run_one(lock, this_thread, private_op_queue, ec); lock.lock())
     if (n != (std::numeric_limits<std::size_t>::max)())
       ++n;
   return n;
@@ -143,31 +158,53 @@
     return 0;
   }
 
- call_stack<task_io_service>::context ctx(this);
-
- idle_thread_info this_idle_thread;
- this_idle_thread.next = 0;
+ thread_info this_thread;
+ event wakeup_event;
+ this_thread.wakeup_event = &wakeup_event;
+ op_queue<operation> private_op_queue;
+ this_thread.private_op_queue = 0;
+ this_thread.next = 0;
+ thread_call_stack::context ctx(this, this_thread);
 
   mutex::scoped_lock lock(mutex_);
 
- return do_one(lock, &this_idle_thread);
+ return do_run_one(lock, this_thread, private_op_queue, ec);
 }
 
 std::size_t task_io_service::poll(boost::system::error_code& ec)
 {
+ ec = boost::system::error_code();
   if (outstanding_work_ == 0)
   {
     stop();
- ec = boost::system::error_code();
     return 0;
   }
 
- call_stack<task_io_service>::context ctx(this);
+ thread_info this_thread;
+ this_thread.wakeup_event = 0;
+ op_queue<operation> private_op_queue;
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ this_thread.private_op_queue = one_thread_ == 1 ? &private_op_queue : 0;
+#else // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ this_thread.private_op_queue = 0;
+#endif // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ this_thread.next = 0;
+ thread_call_stack::context ctx(this, this_thread);
 
   mutex::scoped_lock lock(mutex_);
 
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ // We want to support nested calls to poll() and poll_one(), so any handlers
+ // that are already on a thread-private queue need to be put on to the main
+ // queue now.
+ if (one_thread_)
+ if (thread_info* outer_thread_info = ctx.next_by_key())
+ if (outer_thread_info->private_op_queue)
+ op_queue_.push(*outer_thread_info->private_op_queue);
+#endif // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+
   std::size_t n = 0;
- for (; do_one(lock, 0); lock.lock())
+ for (; do_poll_one(lock, private_op_queue, ec); lock.lock())
     if (n != (std::numeric_limits<std::size_t>::max)())
       ++n;
   return n;
@@ -182,11 +219,26 @@
     return 0;
   }
 
- call_stack<task_io_service>::context ctx(this);
+ thread_info this_thread;
+ this_thread.wakeup_event = 0;
+ op_queue<operation> private_op_queue;
+ this_thread.private_op_queue = 0;
+ this_thread.next = 0;
+ thread_call_stack::context ctx(this, this_thread);
 
   mutex::scoped_lock lock(mutex_);
 
- return do_one(lock, 0);
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ // We want to support nested calls to poll() and poll_one(), so any handlers
+ // that are already on a thread-private queue need to be put on to the main
+ // queue now.
+ if (one_thread_)
+ if (thread_info* outer_thread_info = ctx.next_by_key())
+ if (outer_thread_info->private_op_queue)
+ op_queue_.push(*outer_thread_info->private_op_queue);
+#endif // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+
+ return do_poll_one(lock, private_op_queue, ec);
 }
 
 void task_io_service::stop()
@@ -215,6 +267,20 @@
 
 void task_io_service::post_deferred_completion(task_io_service::operation* op)
 {
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ if (one_thread_)
+ {
+ if (thread_info* this_thread = thread_call_stack::contains(this))
+ {
+ if (this_thread->private_op_queue)
+ {
+ this_thread->private_op_queue->push(op);
+ return;
+ }
+ }
+ }
+#endif // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+
   mutex::scoped_lock lock(mutex_);
   op_queue_.push(op);
   wake_one_thread_and_unlock(lock);
@@ -225,6 +291,20 @@
 {
   if (!ops.empty())
   {
+#if defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+ if (one_thread_)
+ {
+ if (thread_info* this_thread = thread_call_stack::contains(this))
+ {
+ if (this_thread->private_op_queue)
+ {
+ this_thread->private_op_queue->push(ops);
+ return;
+ }
+ }
+ }
+#endif // defined(BOOST_HAS_THREADS) && !defined(BOOST_ASIO_DISABLE_THREADS)
+
     mutex::scoped_lock lock(mutex_);
     op_queue_.push(ops);
     wake_one_thread_and_unlock(lock);
@@ -238,11 +318,10 @@
   ops2.push(ops);
 }
 
-std::size_t task_io_service::do_one(mutex::scoped_lock& lock,
- task_io_service::idle_thread_info* this_idle_thread)
+std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock,
+ task_io_service::thread_info& this_thread,
+ op_queue<operation>& private_op_queue, const boost::system::error_code& ec)
 {
- bool polling = !this_idle_thread;
- bool task_has_run = false;
   while (!stopped_)
   {
     if (!op_queue_.empty())
@@ -254,61 +333,103 @@
 
       if (o == &task_operation_)
       {
- task_interrupted_ = more_handlers || polling;
+ task_interrupted_ = more_handlers;
 
- // If the task has already run and we're polling then we're done.
- if (task_has_run && polling)
- {
- task_interrupted_ = true;
- op_queue_.push(&task_operation_);
- return 0;
- }
- task_has_run = true;
-
- if (!more_handlers || !wake_one_idle_thread_and_unlock(lock))
+ if (more_handlers && !one_thread_)
+ wake_one_idle_thread_and_unlock(lock);
+ else
           lock.unlock();
 
         op_queue<operation> completed_ops;
- task_cleanup c = { this, &lock, &completed_ops };
- (void)c;
+ task_cleanup on_exit = { this, &lock, &completed_ops };
+ (void)on_exit;
 
         // 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);
+ task_->run(!more_handlers, completed_ops);
       }
       else
       {
- if (more_handlers)
+ std::size_t task_result = o->task_result_;
+
+ if (more_handlers && !one_thread_)
           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 };
+ work_cleanup on_exit = { this, &lock, &private_op_queue };
         (void)on_exit;
 
- // Complete the operation. May throw an exception.
- o->complete(*this); // deletes the operation object
+ // Complete the operation. May throw an exception. Deletes the object.
+ o->complete(*this, ec, task_result);
 
         return 1;
       }
     }
- else if (this_idle_thread)
+ else
     {
       // Nothing to run right now, so just wait for work to do.
- this_idle_thread->next = first_idle_thread_;
- first_idle_thread_ = this_idle_thread;
- this_idle_thread->wakeup_event.clear(lock);
- this_idle_thread->wakeup_event.wait(lock);
+ this_thread.next = first_idle_thread_;
+ first_idle_thread_ = &this_thread;
+ this_thread.wakeup_event->clear(lock);
+ this_thread.wakeup_event->wait(lock);
     }
- else
+ }
+
+ return 0;
+}
+
+std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock,
+ op_queue<operation>& private_op_queue, const boost::system::error_code& ec)
+{
+ if (stopped_)
+ return 0;
+
+ operation* o = op_queue_.front();
+ if (o == &task_operation_)
+ {
+ op_queue_.pop();
+ lock.unlock();
+
     {
- return 0;
+ 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(false, completed_ops);
     }
+
+ o = op_queue_.front();
+ if (o == &task_operation_)
+ return 0;
   }
 
- return 0;
+ if (o == 0)
+ return 0;
+
+ op_queue_.pop();
+ bool more_handlers = (!op_queue_.empty());
+
+ std::size_t task_result = o->task_result_;
+
+ if (more_handlers && !one_thread_)
+ wake_one_thread_and_unlock(lock);
+ else
+ lock.unlock();
+
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_cleanup on_exit = { this, &lock, &private_op_queue };
+ (void)on_exit;
+
+ // Complete the operation. May throw an exception. Deletes the object.
+ o->complete(*this, ec, task_result);
+
+ return 1;
 }
 
 void task_io_service::stop_all_threads(
@@ -318,10 +439,10 @@
 
   while (first_idle_thread_)
   {
- idle_thread_info* idle_thread = first_idle_thread_;
+ 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(lock);
   }
 
   if (!task_interrupted_ && task_)
@@ -336,10 +457,10 @@
 {
   if (first_idle_thread_)
   {
- idle_thread_info* idle_thread = first_idle_thread_;
+ thread_info* idle_thread = first_idle_thread_;
     first_idle_thread_ = idle_thread->next;
     idle_thread->next = 0;
- idle_thread->wakeup_event.signal_and_unlock(lock);
+ idle_thread->wakeup_event->signal_and_unlock(lock);
     return true;
   }
   return false;

Modified: trunk/boost/asio/detail/impl/win_iocp_io_service.hpp
==============================================================================
--- trunk/boost/asio/detail/impl/win_iocp_io_service.hpp (original)
+++ trunk/boost/asio/detail/impl/win_iocp_io_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -19,7 +19,6 @@
 
 #if defined(BOOST_ASIO_HAS_IOCP)
 
-#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>
@@ -36,7 +35,7 @@
 {
   if (call_stack<win_iocp_io_service>::contains(this))
   {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::full);
     boost_asio_handler_invoke_helpers::invoke(handler, handler);
   }
   else

Modified: trunk/boost/asio/detail/impl/win_iocp_io_service.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/win_iocp_io_service.ipp (original)
+++ trunk/boost/asio/detail/impl/win_iocp_io_service.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -62,7 +62,8 @@
   win_iocp_io_service* io_service_;
 };
 
-win_iocp_io_service::win_iocp_io_service(boost::asio::io_service& io_service)
+win_iocp_io_service::win_iocp_io_service(
+ boost::asio::io_service& io_service, size_t concurrency_hint)
   : boost::asio::detail::service_base<win_iocp_io_service>(io_service),
     iocp_(),
     outstanding_work_(0),
@@ -71,10 +72,7 @@
     dispatch_required_(0)
 {
   BOOST_ASIO_HANDLER_TRACKING_INIT;
-}
 
-void win_iocp_io_service::init(size_t concurrency_hint)
-{
   iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
       static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
   if (!iocp_.handle)

Modified: trunk/boost/asio/detail/kqueue_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/kqueue_reactor.hpp (original)
+++ trunk/boost/asio/detail/kqueue_reactor.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -62,12 +62,16 @@
   {
     friend class kqueue_reactor;
     friend class object_pool_access;
+
+ descriptor_state* next_;
+ descriptor_state* prev_;
+
+ bool op_queue_is_empty_[max_ops];
+
     mutex mutex_;
     int descriptor_;
     op_queue<reactor_op> op_queue_[max_ops];
     bool shutdown_;
- descriptor_state* next_;
- descriptor_state* prev_;
   };
 
   // Per-descriptor data.

Modified: trunk/boost/asio/detail/macos_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/macos_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/macos_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -31,8 +31,16 @@
   : private noncopyable
 {
 public:
- // Constructor.
- macos_fenced_block()
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit macos_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit macos_fenced_block(full_t)
   {
     OSMemoryBarrier();
   }

Modified: trunk/boost/asio/detail/null_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/null_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/null_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -25,8 +25,10 @@
   : private noncopyable
 {
 public:
+ enum half_or_full_t { half, full };
+
   // Constructor.
- null_fenced_block()
+ explicit null_fenced_block(half_or_full_t)
   {
   }
 

Modified: trunk/boost/asio/detail/reactive_null_buffers_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_null_buffers_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_null_buffers_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -47,7 +47,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base));
@@ -69,7 +70,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/reactive_socket_accept_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_accept_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_accept_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -95,7 +95,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));
@@ -117,7 +118,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/reactive_socket_connect_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_connect_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_connect_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -64,7 +64,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_socket_connect_op* o
@@ -87,7 +88,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/reactive_socket_recv_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_recv_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_recv_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -82,7 +82,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));
@@ -104,7 +105,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/reactive_socket_recvfrom_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_recvfrom_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_recvfrom_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -91,7 +91,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_socket_recvfrom_op* o(
@@ -114,7 +115,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/reactive_socket_recvmsg_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_recvmsg_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_recvmsg_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -83,7 +83,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_socket_recvmsg_op* o(
@@ -106,7 +107,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/reactive_socket_send_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_send_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_send_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -79,7 +79,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base));
@@ -101,7 +102,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/reactive_socket_sendto_op.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_sendto_op.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_sendto_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -82,7 +82,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base));
@@ -104,7 +105,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/resolve_endpoint_op.hpp
==============================================================================
--- trunk/boost/asio/detail/resolve_endpoint_op.hpp (original)
+++ trunk/boost/asio/detail/resolve_endpoint_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -53,7 +53,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the operation object.
     resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
@@ -96,7 +97,7 @@
 
       if (owner)
       {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
         BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
         boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
         BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/resolve_op.hpp
==============================================================================
--- trunk/boost/asio/detail/resolve_op.hpp (original)
+++ trunk/boost/asio/detail/resolve_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -61,7 +61,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the operation object.
     resolve_op* o(static_cast<resolve_op*>(base));
@@ -106,7 +107,7 @@
 
       if (owner)
       {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
         BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
         boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
         BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/service_registry.hpp
==============================================================================
--- trunk/boost/asio/detail/service_registry.hpp (original)
+++ trunk/boost/asio/detail/service_registry.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -52,8 +52,10 @@
   : private noncopyable
 {
 public:
- // Constructor.
- BOOST_ASIO_DECL service_registry(boost::asio::io_service& o);
+ // Constructor. Adds the initial service.
+ template <typename Service, typename Arg>
+ service_registry(boost::asio::io_service& o,
+ Service* initial_service, Arg arg);
 
   // Destructor.
   BOOST_ASIO_DECL ~service_registry();
@@ -61,6 +63,11 @@
   // Notify all services of a fork event.
   BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event fork_ev);
 
+ // Get the first service object cast to the specified type. Called during
+ // io_service construction and so performs no locking or type checking.
+ template <typename Service>
+ Service& first_service();
+
   // Get the service object corresponding to the specified service type. Will
   // create a new service object automatically if no such object already
   // exists. Ownership of the service object is not transferred to the caller.
@@ -123,8 +130,8 @@
       const boost::asio::io_service::service::key& key,
       factory_type factory);
 
- // Add a service object. Returns false on error, in which case ownership of
- // the object is retained by the caller.
+ // Add a service object. Throws on error, in which case ownership of the
+ // object is retained by the caller.
   BOOST_ASIO_DECL void do_add_service(
       const boost::asio::io_service::service::key& key,
       boost::asio::io_service::service* new_service);

Modified: trunk/boost/asio/detail/signal_handler.hpp
==============================================================================
--- trunk/boost/asio/detail/signal_handler.hpp (original)
+++ trunk/boost/asio/detail/signal_handler.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -40,7 +40,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     signal_handler* h(static_cast<signal_handler*>(base));
@@ -62,7 +63,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/signal_set_service.hpp
==============================================================================
--- trunk/boost/asio/detail/signal_set_service.hpp (original)
+++ trunk/boost/asio/detail/signal_set_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -17,8 +17,8 @@
 
 #include <boost/asio/detail/config.hpp>
 
-#include <csignal>
 #include <cstddef>
+#include <signal.h>
 #include <boost/asio/error.hpp>
 #include <boost/asio/io_service.hpp>
 #include <boost/asio/detail/handler_alloc_helpers.hpp>

Modified: trunk/boost/asio/detail/solaris_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/solaris_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/solaris_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -31,8 +31,16 @@
   : private noncopyable
 {
 public:
- // Constructor.
- solaris_fenced_block()
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit solaris_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit solaris_fenced_block(full_t)
   {
     membar_consumer();
   }

Modified: trunk/boost/asio/detail/strand_service.hpp
==============================================================================
--- trunk/boost/asio/detail/strand_service.hpp (original)
+++ trunk/boost/asio/detail/strand_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -95,7 +95,7 @@
   BOOST_ASIO_DECL void do_post(implementation_type& impl, operation* op);
 
   BOOST_ASIO_DECL static void do_complete(io_service_impl* owner,
- operation* base, boost::system::error_code ec,
+ operation* base, const boost::system::error_code& ec,
       std::size_t bytes_transferred);
 
   // The io_service implementation used to post completions.

Modified: trunk/boost/asio/detail/task_io_service.hpp
==============================================================================
--- trunk/boost/asio/detail/task_io_service.hpp (original)
+++ trunk/boost/asio/detail/task_io_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -22,6 +22,7 @@
 #include <boost/system/error_code.hpp>
 #include <boost/asio/io_service.hpp>
 #include <boost/asio/detail/atomic_count.hpp>
+#include <boost/asio/detail/call_stack.hpp>
 #include <boost/asio/detail/mutex.hpp>
 #include <boost/asio/detail/op_queue.hpp>
 #include <boost/asio/detail/reactor_fwd.hpp>
@@ -40,11 +41,10 @@
 public:
   typedef task_io_service_operation operation;
 
- // Constructor.
- BOOST_ASIO_DECL task_io_service(boost::asio::io_service& io_service);
-
- // How many concurrent threads are likely to run the io_service.
- BOOST_ASIO_DECL void init(std::size_t concurrency_hint);
+ // Constructor. Specifies the number of concurrent threads that are likely to
+ // run the io_service. If set to 1 certain optimisation are performed.
+ BOOST_ASIO_DECL task_io_service(boost::asio::io_service& io_service,
+ std::size_t concurrency_hint = 0);
 
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
@@ -86,6 +86,12 @@
       stop();
   }
 
+ // Return whether a handler can be dispatched immediately.
+ bool can_dispatch()
+ {
+ return thread_call_stack::contains(this);
+ }
+
   // Request invocation of the given handler.
   template <typename Handler>
   void dispatch(Handler handler);
@@ -112,11 +118,17 @@
 
 private:
   // Structure containing information about an idle thread.
- struct idle_thread_info;
+ struct thread_info;
 
   // Run at most one operation. Blocks only if this_idle_thread is non-null.
- BOOST_ASIO_DECL std::size_t do_one(mutex::scoped_lock& lock,
- idle_thread_info* this_idle_thread);
+ BOOST_ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock,
+ thread_info& this_thread, op_queue<operation>& private_op_queue,
+ const boost::system::error_code& ec);
+
+ // Poll for at most one operation.
+ BOOST_ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock,
+ op_queue<operation>& private_op_queue,
+ const boost::system::error_code& ec);
 
   // Stop the task and all idle threads.
   BOOST_ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);
@@ -135,8 +147,12 @@
   struct task_cleanup;
   friend struct task_cleanup;
 
- // Helper class to call work_finished() on block exit.
- struct work_finished_on_block_exit;
+ // Helper class to call work-related operations on block exit.
+ struct work_cleanup;
+ friend struct work_cleanup;
+
+ // Whether to optimise for single-threaded use cases.
+ const bool one_thread_;
 
   // Mutex to protect access to internal data.
   mutable mutex mutex_;
@@ -165,8 +181,11 @@
   // Flag to indicate that the dispatcher has been shut down.
   bool shutdown_;
 
+ // Per-thread call stack to track the state of each thread in the io_service.
+ typedef call_stack<task_io_service, thread_info> thread_call_stack;
+
   // The threads that are currently idle.
- idle_thread_info* first_idle_thread_;
+ thread_info* first_idle_thread_;
 };
 
 } // namespace detail

Modified: trunk/boost/asio/detail/task_io_service_operation.hpp
==============================================================================
--- trunk/boost/asio/detail/task_io_service_operation.hpp (original)
+++ trunk/boost/asio/detail/task_io_service_operation.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -31,9 +31,10 @@
 class task_io_service_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER
 {
 public:
- void complete(task_io_service& owner)
+ void complete(task_io_service& owner,
+ const boost::system::error_code& ec, std::size_t bytes_transferred)
   {
- func_(&owner, this, boost::system::error_code(), 0);
+ func_(&owner, this, ec, bytes_transferred);
   }
 
   void destroy()
@@ -44,11 +45,12 @@
 protected:
   typedef void (*func_type)(task_io_service*,
       task_io_service_operation*,
- boost::system::error_code, std::size_t);
+ const boost::system::error_code&, std::size_t);
 
   task_io_service_operation(func_type func)
     : next_(0),
- func_(func)
+ func_(func),
+ task_result_(0)
   {
   }
 
@@ -61,6 +63,9 @@
   friend class op_queue_access;
   task_io_service_operation* next_;
   func_type func_;
+protected:
+ friend class task_io_service;
+ unsigned int task_result_; // Passed into bytes transferred.
 };
 
 } // namespace detail

Modified: trunk/boost/asio/detail/wait_handler.hpp
==============================================================================
--- trunk/boost/asio/detail/wait_handler.hpp (original)
+++ trunk/boost/asio/detail/wait_handler.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -40,7 +40,8 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
   {
     // Take ownership of the handler object.
     wait_handler* h(static_cast<wait_handler*>(base));
@@ -62,7 +63,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_fenced_block.hpp
==============================================================================
--- trunk/boost/asio/detail/win_fenced_block.hpp (original)
+++ trunk/boost/asio/detail/win_fenced_block.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -31,8 +31,16 @@
   : private noncopyable
 {
 public:
- // Constructor.
- win_fenced_block()
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit win_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit win_fenced_block(full_t)
   {
 #if defined(__BORLANDC__)
     LONG barrier = 0;

Modified: trunk/boost/asio/detail/win_iocp_handle_read_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_handle_read_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_handle_read_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -50,8 +50,11 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& result_ec,
+ std::size_t bytes_transferred)
   {
+ boost::system::error_code ec(result_ec);
+
     // Take ownership of the operation object.
     win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));
     ptr p = { boost::addressof(o->handler_), o, o };
@@ -85,7 +88,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_handle_write_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_handle_write_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_handle_write_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -49,7 +49,7 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& ec, std::size_t bytes_transferred)
   {
     // Take ownership of the operation object.
     win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base));
@@ -80,7 +80,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_io_service.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_io_service.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_io_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -21,6 +21,7 @@
 
 #include <boost/limits.hpp>
 #include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/call_stack.hpp>
 #include <boost/asio/detail/mutex.hpp>
 #include <boost/asio/detail/op_queue.hpp>
 #include <boost/asio/detail/scoped_ptr.hpp>
@@ -45,10 +46,11 @@
   : public boost::asio::detail::service_base<win_iocp_io_service>
 {
 public:
- // Constructor.
- BOOST_ASIO_DECL win_iocp_io_service(boost::asio::io_service& io_service);
 
- BOOST_ASIO_DECL void init(size_t concurrency_hint);
+ // Constructor. Specifies a concurrency hint that is passed through to the
+ // underlying I/O completion port.
+ BOOST_ASIO_DECL win_iocp_io_service(boost::asio::io_service& io_service,
+ size_t concurrency_hint = 0);
 
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
@@ -102,6 +104,12 @@
       stop();
   }
 
+ // Return whether a handler can be dispatched immediately.
+ bool can_dispatch()
+ {
+ return call_stack<win_iocp_io_service>::contains(this) != 0;
+ }
+
   // Request invocation of the given handler.
   template <typename Handler>
   void dispatch(Handler handler);

Modified: trunk/boost/asio/detail/win_iocp_null_buffers_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_null_buffers_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_null_buffers_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -56,8 +56,11 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& result_ec,
+ std::size_t bytes_transferred)
   {
+ boost::system::error_code ec(result_ec);
+
     // Take ownership of the operation object.
     win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));
     ptr p = { boost::addressof(o->handler_), o, o };
@@ -95,7 +98,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_operation.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_operation.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_operation.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -38,8 +38,8 @@
 {
 public:
   void complete(win_iocp_io_service& owner,
- const boost::system::error_code& ec = boost::system::error_code(),
- std::size_t bytes_transferred = 0)
+ const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
   {
     func_(&owner, this, ec, bytes_transferred);
   }
@@ -50,8 +50,9 @@
   }
 
 protected:
- typedef void (*func_type)(win_iocp_io_service*,
- win_iocp_operation*, boost::system::error_code, std::size_t);
+ typedef void (*func_type)(
+ win_iocp_io_service*, win_iocp_operation*,
+ const boost::system::error_code&, std::size_t);
 
   win_iocp_operation(func_type func)
     : next_(0),

Modified: trunk/boost/asio/detail/win_iocp_overlapped_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_overlapped_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_overlapped_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -46,7 +46,7 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& ec, std::size_t bytes_transferred)
   {
     // Take ownership of the operation object.
     win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base));
@@ -68,7 +68,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_socket_accept_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_socket_accept_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_socket_accept_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -73,8 +73,11 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t /*bytes_transferred*/)
+ const boost::system::error_code& result_ec,
+ std::size_t /*bytes_transferred*/)
   {
+ boost::system::error_code ec(result_ec);
+
     // Take ownership of the operation object.
     win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
     ptr p = { boost::addressof(o->handler_), o, o };
@@ -134,7 +137,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_socket_recv_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_socket_recv_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_socket_recv_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -53,8 +53,11 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& result_ec,
+ std::size_t bytes_transferred)
   {
+ boost::system::error_code ec(result_ec);
+
     // Take ownership of the operation object.
     win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));
     ptr p = { boost::addressof(o->handler_), o, o };
@@ -89,7 +92,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -59,8 +59,11 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& result_ec,
+ std::size_t bytes_transferred)
   {
+ boost::system::error_code ec(result_ec);
+
     // Take ownership of the operation object.
     win_iocp_socket_recvfrom_op* o(
         static_cast<win_iocp_socket_recvfrom_op*>(base));
@@ -96,7 +99,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -55,8 +55,11 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& result_ec,
+ std::size_t bytes_transferred)
   {
+ boost::system::error_code ec(result_ec);
+
     // Take ownership of the operation object.
     win_iocp_socket_recvmsg_op* o(
         static_cast<win_iocp_socket_recvmsg_op*>(base));
@@ -90,7 +93,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/detail/win_iocp_socket_send_op.hpp
==============================================================================
--- trunk/boost/asio/detail/win_iocp_socket_send_op.hpp (original)
+++ trunk/boost/asio/detail/win_iocp_socket_send_op.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -51,8 +51,11 @@
   }
 
   static void do_complete(io_service_impl* owner, operation* base,
- boost::system::error_code ec, std::size_t bytes_transferred)
+ const boost::system::error_code& result_ec,
+ std::size_t bytes_transferred)
   {
+ boost::system::error_code ec(result_ec);
+
     // Take ownership of the operation object.
     win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));
     ptr p = { boost::addressof(o->handler_), o, o };
@@ -84,7 +87,7 @@
     // Make the upcall if required.
     if (owner)
     {
- boost::asio::detail::fenced_block b;
+ fenced_block b(fenced_block::half);
       BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
       boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_);
       BOOST_ASIO_HANDLER_INVOCATION_END;

Modified: trunk/boost/asio/impl/io_service.hpp
==============================================================================
--- trunk/boost/asio/impl/io_service.hpp (original)
+++ trunk/boost/asio/impl/io_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -33,6 +33,13 @@
   return ios.service_registry_->template use_service<Service>();
 }
 
+template <>
+inline detail::io_service_impl& use_service<detail::io_service_impl>(
+ io_service& ios)
+{
+ return ios.impl_;
+}
+
 template <typename Service>
 inline void add_service(io_service& ios, Service* svc)
 {
@@ -102,25 +109,25 @@
 }
 
 inline io_service::work::work(boost::asio::io_service& io_service)
- : io_service_(io_service)
+ : io_service_impl_(io_service.impl_)
 {
- io_service_.impl_.work_started();
+ io_service_impl_.work_started();
 }
 
 inline io_service::work::work(const work& other)
- : io_service_(other.io_service_)
+ : io_service_impl_(other.io_service_impl_)
 {
- io_service_.impl_.work_started();
+ io_service_impl_.work_started();
 }
 
 inline io_service::work::~work()
 {
- io_service_.impl_.work_finished();
+ io_service_impl_.work_finished();
 }
 
 inline boost::asio::io_service& io_service::work::get_io_service()
 {
- return io_service_;
+ return io_service_impl_.get_io_service();
 }
 
 inline boost::asio::io_service& io_service::service::get_io_service()

Modified: trunk/boost/asio/impl/io_service.ipp
==============================================================================
--- trunk/boost/asio/impl/io_service.ipp (original)
+++ trunk/boost/asio/impl/io_service.ipp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -18,6 +18,7 @@
 #include <boost/asio/detail/config.hpp>
 #include <boost/limits.hpp>
 #include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/scoped_ptr.hpp>
 #include <boost/asio/detail/service_registry.hpp>
 #include <boost/asio/detail/throw_error.hpp>
 
@@ -33,17 +34,18 @@
 namespace asio {
 
 io_service::io_service()
- : service_registry_(new boost::asio::detail::service_registry(*this)),
- impl_(service_registry_->use_service<impl_type>())
+ : service_registry_(new boost::asio::detail::service_registry(
+ *this, static_cast<impl_type*>(0),
+ (std::numeric_limits<std::size_t>::max)())),
+ impl_(service_registry_->first_service<impl_type>())
 {
- impl_.init((std::numeric_limits<std::size_t>::max)());
 }
 
 io_service::io_service(std::size_t concurrency_hint)
- : service_registry_(new boost::asio::detail::service_registry(*this)),
- impl_(service_registry_->use_service<impl_type>())
+ : service_registry_(new boost::asio::detail::service_registry(
+ *this, static_cast<impl_type*>(0), concurrency_hint)),
+ impl_(service_registry_->first_service<impl_type>())
 {
- impl_.init(concurrency_hint);
 }
 
 io_service::~io_service()

Modified: trunk/boost/asio/io_service.hpp
==============================================================================
--- trunk/boost/asio/io_service.hpp (original)
+++ trunk/boost/asio/io_service.hpp 2011-10-08 17:58:10 EDT (Sat, 08 Oct 2011)
@@ -658,8 +658,8 @@
   // Prevent assignment.
   void operator=(const work& other);
 
- // The io_service.
- boost::asio::io_service& io_service_;
+ // The io_service implementation.
+ detail::io_service_impl& io_service_impl_;
 };
 
 /// Class used to uniquely identify a service.


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