summaryrefslogtreecommitdiff
path: root/ace/Timer_Queue.cpp
diff options
context:
space:
mode:
authorlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1996-10-21 21:41:34 +0000
committerlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1996-10-21 21:41:34 +0000
commita5fdebc5f6375078ec1763850a4ca23ec7fe6458 (patch)
treebcf0a25c3d45a209a6e3ac37b233a4812f29c732 /ace/Timer_Queue.cpp
downloadATCD-a5fdebc5f6375078ec1763850a4ca23ec7fe6458.tar.gz
Initial revision
Diffstat (limited to 'ace/Timer_Queue.cpp')
-rw-r--r--ace/Timer_Queue.cpp332
1 files changed, 332 insertions, 0 deletions
diff --git a/ace/Timer_Queue.cpp b/ace/Timer_Queue.cpp
new file mode 100644
index 00000000000..9a26fb4bbf0
--- /dev/null
+++ b/ace/Timer_Queue.cpp
@@ -0,0 +1,332 @@
+// Timer_Queue.cpp
+// $Id$
+
+#define ACE_BUILD_DLL
+#include "ace/Timer_Queue.h"
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Timer_Node)
+
+void
+ACE_Timer_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_Node::dump");
+}
+
+ACE_Timer_Node::ACE_Timer_Node (ACE_Event_Handler *h,
+ const void *a,
+ const ACE_Time_Value &t,
+ const ACE_Time_Value &i,
+ ACE_Timer_Node *n,
+ int timer_id)
+ : handler_ (h),
+ arg_ (a),
+ timer_value_ (t),
+ interval_ (i),
+ next_ (n),
+ timer_id_ (timer_id)
+{
+ ACE_TRACE ("ACE_Timer_Node::ACE_Timer_Node");
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Timer_Queue)
+
+void
+ACE_Timer_Queue::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_Queue::dump");
+}
+
+// Create an empty queue.
+
+ACE_Timer_Queue::ACE_Timer_Queue (void)
+ : head_ (0),
+ timer_id_ (0)
+{
+ ACE_TRACE ("ACE_Timer_Queue::ACE_Timer_Queue");
+}
+
+// Checks if queue is empty.
+
+int
+ACE_Timer_Queue::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Timer_Queue::is_empty");
+ return this->head_ == 0;
+}
+
+// Returns earliest time in a non-empty queue.
+
+const ACE_Time_Value &
+ACE_Timer_Queue::earliest_time (void) const
+{
+ ACE_TRACE ("ACE_Timer_Queue::earliest_time");
+ return this->head_->timer_value_;
+}
+
+// Remove all remaining items in the queue.
+
+ACE_Timer_Queue::~ACE_Timer_Queue (void)
+{
+ ACE_TRACE ("ACE_Timer_Queue::~ACE_Timer_Queue");
+ ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_));
+
+ ACE_Timer_Node *curr = this->head_;
+
+ while (curr != 0)
+ {
+ ACE_Timer_Node *next = curr->next_;
+ delete curr;
+ curr = next;
+ }
+}
+
+// Reschedule a periodic timer. This function must be called with the
+// mutex lock held.
+
+void
+ACE_Timer_Queue::reschedule (ACE_Timer_Node *expired)
+{
+ ACE_TRACE ("ACE_Timer_Queue::reschedule");
+ if (this->is_empty () || expired->timer_value_ < this->earliest_time ())
+ {
+ expired->next_ = this->head_;
+ this->head_ = expired;
+ }
+ else
+ {
+ ACE_Timer_Node *prev = this->head_;
+ ACE_Timer_Node *after = this->head_->next_;
+
+ // Locate the proper position in the queue.
+
+ while (after != 0
+ && expired->timer_value_ > after->timer_value_)
+ {
+ prev = after;
+ after = after->next_;
+ }
+
+ expired->next_ = after;
+ prev->next_ = expired;
+ }
+}
+
+// Insert a new handler that expires at time future_time; if interval
+// is > 0, the handler will be reinvoked periodically.
+
+int
+ACE_Timer_Queue::schedule (ACE_Event_Handler *handler,
+ const void *arg,
+ const ACE_Time_Value &future_time,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_Timer_Queue::schedule");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ // Increment the sequence number (it will wrap around).
+ this->timer_id_++;
+
+ if (this->is_empty () || future_time < this->earliest_time ())
+ {
+ // Place at the beginning of the list.
+ ACE_NEW_RETURN (this->head_,
+ ACE_Timer_Node (handler,
+ arg,
+ future_time,
+ interval,
+ this->head_,
+ this->timer_id_),
+ -1);
+ return this->head_ ? this->timer_id_ : -1;
+ }
+ else // Place in the middle of the list somewhere.
+ {
+ ACE_Timer_Node *prev = this->head_;
+ ACE_Timer_Node *after = this->head_->next_;
+
+ while (after != 0 && future_time > after->timer_value_)
+ {
+ prev = after;
+ after = after->next_;
+ }
+
+ ACE_NEW_RETURN (prev->next_,
+ ACE_Timer_Node (handler,
+ arg,
+ future_time,
+ interval,
+ after,
+ this->timer_id_),
+ -1);
+ return prev->next_ ? this->timer_id_ : -1;
+ }
+}
+
+// Locate and remove the single <ACE_Event_Handler> with a value of
+// <timer_id> from the timer queue.
+
+int
+ACE_Timer_Queue::cancel (int timer_id, const void **arg)
+{
+ ACE_TRACE ("ACE_Timer_Queue::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ACE_Timer_Node *prev = 0;
+ ACE_Timer_Node *curr = 0;
+
+ // Try to locate the ACE_Timer_Node that matches the timer_id.
+
+ for (curr = this->head_;
+ curr != 0 && curr->timer_id_ != timer_id;
+ curr = curr->next_)
+ prev = curr;
+
+ if (curr != 0)
+ {
+ if (prev == 0)
+ this->head_ = curr->next_;
+ else
+ prev->next_ = curr->next_;
+
+ if (arg != 0)
+ *arg = curr->arg_;
+
+ delete curr;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+// Locate and remove all values of <handler> from the timer queue.
+
+int
+ACE_Timer_Queue::cancel (ACE_Event_Handler *handler)
+{
+ ACE_TRACE ("ACE_Timer_Queue::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ACE_Timer_Node *prev = 0;
+ ACE_Timer_Node *curr = this->head_;
+
+ while (curr != 0)
+ {
+ if (curr->handler_ == handler)
+ {
+ if (prev == 0)
+ {
+ this->head_ = curr->next_;
+ delete curr;
+ curr = this->head_;
+ }
+ else
+ {
+ prev->next_ = curr->next_;
+ delete curr;
+ curr = prev->next_;
+ }
+ }
+ else
+ {
+ prev = curr;
+ curr = curr->next_;
+ }
+ }
+
+ return 0;
+}
+
+// Run the <handle_timeout> method for all Timers whose values are <=
+// <cur_time>.
+
+int
+ACE_Timer_Queue::expire (const ACE_Time_Value &cur_time)
+{
+ ACE_TRACE ("ACE_Timer_Queue::expire");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ for (;;)
+ {
+ if (this->is_empty () || this->earliest_time () > cur_time)
+ break; // There aren't any more timers eligible to expire.
+
+ ACE_Timer_Node *expired = this->head_;
+ ACE_Event_Handler *handler =
+ (ACE_Event_Handler *) expired->handler_;
+ const void *arg = expired->arg_;
+ int reclaim = 1;
+ int result;
+
+ this->head_ = this->head_->next_;
+
+ // Check whether this is an interval timer.
+ if (expired->interval_ > ACE_Time_Value::zero)
+ {
+ // Make sure that we skip past values that have already
+ // "expired".
+ do
+ expired->timer_value_ += expired->interval_;
+ while (expired->timer_value_ <= cur_time);
+
+ // Since this is an interval timer, we need to reschedule
+ // it.
+ this->reschedule (expired);
+ reclaim = 0;
+ }
+
+ // Perform the callback.
+ result = handler->handle_timeout (cur_time, arg);
+
+ if (result == -1)
+ this->cancel (handler);
+
+ if (reclaim)
+ delete expired;
+ }
+ return 0;
+}
+
+// Determines the maximum amount of time that the Reactor must wait
+// before timing out. This is computed as the smaller of (1) the
+// amount the caller requested when calling handle_events() and (2)
+// the earliest time registered in the Timer Queue (if any). Must be
+// called with locks held since it returns a pointer to a Time_Value
+// object stored in the Timer_Queue object itself. If the lock isn't
+// held we'll have reentrancy problems!)
+
+ACE_Time_Value *
+ACE_Timer_Queue::calculate_timeout (ACE_Time_Value *max_wait_time)
+{
+ ACE_TRACE ("ACE_Timer_Queue::calculate_timeout");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, max_wait_time));
+
+ if (this->is_empty ())
+ // Nothing on the Timer_Queue, so use whatever the caller gave us.
+ return max_wait_time;
+ else
+ {
+ ACE_Time_Value cur_time = ACE_OS::gettimeofday ();
+
+ if (this->earliest_time () > cur_time)
+ {
+ // The earliest item on the Timer_Queue is still in the
+ // future. Therefore, use the smaller of (1) caller's wait
+ // time or (2) the delta time between now and the earliest
+ // time on the Timer_Queue.
+
+ this->timeout_ = this->earliest_time () - cur_time;
+ if (max_wait_time == 0 || *max_wait_time > timeout_)
+ return &this->timeout_;
+ else
+ return max_wait_time;
+ }
+ else
+ {
+ // The earliest item on the Timer_Queue is now in the past.
+ // Therefore, we've got to "poll" the Reactor, i.e., it must
+ // just check the descriptors and then dispatch timers, etc.
+ this->timeout_ = ACE_Time_Value::zero;
+ return &this->timeout_;
+ }
+ }
+}