diff options
author | brunsch <brunsch@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1997-06-04 00:28:45 +0000 |
---|---|---|
committer | brunsch <brunsch@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1997-06-04 00:28:45 +0000 |
commit | 1e92c1984331cacea0b72d9d817f28b8dacdc218 (patch) | |
tree | df56cae7425595d3da052496955161fadc6bc852 /ace/Timer_Wheel_T.cpp | |
parent | 35d1135d0091ec71142a95fdbc7c3a3bb741ebec (diff) | |
download | ATCD-1e92c1984331cacea0b72d9d817f28b8dacdc218.tar.gz |
*** empty log message ***
Diffstat (limited to 'ace/Timer_Wheel_T.cpp')
-rw-r--r-- | ace/Timer_Wheel_T.cpp | 539 |
1 files changed, 366 insertions, 173 deletions
diff --git a/ace/Timer_Wheel_T.cpp b/ace/Timer_Wheel_T.cpp index 99d597f18e7..ceb8e44bf7d 100644 --- a/ace/Timer_Wheel_T.cpp +++ b/ace/Timer_Wheel_T.cpp @@ -5,90 +5,156 @@ #include "ace/Timer_Wheel_T.h" + +// Constructor that takes in a <wheel>, a reference to the timer queue + template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Wheel_Iterator_T (ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK> &wheel) : timer_wheel_ (wheel) { + // Nothing } -template <class TYPE, class FUNCTOR, class LOCK> int -ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>::next (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *&node, - const ACE_Time_Value &cur_time) + +// Positions the iterator at the first node in the timing wheel + +template <class TYPE, class FUNCTOR, class LOCK> void +ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>::first (void) { - if (this->timer_wheel_.wheel_[this->pos_]->next_ == this->timer_wheel_.wheel_[this->pos_] - || this->timer_wheel_.wheel_[this->pos_]->next_->timer_value_ > this->time_) + for (this->pos_ = 0; + this->pos_ < this->timer_wheel_.wheel_size_; + this->pos_++) { - ACE_Time_Value et = this->timer_wheel_.earliest_time (); + // Skip over empty entries + if (this->timer_wheel_.wheel_[this->pos_]->get_next () != + this->timer_wheel_.wheel_[this->pos_]) + { + this->list_item_ = this->timer_wheel_.wheel_[this->pos_]->get_next (); + return; + } + } + + // The queue is empty if we are here + this->list_item_ = NULL; +} - if (this->timer_wheel_.size_ == 0 || et > cur_time) - return 0; - this->pos_ = (et.usec () / this->timer_wheel_.resolution_) - % this->timer_wheel_.wheel_size_; - this->time_ = ACE_Time_Value (et.sec (), - this->pos_ * this->timer_wheel_.resolution_); +// Positions the iterator at the next node in list or goes to the next +// list + +template <class TYPE, class FUNCTOR, class LOCK> void +ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>::next (void) +{ + if (this->isdone ()) + return; + + this->list_item_ = this->list_item_->get_next (); + + // If there is no more in the current list, go to the next + if (this->list_item_ == this->timer_wheel_.wheel_[this->pos_]) + { + for (this->pos_++; this->pos_ < this->timer_wheel_.wheel_size_; this->pos_++) + { + // Check for an empty entry + if (this->timer_wheel_.wheel_[this->pos_]->get_next () != + this->timer_wheel_.wheel_[this->pos_]) + { + this->list_item_ = this->timer_wheel_.wheel_[this->pos_]->get_next (); + return; + } + } + + this->list_item_ = NULL; } +} - // Remove the earliest item - node = this->timer_wheel_.wheel_[this->pos_]->next_; - node->prev_->next_ = node->next_; - node->next_->prev_ = node->prev_; - this->timer_wheel_.size_--; - return 1; +// Returns true when we are at the end (when list_item_ == 0) + +template <class TYPE, class FUNCTOR, class LOCK> int +ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>::isdone (void) +{ + return this->list_item_ == NULL; } -template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>::reset (void) + +// Returns the node at the current position in the sequence + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * +ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>::item (void) { - ACE_Time_Value et = this->timer_wheel_.earliest_time (); + if (this->isdone ()) + return NULL; - this->pos_ = (et.usec () / this->timer_wheel_.resolution_) - % this->timer_wheel_.wheel_size_; - this->time_ = ACE_Time_Value (et.sec (), - this->pos_ * this->timer_wheel_.resolution_); + return this->list_item_; } -ACE_ALLOC_HOOK_DEFINE(ACE_Timer_Wheel_T) - template <class TYPE, class FUNCTOR, class LOCK> +// Constructor that sets up the timing wheel and also may preallocate some +// nodes on the free list + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Wheel_T (size_t wheelsize, size_t resolution, size_t prealloc, - FUNCTOR *upcall_functor) - : INHERITED (upcall_functor), + FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) + : INHERITED (upcall_functor, freelist), wheel_size_ (wheelsize), resolution_ (resolution), - current_pos_ ((ACE_OS::gettimeofday ().usec () / resolution) % wheel_size_), - current_time_ (ACE_OS::gettimeofday ()), - size_ (0), - iterator_ (*this), - freelist_ (NULL) + earliest_pos_ (0), + iterator_ (*this) { ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T"); size_t i; + this->gettimeofday (ACE_High_Res_Timer::gettimeofday); + // Create the timing wheel - ACE_NEW (this->wheel_, (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *[wheelsize])); + ACE_NEW (this->wheel_, (ACE_Timer_Node_T<TYPE> *[wheelsize])); + + // Create the dummy nodes for (i = 0; i < wheelsize; i++) { - // Create the dummy nodes - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *tempnode = this->alloc_node (); - tempnode->next_ = tempnode->prev_ = tempnode; + ACE_Timer_Node_T<TYPE> *tempnode = this->alloc_node (); + tempnode->set_next (tempnode); + tempnode->set_prev (tempnode); this->wheel_[i] = tempnode; } // Do the preallocation - for (i = 0; i < prealloc; i++) + this->free_list_->resize (prealloc); +} + +template <class TYPE, class FUNCTOR, class LOCK> +ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Wheel_T (FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) + : INHERITED (upcall_functor, freelist), + wheel_size_ (ACE_DEFAULT_TIMER_WHEEL_SIZE), + resolution_ (ACE_DEFAULT_TIMER_WHEEL_RESOLUTION), + earliest_pos_ (0), + iterator_ (*this) +{ + ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T"); + size_t i; + + this->gettimeofday (ACE_High_Res_Timer::gettimeofday); + + // Create the timing wheel + ACE_NEW (this->wheel_, (ACE_Timer_Node_T<TYPE> *[this->wheel_size_])); + + // Create the dummy nodes + for (i = 0; i < this->wheel_size_; i++) { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp; - ACE_NEW (temp, (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>)); - temp->next_ = this->freelist_; - this->freelist_ = temp; + ACE_Timer_Node_T<TYPE> *tempnode = this->alloc_node (); + tempnode->set_next (tempnode); + tempnode->set_prev (tempnode); + this->wheel_[i] = tempnode; } } +// Destructor just cleans up its memory template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_Wheel_T (void) @@ -98,65 +164,50 @@ ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_Wheel_T (void) for (size_t i = 0; i < this->wheel_size_; i++) { // delete nodes until only the dummy node is left - while (this->wheel_[i]->next_ != this->wheel_[i]) + while (this->wheel_[i]->get_next () != this->wheel_[i]) { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *next = this->wheel_[i]->next_; - this->wheel_[i]->next_ = next->next_; - next->next_->prev_ = this->wheel_[i]; - this->free_node (next); + ACE_Timer_Node_T<TYPE> *next = this->wheel_[i]->get_next (); + this->wheel_[i]->set_next (next->get_next ()); + next->get_next ()->set_prev (this->wheel_[i]); + this->upcall_functor ().deletion (*this, next->get_type (), next->get_act ()); + this->free_node (next); } // and now delete the dummy node delete this->wheel_[i]; } - // Get rid of the freelist now - while (this->freelist_ != NULL) - { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->freelist_; - this->freelist_ = temp->next_; - delete temp; - } - + // finally delete the wheel delete [] this->wheel_; } + +// Checks to see if <earliest_pos> points to a empty list (then it is empty) + template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::is_empty (void) const { ACE_TRACE ("ACE_Timer_Wheel_T::is_empty"); - // Just check the size - return this->size_ == 0; + return this->wheel_[this->earliest_pos_]->get_next () == this->wheel_[this->earliest_pos_]; } + +// Returns the first (earliest) node in the <wheel_>'s <earliest_pos_> list + template <class TYPE, class FUNCTOR, class LOCK> const ACE_Time_Value & ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::earliest_time (void) const { ACE_TRACE ("ACE_Timer_Wheel_T::earliest_time"); - ACE_Time_Value earliest_time; - size_t earliest_pos = 0; - - // Check every entry in the table - for (size_t i = 0; i < this->wheel_size_; i++) - { - // Check for an empty entry - if (this->wheel_[i]->next_ != this->wheel_[i]) - { - // if initialization or if the time is earlier - if (earliest_time == ACE_Time_Value::zero - || this->wheel_[i]->timer_value_ < earliest_time) - { - earliest_time = this->wheel_[i]->next_->timer_value_; - earliest_pos = i; - } - } - } - - return this->wheel_[earliest_pos]->next_->timer_value_; + if (this->is_empty ()) + return ACE_Time_Value::zero; + else + return this->wheel_[this->earliest_pos_]->get_next ()->get_timer_value (); } +// Create the node and pass it to reschedule. Also check to see if the +// <earliest_pos> should be changed. template <class TYPE, class FUNCTOR, class LOCK> long ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::schedule (const TYPE &type, @@ -167,30 +218,36 @@ ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::schedule (const TYPE &type, ACE_TRACE ("ACE_Timer_Wheel_T::schedule"); ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *tempnode = this->alloc_node (); + ACE_Timer_Node_T<TYPE> *tempnode = this->alloc_node (); if (tempnode) { // Note that the timer_id is actually the pointer to the node - // Use operator placement new. - new (tempnode) ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> (type, - act, - delay, - interval, - NULL, - NULL, - (long) tempnode); - + // Set the details of the node + tempnode->set (type, + act, + delay, + interval, + NULL, + NULL, + (long) tempnode); + + // Reschedule will insert it into the correct position this->reschedule (tempnode); - return tempnode->timer_id_; + + return tempnode->get_timer_id (); } - // Failure return. + // Failure return errno = ENOMEM; return -1; } + +// Goes through every list in the wheel and if it finds a node with <type> +// then it removes the node and continues on looking for other nodes + template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::cancel (const TYPE &type, int dont_call_handle_close) @@ -200,38 +257,66 @@ ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::cancel (const TYPE &type, int number_of_cancellations = 0; + // Walk through the wheel for (size_t i = 0; i < this->wheel_size_; i++) { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *curr = this->wheel_[i]->next_; + ACE_Timer_Node_T<TYPE> *curr = this->wheel_[i]->get_next (); + // Walk through the list while (curr != this->wheel_[i]) { - if (curr->type_ == type) + if (curr->get_type () == type) { + // Cancel it and remove it. number_of_cancellations++; if (dont_call_handle_close == 0 && number_of_cancellations == 1) - this->upcall_functor_.cancellation (*this, curr->type_); + this->upcall_functor ().cancellation (*this, curr->get_type ()); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *tempnode = curr; - curr->prev_->next_ = curr->next_; - curr->next_->prev_ = curr->prev_; - curr = curr->next_; - - this->free_node (tempnode); + // Detach it from the list + ACE_Timer_Node_T<TYPE> *tempnode = curr; + curr->get_prev ()->set_next (curr->get_next ()); + curr->get_next ()->set_prev (curr->get_prev ()); + + // Go on to the next and delete the detached node + curr = curr->get_next (); + this->free_node (tempnode); } else { - curr = curr->next_; + curr = curr->get_next (); } } } - this->size_ -= number_of_cancellations; + // Look for a new earliest time + + ACE_Time_Value earliest_time; // defaults to zero + + // Check every entry in the table + for (i = 0; i < this->wheel_size_; i++) + { + // Skip empty entries + if (this->wheel_[i]->get_next () != this->wheel_[i]) + { + // if initialization or if the time is earlier + if (earliest_time == ACE_Time_Value::zero + || this->wheel_[i]->get_timer_value () < earliest_time) + { + earliest_time = this->wheel_[i]->get_next ()->get_timer_value (); + this->earliest_pos_ = i; + } + } + } + return number_of_cancellations; } + +// Takes the <timer_id> and casts it to a pointer. Then it removes it +// from its neighbors + template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::cancel (long timer_id, const void **act, @@ -240,30 +325,62 @@ ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::cancel (long timer_id, ACE_TRACE ("ACE_Timer_Wheel_T::cancel"); ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *node = (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *) timer_id; + // Make sure we are getting a valid <timer_id>, not an error + // returned by schedule () + if (timer_id == -1) + return 0; - ACE_ASSERT (timer_id == node->timer_id_); - - // Check to see if the node looks like a true ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> - if (timer_id == node->timer_id_) + ACE_Timer_Node_T<TYPE> *node = (ACE_Timer_Node_T<TYPE> *) timer_id; + + // Check to see if the node looks like a true ACE_Timer_Node_T<TYPE> + if (timer_id == node->get_timer_id ()) { - node->next_->prev_ = node->prev_; - node->prev_->next_ = node->next_; + node->get_next ()->set_prev (node->get_prev ()); + node->get_prev ()->set_next (node->get_next ()); if (act != 0) - *act = node->act_; + *act = node->get_act (); if (dont_call_handle_close == 0) - this->upcall_functor_.cancellation (*this, node->type_); + this->upcall_functor ().cancellation (*this, node->get_type ()); + + // Find out what position it is in + size_t pos = (node->get_timer_value ().usec () / this->resolution_) % this->wheel_size_; this->free_node (node); - this->size_--; + + // Get the new earliest time if we have to + + if (pos == this->earliest_pos_) + { + ACE_Time_Value earliest_time; // defaults to zero + + // Check every entry in the table + for (size_t i = 0; i < this->wheel_size_; i++) + { + // Skip empty entries + if (this->wheel_[i]->get_next () != this->wheel_[i]) + { + // if initialization or if the time is earlier + if (earliest_time == ACE_Time_Value::zero + || this->wheel_[i]->get_timer_value () < earliest_time) + { + earliest_time = this->wheel_[i]->get_next ()->get_timer_value (); + this->earliest_pos_ = i; + } + } + } + } + return 1; } // Didn't find it if we are here return 0; } + + +// Dumps out some properties of this object template <class TYPE, class FUNCTOR, class LOCK> void ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::dump (void) const @@ -273,119 +390,195 @@ ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::dump (void) const ACE_DEBUG ((LM_DEBUG, "\nwheel_size_ = %d", this->wheel_size_)); ACE_DEBUG ((LM_DEBUG, "\nresolution_ = %d", this->resolution_)); - ACE_DEBUG ((LM_DEBUG, "\ncurrent_pos_ = %d", this->current_pos_)); - ACE_DEBUG ((LM_DEBUG, "\nsize_ = %d", this->size_)); ACE_DEBUG ((LM_DEBUG, "\nwheel_ = \n")); for (size_t i = 0; i < this->wheel_size_; i++) { ACE_DEBUG ((LM_DEBUG, "%d\n", i)); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->wheel_[i]->next_; + ACE_Timer_Node_T<TYPE> *temp = this->wheel_[i]->get_next (); while (temp != this->wheel_[i]) { temp->dump (); - temp = temp->next_; + temp = temp->get_next (); } } ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } -template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> * -ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::alloc_node (void) -{ - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp; - if (this->freelist_ == NULL) - { - ACE_NEW_RETURN (temp, - (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>), - 0); - } - else - { - temp = this->freelist_; - this->freelist_ = temp->next_; - } - - return temp; -} +// Removes the earliest node and then find the new <earliest_pos_> -template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::free_node (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *node) +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * +ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::remove_first (void) { - // Add to the beginning of the freelist - node->next_ = this->freelist_; - this->freelist_ = node; + ACE_TRACE ("ACE_Timer_Wheel_T::remove_first"); - // Change the timer id so a cancel on this would not try to - // delete it - node->timer_id_ = 0; -} - -template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> * -ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::remove (void) -{ - ACE_TRACE ("ACE_Timer_Wheel_T::remove"); + // Remove the item + ACE_Timer_Node_T<TYPE> *temp = this->wheel_[this->earliest_pos_]->get_next (); + temp->get_prev ()->set_next (temp->get_next ()); + temp->get_next ()->set_prev (temp->get_prev ()); ACE_Time_Value earliest_time; - size_t earliest_pos = 0; - - // Check every entry in the table + + // Check every entry in the table for the new earliest item for (size_t i = 0; i < this->wheel_size_; i++) { // Check for an empty entry - if (this->wheel_[i]->next_ != this->wheel_[i]) + if (this->wheel_[i]->get_next () != this->wheel_[i]) { // if initialization or if the time is earlier if (earliest_time == ACE_Time_Value::zero - || this->wheel_[i]->timer_value_ < earliest_time) + || this->wheel_[i]->get_timer_value () < earliest_time) { - earliest_time = this->wheel_[i]->next_->timer_value_; - earliest_pos = i; + earliest_time = this->wheel_[i]->get_next ()->get_timer_value (); + this->earliest_pos_ = i; } } } - // Remove and return - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->wheel_[earliest_pos]->next_; - temp->prev_->next_ = temp->next_; - temp->next_->prev_ = temp->prev_; - - this->size_--; return temp; } + +// Takes an ACE_Timer_Node and inserts it into the correct position in the correct +// list + template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::reschedule (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *expired) +ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::reschedule (ACE_Timer_Node_T<TYPE> *expired) { ACE_TRACE ("ACE_Timer_Wheel_T::reschedule"); - size_t pos = (expired->timer_value_.usec () / this->resolution_) % this->wheel_size_; + size_t pos = (expired->get_timer_value ().usec () / this->resolution_) % this->wheel_size_; + + // See if we need to update the earliest time + if (this->earliest_time () == ACE_Time_Value::zero + || this->earliest_time () < expired->get_timer_value ()) + this->earliest_pos_ = pos; // Insert time into dummy node - this->wheel_[pos]->timer_value_ = expired->timer_value_; - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *cursor = this->wheel_[pos]->next_; + this->wheel_[pos]->set_timer_value (expired->get_timer_value ()); + ACE_Timer_Node_T<TYPE> *cursor = this->wheel_[pos]->get_next (); // Find position to insert - while (cursor->timer_value_ < expired->timer_value_) - cursor = cursor->next_; + while (cursor->get_timer_value () < expired->get_timer_value ()) + cursor = cursor->get_next (); // Insert - expired->prev_ = cursor->prev_; - expired->next_ = cursor; - cursor->prev_ = expired; - expired->prev_->next_ = expired; - - this->size_++; + expired->set_prev (cursor->get_prev ()); + expired->set_next (cursor); + cursor->set_prev (expired); + expired->get_prev ()->set_next (expired); } + +// Just return the iterator + template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> & ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::iter (void) { - this->iterator_.reset (); return this->iterator_; } + +// Specialized expire which expires in total order. It is optimized by keeping +// track of the list with the earliest element and the next earliest list. It +// then goes through the earliest list until it can switch to the second list. +// it keeps going until it finishes with everything before the <cur_time> + +template <class TYPE, class FUNCTOR, class LOCK> int +ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>::expire (const ACE_Time_Value &cur_time) +{ + ACE_TRACE ("ACE_Timer_Wheel_T::expire"); + ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); + + int number_of_timers_expired = 0; + size_t i; + size_t earliest = this->wheel_size_; + ACE_Time_Value earliest_time = cur_time; + size_t next_earliest = this->wheel_size_; + ACE_Time_Value next_earliest_time; + + // Find the earliest time + for (i = 0; i < this->wheel_size_; i++) + { + if (this->wheel_[i]->get_next () != this->wheel_[i] + && this->wheel_[i]->get_next ()->get_timer_value () < earliest_time) + { + earliest = i; + earliest_time = this->wheel_[i]->get_next ()->get_timer_value (); + } + } + + // Check to see if there is anything to expire + if (this->wheel_[earliest]->get_next ()->get_timer_value () > cur_time) + return 0; + + do + { + next_earliest_time = cur_time; + + // Find 2nd earliest position + for (i = 0; i < this->wheel_size_; i++) + { + if (i != earliest + && this->wheel_[i]->get_next () != this->wheel_[i] + && this->wheel_[i]->get_next ()->get_timer_value () < next_earliest_time) + { + next_earliest = i; + next_earliest_time = this->wheel_[i]->get_next ()->get_timer_value (); + } + } + + while (this->wheel_[earliest]->get_next ()->get_timer_value () < next_earliest_time) + { + // Remove the first node in the earliest position + ACE_Timer_Node_T<TYPE> *expired = this->wheel_[earliest]->get_next (); + this->wheel_[earliest]->set_next (expired->get_next ()); + expired->get_next ()->set_prev (this->wheel_[earliest]); + + TYPE &type = expired->get_type (); + const void *act = expired->get_act (); + int reclaim = 1; + + // Check if this is an interval timer. + if (expired->get_interval () > ACE_Time_Value::zero) + { + // Make sure that we skip past values that have already + // "expired". + do + expired->set_timer_value (expired->get_timer_value () + expired->get_interval ()); + while (expired->get_timer_value () <= cur_time); + + // Since this is an interval timer, we need to reschedule + // it. + this->reschedule (expired); + reclaim = 0; + } + + // call the functor + this->upcall (type, act, cur_time); + + if (reclaim) + // Free up the node and the token + this->free_node (expired); + + ++number_of_timers_expired; + + // Check to see if we are empty + if (this->wheel_[earliest]->get_next () == this->wheel_[earliest]) + break; + } + + if (next_earliest_time == cur_time) + break; + + earliest = next_earliest; + } while (next_earliest != this->wheel_size_); + + return number_of_timers_expired; +} + + #endif /* ACE_TIMER_WHEEL_T_C */ |