summaryrefslogtreecommitdiff
path: root/ACE/ace/Dev_Poll_Reactor.cpp
diff options
context:
space:
mode:
authorSteve Huston <shuston@riverace.com>2010-02-04 15:56:09 +0000
committerSteve Huston <shuston@riverace.com>2010-02-04 15:56:09 +0000
commit92f81e71a40021f42b36376b24894ccd09745b98 (patch)
tree13a10f1f239ec5cf43dc2dd5976b2f1416ac20d6 /ACE/ace/Dev_Poll_Reactor.cpp
parent381a942f035821902725148480fa6cc9d86e0331 (diff)
downloadATCD-92f81e71a40021f42b36376b24894ccd09745b98.tar.gz
ChangeLogTag:Thu Feb 4 15:32:24 UTC 2010 Steve Huston <shuston@riverace.com>
Diffstat (limited to 'ACE/ace/Dev_Poll_Reactor.cpp')
-rw-r--r--ACE/ace/Dev_Poll_Reactor.cpp102
1 files changed, 80 insertions, 22 deletions
diff --git a/ACE/ace/Dev_Poll_Reactor.cpp b/ACE/ace/Dev_Poll_Reactor.cpp
index 78dcc03672b..c70d346c0dd 100644
--- a/ACE/ace/Dev_Poll_Reactor.cpp
+++ b/ACE/ace/Dev_Poll_Reactor.cpp
@@ -609,6 +609,9 @@ ACE_Dev_Poll_Reactor::ACE_Dev_Poll_Reactor (ACE_Sig_Handler *sh,
, poll_fd_ (ACE_INVALID_HANDLE)
, size_ (0)
// , ready_set_ ()
+#if defined (ACE_HAS_EVENT_POLL)
+ , epoll_wait_in_progress_ (false)
+#endif /* ACE_HAS_EVENT_POLL */
#if defined (ACE_HAS_DEV_POLL)
, dp_fds_ (0)
, start_pfds_ (0)
@@ -965,11 +968,33 @@ ACE_Dev_Poll_Reactor::work_pending_i (ACE_Time_Value * max_wait_time)
#if defined (ACE_HAS_EVENT_POLL)
- // Wait for an event.
- int const nfds = ::epoll_wait (this->poll_fd_,
- &this->event_,
- 1,
- static_cast<int> (timeout));
+ // See if there are handlers that have to be resumed before waiting.
+ {
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->to_be_resumed_lock_, -1);
+ this->epoll_wait_in_progress_ = true;
+ for (Resume_Map::iterator i = this->to_be_resumed_.begin ();
+ i != this->to_be_resumed_.end ();
+ ++i)
+ {
+ // Make sure that 1) the handle is still registered,
+ // 2) the registered handler is the one we're waiting to resume.
+ Event_Tuple *info = this->handler_rep_.find (i->first);
+ if (info != 0 && info->event_handler == i->second)
+ {
+ this->resume_handler_i (i->first);
+ }
+ }
+ this->to_be_resumed_.clear ();
+ }
+
+ // Wait for an event.
+ int const nfds = ::epoll_wait (this->poll_fd_,
+ &this->event_,
+ 1,
+ static_cast<int> (timeout));
+ // Count on this being an atomic update; at worst, we may get an
+ // extraneous notify() from dispatch_io_event.
+ this->epoll_wait_in_progress_ = false;
#else
@@ -1281,13 +1306,13 @@ ACE_Dev_Poll_Reactor::dispatch_io_event (Token_Guard &guard)
// With epoll, events are registered with oneshot, so the handle is
// effectively suspended; future calls to epoll_wait() will select
// the next event, so they're not managed here.
- // The hitch to this is that the notify handler must always be resumed
- // immediately, before letting go of the guard. Else it's possible to
- // get into a state where all handles, including the notify pipe, are
- // suspended and that means the wait thread can't be interrupted.
- info->suspended = true;
- if (eh == this->notify_handler_)
- this->resume_handler_i (handle);
+ // The hitch to this is that the notify handler is always registered
+ // WITHOUT oneshot and is never suspended/resumed. This avoids endless
+ // notify loops caused by the notify handler requiring a resumption
+ // which requires the token, which requires a notify, etc. described
+ // in Bugzilla 3714. So, never suspend the notify handler.
+ if (eh != this->notify_handler_)
+ info->suspended = true;
#endif /* ACE_HAS_DEV_POLL */
int status = 0; // gets callback status, below.
@@ -1299,6 +1324,10 @@ ACE_Dev_Poll_Reactor::dispatch_io_event (Token_Guard &guard)
// notified handlers themselves is done in the notify handler.
ACE_Dev_Poll_Handler_Guard eh_guard (eh);
+ bool reactor_resumes_eh =
+ eh->resume_handler () ==
+ ACE_Event_Handler::ACE_REACTOR_RESUMES_HANDLER;
+
// Release the reactor token before upcall.
guard.release_token ();
@@ -1306,6 +1335,39 @@ ACE_Dev_Poll_Reactor::dispatch_io_event (Token_Guard &guard)
// if callback returns > 0. We come back with either 0 or < 0.
status = this->upcall (eh, callback, handle);
+ if (eh == this->notify_handler_)
+ return status == 0 ? 1 : -1;
+
+ // If the callback returned 0, epoll-based needs to resume the
+ // suspended handler but dev/poll doesn't.
+ // The epoll case is optimized to not acquire the token in order
+ // to resume the handler; the handler is added to a list of those
+ // that need to be resumed and is handled by the next leader
+ // that does an epoll_wait().
+ // In both epoll and dev/poll cases, if the callback returns <0,
+ // the token needs to be acquired and the handler checked and
+ // removed if it hasn't already been.
+ if (status == 0)
+ {
+#ifdef ACE_HAS_EVENT_POLL
+ // epoll-based effectively suspends handlers around the upcall.
+ // If the handler must be resumed, add it to the list.
+ if (reactor_resumes_eh)
+ {
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX,
+ grd,
+ this->to_be_resumed_lock_,
+ -1);
+ bool map_was_empty = this->to_be_resumed_.empty();
+ this->to_be_resumed_.insert
+ (Resume_Map::value_type (handle, eh));
+ if (this->epoll_wait_in_progress_ && map_was_empty)
+ this->notify();
+ }
+#endif /* ACE_HAS_EVENT_POLL */
+ return 1;
+ }
+
// All state in the handler repository may have changed during the
// upcall while other threads had the token. Thus, reacquire the
// token and evaluate what's needed. If the upcalled handler is still
@@ -1317,15 +1379,6 @@ ACE_Dev_Poll_Reactor::dispatch_io_event (Token_Guard &guard)
{
if (status < 0)
this->remove_handler_i (handle, disp_mask);
-
-#ifdef ACE_HAS_EVENT_POLL
- // epoll-based effectively suspends handlers around the upcall.
- // If the handler must be resumed here, do it now.
- if (info->suspended &&
- (eh->resume_handler () ==
- ACE_Event_Handler::ACE_REACTOR_RESUMES_HANDLER))
- this->resume_handler_i (handle);
-#endif /* ACE_HAS_EVENT_POLL */
}
}
// Scope close handles eh ref count decrement, if needed.
@@ -1428,8 +1481,13 @@ ACE_Dev_Poll_Reactor::register_handler_i (ACE_HANDLE handle,
ACE_OS::memset (&epev, 0, sizeof (epev));
static const int op = EPOLL_CTL_ADD;
- epev.events = this->reactor_mask_to_poll_event (mask) | EPOLLONESHOT;
epev.data.fd = handle;
+ epev.events = this->reactor_mask_to_poll_event (mask);
+ // All but the notify handler get registered with oneshot to facilitate
+ // auto suspend before the upcall. See dispatch_io_event for more
+ // information.
+ if (event_handler != this->notify_handler_)
+ epev.events |= EPOLLONESHOT;
if (::epoll_ctl (this->poll_fd_, op, handle, &epev) == -1)
{