summaryrefslogtreecommitdiff
path: root/ace/ReactorEx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ace/ReactorEx.cpp')
-rw-r--r--ace/ReactorEx.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/ace/ReactorEx.cpp b/ace/ReactorEx.cpp
new file mode 100644
index 00000000000..6a55493a11b
--- /dev/null
+++ b/ace/ReactorEx.cpp
@@ -0,0 +1,282 @@
+// ReactorEx.cpp
+// $Id$
+
+#define ACE_BUILD_DLL
+#include "ace/ReactorEx.h"
+
+#if defined (ACE_WIN32)
+
+#if !defined (__ACE_INLINE__)
+#include "ace/ReactorEx.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_ReactorEx::ACE_ReactorEx (void)
+ : active_handles_ (0),
+ timer_skew_ (0, ACE_TIMER_SKEW),
+ token_ (*this)
+{
+ if (this->register_handler (&this->notify_handler_) == -1)
+ ACE_ERROR ((LM_ERROR, "%p\n", "registering notify handler"));
+}
+
+ACE_ReactorEx::~ACE_ReactorEx (void)
+{
+}
+
+int
+ACE_ReactorEx::notify (void)
+{
+ ACE_GUARD_RETURN (ACE_ReactorEx_Token, ace_mon, this->token_, -1);
+
+ return notify_handler_.notify ();
+}
+
+int
+ACE_ReactorEx::register_handler (ACE_Event_Handler *eh,
+ ACE_HANDLE handle)
+{
+ ACE_GUARD_RETURN (ACE_ReactorEx_Token, ace_mon, this->token_, -1);
+
+ if (this->active_handles_ >= ACE_ReactorEx::MAX_SIZE)
+ return -1;
+
+ if (handle == ACE_INVALID_HANDLE)
+ handle = eh->get_handle ();
+ this->handles_[this->active_handles_] = handle;
+ this->handlers_[this->active_handles_] = eh;
+ this->active_handles_++;
+ return 0;
+}
+
+// Removes -eh- from the ReactorEx. Note that the ReactorEx will call
+// eh->get_handle() to extract the underlying I/O handle.
+
+int
+ACE_ReactorEx::remove_handler (ACE_Event_Handler *eh,
+ ACE_Reactor_Mask mask)
+{
+ ACE_GUARD_RETURN (ACE_ReactorEx_Token, ace_mon, this->token_, -1);
+
+ ACE_HANDLE handle = eh->get_handle ();
+
+ // Go through all the handles looking for -handle-. Even if we find
+ // it, we continue through the rest of the list. -handle- could
+ // appear multiple times.
+ for (size_t index = 0; index < this->active_handles_; index++)
+ {
+ if (this->handles_[index] == handle)
+ {
+ if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::DONT_CALL) == 0)
+ handlers_[index]->handle_close (handle,
+ ACE_Event_Handler::NULL_MASK);
+
+ // If there was only one handle, reset the pointer to 0.
+ if (this->active_handles_ == 1)
+ {
+ // This is logically correct, but probably should never
+ // happen. This means that ACE_ReactorEx_Notify is
+ // being removed! We'll do it anyway and print out a
+ // warning.
+ this->active_handles_ = 0;
+ ACE_ERROR ((LM_ERROR, "ReactorEx: ReactorEx_Notify was"
+ "just removed!\n"));
+ }
+ // Otherwise, take the handle and handler from the back and
+ // overwrite the ones being removed.
+ else
+ {
+ this->handles_[index] = this->handles_[--this->active_handles_];
+ this->handlers_[index] = this->handlers_[this->active_handles_];
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+ACE_ReactorEx::schedule_timer (ACE_Event_Handler *handler,
+ const void *arg,
+ const ACE_Time_Value &delta_time,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_ReactorEx::schedule_timer");
+
+ return this->timer_queue_.schedule
+ (handler, arg, ACE_OS::gettimeofday () + delta_time, interval);
+}
+
+int
+ACE_ReactorEx::handle_events (ACE_Time_Value *how_long,
+ int wait_all)
+{
+ // @@ Need to implement -wait_all-.
+
+ DWORD wait_status;
+ int handles_skipped = 0;
+ // These relative_things are moved through the handles_ each time
+ // handle_events is called. Set relative index = -1 so we can check
+ // in case of timeouts.
+ int relative_index = -1;
+ ACE_HANDLE *relative_handles = this->handles_;
+ ACE_Event_Handler **relative_handlers = this->handlers_;
+
+ // Stash the current time.
+ ACE_Time_Value prev_time = ACE_OS::gettimeofday ();
+ // Check for pending timeout events.
+ how_long = timer_queue_.calculate_timeout (how_long);
+ // Translate into Win32 time value.
+ int timeout = how_long == 0 ? INFINITE : how_long->msec ();
+
+ int active_handles = this->active_handles_;
+
+ while (active_handles > 0)
+ {
+ wait_status = ::WaitForMultipleObjects (active_handles,
+ relative_handles,
+ wait_all,
+ timeout);
+ if (!this->timer_queue_.is_empty ())
+ // Fudge factor accounts for problems with Solaris timers...
+ this->timer_queue_.expire (ACE_OS::gettimeofday () + this->timer_skew_);
+
+ // Compute the time while the ReactorEx was processing.
+ ACE_Time_Value elapsed_time = ACE_OS::gettimeofday () - prev_time;
+
+ // Update -how_long- to reflect the amount of time since
+ // handle_events was called. This is computed in case we return
+ // from the switch.
+ if (how_long != 0)
+ {
+ if (*how_long > elapsed_time)
+ *how_long = *how_long - elapsed_time;
+ else
+ *how_long = ACE_Time_Value::zero; // Used all of timeout.
+ }
+
+ switch (wait_status)
+ {
+ case WAIT_TIMEOUT:
+ errno = ETIME;
+ // If we timed out on the first call, return 0, otherwise
+ // an event must have occured; return 1.
+ return relative_index == -1 ? 0 : 1;
+ case WAIT_FAILED:
+ errno = ::GetLastError ();
+ return -1;
+ default:
+ {
+ // @@ Need to implement WAIT_ABANDONED_0 stuff.
+ relative_index = wait_status - WAIT_OBJECT_0;
+
+ if (relative_handlers[relative_index]->handle_signal (0) == -1)
+ // If we remove a handler, then the index should stay
+ // the same, since it may have been replaced with the
+ // end handle by remove_handler.
+ this->remove_handler (relative_handlers[relative_index]);
+ else
+ // If we did not remove the handler, then move the index
+ // up one so that we skip this handler on the next
+ // iteration.
+ relative_index++;
+
+ // Update the relative pointers.
+ relative_handles = &relative_handles[relative_index];
+ relative_handlers = &relative_handlers[relative_index];
+
+ // The number of remaining active handles is
+ // active_handles_ less the number of handles we skipped
+ // over.
+ handles_skipped += relative_index;
+ active_handles = this->active_handles_ - handles_skipped;
+
+ // Make the timeout be zero so that we don't block on any
+ // subsequent calls to WaitForMultipleObjects. Rather, we
+ // just poll through the rest looking for signaled handles.
+ timeout = 0;
+ }
+ }
+ }
+
+ // Compute the time while the ReactorEx was processing. Note that
+ // this is recomputed to reflect time spent dispatching handlers.
+ ACE_Time_Value elapsed_time = ACE_OS::gettimeofday () - prev_time;
+
+ // Update how_long to reflect the amount of time since handle_events
+ // was called.
+ if (how_long != 0)
+ {
+ if (*how_long > elapsed_time)
+ *how_long = *how_long - elapsed_time;
+ else
+ *how_long = ACE_Time_Value::zero; // Used all of timeout.
+ }
+
+ return 0;
+}
+
+// ************************************************************
+
+void
+ACE_ReactorEx_Token::dump (void) const
+{
+ ACE_TRACE ("ACE_ReactorEx_Token::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, "\n"));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_ReactorEx_Token::ACE_ReactorEx_Token (ACE_ReactorEx &r)
+ : reactorEx_ (r)
+#if defined (ACE_ReactorEx_HAS_DEADLOCK_DETECTION)
+ , ACE_Local_Mutex (0) // Triggers unique name by stringifying "this"...
+#endif /* ACE_ReactorEx_HAS_DEADLOCK_DETECTION */
+{
+ ACE_TRACE ("ACE_ReactorEx_Token::ACE_ReactorEx_Token");
+}
+
+// Used to wakeup the Reactor.
+
+void
+ACE_ReactorEx_Token::sleep_hook (void)
+{
+ ACE_TRACE ("ACE_ReactorEx_Token::sleep_hook");
+ if (this->reactorEx_.notify () == -1)
+ ACE_ERROR ((LM_ERROR, "%p\n", "sleep_hook failed"));
+}
+
+// ************************************************************
+
+ACE_ReactorEx_Notify::ACE_ReactorEx_Notify (void)
+{
+ // Create an "auto-reset" event that is used to unblock the
+ // ReactorEx.
+ handle_ = ::CreateEvent (NULL, FALSE, FALSE, NULL);
+}
+
+ACE_ReactorEx_Notify::~ACE_ReactorEx_Notify (void)
+{
+ ACE_OS::close (handle_);
+}
+
+ACE_HANDLE
+ACE_ReactorEx_Notify::get_handle (void) const
+{
+ return this->handle_;
+}
+
+int
+ACE_ReactorEx_Notify::handle_signal (int signum, siginfo_t *, ucontext_t *)
+{
+ // Do nothing.
+ return 0;
+}
+
+int
+ACE_ReactorEx_Notify::notify (void)
+{
+ return ::SetEvent (handle_) ? 0 : -1;
+}
+
+#endif /* ACE_WIN32 */