diff options
author | Ossama Othman <ossama-othman@users.noreply.github.com> | 2002-05-02 20:29:34 +0000 |
---|---|---|
committer | Ossama Othman <ossama-othman@users.noreply.github.com> | 2002-05-02 20:29:34 +0000 |
commit | d3581fe4d84c284914e5abe342a51cd4ea78f1f2 (patch) | |
tree | 3f36484142eb05652696018ce1e63f822618c4b8 | |
parent | 7357ae2b7b412d9ee9fcb09e405299614e085291 (diff) | |
download | ATCD-d3581fe4d84c284914e5abe342a51cd4ea78f1f2.tar.gz |
ChangeLogTag:Thu May 2 13:28:01 2002 Ossama Othman <ossama@uci.edu>
-rw-r--r-- | ChangeLog | 67 | ||||
-rw-r--r-- | ChangeLogs/ChangeLog-02a | 67 | ||||
-rw-r--r-- | ChangeLogs/ChangeLog-03a | 67 | ||||
-rw-r--r-- | ace/Dev_Poll_Reactor.cpp | 296 | ||||
-rw-r--r-- | ace/Dev_Poll_Reactor.h | 66 | ||||
-rw-r--r-- | ace/Dev_Poll_Reactor.inl | 30 |
6 files changed, 465 insertions, 128 deletions
diff --git a/ChangeLog b/ChangeLog index 241a940b237..6549be36697 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,70 @@ +Thu May 2 13:28:01 2002 Ossama Othman <ossama@uci.edu> + + * ace/Dev_Poll_Reactor.h: + + Updated some documentation. + + * ace/Dev_Poll_Reactor.inl (upcall): + + New method containing common upcall operations for all types of + IO events. + + * ace/Dev_Poll_Reactor.cpp: + + Commented out "ready set" code since the upcall will simply loop + until the event handler no longer desires callbacks. This is + okay since multiple threads may dispatch event handlers (similar + to what the TP_Reactor does). + + (close): + + Cleaned up memory and resource leaks. + + (handle_events_i, work_pending_i): + + Moved "event polling" code to the new work_pending_i() method. + handle_events_i() now calls that method to determine if any + events must be dispatched. + + If the underlying ioctl() call was interrupted (e.g. via the + INTR signal), i.e. returns -1 with errno set to EINTR, then + automatically restart the event loop if so desired by the user. + + (work_pending): + + Implemented this method. It simply grabs the reactor lock and + calls the new work_pending_i() method. + + (dispatch_io_events): + + Call the remove_handler() method that acquires the lock instead + of the one doesn't. The lock must be reacquired since reactor + state will potentially change during an upcall and since the + lock was released prior to dispatching the upcall. Fixes a race + condition. + + Directly use pollfd pointers as the loop variables instead of an + integer. No need for the additional indirection. + + Since the underlying event demultiplexing mechansim (`/dev/poll' + or '/dev/epoll') is stateful, and since only one result buffer + is used, all pending events (i.e. those retrieved from a + previous poll) must be dispatched before any additional event + can be polled. As such, the Dev_Poll_Reactor keeps track of the + progress of events that have been dispatched. + + The semantics of the event loop in the presence of multiple + threads is non-trivial. The "start point" of the loop will be + incremented each time an event handler is dispatched, which may + be done across multiple threads. Multiple threads may change + the loop variables. Care must be taken to only change those + variables with the reactor lock held. + + (dispatch_timer_handlers): + + Release the reactor lock during the upcall. Fixes a potential + deadlock. + Thu May 2 10:35:25 2002 Phil Mesnier <mesnier_p@ociweb.com> * ace/Log_Msg.cpp: ACE_Log_Msg::open() did not properly initialize a diff --git a/ChangeLogs/ChangeLog-02a b/ChangeLogs/ChangeLog-02a index 241a940b237..6549be36697 100644 --- a/ChangeLogs/ChangeLog-02a +++ b/ChangeLogs/ChangeLog-02a @@ -1,3 +1,70 @@ +Thu May 2 13:28:01 2002 Ossama Othman <ossama@uci.edu> + + * ace/Dev_Poll_Reactor.h: + + Updated some documentation. + + * ace/Dev_Poll_Reactor.inl (upcall): + + New method containing common upcall operations for all types of + IO events. + + * ace/Dev_Poll_Reactor.cpp: + + Commented out "ready set" code since the upcall will simply loop + until the event handler no longer desires callbacks. This is + okay since multiple threads may dispatch event handlers (similar + to what the TP_Reactor does). + + (close): + + Cleaned up memory and resource leaks. + + (handle_events_i, work_pending_i): + + Moved "event polling" code to the new work_pending_i() method. + handle_events_i() now calls that method to determine if any + events must be dispatched. + + If the underlying ioctl() call was interrupted (e.g. via the + INTR signal), i.e. returns -1 with errno set to EINTR, then + automatically restart the event loop if so desired by the user. + + (work_pending): + + Implemented this method. It simply grabs the reactor lock and + calls the new work_pending_i() method. + + (dispatch_io_events): + + Call the remove_handler() method that acquires the lock instead + of the one doesn't. The lock must be reacquired since reactor + state will potentially change during an upcall and since the + lock was released prior to dispatching the upcall. Fixes a race + condition. + + Directly use pollfd pointers as the loop variables instead of an + integer. No need for the additional indirection. + + Since the underlying event demultiplexing mechansim (`/dev/poll' + or '/dev/epoll') is stateful, and since only one result buffer + is used, all pending events (i.e. those retrieved from a + previous poll) must be dispatched before any additional event + can be polled. As such, the Dev_Poll_Reactor keeps track of the + progress of events that have been dispatched. + + The semantics of the event loop in the presence of multiple + threads is non-trivial. The "start point" of the loop will be + incremented each time an event handler is dispatched, which may + be done across multiple threads. Multiple threads may change + the loop variables. Care must be taken to only change those + variables with the reactor lock held. + + (dispatch_timer_handlers): + + Release the reactor lock during the upcall. Fixes a potential + deadlock. + Thu May 2 10:35:25 2002 Phil Mesnier <mesnier_p@ociweb.com> * ace/Log_Msg.cpp: ACE_Log_Msg::open() did not properly initialize a diff --git a/ChangeLogs/ChangeLog-03a b/ChangeLogs/ChangeLog-03a index 241a940b237..6549be36697 100644 --- a/ChangeLogs/ChangeLog-03a +++ b/ChangeLogs/ChangeLog-03a @@ -1,3 +1,70 @@ +Thu May 2 13:28:01 2002 Ossama Othman <ossama@uci.edu> + + * ace/Dev_Poll_Reactor.h: + + Updated some documentation. + + * ace/Dev_Poll_Reactor.inl (upcall): + + New method containing common upcall operations for all types of + IO events. + + * ace/Dev_Poll_Reactor.cpp: + + Commented out "ready set" code since the upcall will simply loop + until the event handler no longer desires callbacks. This is + okay since multiple threads may dispatch event handlers (similar + to what the TP_Reactor does). + + (close): + + Cleaned up memory and resource leaks. + + (handle_events_i, work_pending_i): + + Moved "event polling" code to the new work_pending_i() method. + handle_events_i() now calls that method to determine if any + events must be dispatched. + + If the underlying ioctl() call was interrupted (e.g. via the + INTR signal), i.e. returns -1 with errno set to EINTR, then + automatically restart the event loop if so desired by the user. + + (work_pending): + + Implemented this method. It simply grabs the reactor lock and + calls the new work_pending_i() method. + + (dispatch_io_events): + + Call the remove_handler() method that acquires the lock instead + of the one doesn't. The lock must be reacquired since reactor + state will potentially change during an upcall and since the + lock was released prior to dispatching the upcall. Fixes a race + condition. + + Directly use pollfd pointers as the loop variables instead of an + integer. No need for the additional indirection. + + Since the underlying event demultiplexing mechansim (`/dev/poll' + or '/dev/epoll') is stateful, and since only one result buffer + is used, all pending events (i.e. those retrieved from a + previous poll) must be dispatched before any additional event + can be polled. As such, the Dev_Poll_Reactor keeps track of the + progress of events that have been dispatched. + + The semantics of the event loop in the presence of multiple + threads is non-trivial. The "start point" of the loop will be + incremented each time an event handler is dispatched, which may + be done across multiple threads. Multiple threads may change + the loop variables. Care must be taken to only change those + variables with the reactor lock held. + + (dispatch_timer_handlers): + + Release the reactor lock during the upcall. Fixes a potential + deadlock. + Thu May 2 10:35:25 2002 Phil Mesnier <mesnier_p@ociweb.com> * ace/Log_Msg.cpp: ACE_Log_Msg::open() did not properly initialize a diff --git a/ace/Dev_Poll_Reactor.cpp b/ace/Dev_Poll_Reactor.cpp index 019975b174c..d357701098f 100644 --- a/ace/Dev_Poll_Reactor.cpp +++ b/ace/Dev_Poll_Reactor.cpp @@ -1032,117 +1032,178 @@ ACE_Dev_Poll_Reactor::close (void) result = ACE_OS::close (this->poll_fd_); } + if (this->delete_signal_handler_) + { + delete this->signal_handler_; + this->signal_handler_ = 0; + this->delete_signal_handler_ = 0; + } + + (void) this->handler_rep_.close (); + + if (this->delete_timer_queue_) + { + delete this->timer_queue_; + this->timer_queue_ = 0; + this->delete_timer_queue_ = 0; + } + + if (this->notify_handler_ != 0) + this->notify_handler_->close (); + + if (this->delete_notify_handler_) + { + delete this->notify_handler_; + this->notify_handler_ = 0; + this->delete_notify_handler_ = 0; + } + this->poll_fd_ = ACE_INVALID_HANDLE; + this->start_pfds_ = 0; + this->end_pfds_ = 0; + this->initialized_ = 0; return result; } int -ACE_Dev_Poll_Reactor::work_pending (const ACE_Time_Value & /* max_wait_time */) +ACE_Dev_Poll_Reactor::work_pending (const ACE_Time_Value & max_wait_time) { ACE_TRACE ("ACE_Dev_Poll_Reactor::work_pending"); - // /dev/epoll is a "state change" interface, not a "state - // monitoring" interface. This means that it is not possible to - // provide the semantics required by this method. - ACE_NOTSUP_RETURN (-1); -} - -int -ACE_Dev_Poll_Reactor::handle_events (ACE_Time_Value *max_wait_time) -{ - ACE_TRACE ("ACE_Dev_Poll_Reactor::handle_events"); - // Stash the current time // // The destructor of this object will automatically compute how much // time elapsed since this method was called. - ACE_Countdown_Time countdown (max_wait_time); + ACE_Time_Value mwt (max_wait_time); + ACE_MT (ACE_Countdown_Time countdown (&mwt)); ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, -1)); - if (this->deactivated_) - return -1; - // Update the countdown to reflect time waiting for the mutex. ACE_MT (countdown.update ()); - return this->handle_events_i (max_wait_time); + return this->work_pending_i (mwt); } int -ACE_Dev_Poll_Reactor::handle_events_i (ACE_Time_Value *max_wait_time) +ACE_Dev_Poll_Reactor::work_pending_i (ACE_Time_Value & max_wait_time) { - ACE_TRACE ("ACE_Dev_Poll_Reactor::handle_events_i"); + ACE_TRACE ("ACE_Dev_Poll_Reactor::work_pending_i"); - int io_handlers_dispatched = 0; + if (this->deactivated_) + return 0; - // Dispatch all "ready" events before polling for events. - if (this->ready_set_.nfds > 0 - && this->dispatch_io_events (this->ready_set_.pfds, - this->ready_set_.nfds, - io_handlers_dispatched) != 0) - return -1; + if (this->start_pfds_ != this->end_pfds_) + return 1; // We still have work_pending() do not poll for + // additional events. - // Check if additional events are "ready" before polling. - if (this->ready_set_.nfds == 0) - { - ACE_Time_Value timer_buf (0); - ACE_Time_Value *this_timeout = 0; + ACE_Time_Value timer_buf (0); + ACE_Time_Value *this_timeout = 0; - this_timeout = this->timer_queue_->calculate_timeout (max_wait_time, - &timer_buf); + this_timeout = this->timer_queue_->calculate_timeout (&max_wait_time, + &timer_buf); - long timeout = - (this_timeout == 0 ? -1 /* Infinity */ : this_timeout->msec ()); + long timeout = + (this_timeout == 0 ? -1 /* Infinity */ : this_timeout->msec ()); #if defined (ACE_HAS_EVENT_POLL) - struct evpoll evp; + struct evpoll evp; - evp.ep_timeout = timeout; // Milliseconds - evp.ep_resoff = 0; + evp.ep_timeout = timeout; // Milliseconds + evp.ep_resoff = 0; - // Poll for events - int nfds = ACE_OS::ioctl (this->poll_fd_, EP_POLL, &evp); + // Poll for events + int nfds = ACE_OS::ioctl (this->poll_fd_, EP_POLL, &evp); - if (nfds > 0) - ACE_DEBUG ((LM_DEBUG, "%%%%%% RECEIVED EVENTS ON %d handles.\n", - nfds)); + if (nfds > 0) + ACE_DEBUG ((LM_DEBUG, "%%%%%% RECEIVED EVENTS ON %d handles.\n", + nfds)); - // Retrieve the results from the memory map. - struct pollfd *pfds = - ACE_reinterpret_cast (struct pollfd *, - this->mmap_ + evp.ep_resoff); + // Retrieve the results from the memory map. + this->start_pfds_ = + ACE_reinterpret_cast (struct pollfd *, + this->mmap_ + evp.ep_resoff); #else - struct dvpoll dvp; + struct dvpoll dvp; - dvp.dp_fds = this->dp_fds_; - dvp.dp_nfds = this->size_; - dvp.dp_timeout = timeout; // Milliseconds + dvp.dp_fds = this->dp_fds_; + dvp.dp_nfds = this->size_; + dvp.dp_timeout = timeout; // Milliseconds - // Poll for events - int nfds = ACE_OS::ioctl (this->poll_fd_, DP_POLL, &dvp); + // Poll for events + int nfds = ACE_OS::ioctl (this->poll_fd_, DP_POLL, &dvp); - // Retrieve the results from the pollfd array. - struct pollfd *pfds = dvp.dp_fds; + // Retrieve the results from the pollfd array. + this->start_pfds_ = dvp.dp_fds; #endif /* ACE_HAS_EVENT_POLL */ - return this->dispatch (pfds, - nfds); + // If nfds == 0 then end_pfds_ == start_pfds_ meaning that there is + // no work pending. If nfds > 0 then there is work pending. + // Otherwise an error occurred. + if (nfds > -1) + this->end_pfds_ = this->start_pfds_ + nfds; + + return (nfds > 0 ? 1 : nfds); +} + + +int +ACE_Dev_Poll_Reactor::handle_events (ACE_Time_Value *max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::handle_events"); + + // Stash the current time + // + // The destructor of this object will automatically compute how much + // time elapsed since this method was called. + ACE_MT (ACE_Countdown_Time countdown (max_wait_time)); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, -1)); + + if (this->deactivated_) + return -1; + + // Update the countdown to reflect time waiting for the mutex. + ACE_MT (countdown.update ()); + + return this->handle_events_i (max_wait_time); +} + +int +ACE_Dev_Poll_Reactor::handle_events_i (ACE_Time_Value *max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::handle_events_i"); + + int result = 0; + int active_handle_count = 0; + + // Poll for events + // + // If the underlying ioctl() call was interrupted via the interrupt + // signal (i.e. returned -1 with errno == EINTR) then the loop will + // be restarted if so desired. + do + { + result = this->work_pending_i (*max_wait_time); } + while (result == -1 && this->restart_ != 0 && errno == EINTR); - // this->state_changed_ = 1; + if (result == 0 || (result == -1 && errno == ETIME)) + return 0; + else if (result == -1) + return -1; - return io_handlers_dispatched; + // Dispatch the events, if any. + return this->dispatch (); } int -ACE_Dev_Poll_Reactor::dispatch (struct pollfd *pfds, - int active_handle_count) +ACE_Dev_Poll_Reactor::dispatch (int active_handle_count) { ACE_TRACE ("ACE_Dev_Poll_Reactor::dispatch"); @@ -1224,9 +1285,7 @@ ACE_Dev_Poll_Reactor::dispatch (struct pollfd *pfds, #endif /* 0 */ // Finally, dispatch the I/O handlers. - else if (this->dispatch_io_events (pfds, - active_handle_count, - io_handlers_dispatched) == -1) + else if (this->dispatch_io_events (io_handlers_dispatched) == -1) // State has changed, so exit loop. break; } @@ -1237,14 +1296,18 @@ ACE_Dev_Poll_Reactor::dispatch (struct pollfd *pfds, int ACE_Dev_Poll_Reactor::dispatch_timer_handlers ( - int &number_of_handlers_dispatched) + int &number_of_timers_cancelled) { - number_of_handlers_dispatched += this->timer_queue_->expire (); + // Release the lock during the upcall. + ACE_Reverse_Lock<ACE_SYNCH_MUTEX> reverse_lock (this->lock_); + ACE_GUARD_RETURN (ACE_Reverse_Lock<ACE_SYNCH_MUTEX>, + reverse_guard, + reverse_lock, + -1); -// if (this->state_changed_) -// return -1; -// else - return 0; + number_of_timers_cancelled += this->timer_queue_->expire (); + + return 0; } #if 0 @@ -1275,35 +1338,37 @@ ACE_Dev_Poll_Reactor::dispatch_notification_handlers ( #endif /* 0 */ int -ACE_Dev_Poll_Reactor::dispatch_io_events (struct pollfd *pfds, - int nfds, - int &io_handlers_dispatched) +ACE_Dev_Poll_Reactor::dispatch_io_events (int &io_handlers_dispatched) { - // nfds == 0 : timeout - // nfds > 0 : number of file descriptors (all received events) - // nfds < 0 : error - if (nfds < 0) - return -1; - - // Prepare the ready set to use the result buffer set by the ioctl() - // poll call. - this->ready_set_.pfds = pfds; - - // Reset the "ready" file descriptor count. - this->ready_set_.nfds = 0; + // Since the underlying event demultiplexing mechansim (`/dev/poll' + // or '/dev/epoll') is stateful, and since only one result buffer is + // used, all pending events (i.e. those retrieved from a previous + // poll) must be dispatched before any additional event can be + // polled. As such, the Dev_Poll_Reactor keeps track of the + // progress of events that have been dispatched. // Dispatch the events. // + // The semantics of this loop in the presence of multiple threads is + // non-trivial. this->start_pfds_ will be incremented each time an + // event handler is dispatched, which may be done across multiple + // threads. Multiple threads may change the loop variables. Care + // must be taken to only change those variables with the reactor + // lock held. + // // Notice that pfds only contains file descriptors that have // received events. - for (int i = 0; i < nfds; ++i, ++pfds) + for (struct pollfd *& pfds = this->start_pfds_; + pfds < this->end_pfds_; + /* Nothing to do before next loop iteration */) { const ACE_HANDLE handle = pfds->fd; const short revents = pfds->revents; - // Events to be dispatched the next time the ready set is - // processed. - short ready_set_events = 0; + // Increment the pointer to the next pollfd element before we + // release the lock. Otherwise event handlers end up being + // dispatched multiple times for the same poll. + ++pfds; ACE_Event_Handler *eh = this->handler_rep_.find (handle); @@ -1325,13 +1390,16 @@ ACE_Dev_Poll_Reactor::dispatch_io_events (struct pollfd *pfds, { ACE_DEBUG ((LM_DEBUG, "GOT POLLOUT EVENT\n")); - status = eh->handle_output (handle); + int status = + this->upcall (eh, ACE_Event_Handler::handle_output, handle); if (status < 0) - return this->remove_handler_i (handle, + { + // Note that the lock is reacquired in + // remove_handler(). + return this->remove_handler (handle, ACE_Event_Handler::WRITE_MASK); - else if (status > 0) - ACE_SET_BITS (ready_set_events, POLLOUT); + } io_handlers_dispatched++; } @@ -1341,13 +1409,16 @@ ACE_Dev_Poll_Reactor::dispatch_io_events (struct pollfd *pfds, { ACE_DEBUG ((LM_DEBUG, "GOT POLLPRI EVENT\n")); - status = eh->handle_exception (handle); + int status = + this->upcall (eh, ACE_Event_Handler::handle_exception, handle); if (status < 0) - return this->remove_handler_i (handle, + { + // Note that the lock is reacquired in + // remove_handler(). + return this->remove_handler (handle, ACE_Event_Handler::EXCEPT_MASK); - else if (status > 0) - ACE_SET_BITS (ready_set_events, POLLPRI); + } io_handlers_dispatched++; } @@ -1359,26 +1430,20 @@ ACE_Dev_Poll_Reactor::dispatch_io_events (struct pollfd *pfds, // "GOT POLLIN EVENT ON HANDLE <%d>\n", // handle)); - status = eh->handle_input (handle); + int status = + this->upcall (eh, ACE_Event_Handler::handle_input, handle); if (status < 0) - return this->remove_handler_i (handle, + { + // Note that the lock is reacquired in + // remove_handler(). + return this->remove_handler (handle, ACE_Event_Handler::READ_MASK); - else if (status > 0) - ACE_SET_BITS (ready_set_events, POLLIN); + } io_handlers_dispatched++; } - } - - if (ready_set_events != 0) - { - // Notice that all events for pfds have been dispatched - // at this point in time so overwriting its revents field is - // safe. - pfds->revents = ready_set_events; - this->ready_set_.pfds[this->ready_set_.nfds++] = *pfds; - } + } // The reactor lock is reacquired upon leaving this scope. } return 0; @@ -1525,7 +1590,7 @@ ACE_Dev_Poll_Reactor::register_handler (const ACE_Handle_Set &handle_set, return 0; } - + int ACE_Dev_Poll_Reactor::register_handler (int signum, ACE_Event_Handler *new_sh, @@ -2128,6 +2193,9 @@ ACE_Dev_Poll_Reactor::owner (ACE_thread_t /* new_owner */, { ACE_TRACE ("ACE_Dev_Poll_Reactor::owner"); + // There is no need to set the owner of the event loop. Multiple + // threads may invoke the event loop simulataneously. + return 0; } @@ -2136,6 +2204,9 @@ ACE_Dev_Poll_Reactor::owner (ACE_thread_t * /* owner */) { ACE_TRACE ("ACE_Dev_Poll_Reactor::owner"); + // There is no need to set the owner of the event loop. Multiple + // threads may invoke the event loop simulataneously. + return 0; } @@ -2321,6 +2392,7 @@ ACE_Dev_Poll_Reactor::dump (void) const ACE_TRACE ("ACE_Dev_Poll_Reactor::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("restart_ = %d\n"), this->restart_)); ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("initialized_ = %d"), this->initialized_)); diff --git a/ace/Dev_Poll_Reactor.h b/ace/Dev_Poll_Reactor.h index 662d437d7cd..5a3615ee2e7 100644 --- a/ace/Dev_Poll_Reactor.h +++ b/ace/Dev_Poll_Reactor.h @@ -88,12 +88,13 @@ public: * counted event handlers need not pay for reference counting * resources. */ - size_t refcount; + unsigned long refcount; }; // --------------------------------------------------------------------- +#if 0 /** * @class ACE_Dev_Poll_Ready_Set * @@ -135,6 +136,7 @@ public: int nfds; }; +#endif /* 0 */ // --------------------------------------------------------------------- @@ -376,14 +378,14 @@ public: /** * @return Returns the updated reference count. */ - size_t add_ref (ACE_HANDLE handle); + unsigned long add_ref (ACE_HANDLE handle); /// Decrease the reference count on the event handler corresponding /// to the given file descriptor. /** * @return Returns the updated reference count. */ - size_t remove_ref (ACE_HANDLE handle); + unsigned long remove_ref (ACE_HANDLE handle); //@} /** @@ -864,25 +866,50 @@ public: /// Returns a reference to the Reactor's internal lock. virtual ACE_Lock &lock (void); - /// Wake up all threads in waiting in the event loop + /// Wake up all threads waiting in the event loop. virtual void wakeup_all_threads (void); /// Transfers ownership of Reactor_Impl to the new_owner. + /** + * @note There is no need to set the owner of the event loop for the + * ACE_Dev_Poll_Reactor. Multiple threads may invoke the + * event loop simulataneously. As such, this method is a + * no-op. + */ virtual int owner (ACE_thread_t new_owner, ACE_thread_t *old_owner = 0); /// Return the ID of the "owner" thread. + /** + * @note There is no need to set the owner of the event loop for the + * ACE_Dev_Poll_Reactor. Multiple threads may invoke the + * event loop simulataneously. As such, this method is a + * no-op. + */ virtual int owner (ACE_thread_t *owner); /// Get the existing restart value. virtual int restart (void); /// Set a new value for restart and return the original value. + /** + * @param r If zero, then the event loop will not be automatically + * restarted if the underlying poll is interrupted via the + * INTR (interrupt) signal. + * + * @return Returns the previous "restart" value. + */ virtual int restart (int r); /// Set position of the owner thread. + /** + * @note This is currently a no-op. + */ virtual void requeue_position (int); /// Get position of the owner thread. + /** + * @note This is currently a no-op. + */ virtual int requeue_position (void); /** @@ -914,9 +941,6 @@ public: * @name Low-level ready_set mask manipulation methods * * These methods are unimplemented. - * @par - * As implemented, the ready_set may only be indirectly manipulated - * by returning a value greater than zero from an event handler. */ //@{ @@ -941,6 +965,17 @@ public: protected: + /// Non-locking version of wait_pending(). + /** + * Returns non-zero if there are I/O events "ready" for dispatching, + * but does not actually dispatch the event handlers. By default, + * don't block while checking this, i.e., "poll". + * + * @note It is only possible to achieve millisecond timeout + * resolutions with the ACE_Dev_Poll_Reactor. + */ + int work_pending_i (ACE_Time_Value &max_wait_time); + /// Poll for events and return the number of event handlers that /// were dispatched. /** @@ -948,8 +983,13 @@ protected: */ int handle_events_i (ACE_Time_Value *max_wait_time); + /// Perform the upcall with the given event handler method. + int upcall (ACE_Event_Handler *event_handler, + int (ACE_Event_Handler::*callback)(ACE_HANDLE), + ACE_HANDLE handle); + /** - * Dispatche ACE_Event_Handlers for time events, I/O events, and + * Dispatch ACE_Event_Handlers for time events, I/O events, and * signal events. Returns the total number of ACE_Event_Handlers * that were dispatched or -1 if something goes wrong. */ @@ -1009,17 +1049,19 @@ protected: /// Track HANDLES we are interested in for various events that must /// be dispatched *without* polling. - ACE_Dev_Poll_Ready_Set ready_set_; + /// ACE_Dev_Poll_Ready_Set ready_set_; #if defined (ACE_HAS_EVENT_POLL) - /// The memory map to which `/dev/poll' or `/dev/poll' will feed its - /// results. + /// The memory map that `/dev/epoll' will feed its results to. char *mmap_; #else - /// + /// The pollfd array that `/dev/poll' will feed its results to. struct pollfd *dp_fds_; #endif /* ACE_HAS_EVENT_POLL */ + /// Pointer to the array + struct pollfd *pfds_; + /// This flag is used to keep track of whether we are actively handling /// events or not. sig_atomic_t deactivated_; diff --git a/ace/Dev_Poll_Reactor.inl b/ace/Dev_Poll_Reactor.inl index d7642eede2a..74ff5c2dc2a 100644 --- a/ace/Dev_Poll_Reactor.inl +++ b/ace/Dev_Poll_Reactor.inl @@ -13,13 +13,14 @@ ACE_Dev_Poll_Event_Tuple::ACE_Dev_Poll_Event_Tuple (void) // --------------------------------------------------------------------- - +#if 0 ACE_INLINE ACE_Dev_Poll_Ready_Set::ACE_Dev_Poll_Ready_Set (void) : pfds (0), nfds (0) { } +#endif /* 0 */ // --------------------------------------------------------------------- @@ -90,7 +91,7 @@ ACE_Dev_Poll_Reactor_Handler_Repository::size (void) const return this->max_size_; } -ACE_INLINE size_t +ACE_INLINE unsigned long ACE_Dev_Poll_Reactor_Handler_Repository::add_ref (ACE_HANDLE handle) { // ACE_TRACE ("ACE_Dev_Poll_Reactor_Handler_Repository::add_ref"); @@ -103,7 +104,7 @@ ACE_Dev_Poll_Reactor_Handler_Repository::add_ref (ACE_HANDLE handle) return 0; } -ACE_INLINE size_t +ACE_INLINE unsigned long ACE_Dev_Poll_Reactor_Handler_Repository::remove_ref (ACE_HANDLE handle) { // ACE_TRACE ("ACE_Dev_Poll_Reactor_Handler_Repository::remove_ref"); @@ -112,7 +113,7 @@ ACE_Dev_Poll_Reactor_Handler_Repository::remove_ref (ACE_HANDLE handle) if (this->handle_in_range (handle)) { - size_t & refcount = this->handlers_[handle].refcount; + unsigned long & refcount = this->handlers_[handle].refcount; ACE_ASSERT (refcount > 0); @@ -177,3 +178,24 @@ ACE_Dev_Poll_Handler_Guard::~ACE_Dev_Poll_Handler_Guard (void) * dispatch the handler. */ } + +// --------------------------------------------------------------------- + +ACE_INLINE int +ACE_Dev_Poll_Reactor::upcall (ACE_Event_Handler *event_handler, + int (ACE_Event_Handler::*callback)(ACE_HANDLE), + ACE_HANDLE handle) +{ + // If the handler returns positive value (requesting a reactor + // callback) just call back as many times as the handler requests + // it. Other threads are off handling other things. + int status = 0; + + do + { + status = (event_handler->*callback) (handle); + } + while (status > 0); + + return status; +} |