|
Boost-Commit : |
From: chris_at_[hidden]
Date: 2007-11-12 07:07:39
Author: chris_kohlhoff
Date: 2007-11-12 07:07:39 EST (Mon, 12 Nov 2007)
New Revision: 41028
URL: http://svn.boost.org/trac/boost/changeset/41028
Log:
Cannot perform concurrent operations on the /dev/poll descriptor where
the sockets descriptors involved may already be being waited on. Changed
the dev_poll_reactor class to keep a vector of pending event changes and
interrupt the /dev/poll ioctl() wait to apply it.
Text files modified:
trunk/boost/asio/detail/dev_poll_reactor.hpp | 106 +++++++++++++++++++++------------------
1 files changed, 57 insertions(+), 49 deletions(-)
Modified: trunk/boost/asio/detail/dev_poll_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/dev_poll_reactor.hpp (original)
+++ trunk/boost/asio/detail/dev_poll_reactor.hpp 2007-11-12 07:07:39 EST (Mon, 12 Nov 2007)
@@ -141,22 +141,13 @@
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
- ::pollfd ev = { 0 };
- ev.fd = descriptor;
+ ::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLIN | POLLERR | POLLHUP;
if (write_op_queue_.has_operation(descriptor))
ev.events |= POLLOUT;
if (except_op_queue_.has_operation(descriptor))
ev.events |= POLLPRI;
- ev.revents = 0;
-
- int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
- if (result != sizeof(ev))
- {
- boost::system::error_code ec(errno,
- boost::asio::error::system_category);
- read_op_queue_.dispatch_all_operations(descriptor, ec);
- }
+ interrupter_.interrupt();
}
}
@@ -176,22 +167,13 @@
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
- ::pollfd ev = { 0 };
- ev.fd = descriptor;
+ ::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLOUT | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
if (except_op_queue_.has_operation(descriptor))
ev.events |= POLLPRI;
- ev.revents = 0;
-
- int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
- if (result != sizeof(ev))
- {
- boost::system::error_code ec(errno,
- boost::asio::error::system_category);
- write_op_queue_.dispatch_all_operations(descriptor, ec);
- }
+ interrupter_.interrupt();
}
}
@@ -207,22 +189,13 @@
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
- ::pollfd ev = { 0 };
- ev.fd = descriptor;
+ ::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLPRI | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
if (write_op_queue_.has_operation(descriptor))
ev.events |= POLLOUT;
- ev.revents = 0;
-
- int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
- if (result != sizeof(ev))
- {
- boost::system::error_code ec(errno,
- boost::asio::error::system_category);
- except_op_queue_.dispatch_all_operations(descriptor, ec);
- }
+ interrupter_.interrupt();
}
}
@@ -242,21 +215,11 @@
&& need_mod;
if (need_mod)
{
- ::pollfd ev = { 0 };
- ev.fd = descriptor;
+ ::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= POLLIN;
- ev.revents = 0;
-
- int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
- if (result != sizeof(ev))
- {
- boost::system::error_code ec(errno,
- boost::asio::error::system_category);
- write_op_queue_.dispatch_all_operations(descriptor, ec);
- except_op_queue_.dispatch_all_operations(descriptor, ec);
- }
+ interrupter_.interrupt();
}
}
@@ -286,11 +249,9 @@
boost::asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from /dev/poll.
- ::pollfd ev = { 0 };
- ev.fd = descriptor;
+ ::pollfd& ev = add_pending_event_change(descriptor);
ev.events = POLLREMOVE;
- ev.revents = 0;
- ::write(dev_poll_fd_, &ev, sizeof(ev));
+ interrupter_.interrupt();
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor);
@@ -375,6 +336,26 @@
return;
}
+ // Write the pending event registration changes to the /dev/poll descriptor.
+ std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
+ errno = 0;
+ int result = ::write(dev_poll_fd_,
+ &pending_event_changes_[0], events_size);
+ if (result != static_cast<int>(events_size))
+ {
+ for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
+ {
+ int descriptor = pending_event_changes_[i].fd;
+ boost::system::error_code ec = boost::system::error_code(
+ errno, boost::asio::error::system_category);
+ read_op_queue_.dispatch_all_operations(descriptor, ec);
+ write_op_queue_.dispatch_all_operations(descriptor, ec);
+ except_op_queue_.dispatch_all_operations(descriptor, ec);
+ }
+ }
+ pending_event_changes_.clear();
+ pending_event_change_index_.clear();
+
int timeout = block ? get_timeout() : 0;
wait_in_progress_ = true;
lock.unlock();
@@ -589,12 +570,39 @@
timer_queues_for_cleanup_[i]->cleanup_timers();
}
+ // Add a pending event entry for the given descriptor.
+ ::pollfd& add_pending_event_change(int descriptor)
+ {
+ hash_map<int, std::size_t>::iterator iter
+ = pending_event_change_index_.find(descriptor);
+ if (iter == pending_event_change_index_.end())
+ {
+ std::size_t index = pending_event_changes_.size();
+ pending_event_changes_.reserve(pending_event_changes_.size() + 1);
+ pending_event_change_index_.insert(std::make_pair(descriptor, index));
+ pending_event_changes_.push_back(::pollfd());
+ pending_event_changes_[index].fd = descriptor;
+ pending_event_changes_[index].revents = 0;
+ return pending_event_changes_[index];
+ }
+ else
+ {
+ return pending_event_changes_[iter->second];
+ }
+ }
+
// Mutex to protect access to internal data.
boost::asio::detail::mutex mutex_;
// The /dev/poll file descriptor.
int dev_poll_fd_;
+ // Vector of /dev/poll events waiting to be written to the descriptor.
+ std::vector< ::pollfd> pending_event_changes_;
+
+ // Hash map to associate a descriptor with a pending event change index.
+ hash_map<int, std::size_t> pending_event_change_index_;
+
// Whether the DP_POLL operation is currently in progress
bool wait_in_progress_;
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