Boost logo

Boost-Commit :

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


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

Log:
Set size of select fd_set at runtime when using Windows.
Text files modified:
   trunk/boost/asio/detail/impl/select_reactor.ipp | 36 ++++++++++++----------
   trunk/boost/asio/detail/posix_fd_set_adapter.hpp | 9 +++++
   trunk/boost/asio/detail/select_reactor.hpp | 4 ++
   trunk/boost/asio/detail/win_fd_set_adapter.hpp | 63 ++++++++++++++++++++++++++++++---------
   4 files changed, 80 insertions(+), 32 deletions(-)

Modified: trunk/boost/asio/detail/impl/select_reactor.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/select_reactor.ipp (original)
+++ trunk/boost/asio/detail/impl/select_reactor.ipp 2011-10-08 17:25:20 EDT (Sat, 08 Oct 2011)
@@ -172,27 +172,28 @@
 #endif // defined(BOOST_ASIO_HAS_IOCP)
 
   // Set up the descriptor sets.
- fd_set_adapter fds[max_select_ops];
- fds[read_op].set(interrupter_.read_descriptor());
+ for (int i = 0; i < max_select_ops; ++i)
+ fd_sets_[i].reset();
+ fd_sets_[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)
   {
     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();
+ op_queue_[i].get_descriptors(fd_sets_[i], ops);
+ if (fd_sets_[i].max_descriptor() > max_fd)
+ max_fd = fd_sets_[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();
+ op_queue_[connect_op].get_descriptors(fd_sets_[write_op], ops);
+ if (fd_sets_[write_op].max_descriptor() > max_fd)
+ max_fd = fd_sets_[write_op].max_descriptor();
+ op_queue_[connect_op].get_descriptors(fd_sets_[except_op], ops);
+ if (fd_sets_[except_op].max_descriptor() > max_fd)
+ max_fd = fd_sets_[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
@@ -209,11 +210,14 @@
   // 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),
- fds[read_op], fds[write_op], fds[except_op], tv, ec);
+ fd_sets_[read_op], fd_sets_[write_op], fd_sets_[except_op], tv, ec);
 
   // Reset the interrupter.
- if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor()))
+ if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor()))
+ {
     interrupter_.reset();
+ --retval;
+ }
 
   lock.lock();
 
@@ -223,15 +227,15 @@
 #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);
+ fd_sets_[except_op], ops);
     op_queue_[connect_op].perform_operations_for_descriptors(
- fds[write_op], ops);
+ fd_sets_[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.
     for (int i = max_select_ops - 1; i >= 0; --i)
- op_queue_[i].perform_operations_for_descriptors(fds[i], ops);
+ op_queue_[i].perform_operations_for_descriptors(fd_sets_[i], ops);
   }
   timer_queues_.get_ready_timers(ops);
 }

Modified: trunk/boost/asio/detail/posix_fd_set_adapter.hpp
==============================================================================
--- trunk/boost/asio/detail/posix_fd_set_adapter.hpp (original)
+++ trunk/boost/asio/detail/posix_fd_set_adapter.hpp 2011-10-08 17:25:20 EDT (Sat, 08 Oct 2011)
@@ -20,6 +20,7 @@
 #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
 #include <cstring>
+#include <boost/asio/detail/noncopyable.hpp>
 #include <boost/asio/detail/socket_types.hpp>
 
 #include <boost/asio/detail/push_options.hpp>
@@ -29,7 +30,7 @@
 namespace detail {
 
 // Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
-class posix_fd_set_adapter
+class posix_fd_set_adapter : noncopyable
 {
 public:
   posix_fd_set_adapter()
@@ -39,6 +40,12 @@
     FD_ZERO(&fd_set_);
   }
 
+ void reset()
+ {
+ using namespace std; // Needed for memset on Solaris.
+ FD_ZERO(&fd_set_);
+ }
+
   bool set(socket_type descriptor)
   {
     if (descriptor < (socket_type)FD_SETSIZE)

Modified: trunk/boost/asio/detail/select_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/select_reactor.hpp (original)
+++ trunk/boost/asio/detail/select_reactor.hpp 2011-10-08 17:25:20 EDT (Sat, 08 Oct 2011)
@@ -24,6 +24,7 @@
 
 #include <boost/limits.hpp>
 #include <cstddef>
+#include <boost/asio/detail/fd_set_adapter.hpp>
 #include <boost/asio/detail/mutex.hpp>
 #include <boost/asio/detail/op_queue.hpp>
 #include <boost/asio/detail/reactor_op.hpp>
@@ -183,6 +184,9 @@
   // The queues of read, write and except operations.
   reactor_op_queue<socket_type> op_queue_[max_ops];
 
+ // The file descriptor sets to be passed to the select system call.
+ fd_set_adapter fd_sets_[max_select_ops];
+
   // The timer queues.
   timer_queue_set timer_queues_;
 

Modified: trunk/boost/asio/detail/win_fd_set_adapter.hpp
==============================================================================
--- trunk/boost/asio/detail/win_fd_set_adapter.hpp (original)
+++ trunk/boost/asio/detail/win_fd_set_adapter.hpp 2011-10-08 17:25:20 EDT (Sat, 08 Oct 2011)
@@ -19,6 +19,7 @@
 
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
 
+#include <boost/asio/detail/noncopyable.hpp>
 #include <boost/asio/detail/socket_types.hpp>
 
 #include <boost/asio/detail/push_options.hpp>
@@ -28,39 +29,67 @@
 namespace detail {
 
 // Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
-class win_fd_set_adapter
+class win_fd_set_adapter : noncopyable
 {
 public:
- enum { win_fd_set_size = 1024 };
+ enum { default_fd_set_size = 1024 };
 
   win_fd_set_adapter()
- : max_descriptor_(invalid_socket)
+ : capacity_(default_fd_set_size),
+ max_descriptor_(invalid_socket)
   {
- fd_set_.fd_count = 0;
+ fd_set_ = static_cast<win_fd_set*>(::operator new(
+ sizeof(win_fd_set) - sizeof(SOCKET)
+ + sizeof(SOCKET) * (capacity_)));
+ fd_set_->fd_count = 0;
+ }
+
+ ~win_fd_set_adapter()
+ {
+ ::operator delete(fd_set_);
+ }
+
+ void reset()
+ {
+ fd_set_->fd_count = 0;
+ max_descriptor_ = invalid_socket;
   }
 
   bool set(socket_type descriptor)
   {
- for (u_int i = 0; i < fd_set_.fd_count; ++i)
- if (fd_set_.fd_array[i] == descriptor)
+ for (u_int i = 0; i < fd_set_->fd_count; ++i)
+ if (fd_set_->fd_array[i] == descriptor)
         return true;
- if (fd_set_.fd_count < win_fd_set_size)
+
+ if (fd_set_->fd_count == capacity_)
     {
- fd_set_.fd_array[fd_set_.fd_count++] = descriptor;
- return true;
+ u_int new_capacity = capacity_ + capacity_ / 2;
+ win_fd_set* new_fd_set = static_cast<win_fd_set*>(::operator new(
+ sizeof(win_fd_set) - sizeof(SOCKET)
+ + sizeof(SOCKET) * (new_capacity)));
+
+ new_fd_set->fd_count = fd_set_->fd_count;
+ for (u_int i = 0; i < fd_set_->fd_count; ++i)
+ new_fd_set->fd_array[i] = fd_set_->fd_array[i];
+
+ ::operator delete(fd_set_);
+ fd_set_ = new_fd_set;
+ capacity_ = new_capacity;
     }
- return false;
+
+ fd_set_->fd_array[fd_set_->fd_count++] = descriptor;
+ return true;
   }
 
   bool is_set(socket_type descriptor) const
   {
     return !!__WSAFDIsSet(descriptor,
- const_cast<fd_set*>(reinterpret_cast<const fd_set*>(&fd_set_)));
+ const_cast<fd_set*>(reinterpret_cast<const fd_set*>(fd_set_)));
   }
 
   operator fd_set*()
   {
- return reinterpret_cast<fd_set*>(&fd_set_);
+ return reinterpret_cast<fd_set*>(fd_set_);
   }
 
   socket_type max_descriptor() const
@@ -69,15 +98,19 @@
   }
 
 private:
+
   // This structure is defined to be compatible with the Windows API fd_set
- // structure, but without being dependent on the value of FD_SETSIZE.
+ // structure, but without being dependent on the value of FD_SETSIZE. We use
+ // the "struct hack" to allow the number of descriptors to be varied at
+ // runtime.
   struct win_fd_set
   {
     u_int fd_count;
- SOCKET fd_array[win_fd_set_size];
+ SOCKET fd_array[1];
   };
 
- win_fd_set fd_set_;
+ win_fd_set* fd_set_;
+ u_int capacity_;
   socket_type max_descriptor_;
 };
 


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