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 | |
parent | 35d1135d0091ec71142a95fdbc7c3a3bb741ebec (diff) | |
download | ATCD-1e92c1984331cacea0b72d9d817f28b8dacdc218.tar.gz |
*** empty log message ***
-rw-r--r-- | ChangeLog-97a | 114 | ||||
-rw-r--r-- | ace/Free_List.cpp | 105 | ||||
-rw-r--r-- | ace/Free_List.h | 134 | ||||
-rw-r--r-- | ace/Free_List.i | 65 | ||||
-rw-r--r-- | ace/OS.h | 12 | ||||
-rw-r--r-- | ace/Proactor.cpp | 13 | ||||
-rw-r--r-- | ace/Proactor.h | 7 | ||||
-rw-r--r-- | ace/Timer_Hash.h | 64 | ||||
-rw-r--r-- | ace/Timer_Hash_T.cpp | 482 | ||||
-rw-r--r-- | ace/Timer_Hash_T.h | 234 | ||||
-rw-r--r-- | ace/Timer_Heap.h | 4 | ||||
-rw-r--r-- | ace/Timer_Heap_T.cpp | 222 | ||||
-rw-r--r-- | ace/Timer_Heap_T.h | 78 | ||||
-rw-r--r-- | ace/Timer_List.h | 4 | ||||
-rw-r--r-- | ace/Timer_List_T.cpp | 322 | ||||
-rw-r--r-- | ace/Timer_List_T.h | 63 | ||||
-rw-r--r-- | ace/Timer_Queue.cpp | 39 | ||||
-rw-r--r-- | ace/Timer_Queue.h | 31 | ||||
-rw-r--r-- | ace/Timer_Queue.i | 22 | ||||
-rw-r--r-- | ace/Timer_Queue_T.cpp | 121 | ||||
-rw-r--r-- | ace/Timer_Queue_T.h | 189 | ||||
-rw-r--r-- | ace/Timer_Queue_T.i | 134 | ||||
-rw-r--r-- | ace/Timer_Wheel.h | 4 | ||||
-rw-r--r-- | ace/Timer_Wheel_T.cpp | 539 | ||||
-rw-r--r-- | ace/Timer_Wheel_T.h | 117 | ||||
-rw-r--r-- | tests/Timer_Queue_Test.cpp | 271 |
26 files changed, 2601 insertions, 789 deletions
diff --git a/ChangeLog-97a b/ChangeLog-97a index 239f046aeb5..6efff97c981 100644 --- a/ChangeLog-97a +++ b/ChangeLog-97a @@ -1,3 +1,117 @@ +Tue Jun 3 18:16:02 1997 Darrell Brunsch <brunsch@cs.wustl.edu> + + * ace/Timer_Queue.*: + + Templatized ACE_Event_Handler_Handle_Timeout_Upcall with LOCK + + Added deletion() to Upcall Functors. This gets called if there + are any nodes in a queue and the queue's destructor is called + + * ace/Timer_Queue_T.*: + + Changed iterator accessor to public + + Removed two template parameters from ACE_Timer_Node_T so only + EVENT is left. Added accessors instead of using friendships, and + deleted the constructor (use set() instead) + + Changed iterator into a general iterator (with first(), next(), + isdone() and item () methods) + + Added remove_first () method that removes and returns the earliest + timer in the queue + + Added ACE_Free_List support + + * ace/Timer_Heap*: + + Added upcall functor deletion() support + + Added remove_first () method that removes and returns the earliest + timer in the queue + + * ace/Timer_List*: + + Changed to double-linked circular list and changed the timer_id to + be a pointer to the node (like it is in Timer Wheel and Timer Hash) + + Added upcall functor deletion() support + + Added remove_first () method that removes and returns the earliest + timer in the queue + + Added check for timer_id of -1 so we don't try to delete the error + code if it is passed into cancel + + Changed Timer_List_Iterator_T constructor parameter from list to + listParm to resolve a conflict with STL. Thanks to Todd Barkalow + <barkate@louisville.stortek.com> for this fix + + * ace/Timer_Wheel*: + + Added HighRes timer support + + Added upcall functor deletion() support + + Added earliest_pos_ variable to keep track of the list with the + earliest node + + Created an expire that is specialized for ACE_Timer_Wheel + + Added remove_first () method that removes and returns the earliest + timer in the queue + + Added check for timer_id of -1 so we don't try to delete the error + code if it is passed into cancel + + * ace/Timer_Hash*: + + Added Timer Hash Queue - This is a class that can take another + timer queue type (Timer List, Timer Heap...) as a template + parameter (BUCKET) and then do an intermediate hash of a timer to + determine which queue among a table of timer queues to put the + timer into. ACE_Timer_Hash is typedefed to the Timer List version + and ACE_Timer_Hash_Heap is typedefed to the Timer Heap version + + Added HighRes timer support + + Added upcall functor deletion() support + + Created an expire that is specialized for ACE_Timer_Hash + + Added remove_first () method that removes and returns the earliest + timer in the queue + + Added check for timer_id of -1 so we don't try to delete the error + code if it is passed into cancel + + * ace/Free_List.* + + Added ACE_Free_List<T> and ACE_Locked_Free_List<T, LOCK>. These + are used to maintain free lists of nodes. ACE_Free_List is a + abstract class where ACE_Locked_Free_List is a concrete one that + has a mutex parameter (LOCK). + + * ace/OS.h: + + Added ACE_DEFAULT_TIMER_HASH_TABLE_SIZE constant + + Added ACE_DEFAULT_FREE_LIST_* constants + + * ace/Proactor.*: + + Added deletion() to Upcall Functors. This gets called if there + are any nodes in a queue and the queue's destructor is called. + + * tests/Timer_Queue_Test.cpp: + + Added HighRes timer support + + Changed the array of timer queues into a list (to more easily + add/remove/comment out an entry) + + Added some more performance tests with randomization + Tue Jun 3 00:26:06 1997 Douglas C. Schmidt <schmidt@tango.cs.wustl.edu> * ace/OS.h: Changed the access protection for ACE_cond_t, diff --git a/ace/Free_List.cpp b/ace/Free_List.cpp new file mode 100644 index 00000000000..746aff21a41 --- /dev/null +++ b/ace/Free_List.cpp @@ -0,0 +1,105 @@ +#if !defined (ACE_FREE_LIST_C) +#define ACE_FREE_LIST_C + +#include "ace/Free_List.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Free_List.i" +#endif /* __ACE_INLINE__ */ + +// Empty constructor + +template <class T> +ACE_Free_List<T>::~ACE_Free_List (void) +{ + // Nothing +} + + +// Default constructor that takes in a preallocation number (<prealloc>), a +// low and high water mark (<lwm> and <hwm>) and an increment value (<inc>) + +template <class T, class LOCK> +ACE_Locked_Free_List<T, LOCK>::ACE_Locked_Free_List (size_t prealloc, + size_t lwm, + size_t hwm, + size_t inc, + LOCK *mutex) + : free_list_ (NULL), + lwm_ (lwm), + hwm_ (hwm), + inc_ (inc), + size_ (0), + mutex_ (mutex == 0 ? new LOCK : mutex), + delete_mutex_ (mutex == 0) +{ + this->alloc (prealloc); +} + + +// Destructor - removes all the elements from the free_list + +template <class T, class LOCK> +ACE_Locked_Free_List<T, LOCK>::~ACE_Locked_Free_List (void) +{ + while (this->free_list_ != NULL) + { + T *temp = this->free_list_; + this->free_list_ = this->free_list_->get_next (); + delete temp; + } + + if (this->delete_mutex_) + delete this->mutex_; +} + + +// Allocates <n> extra nodes for the freelist + +template <class T, class LOCK> void +ACE_Locked_Free_List<T, LOCK>::alloc (size_t n) +{ + ACE_MT (ACE_GUARD (LOCK, ace_mon, *this->mutex_)); + for (;n > 0; n--, this->size_++) + { + T *temp; + ACE_NEW (temp, T); + temp->set_next (this->free_list_); + this->free_list_ = temp; + } +} + + +// Removes and frees <n> nodes from the freelist + +template <class T, class LOCK> void +ACE_Locked_Free_List<T, LOCK>::dealloc (size_t n) +{ + ACE_MT (ACE_GUARD (LOCK, ace_mon, *this->mutex_)); + for (;this->free_list_ != NULL && n > 0; this->size_--, n--) + { + T *temp = this->free_list_; + this->free_list_ = this->free_list_->get_next (); + delete temp; + } +} + + +// returns a reference to the mutex +template <class T, class LOCK> LOCK & +ACE_Locked_Free_List<T, LOCK>::get_mutex (void) +{ + return *this->mutex_; +} + +template <class T, class LOCK> void +ACE_Locked_Free_List<T, LOCK>::set_mutex (LOCK &mutex) +{ + if (this->delete_mutex_) + delete this->mutex_; + + this->mutex_ = &mutex; + this->delete_mutex_ = 0; +} + +#endif /* ACE_FREE_LIST_C */ diff --git a/ace/Free_List.h b/ace/Free_List.h new file mode 100644 index 00000000000..c30fe9e23a5 --- /dev/null +++ b/ace/Free_List.h @@ -0,0 +1,134 @@ +/* -*- C++ -*- */ + +// ============================================================================ +// +// = LIBRARY +// ace +// +// = FILENAME +// Free_List.h +// +// = AUTHOR +// Darrell Brunsch (brunsch@cs.wustl.edu) +// +// ============================================================================ + +#if !defined(ACE_FREE_LIST_H) +#define ACE_FREE_LIST_H + +#include "ace/OS.h" + +template <class T> +class ACE_Free_List + // = TITLE + // Implements a free list + // + // = DESCRIPTION + // This class maintains a free list of nodes of type T. +{ +public: + virtual ~ACE_Free_List (void) = 0; + // Destructor - removes all the elements from the free_list + + virtual void add (T *element) = 0; + // Inserts an element onto the free list (if it isn't past the high water mark) + + virtual T *remove (void) = 0; + // Takes a element off the freelist and returns it. It creates <inc> new elements + // if the size is at or below the low water mark. + + virtual size_t size () = 0; + // Returns the current size of the free list + + virtual void resize (size_t newsize) = 0; + // Resizes the free list to <newsize> +}; + +template <class T, class LOCK> +class ACE_Locked_Free_List : public ACE_Free_List<T> + // = TITLE + // Implements a free list + // + // = DESCRIPTION + // This class maintains a free list of nodes of type T. It depends on + // the type T having a get_next () and set_next () method. It maintains + // a mutex so the freelist can be used in a multithreaded program . +{ +public: + ACE_Locked_Free_List (size_t prealloc = ACE_DEFAULT_FREE_LIST_PREALLOC, + size_t lwm = ACE_DEFAULT_FREE_LIST_LWM, + size_t hwm = ACE_DEFAULT_FREE_LIST_HWM, + size_t inc = ACE_DEFAULT_FREE_LIST_INC, + LOCK *mutex = 0); + // Default constructor that takes in a preallocation number (<prealloc>), a + // low and high water mark (<lwm> and <hwm>) and an increment value (<inc>) + + virtual ~ACE_Locked_Free_List (void); + // Destructor - removes all the elements from the free_list + + virtual void add (T *element); + // Inserts an element onto the free list (if it isn't past the high water mark) + + virtual T *remove (void); + // Takes a element off the freelist and returns it. It creates <inc> new elements + // if the size is at or below the low water mark. + + virtual size_t size (); + // Returns the current size of the free list + + virtual void resize (size_t newsize); + // Resizes the free list to <newsize> + + LOCK &get_mutex (void); + // Returns a reference to the mutex + + void set_mutex (LOCK &mutex); + // Sets the mutex to <mutex> + +protected: + virtual void alloc (size_t n); + // Allocates <n> extra nodes for the freelist + + virtual void dealloc (size_t n); + // Removes and frees <n> nodes from the freelist + + T *free_list_; + // Pointer to the first node in the freelist + + size_t lwm_; + // Low water mark + + size_t hwm_; + // High water mark + + size_t inc_; + // Increment value + + size_t size_; + // Keeps track of the size of the list + + LOCK *mutex_; + // Synchronization variable for <ACE_Timer_Queue>. + + int delete_mutex_; + // flag to remember ownership of the mutex + +private: + // = Don't allow these operations for now. + ACE_Locked_Free_List (const ACE_Locked_Free_List<T, LOCK> &); + void operator= (const ACE_Locked_Free_List<T, LOCK> &); +}; + +#if defined (__ACE_INLINE__) +#include "ace/Free_List.i" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Free_List.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Free_List.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_FREE_LIST_H */ diff --git a/ace/Free_List.i b/ace/Free_List.i new file mode 100644 index 00000000000..e9447fe4ba5 --- /dev/null +++ b/ace/Free_List.i @@ -0,0 +1,65 @@ +/* -*- C++ -*- */ + +// Inserts an element onto the free list (if it isn't past the high water mark) + +template <class T, class LOCK> ACE_INLINE void +ACE_Locked_Free_List<T, LOCK>::add (T *element) +{ + ACE_MT (ACE_GUARD (LOCK, ace_mon, *this->mutex_)); + // Check to see that we not at the high water mark + if (this->size_ >= this->hwm_) + { + element->set_next (this->free_list_); + this->free_list_ = element; + this->size_++; + } + else + delete element; +} + + +// Takes a element off the freelist and returns it. It creates <inc> new elements +// if the size is at the low water mark. + +template <class T, class LOCK> ACE_INLINE T * +ACE_Locked_Free_List<T, LOCK>::remove (void) +{ + ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, *this->mutex_, 0)); + T *temp; + + // If we are at the low water mark, add some nodes + if (this->size_ <= this->lwm_) + this->alloc (this->inc_); + + // Remove a node + temp = this->free_list_; + this->free_list_ = this->free_list_->get_next (); + this->size_--; + + return temp; +} + + +// Returns the current size of the free list + +template <class T, class LOCK> ACE_INLINE size_t +ACE_Locked_Free_List<T, LOCK>::size () +{ + return this->size_; +} + + +// Resizes the free list to <newsize> + +template <class T, class LOCK> ACE_INLINE void +ACE_Locked_Free_List<T, LOCK>::resize (size_t newsize) +{ + ACE_MT (ACE_GUARD (LOCK, ace_mon, *this->mutex_)); + // Check to see if we grow or shrink + if (newsize < this->size_) + this->dealloc (this->size_ - newsize); + else + this->alloc (newsize - this->size_); +} + + @@ -1,5 +1,4 @@ /* -*- C++ -*- */ -// $Id$ // ============================================================================ // @@ -121,7 +120,16 @@ // Defaults for ACE Timer Wheel #define ACE_DEFAULT_TIMER_WHEEL_SIZE 1024 -#define ACE_DEFAULT_TIMER_WHEEL_RESOLUTION 1000 +#define ACE_DEFAULT_TIMER_WHEEL_RESOLUTION 100 + +// Default size for ACE Timer Hash table +#define ACE_DEFAULT_TIMER_HASH_TABLE_SIZE 1024 + +// Defaults for the ACE Free List +#define ACE_DEFAULT_FREE_LIST_PREALLOC 0 +#define ACE_DEFAULT_FREE_LIST_LWM 0 +#define ACE_DEFAULT_FREE_LIST_HWM 25000 +#define ACE_DEFAULT_FREE_LIST_INC 100 // Here are all ACE-specific global declarations needed throughout // ACE. diff --git a/ace/Proactor.cpp b/ace/Proactor.cpp index 202a0351099..5d3c3f15500 100644 --- a/ace/Proactor.cpp +++ b/ace/Proactor.cpp @@ -161,6 +161,19 @@ ACE_Proactor_Handle_Timeout_Upcall::cancellation (TIMER_QUEUE &timer_queue, return 0; } +int +ACE_Proactor_Handle_Timeout_Upcall::deletion (TIMER_QUEUE &timer_queue, + ACE_Handler *handler, + const void *arg) +{ + ACE_UNUSED_ARG (timer_queue); + ACE_UNUSED_ARG (handler); + ACE_UNUSED_ARG (arg); + + // Do nothing + return 0; +} + int ACE_Proactor_Handle_Timeout_Upcall::proactor (ACE_Proactor &proactor) { diff --git a/ace/Proactor.h b/ace/Proactor.h index 45b1b27c472..bab67676b14 100644 --- a/ace/Proactor.h +++ b/ace/Proactor.h @@ -66,8 +66,13 @@ public: ACE_Handler *handler); // This method is called when the timer is canceled + int deletion (TIMER_QUEUE &timer_queue, + ACE_Handler *handler, + const void *arg); + // This method is called when the timer queue is destroyed and + // the timer is still contained in it + protected: - int proactor (ACE_Proactor &proactor); // Set the proactor. This will fail, if one is already set! diff --git a/ace/Timer_Hash.h b/ace/Timer_Hash.h new file mode 100644 index 00000000000..d3f465373d4 --- /dev/null +++ b/ace/Timer_Hash.h @@ -0,0 +1,64 @@ +/* -*- C++ -*- */ + +// ============================================================================ +// +// = LIBRARY +// ace +// +// = FILENAME +// Timer_Hash.h +// +// = AUTHOR +// Darrell Brunsch <brunsch@cs.wustl.edu> +// +// ============================================================================ + +#if !defined (ACE_TIMER_HASH_H) +#define ACE_TIMER_HASH_H + +#include "ace/Timer_Hash_T.h" +#include "ace/Timer_List_T.h" +// The following typedef are here for ease of use + +typedef ACE_Timer_Hash_Upcall <ACE_Event_Handler *, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, + ACE_SYNCH_RECURSIVE_MUTEX> + ACE_Hash_Upcall; + +typedef ACE_Timer_List_T <ACE_Event_Handler *, + ACE_Hash_Upcall, + ACE_Null_Mutex> + ACE_Hash_Timer_List; + +typedef ACE_Timer_Heap_T <ACE_Event_Handler *, + ACE_Hash_Upcall, + ACE_Null_Mutex> + ACE_Hash_Timer_Heap; + + +typedef ACE_Timer_Hash_T<ACE_Event_Handler *, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, + ACE_SYNCH_RECURSIVE_MUTEX, + ACE_Hash_Timer_List> + + ACE_Timer_Hash; + +typedef ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, + ACE_SYNCH_RECURSIVE_MUTEX, + ACE_Hash_Timer_List> + ACE_Timer_Hash_Iterator; + +typedef ACE_Timer_Hash_T<ACE_Event_Handler *, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, + ACE_SYNCH_RECURSIVE_MUTEX, + ACE_Hash_Timer_Heap> + ACE_Timer_Hash_Heap; + +typedef ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, + ACE_SYNCH_RECURSIVE_MUTEX, + ACE_Hash_Timer_Heap> + ACE_Timer_Hash_Heap_Iterator; + +#endif /* ACE_TIMER_HASH_H */ diff --git a/ace/Timer_Hash_T.cpp b/ace/Timer_Hash_T.cpp new file mode 100644 index 00000000000..e7389bb3675 --- /dev/null +++ b/ace/Timer_Hash_T.cpp @@ -0,0 +1,482 @@ +#if !defined (ACE_TIMER_HASH_T_C) +#define ACE_TIMER_HASH_T_C + +#define ACE_BUILD_DLL + +#include "ace/Timer_Hash_T.h" + +struct Hash_Token +{ + Hash_Token (const void *act, size_t pos, long orig_id) + : act_ (act), pos_ (pos), orig_id_ (orig_id) + {} + + const void *act_; + size_t pos_; + long orig_id_; +}; + +// Default constructor + +template <class TYPE, class FUNCTOR, class LOCK> +ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>::ACE_Timer_Hash_Upcall (void) + : timer_hash_ (NULL) +{ + // Nothing +} + +// Constructor that specifies a Timer_Hash to call up to + +template <class TYPE, class FUNCTOR, class LOCK> +ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>::ACE_Timer_Hash_Upcall (ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> *timer_hash) + : timer_hash_ (timer_hash) +{ + // Nothing +} + + +// Calls up to timer_hash's upcall functor + +template <class TYPE, class FUNCTOR, class LOCK> int +ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>::timeout (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler, + const void *arg, + const ACE_Time_Value &cur_time) +{ + ACE_UNUSED_ARG (timer_queue); + + Hash_Token *h = (Hash_Token *)arg; + + int ret = this->timer_hash_->upcall_functor ().timeout (*this->timer_hash_, + handler, + h->act_, + cur_time); + delete h; + return ret; +} + + +// Calls up to timer_hash's upcall functor + +template <class TYPE, class FUNCTOR, class LOCK> int +ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>::cancellation (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler) +{ + ACE_UNUSED_ARG (timer_queue); + return this->timer_hash_->upcall_functor ().cancellation (*this->timer_hash_, + handler); +} + + +// Calls up to timer_hash's upcall functor + +template <class TYPE, class FUNCTOR, class LOCK> int +ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>::deletion (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler, + const void *arg) +{ + ACE_UNUSED_ARG (timer_queue); + + Hash_Token *h = (Hash_Token *)arg; + + int ret = this->timer_hash_->upcall_functor ().deletion (*this->timer_hash_, + handler, + h->act_); + delete h; + return ret; +} + + + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> +ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, LOCK, BUCKET>::ACE_Timer_Hash_Iterator_T (ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET> &hash) + : timer_hash_ (hash) +{ + // Nothing +} + + +// Positions the iterator at the first node in the timing hash table + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> void +ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, LOCK, BUCKET>::first (void) +{ + for (this->position_ = 0; + this->position_ < this->timer_hash_.table_size_; + this->position_++) + { + // Check for an empty entry + if (!this->timer_hash_.table_[this->position_]->is_empty ()) + { + this->iter_ = &this->timer_hash_.table_[this->position_]->iter (); + this->iter_->first (); + return; + } + } + + // Didn't find any + this->iter_ = NULL; +} + + +// Positions the iterator at the next node in the bucket or goes to the next +// bucket + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> void +ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, LOCK, BUCKET>::next (void) +{ + if (this->isdone ()) + return; + + // If there is no more in the current bucket, go to the next + if (this->iter_->isdone ()) + { + for (this->position_++; this->position_ < this->timer_hash_.table_size_; this->position_++) + { + // Check for an empty entry + if (!this->timer_hash_.table_[this->position_]->is_empty ()) + { + this->iter_ = &this->timer_hash_.table_[this->position_]->iter (); + this->iter_->first (); + return; + } + } + + // Didn't find any + this->iter_ = NULL; + } + else + this->iter_->next (); +} + + +// Returns true when we are at the end (when bucket_item_ == 0) + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> int +ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, LOCK, BUCKET>::isdone (void) +{ + return this->iter_ == NULL; +} + + +// Returns the node at the current position in the sequence + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> ACE_Timer_Node_T<TYPE> * +ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, LOCK, BUCKET>::item (void) +{ + if (this->isdone ()) + return NULL; + + return this->iter_->item (); +} + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> & +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::iter (void) +{ + return this->iterator_; +} + +// Create an empty queue. + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::ACE_Timer_Hash_T (size_t table_size, + FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) + : ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> (upcall_functor, freelist), + size_ (0), + table_ (new BUCKET* [table_size]), + table_size_ (table_size), + table_functor_ (this), + earliest_position_ (0), + iterator_ (*this) +{ + ACE_TRACE ("ACE_Timer_Hash_T::ACE_Timer_Hash_T"); + + this->gettimeofday (ACE_High_Res_Timer::gettimeofday); + + for (size_t i = 0; i < table_size; i++) + { + this->table_[i] = new BUCKET; + this->table_[i]->gettimeofday (ACE_High_Res_Timer::gettimeofday); + this->table_[i]->set_upcall_functor (&this->table_functor_); + this->table_[i]->free_list (this->free_list_); + } + + this->table_functor_; +} + + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::ACE_Timer_Hash_T (FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) + : ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> (upcall_functor, freelist), + size_ (0), + table_ (new BUCKET* [ACE_DEFAULT_TIMER_HASH_TABLE_SIZE]), + table_size_ (ACE_DEFAULT_TIMER_HASH_TABLE_SIZE), + table_functor_ (this), + earliest_position_ (0), + iterator_ (*this) +{ + ACE_TRACE ("ACE_Timer_Hash_T::ACE_Timer_Hash_T"); + + this->gettimeofday (ACE_High_Res_Timer::gettimeofday); + + for (size_t i = 0; i < this->table_size_; i++) + { + this->table_[i] = new BUCKET (&this->table_functor_, this->free_list_); + this->table_[i]->gettimeofday (ACE_High_Res_Timer::gettimeofday); + } + + this->table_functor_; +} + + +// Remove all remaining items in the Queue. + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::~ACE_Timer_Hash_T (void) +{ + ACE_TRACE ("ACE_Timer_Hash_T::~ACE_Timer_Hash_T"); + ACE_MT (ACE_GUARD (LOCK, ace_mon, this->mutex_)); + + for (size_t i = 0; i < this->table_size_; i++) + delete this->table_[i]; + + delete [] this->table_; +} + +// Checks if queue is empty. + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> int +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::is_empty (void) const +{ + ACE_TRACE ("ACE_Timer_Hash_T::is_empty"); + return this->table_[this->earliest_position_]->is_empty (); +} + + +// Returns earliest time in a non-empty bucket + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> const ACE_Time_Value & +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::earliest_time (void) const +{ + ACE_TRACE ("ACE_Timer_Hash_T::earliest_time"); + return this->table_[this->earliest_position_]->earliest_time (); +} + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> void +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::dump (void) const +{ + ACE_TRACE ("ACE_Timer_Hash_T::dump"); + ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_DEBUG ((LM_DEBUG, "\ntable_size_ = %d", this->table_size_)); + ACE_DEBUG ((LM_DEBUG, "\nearliest_position_ = %d", this->earliest_position_)); + for (size_t i = 0; i < this->table_size_; i++) + if (!this->table_[i]->is_empty ()) + ACE_DEBUG ((LM_DEBUG, "\nBucket %d contains nodes", i)); + ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +} + + +// Reschedule a periodic timer. This function must be called with the +// mutex lock held. + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> void +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::reschedule (ACE_Timer_Node_T<TYPE> *expired) +{ + ACE_TRACE ("ACE_Timer_Hash_T::reschedule"); + + size_t position = expired->get_timer_value ().usec () % this->table_size_; + + Hash_Token *h = (Hash_Token *)expired->get_act (); + + h->orig_id_ = this->table_[position]->schedule (expired->get_type (), + h, + expired->get_timer_value (), + expired->get_interval ()); + + if (this->table_[this->earliest_position_]->is_empty () + || this->table_[this->earliest_position_]->earliest_time () < this->table_[position]->earliest_time ()) + this->earliest_position_ = position; +} + + +// Insert a new handler that expires at time future_time; if interval +// is > 0, the handler will be reinvoked periodically. + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> long +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::schedule (const TYPE &type, + const void *act, + const ACE_Time_Value &future_time, + const ACE_Time_Value &interval) +{ + ACE_TRACE ("ACE_Timer_Hash_T::schedule"); + ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); + + size_t position = future_time.usec () % this->table_size_; + + Hash_Token *h = new Hash_Token (act, position, 0); + + h->orig_id_ = this->table_[position]->schedule (type, + h, + future_time, + interval); + + if (this->table_[this->earliest_position_]->is_empty () + || this->table_[this->earliest_position_]->earliest_time () < this->table_[position]->earliest_time ()) + this->earliest_position_ = position; + + ++this->size_; + + return (long) h; +} + +// Locate and remove the single <ACE_Event_Handler> with a value of +// <timer_id> from the correct table timer queue. + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> int +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::cancel (long timer_id, + const void **act, + int dont_call) +{ + ACE_TRACE ("ACE_Timer_Hash_T::cancel"); + ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); + + // Make sure we are getting a valid <timer_id>, not an error + // returned by schedule () + if (timer_id == -1) + return 0; + + Hash_Token *h = (Hash_Token *)timer_id; + + int ret = this->table_[h->pos_]->cancel (h->orig_id_, act, dont_call); + + if (act != 0) + *act = h->act_; + + delete h; + + --this->size_; + + return ret; +} + + +// Locate and remove all values of <type> from the timer queue. + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> int +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::cancel (const TYPE &type, + int dont_call) +{ + ACE_TRACE ("ACE_Timer_Hash_T::cancel"); + ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); + + size_t i; // loop variable + + Hash_Token **timer_ids = new Hash_Token *[this->size_]; + size_t pos = 0; + + for (i = 0; i < this->table_size_; i++) + { + ACE_Timer_Queue_Iterator_T<TYPE, ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>, ACE_Null_Mutex> &iter = this->table_[i]->iter (); + for (iter.first (); !iter.isdone (); iter.next ()) + timer_ids[pos++] = (Hash_Token *)iter.item ()->get_act (); + } + + ACE_ASSERT (pos <= this->size_); + + for (i = 0; i < pos; i++) + { + this->table_[timer_ids[i]->pos_]->cancel (timer_ids[i]->orig_id_, 0, dont_call); + + dont_call = 1; // Make sure the functor is only called on the first expiration + + delete timer_ids[i]; + + --this->size_; + } + + delete timer_ids; + + return pos; +} + + +// Removes the earliest node and finds the new earliest position + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> ACE_Timer_Node_T<TYPE> * +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::remove_first (void) +{ + if (this->is_empty ()) + return NULL; + + ACE_Timer_Node_T<TYPE> *temp = this->table_[this->earliest_position_]->remove_first (); + + for (size_t i = 0; i < this->table_size_; i++) + if (!this->table_[i]->is_empty ()) + if (this->earliest_time () == ACE_Time_Value::zero + || this->table_[i]->earliest_time () < this->earliest_time ()) + this->earliest_position_ = i; + + --this->size_; + + return temp; +} + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> int +ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET>::expire (const ACE_Time_Value &cur_time) +{ + ACE_TRACE ("ACE_Timer_Hash_T::expire"); + ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); + + int number_of_timers_expired = 0; + + ACE_Timer_Node_T<TYPE> *expired; + + // Go through the table and expire anything that can be expired + + for (size_t i = 0; i < this->table_size_; i++) + { + while (!this->table_[i]->is_empty () && + this->table_[i]->earliest_time () <= cur_time) + { + expired = this->table_[i]->remove_first (); + --this->size_; + 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 + Hash_Token *h = (Hash_Token *)act; + this->upcall (type, h->act_, cur_time); + + if (reclaim) + { + // Free up the node and the token + this->free_node (expired); + delete h; + } + + number_of_timers_expired++; + } + } + + return number_of_timers_expired; +} + +#endif /* ACE_TIMER_HASH_T_C */ diff --git a/ace/Timer_Hash_T.h b/ace/Timer_Hash_T.h new file mode 100644 index 00000000000..d6f61084c2b --- /dev/null +++ b/ace/Timer_Hash_T.h @@ -0,0 +1,234 @@ +/* -*- C++ -*- */ + +// ============================================================================ +// +// = LIBRARY +// ace +// +// = FILENAME +// Timer_Hash_T.h +// +// = AUTHOR +// Darrell Brunsch <brunsch@cs.wustl.edu> +// +// ============================================================================ + +#if !defined (ACE_TIMER_HASH_T_H) +#define ACE_TIMER_HASH_T_H + +#include "ace/Timer_Queue.h" +#include "ace/Free_List.h" + +// Forward declaration. +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> +class ACE_Timer_Hash_T; + +template <class TYPE, class FUNCTOR, class LOCK> +class ACE_Timer_Hash_Upcall + // = TITLE + // Functor for Timer_Hash + // + // = DESCRIPTION + // This class calls up to the Timer Hash's functor from the + // timer queues in the hash table +{ +public: + typedef ACE_Timer_Queue_T<ACE_Event_Handler *, + ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>, + ACE_Null_Mutex> + TIMER_QUEUE; + + ACE_Timer_Hash_Upcall (void); + // Default constructor (creates an invalid object, but needs to be here + // so timer queues using this functor can be constructed) + + ACE_Timer_Hash_Upcall (ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> *timer_hash); + // Constructor that specifies a Timer_Hash to call up to + + int timeout (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler, + const void *arg, + const ACE_Time_Value &cur_time); + // This method is called when the timer expires + + int cancellation (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler); + // This method is called when the timer is canceled + + int deletion (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler, + const void *arg); + // This method is called when the timer queue is destroyed and + // the timer is still contained in it + +private: + ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> *timer_hash_; + // Timer Queue to do the calling up to + + // = Don't allow these operations for now. + ACE_Timer_Hash_Upcall (const ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK> &); + void operator= (const ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK> &); +}; + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> +class ACE_Timer_Hash_Iterator_T : public ACE_Timer_Queue_Iterator_T <TYPE, FUNCTOR, LOCK> + // = TITLE + // Iterates over an <ACE_Timer_Hash>. + // + // = DESCRIPTION + // This is a generic iterator that can be used to visit every + // node of a timer queue. Be aware that it doesn't transverse + // in the order of timeout values. +{ +public: + ACE_Timer_Hash_Iterator_T (ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET> &); + // Constructor. + + virtual void first (void); + // Positions the iterator at the earliest node in the Timer Queue + + virtual void next (void); + // Positions the iterator at the next node in the Timer Queue + + virtual int isdone (void); + // Returns true when there are no more nodes in the sequence + + virtual ACE_Timer_Node_T<TYPE> *item (void); + // Returns the node at the current position in the sequence + +protected: + ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET> &timer_hash_; + // Pointer to the <ACE_Timer_Hash> that we are iterating over. + + size_t position_; + // Current position in <timer_hash_>'s table + + ACE_Timer_Queue_Iterator_T<TYPE, ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK>, ACE_Null_Mutex> *iter_; + // Current iterator used on <position>'s bucket +}; + +template <class TYPE, class FUNCTOR, class LOCK, class BUCKET> +class ACE_Timer_Hash_T : public ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> + // = TITLE + // Provides a hash table of <BUCKET>s as an implementation for + // a timer queue. + // + // = DESCRIPTION + // This implementation uses a hash table of BUCKETs. The hash + // is based on the time_value of the event. Unlike other Timer + // Queues, ACE_Timer_Hash does not expire events in order. +{ +public: + typedef ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, LOCK, BUCKET> HASH_ITERATOR; + // Type of iterator + + friend class ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, LOCK, BUCKET>; + // Iterator is a friend + + typedef ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> INHERITED; + // Type inherited from + + // = Initialization and termination methods. + ACE_Timer_Hash_T (size_t table_size, + FUNCTOR *upcall_functor = 0, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); + // Default constructor. <table_size> determines the size of the + // hash table. <upcall_functor> is the instance of the FUNCTOR + // to be used by the buckets. If <upcall_functor> is 0, a default + // FUNCTOR will be created. + + ACE_Timer_Hash_T (FUNCTOR *upcall_functor = 0, ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); + // Default constructor. <upcall_functor> is the instance of the + // FUNCTOR to be used by the queue. If <upcall_functor> is 0, Timer + // Hash will create a default FUNCTOR. <freelist> the freelist of + // timer nodes. If 0, then a default freelist will be created. The default + // size will be ACE_DEFAULT_TIMERS and there will be no preallocation. + + virtual ~ACE_Timer_Hash_T (void); + // Destructor + + virtual int is_empty (void) const; + // True if queue is empty, else false. + + virtual const ACE_Time_Value &earliest_time (void) const; + // Returns the time of the earlier node in the <ACE_Timer_Hash>. + + virtual long schedule (const TYPE &type, + const void *act, + const ACE_Time_Value &delay, + const ACE_Time_Value &interval = ACE_Time_Value::zero); + // Schedule <type> that will expire after <delay> amount of time. + // If it expires then <act> is passed in as the value to the + // <functor>. If <interval> is != to <ACE_Time_Value::zero> then it + // is used to reschedule the <type> automatically. This method + // returns a <timer_id> that is a pointer to a token which stores + // information about the event. This <timer_id> can be used to cancel + // the timer before it expires. Returns -1 on failure. + + virtual int cancel (const TYPE &type, + int dont_call_handle_close = 1); + // Cancel all timer associated with <type>. If <dont_call> is 0 + // then the <functor> will be invoked. Returns number of timers + // cancelled. + + virtual int cancel (long timer_id, + const void **act = 0, + int dont_call_handle_close = 1); + // Cancel the single timer that matches the <timer_id> value (which + // was returned from the <schedule> method). If act is non-NULL + // then it will be set to point to the ``magic cookie'' argument + // passed in when the timer was registered. This makes it possible + // to free up the memory and avoid memory leaks. If <dont_call> is + // 0 then the <functor> will be invoked. Returns 1 if cancellation + // succeeded and 0 if the <timer_id> wasn't found. + + virtual int expire (const ACE_Time_Value ¤t_time); + // Run the <functor> for all timers whose values are <= <cur_time>. + // This does not account for <timer_skew>. Returns the number of + // timers canceled. + + virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> &iter (void); + // Returns a pointer to this <ACE_Timer_Queue>'s iterator. + + virtual ACE_Timer_Node_T<TYPE> *remove_first (void); + // Removes the earliest node from the queue and returns it + + virtual void dump (void) const; + // Dump the state of an object. + +private: + virtual void reschedule (ACE_Timer_Node_T<TYPE> *); + // Reschedule an "interval" <ACE_Timer_Node>. + + size_t size_; + // Keeps track of the size of the queue + + BUCKET **table_; + // Table of BUCKETS + + size_t table_size_; + // Keeps track of the size of <table> + + ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, LOCK> table_functor_; + // Functor used for the table's timer queues + + size_t earliest_position_; + // Index to the position with the earliest entry + + HASH_ITERATOR iterator_; + // Iterator used to expire timers. + + // = Don't allow these operations for now. + ACE_Timer_Hash_T (const ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET> &); + void operator= (const ACE_Timer_Hash_T<TYPE, FUNCTOR, LOCK, BUCKET> &); +}; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Timer_Hash_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Timer_Hash_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_TIMER_HASH_T_H */ diff --git a/ace/Timer_Heap.h b/ace/Timer_Heap.h index 676ed3b352d..46132a49ef8 100644 --- a/ace/Timer_Heap.h +++ b/ace/Timer_Heap.h @@ -23,12 +23,12 @@ // compatibility. typedef ACE_Timer_Heap_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_Heap; typedef ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_Heap_Iterator; diff --git a/ace/Timer_Heap_T.cpp b/ace/Timer_Heap_T.cpp index 3983b8460c7..54c77eac3e3 100644 --- a/ace/Timer_Heap_T.cpp +++ b/ace/Timer_Heap_T.cpp @@ -1,5 +1,3 @@ -// $Id$ - #if !defined (ACE_TIMER_HEAP_T_C) #define ACE_TIMER_HEAP_T_C @@ -11,6 +9,9 @@ #define ACE_HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2)) #define ACE_HEAP_LCHILD(X) (((X)+(X))+1) + +// Constructor that takes in an <ACE_Timer_Heap_T> to iterate over. + template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_Iterator_T (ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK> &heap) : timer_heap_ (heap) @@ -19,29 +20,52 @@ ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_Iterator_T (ACE_T } -template <class TYPE, class FUNCTOR, class LOCK> int -ACE_Timer_Heap_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 heap array + +template <class TYPE, class FUNCTOR, class LOCK> void +ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, LOCK>::first (void) { - ACE_TRACE ("ACE_Timer_Heap_Iterator::next"); + this->position_ = 0; +} - if (this->timer_heap_.cur_size_ == 0 - || this->timer_heap_.heap_[0]->timer_value_ > cur_time) - return 0; - else - { - // Remove the first item and restore the heap property. - node = this->timer_heap_.remove (0); - return 1; - } +// Positions the iterator at the next node in the heap array + +template <class TYPE, class FUNCTOR, class LOCK> void +ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, LOCK>::next (void) +{ + if (this->position_ != this->timer_heap_.cur_size_) + this->position_++; } + +// Returns true the <position_> is at the end of the heap array + +template <class TYPE, class FUNCTOR, class LOCK> int +ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, LOCK>::isdone (void) +{ + return this->position_ == this->timer_heap_.cur_size_; +} + + +// Returns the node at the current position in the heap or NULL if at the end + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * +ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, LOCK>::item (void) +{ + if (this->position_ != this->timer_heap_.cur_size_) + return this->timer_heap_.heap_[this->position_]; + return NULL; +} + +// Constructor + template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_T (size_t size, int preallocate, - FUNCTOR *upcall_functor) - : INHERITED (upcall_functor), + FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) + : INHERITED (upcall_functor, freelist), max_size_ (size), cur_size_ (0), iterator_ (*this), @@ -49,10 +73,10 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_T (size_t size, preallocated_nodes_ (0), preallocated_nodes_freelist_ (0) { - ACE_TRACE ("ACE_Timer_Heap::ACE_Timer_Heap"); + ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T"); // Create the heap array. - ACE_NEW (this->heap_, (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *[size])); + ACE_NEW (this->heap_, (ACE_Timer_Node_T<TYPE> *[size])); // Create the parallel ACE_NEW (this->timer_ids_, long[size]); @@ -66,7 +90,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_T (size_t size, if (preallocate) { ACE_NEW (this->preallocated_nodes_, - (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>[size])); + (ACE_Timer_Node_T<TYPE>[size])); // Add allocated array to set of such arrays for deletion // on cleanup. @@ -74,11 +98,10 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_T (size_t size, // Form the freelist by linking the next_ pointers together. for (size_t j = 1; j < size; j++) - this->preallocated_nodes_[j - 1].next_ = - &this->preallocated_nodes_[j]; + this->preallocated_nodes_[j - 1].set_next (&this->preallocated_nodes_[j]); // NULL-terminate the freelist. - this->preallocated_nodes_[size - 1].next_ = 0; + this->preallocated_nodes_[size - 1].set_next (0); // Assign the freelist pointer to the front of the list. this->preallocated_nodes_freelist_ = @@ -87,19 +110,57 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_T (size_t size, } template <class TYPE, class FUNCTOR, class LOCK> +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Heap_T (FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) + : INHERITED (upcall_functor, freelist), + max_size_ (ACE_DEFAULT_TIMERS), + cur_size_ (0), + iterator_ (*this), + timer_ids_freelist_ (0), + preallocated_nodes_ (0), + preallocated_nodes_freelist_ (0) +{ + ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T"); + + // Create the heap array. + ACE_NEW (this->heap_, (ACE_Timer_Node_T<TYPE> *[this->max_size_])); + + // Create the parallel + ACE_NEW (this->timer_ids_, long[this->max_size_]); + + // Initialize the "freelist," which uses negative values to + // distinguish freelist elements from "pointers" into the <heap_> + // array. + for (size_t i = 0; i < this->max_size_; i++) + this->timer_ids_[i] = -((long) (i + 1)); +} + + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_Heap_T (void) { ACE_TRACE ("ACE_Timer_Heap::~ACE_Timer_Heap"); + + // Clean up all the nodes still in the queue + for (size_t i = 0; i < this->cur_size_; ) + { + this->upcall_functor ().deletion (*this, + this->heap_[i]->get_type (), + this->heap_[i]->get_act ()); + this->free_node (this->heap_[i]); + } + + delete [] this->heap_; delete [] this->timer_ids_; // clean up any preallocated timer nodes if (preallocated_nodes_ != 0) { - ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *> + ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<TYPE> *> set_iterator (this->preallocated_node_set_); - for (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> **entry = 0; + for (ACE_Timer_Node_T<TYPE> **entry = 0; set_iterator.next (entry) !=0; set_iterator.advance ()) delete [] *entry; @@ -107,6 +168,8 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_Heap_T (void) } + + template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::pop_freelist (void) { @@ -164,7 +227,7 @@ template <class TYPE, class FUNCTOR, class LOCK> const ACE_Time_Value & ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::earliest_time (void) const { ACE_TRACE ("ACE_Timer_Heap::earliest_time"); - return this->heap_[0]->timer_value_; + return this->heap_[0]->get_timer_value (); } @@ -193,24 +256,24 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::dump (void) const } template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::copy (int index, ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *moved_node) +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::copy (int index, ACE_Timer_Node_T<TYPE> *moved_node) { // Insert <moved_node> into its new location in the heap. this->heap_[index] = moved_node; - ACE_ASSERT (moved_node->timer_id_ >= 0 - && moved_node->timer_id_ < (int) this->max_size_); + ACE_ASSERT (moved_node->get_timer_id () >= 0 + && moved_node->get_timer_id () < (int) this->max_size_); // Update the corresponding slot in the parallel <timer_ids_> array. - this->timer_ids_[moved_node->timer_id_] = index; + this->timer_ids_[moved_node->get_timer_id ()] = index; } -template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> * +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::remove (size_t index) { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *removed_node = this->heap_[index]; + ACE_Timer_Node_T<TYPE> *removed_node = this->heap_[index]; // Return this timer id to the freelist. - this->push_freelist (removed_node->timer_id_); + this->push_freelist (removed_node->get_timer_id ()); // Decrement the size of the heap by one since we're removing the // "index"th node. @@ -220,7 +283,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::remove (size_t index) if (index < this->cur_size_) { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *moved_node = this->heap_[this->cur_size_]; + ACE_Timer_Node_T<TYPE> *moved_node = this->heap_[this->cur_size_]; // Move the end node to the location being removed and update // the corresponding slot in the parallel <timer_ids> array. @@ -230,7 +293,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::remove (size_t index) // parent it needs be moved down the heap. size_t parent = ACE_HEAP_PARENT (index); - if (moved_node->timer_value_ >= this->heap_[parent]->timer_value_) + if (moved_node->get_timer_value () >= this->heap_[parent]->get_timer_value ()) this->reheap_down (moved_node, index, ACE_HEAP_LCHILD (index)); else this->reheap_up (moved_node, index, parent); @@ -240,7 +303,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::remove (size_t index) } template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_down (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *moved_node, +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_down (ACE_Timer_Node_T<TYPE> *moved_node, size_t index, size_t child) { @@ -250,12 +313,12 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_down (ACE_Timer_Node_T<TYPE, FUNCT { // Choose the smaller of the two children. if (child + 1 < this->cur_size_ - && this->heap_[child + 1]->timer_value_ < this->heap_[child]->timer_value_) + && this->heap_[child + 1]->get_timer_value () < this->heap_[child]->get_timer_value ()) child++; // Perform a <copy> if the child has a larger timeout value than // the <moved_node>. - if (this->heap_[child]->timer_value_ < moved_node->timer_value_) + if (this->heap_[child]->get_timer_value () < moved_node->get_timer_value ()) { this->copy (index, this->heap_[child]); index = child; @@ -270,7 +333,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_down (ACE_Timer_Node_T<TYPE, FUNCT } template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_up (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *moved_node, +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_up (ACE_Timer_Node_T<TYPE> *moved_node, size_t index, size_t parent) { @@ -280,7 +343,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_up (ACE_Timer_Node_T<TYPE, FUNCTOR { // If the parent node is greater than the <moved_node> we need // to copy it down. - if (moved_node->timer_value_ < this->heap_[parent]->timer_value_) + if (moved_node->get_timer_value () < this->heap_[parent]->get_timer_value ()) { this->copy (index, this->heap_[parent]); index = parent; @@ -296,7 +359,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reheap_up (ACE_Timer_Node_T<TYPE, FUNCTOR } template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::insert (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *new_node) +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::insert (ACE_Timer_Node_T<TYPE> *new_node) { if (this->cur_size_ + 1 >= max_size_) this->grow_heap (); @@ -316,8 +379,8 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::grow_heap (void) // First grow the heap itself. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> **new_heap = 0; - ACE_NEW (new_heap, (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *[new_size])); + ACE_Timer_Node_T<TYPE> **new_heap = 0; + ACE_NEW (new_heap, (ACE_Timer_Node_T<TYPE> *[new_size])); ACE_OS::memcpy (new_heap, this->heap_, max_size_ * sizeof *new_heap); delete [] this->heap_; @@ -346,32 +409,31 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::grow_heap (void) // Create a new array with max_size elements to link in // to existing list. ACE_NEW (this->preallocated_nodes_, - (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>[this->max_size_])); + (ACE_Timer_Node_T<TYPE>[this->max_size_])); // Add it to the set for later deletion this->preallocated_node_set_.insert (this->preallocated_nodes_); // link new nodes together (as for original list). for (size_t k = 1; k < this->max_size_; k++) - this->preallocated_nodes_[k - 1].next_ = - &this->preallocated_nodes_[k]; + this->preallocated_nodes_[k - 1].set_next (&this->preallocated_nodes_[k]); // NULL-terminate the new list. - this->preallocated_nodes_[this->max_size_ - 1].next_ = 0; + this->preallocated_nodes_[this->max_size_ - 1].set_next (0); // link new array to the end of the existling list if (this->preallocated_nodes_freelist_ == 0) this->preallocated_nodes_freelist_ = &preallocated_nodes_[0]; else { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *previous = this->preallocated_nodes_freelist_; + ACE_Timer_Node_T<TYPE> *previous = this->preallocated_nodes_freelist_; - for (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *current = this->preallocated_nodes_freelist_->next_; + for (ACE_Timer_Node_T<TYPE> *current = this->preallocated_nodes_freelist_->get_next (); current != 0; - current = current->next_) + current = current->get_next ()) previous = current; - previous->next_ = &this->preallocated_nodes_[0]; + previous->set_next (&this->preallocated_nodes_[0]); } } @@ -382,7 +444,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::grow_heap (void) // mutex lock held. template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reschedule (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *expired) +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reschedule (ACE_Timer_Node_T<TYPE> *expired) { ACE_TRACE ("ACE_Timer_Heap::reschedule"); @@ -391,7 +453,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::reschedule (ACE_Timer_Node_T<TYPE, FUNCTO } -template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> * +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::alloc_node (void) { ACE_Timer_Node *temp; @@ -399,7 +461,7 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::alloc_node (void) // Only allocate a node if we are *not* using the preallocated heap. if (this->preallocated_nodes_ == 0) ACE_NEW_RETURN (temp, - (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>), + (ACE_Timer_Node_T<TYPE>), 0); else { @@ -411,21 +473,21 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::alloc_node (void) // Remove the first element from the freelist. this->preallocated_nodes_freelist_ = - this->preallocated_nodes_freelist_->next_; + this->preallocated_nodes_freelist_->get_next (); } return temp; } template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::free_node (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *node) +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::free_node (ACE_Timer_Node_T<TYPE> *node) { // Only free up a node if we are *not* using the preallocated heap. if (this->preallocated_nodes_ == 0) delete node; else { - node->next_ = this->preallocated_nodes_freelist_; + node->set_next (this->preallocated_nodes_freelist_); this->preallocated_nodes_freelist_ = node; } } @@ -450,17 +512,17 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::schedule (const TYPE &type, int timer_id = this->timer_id (); // Obtain the memory to the new node. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->alloc_node (); + ACE_Timer_Node_T<TYPE> *temp = this->alloc_node (); if (temp) { - // Use operator placement new. - new (temp) ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> (type, - act, - future_time, - interval, - 0, - timer_id); + temp->set (type, + act, + future_time, + interval, + 0, + timer_id); + this->insert (temp); return timer_id; } @@ -485,21 +547,21 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::cancel (long timer_id, long timer_node_slot = this->timer_ids_[timer_id]; - if (timer_id != this->heap_[timer_node_slot]->timer_id_) + if (timer_id != this->heap_[timer_node_slot]->get_timer_id ()) { - ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->timer_id_); + ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ()); return 0; } else { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->remove (timer_node_slot); + ACE_Timer_Node_T<TYPE> *temp = this->remove (timer_node_slot); if (dont_call == 0) // Call the close hook. - this->upcall_functor_.cancellation (*this, temp->type_); + this->upcall_functor ().cancellation (*this, temp->get_type ()); if (act != 0) - *act = temp->act_; + *act = temp->get_act (); this->free_node (temp); return 1; @@ -521,16 +583,16 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::cancel (const TYPE &type, for (size_t i = 0; i < this->cur_size_; ) { - if (this->heap_[i]->type_ == type) + if (this->heap_[i]->get_type () == type) { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->remove (i); + ACE_Timer_Node_T<TYPE> *temp = this->remove (i); number_of_cancellations++; if (dont_call == 0 && number_of_cancellations == 1) // Call the close hook. - this->upcall_functor_.cancellation (*this, temp->type_); + this->upcall_functor ().cancellation (*this, temp->get_type ()); this->free_node (temp); } @@ -541,5 +603,19 @@ ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::cancel (const TYPE &type, return number_of_cancellations; } + +// Returns the earliest node or returns NULL if the heap is empty. + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T <TYPE> * +ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>::remove_first (void) +{ + ACE_TRACE ("ACE_Timer_Heap_T::remove_first"); + + if (this->cur_size_ == 0) + return NULL; + + return this->remove (0); +} + #endif /* ACE_TIMER_HEAP_T_C */ diff --git a/ace/Timer_Heap_T.h b/ace/Timer_Heap_T.h index 2a2780f2137..0d0e2c9d0cd 100644 --- a/ace/Timer_Heap_T.h +++ b/ace/Timer_Heap_T.h @@ -1,6 +1,4 @@ /* -*- C++ -*- */ -// $Id$ - // ============================================================================ // // = LIBRARY @@ -18,6 +16,7 @@ #define ACE_TIMER_HEAP_T_H #include "ace/Timer_Queue.h" +#include "ace/Free_List.h" #include "ace/Containers.h" // Forward declaration @@ -27,26 +26,35 @@ class ACE_Timer_Heap_T; template <class TYPE, class FUNCTOR, class LOCK> class ACE_Timer_Heap_Iterator_T : public ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> // = TITLE - // Iterates over an <ACE_Timer_Queue>. + // Iterates over an <ACE_Timer_Hash_T>. // // = DESCRIPTION - // This is a special type of iterator that "advances" by moving - // the head of the timer queue up by one every time. + // This is a generic iterator that can be used to visit every + // node of a timer queue. Be aware that it doesn't transverse + // in the order of timeout values. { public: ACE_Timer_Heap_Iterator_T (ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK> &); // Constructor. - virtual int next (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *&timer_node, - const ACE_Time_Value &cur_time); - // Pass back the next <timer_node> that hasn't been seen yet, if its - // <time_value_> <= <cur_time>. In addition, moves the timer queue - // forward by one node. Returns 0 when all <timer_nodes> have been - // seen, else 1. + virtual void first (void); + // Positions the iterator at the earliest node in the Timer Queue + + virtual void next (void); + // Positions the iterator at the next node in the Timer Queue + + virtual int isdone (void); + // Returns true when there are no more nodes in the sequence + + virtual ACE_Timer_Node_T<TYPE> *item (void); + // Returns the node at the current position in the sequence protected: ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK> &timer_heap_; // Pointer to the <ACE_Timer_Heap> that we are iterating over. + + size_t position_; + // Position in the array where the iterator is at }; template <class TYPE, class FUNCTOR, class LOCK> @@ -72,14 +80,23 @@ public: typedef ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> INHERITED; // = Initialization and termination methods. - ACE_Timer_Heap_T (size_t size = ACE_DEFAULT_TIMERS, + ACE_Timer_Heap_T (size_t size, int preallocated = 0, - FUNCTOR *upcall_functor = 0); + FUNCTOR *upcall_functor = 0, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); // The Constructor creates a heap with <size> elements. If // <preallocated> is non-0 then we'll pre-allocate all the memory // for the <ACE_Timer_Nodes>. This saves time and is more // predictable (though it requires more space). Otherwise, we'll - // just allocate the nodes as we need them. + // just allocate the nodes as we need them. This can also take in a + // upcall functor and freelist (if 0, then defaults will be created) + + ACE_Timer_Heap_T (FUNCTOR *upcall_functor = 0, ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); + // Default constructor. <upcall_functor> is the instance of the + // FUNCTOR to be used by the queue. If <upcall_functor> is 0, Timer + // Heap will create a default FUNCTOR. <freelist> the freelist of + // timer nodes. If 0, then a default freelist will be created. The default + // size will be ACE_DEFAULT_TIMERS and there will be no preallocation. virtual ~ACE_Timer_Heap_T (void); // Destructor. @@ -124,31 +141,34 @@ public: // 0 then the <functor> will be invoked. Returns 1 if cancellation // succeeded and 0 if the <timer_id> wasn't found. + virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> &iter (void); + // Returns a pointer to this <ACE_Timer_Queue>'s iterator. + + ACE_Timer_Node_T <TYPE> *remove_first (void); + // Removes the earliest node from the queue and returns it + virtual void dump (void) const; // Dump the state of an object. protected: - virtual void reschedule (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *); + virtual void reschedule (ACE_Timer_Node_T<TYPE> *); // Reschedule an "interval" <ACE_Timer_Node>. - virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> &iter (void); - // Returns a pointer to this <ACE_Timer_Queue>'s iterator. - - virtual ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *alloc_node (void); + virtual ACE_Timer_Node_T<TYPE> *alloc_node (void); // Factory method that allocates a new node (uses operator new if // we're *not* preallocating, otherwise uses an internal freelist). - virtual void free_node (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *); + virtual void free_node (ACE_Timer_Node_T<TYPE> *); // Factory method that frees a previously allocated node (uses // operatord delete if we're *not* preallocating, otherwise uses an // internal freelist). private: - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *remove (size_t index); + ACE_Timer_Node_T<TYPE> *remove (size_t index); // Remove and return the <index>th <ACE_Timer_Node> and restore the // heap property. - void insert (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *new_node); + void insert (ACE_Timer_Node_T<TYPE> *new_node); // Insert <new_node> into the heap and restore the heap property. void grow_heap (void); @@ -156,17 +176,17 @@ private: // If preallocation is used, will also double the size of the // preallocated array of ACE_Timer_Nodes. - void reheap_up (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *new_node, + void reheap_up (ACE_Timer_Node_T<TYPE> *new_node, size_t index, size_t parent); // Restore the heap property, starting at <index>. - void reheap_down (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *moved_node, + void reheap_down (ACE_Timer_Node_T<TYPE> *moved_node, size_t index, size_t child); // Restore the heap property, starting at <index>. - void copy (int index, ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *moved_node); + void copy (int index, ACE_Timer_Node_T<TYPE> *moved_node); // Copy <moved_node> into the <index> slot of <heap_> and move // <index> into the corresponding slot in the <timer_id_> array. @@ -191,7 +211,7 @@ private: HEAP_ITERATOR iterator_; // Iterator used to expire timers. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> **heap_; + ACE_Timer_Node_T<TYPE> **heap_; // Current contents of the Heap, which is organized as a "heap" of // <ACE_Timer_Node> *'s. In this context, a heap is a "partially // ordered, almost complete" binary tree, which is stored in an @@ -211,17 +231,17 @@ private: // "Pointer" to the first element in the freelist contained within // the <timer_ids_> array, which is organized as a stack. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *preallocated_nodes_; + ACE_Timer_Node_T<TYPE> *preallocated_nodes_; // If this is non-0, then we preallocate <max_size_> number of // <ACE_Timer_Node> objects in order to reduce dynamic allocation // costs. In auto-growing implementation, this points to the // last array of nodes allocated. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *preallocated_nodes_freelist_; + ACE_Timer_Node_T<TYPE> *preallocated_nodes_freelist_; // This points to the head of the <preallocated_nodes_> freelist, // which is organized as a stack. - ACE_Unbounded_Set<ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *> preallocated_node_set_; + ACE_Unbounded_Set<ACE_Timer_Node_T<TYPE> *> preallocated_node_set_; // Set of pointers to the arrays of preallocated timer nodes. // Used to delete the allocated memory when required. diff --git a/ace/Timer_List.h b/ace/Timer_List.h index 228a6f21a78..1212985b4b2 100644 --- a/ace/Timer_List.h +++ b/ace/Timer_List.h @@ -23,12 +23,12 @@ // compatibility. typedef ACE_Timer_List_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_List; typedef ACE_Timer_List_Iterator_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_List_Iterator; diff --git a/ace/Timer_List_T.cpp b/ace/Timer_List_T.cpp index 3aecb92845e..4f16d865763 100644 --- a/ace/Timer_List_T.cpp +++ b/ace/Timer_List_T.cpp @@ -1,5 +1,3 @@ -// $Id$ - #if !defined (ACE_TIMER_LIST_T_C) #define ACE_TIMER_LIST_T_C @@ -7,29 +5,58 @@ #include "ace/Timer_List_T.h" +// Default Constructor + template <class TYPE, class FUNCTOR, class LOCK> -ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_List_Iterator_T (ACE_Timer_List_T<TYPE, FUNCTOR, LOCK> &list) - : timer_list_ (list) +ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_List_Iterator_T (ACE_Timer_List_T<TYPE, FUNCTOR, LOCK> &listParm) + : timer_list_ (listParm), + position_ (NULL) { + // Nothing } -template <class TYPE, class FUNCTOR, class LOCK> int -ACE_Timer_List_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 node right after the dummy node + +template <class TYPE, class FUNCTOR, class LOCK> void +ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, LOCK>::first (void) { - if (this->timer_list_.head_ == 0 - || this->timer_list_.head_->timer_value_ > cur_time) - return 0; - else - { - node = this->timer_list_.head_; - this->timer_list_.head_ = this->timer_list_.head_->next_; - return 1; - } + this->position_ = this->timer_list_.head_->get_next (); +} + + +// Positions the iterator at the next node in the Timer Queue + +template <class TYPE, class FUNCTOR, class LOCK> void +ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, LOCK>::next (void) +{ + // Make sure that if we are at the end, we don't wrap around + if (this->position_ != this->timer_list_.head_) + this->position_ = this->position_->get_next (); +} + + +// Returns true when we are at <head_> + +template <class TYPE, class FUNCTOR, class LOCK> int +ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, LOCK>::isdone (void) +{ + return this->position_ == this->timer_list_.head_; +} + + +// Returns the node at <position_> or NULL if we are at the end + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * +ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, LOCK>::item (void) +{ + if (this->position_ != this->timer_list_.head_) + return this->position_; + return NULL; } -ACE_ALLOC_HOOK_DEFINE(ACE_Timer_List_T) + +// Return our instance of the iterator template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> & ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::iter (void) @@ -37,271 +64,234 @@ ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::iter (void) return this->iterator_; } + // Create an empty list. template <class TYPE, class FUNCTOR, class LOCK> -ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_List_T (FUNCTOR *upcall_functor) - : ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> (upcall_functor), - head_ (0), +ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_List_T (FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) + : ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> (upcall_functor, freelist), + head_ (new ACE_Timer_Node_T<TYPE>), iterator_ (*this), timer_id_ (0) { - ACE_TRACE ("ACE_Timer_List::ACE_Timer_List"); + ACE_TRACE ("ACE_Timer_List_T::ACE_Timer_List"); + this->head_->set_next (this->head_); + this->head_->set_prev (this->head_); } -// Checks if list is empty. +// Checks if list is empty. template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::is_empty (void) const { - ACE_TRACE ("ACE_Timer_List::is_empty"); - return this->head_ == 0; -} - -template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> * -ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::alloc_node (void) -{ - return new ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>; + ACE_TRACE ("ACE_Timer_List_T::is_empty"); + return this->head_->get_next () == this->head_; } -template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::free_node (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *node) -{ - delete node; -} // Returns earliest time in a non-empty list. - template <class TYPE, class FUNCTOR, class LOCK> const ACE_Time_Value & ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::earliest_time (void) const { - ACE_TRACE ("ACE_Timer_List::earliest_time"); - return this->head_->timer_value_; + ACE_TRACE ("ACE_Timer_List_T::earliest_time"); + return this->head_->get_next ()->get_timer_value (); } + // Remove all remaining items in the list. template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_List_T (void) { - ACE_TRACE ("ACE_Timer_List::~ACE_Timer_List"); + ACE_TRACE ("ACE_Timer_List_T::~ACE_Timer_List_T"); ACE_MT (ACE_GUARD (LOCK, ace_mon, this->mutex_)); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *curr = this->head_; + ACE_Timer_Node_T<TYPE> *curr = this->head_->get_next (); - while (curr != 0) + while (curr != this->head_) { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *next = curr->next_; + ACE_Timer_Node_T<TYPE> *next = curr->get_next (); + this->upcall_functor ().deletion (*this, next->get_type (), next->get_act ()); this->free_node (curr); curr = next; } + + // delete the dummy node + delete this->head_; } template <class TYPE, class FUNCTOR, class LOCK> void ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::dump (void) const { - ACE_TRACE ("ACE_Timer_List::dump"); + ACE_TRACE ("ACE_Timer_List_T::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); - ACE_DEBUG ((LM_DEBUG, "\nhead_ = %d", this->head_)); + size_t count = 0; + ACE_Timer_Node_T<TYPE> *curr = this->head_->get_next (); + while (curr != this->head_) + { + count++; + curr = curr->get_next (); + } + ACE_DEBUG ((LM_DEBUG, "\nsize_ = %d", count)); ACE_DEBUG ((LM_DEBUG, "\ntimer_id_ = %d", this->timer_id_)); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } + // Reschedule a periodic timer. This function must be called with the // mutex lock held. - template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::reschedule (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *expired) +ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::reschedule (ACE_Timer_Node_T<TYPE> *expired) { - ACE_TRACE ("ACE_Timer_List::reschedule"); - if (this->is_empty () - || expired->timer_value_ < this->earliest_time ()) - { - expired->next_ = this->head_; - this->head_ = expired; - } - else - { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *prev = this->head_; - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *after = this->head_->next_; + ACE_TRACE ("ACE_Timer_List_T::reschedule"); - // Locate the proper position in the queue. + ACE_Timer_Node_T<TYPE> *after = this->head_->get_next (); - while (after != 0 - && expired->timer_value_ > after->timer_value_) - { - prev = after; - after = after->next_; - } + // Locate the proper position in the queue. - expired->next_ = after; - prev->next_ = expired; - } + while (after != this->head_ + && expired->get_timer_value () > after->get_timer_value ()) + after = after->get_next (); + + expired->set_next (after); + expired->set_prev (after->get_prev ()); + after->get_prev ()->set_next (expired); + after->set_prev (expired); } + // Insert a new handler that expires at time future_time; if interval // is > 0, the handler will be reinvoked periodically. - template <class TYPE, class FUNCTOR, class LOCK> long ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::schedule (const TYPE &type, const void *act, const ACE_Time_Value &future_time, const ACE_Time_Value &interval) { - ACE_TRACE ("ACE_Timer_List::schedule"); + ACE_TRACE ("ACE_Timer_List_T::schedule"); ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); - // Increment the sequence number (it will wrap around). - long timer_id = this->timer_id (); - - if (this->is_empty () || future_time < this->earliest_time ()) - { - // Place at the beginning of the list. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->alloc_node (); - - // Use operator placement new. - this->head_ = new (temp) ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> (type, - act, - future_time, - interval, - this->head_, - timer_id); - return timer_id; - } - // Place in the middle of the list where it belongs (i.e., sorted in // ascending order of absolute time to expire). - else - { - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *prev = this->head_; - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *after = this->head_->next_; - - while (after != 0 && future_time > after->timer_value_) - { - prev = after; - after = after->next_; - } + ACE_Timer_Node_T<TYPE> *after = this->head_->get_next (); + + while (after != this->head_ && future_time > after->get_timer_value ()) + after = after->get_next (); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *temp = this->alloc_node (); + ACE_Timer_Node_T<TYPE> *temp = this->alloc_node (); - // Use operator placement new. - prev->next_ = new (temp) ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> (type, - act, - future_time, - interval, - after, - timer_id); - return timer_id; - } -} + temp->set (type, + act, + future_time, + interval, + after->get_prev (), + after, + (long) temp); + after->get_prev ()->set_next (temp); + after->set_prev (temp); -template <class TYPE, class FUNCTOR, class LOCK> int -ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::timer_id (void) -{ - // We need to truncate this to <int> for backwards compatibility. - int tid = this->timer_id_++; - - // Make sure this never == -1 - if (tid == -1) - tid = 0; - - return tid; + return (long) temp; } + // Locate and remove the single <ACE_Event_Handler> with a value of // <timer_id> from the timer queue. - template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::cancel (long timer_id, const void **act, int dont_call) { - ACE_TRACE ("ACE_Timer_List::cancel"); + ACE_TRACE ("ACE_Timer_List_T::cancel"); ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *prev = 0; - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *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) + // Make sure we are getting a valid <timer_id>, not an error + // returned by schedule () + if (timer_id == -1) + return 0; + + 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 ()) { - if (prev == 0) - this->head_ = curr->next_; - else - prev->next_ = curr->next_; - + node->get_next ()->set_prev (node->get_prev ()); + node->get_prev ()->set_next (node->get_next ()); + if (act != 0) - *act = curr->act_; + *act = node->get_act (); if (dont_call == 0) - this->upcall_functor_.cancellation (*this, curr->type_); - this->free_node (curr); + this->upcall_functor ().cancellation (*this, node->get_type ()); + + this->free_node (node); return 1; } - else - return 0; + + // Wasn't valid + return 0; } -// Locate and remove all values of <handler> from the timer queue. +// Locate and remove all values of <handler> from the timer queue. template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::cancel (const TYPE &type, int dont_call) { - ACE_TRACE ("ACE_Timer_List::cancel"); + ACE_TRACE ("ACE_Timer_List_T::cancel"); ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *prev = 0; - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *curr = this->head_; + ACE_Timer_Node_T<TYPE> *curr = this->head_->get_next (); int number_of_cancellations = 0; - while (curr != 0) + while (curr != this->head_) { - if (curr->type_ == type) + if (curr->get_type () == type) { number_of_cancellations++; if (dont_call == 0 && number_of_cancellations == 1) - this->upcall_functor_.cancellation (*this, curr->type_); - - if (prev == 0) - { - this->head_ = curr->next_; - this->free_node (curr); - curr = this->head_; - } - else - { - prev->next_ = curr->next_; - this->free_node (curr); - curr = prev->next_; - } + this->upcall_functor ().cancellation (*this, curr->get_type ()); + + curr->get_prev ()->set_next (curr->get_next ()); + curr->get_next ()->set_prev (curr->get_prev ()); + ACE_Timer_Node_T<TYPE> *temp = curr; + curr = curr->get_next (); + this->free_node (temp); } else - { - prev = curr; - curr = curr->next_; - } + curr = curr->get_next (); } return number_of_cancellations; } + +// Removes the first node on the list and returns it. + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * +ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>::remove_first (void) +{ + ACE_TRACE ("ACE_Timer_List_T::remove_first"); + + // remove the node and fix the pointers + ACE_Timer_Node_T<TYPE> *temp = this->head_->get_next (); + this->head_->set_next (temp->get_next ()); + temp->get_next ()->set_prev (this->head_); + + return temp; +} + + #endif /* ACE_TIMER_LIST_T_C */ diff --git a/ace/Timer_List_T.h b/ace/Timer_List_T.h index b164fff5aa6..4364d9eb6ae 100644 --- a/ace/Timer_List_T.h +++ b/ace/Timer_List_T.h @@ -1,6 +1,4 @@ /* -*- C++ -*- */ -// $Id$ - // ============================================================================ // // = LIBRARY @@ -26,26 +24,33 @@ class ACE_Timer_List_T; template <class TYPE, class FUNCTOR, class LOCK> class ACE_Timer_List_Iterator_T : public ACE_Timer_Queue_Iterator_T <TYPE, FUNCTOR, LOCK> // = TITLE - // Iterates over an <ACE_Timer_Queue>. + // Iterates over an <ACE_Timer_List>. // // = DESCRIPTION - // This is a special type of iterator that "advances" by moving - // the head of the timer queue up by one every time. + // This is a generic iterator that can be used to visit every + // node of a timer queue. { public: ACE_Timer_List_Iterator_T (ACE_Timer_List_T<TYPE, FUNCTOR, LOCK> &); // Constructor. - virtual int next (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *&timer_node, - const ACE_Time_Value &cur_time); - // Pass back the next <timer_node> that hasn't been seen yet, if its - // <time_value_> <= <cur_time>. In addition, moves the timer queue - // forward by one node. Returns 0 when all <timer_nodes> have been - // seen, else 1. + virtual void first (void); + // Positions the iterator at the earliest node in the Timer Queue + + virtual void next (void); + // Positions the iterator at the next node in the Timer Queue + + virtual int isdone (void); + // Returns true when there are no more nodes in the sequence + + virtual ACE_Timer_Node_T<TYPE> *item (void); + // Returns the node at the current position in the sequence protected: ACE_Timer_List_T<TYPE, FUNCTOR, LOCK> &timer_list_; // Pointer to the <ACE_Timer_List> that we are iterating over. + + ACE_Timer_Node_T<TYPE> *position_; }; template <class TYPE, class FUNCTOR, class LOCK> @@ -79,10 +84,12 @@ public: // Type inherited from // = Initialization and termination methods. - ACE_Timer_List_T (FUNCTOR *upcall_functor = 0); + ACE_Timer_List_T (FUNCTOR *upcall_functor = 0, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); // Default constructor. <upcall_functor> is the instance of the // FUNCTOR to be used by the list. If <upcall_functor> is 0, a - // default FUNCTOR will be created. + // default FUNCTOR will be created. <freelist> the freelist of + // timer nodes. If 0, then a default freelist will be created. virtual ~ACE_Timer_List_T (void); // Destructor @@ -127,31 +134,29 @@ public: // 0 then the <functor> will be invoked. Returns 1 if cancellation // succeeded and 0 if the <timer_id> wasn't found. + virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> &iter (void); + // Returns a pointer to this <ACE_Timer_Queue>'s iterator. + + virtual ACE_Timer_Node_T<TYPE> *remove_first (void); + // Removes the earliest node from the queue and returns it + virtual void dump (void) const; // Dump the state of an object. + virtual void reschedule (ACE_Timer_Node_T<TYPE> *); + // Reschedule an "interval" <ACE_Timer_Node>. This should be private + // but for now it needs to be public for <ACE_Timer_Hash_T> + protected: - virtual ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *alloc_node (void); +/* virtual ACE_Timer_Node_T<TYPE> *alloc_node (void); // Factory method that allocates a new node (uses operator new). - virtual void free_node (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *); + virtual void free_node (ACE_Timer_Node_T<TYPE> *); // Factory method that frees a previously allocated node (uses // operator delete). - +*/ private: - int timer_id (void); - // Returns a timer id that uniquely identifies this timer. This id - // can be used to cancel a timer via the <cancel (int)> method. The - // timer id returned from this method will never == -1 to avoid - // conflicts with other failure return values. - - virtual void reschedule (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *); - // Reschedule an "interval" <ACE_Timer_Node>. - - virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> &iter (void); - // Returns a pointer to this <ACE_Timer_Queue>'s iterator. - - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *head_; + ACE_Timer_Node_T<TYPE> *head_; // Pointer to linked list of <ACE_Timer_Handles>. LIST_ITERATOR iterator_; diff --git a/ace/Timer_Queue.cpp b/ace/Timer_Queue.cpp index 259f63dea82..dca4e89d916 100644 --- a/ace/Timer_Queue.cpp +++ b/ace/Timer_Queue.cpp @@ -1,4 +1,5 @@ -// $Id$ +#if !defined (ACE_TIMER_QUEUE_C) +#define ACE_TIMER_QUEUE_C #define ACE_BUILD_DLL @@ -7,13 +8,14 @@ #include "ace/Timer_Heap_T.h" #include "ace/Timer_List_T.h" #include "ace/Timer_Wheel_T.h" +#include "ace/Timer_Hash_T.h" #endif /* ACE_TEMPLATES_REQUIRE_SPECIALIZATION */ -int -ACE_Event_Handler_Handle_Timeout_Upcall::timeout (TIMER_QUEUE &timer_queue, - ACE_Event_Handler *handler, - const void *act, - const ACE_Time_Value &cur_time) +template <class LOCK> int +ACE_Event_Handler_Handle_Timeout_Upcall<LOCK>::timeout (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler, + const void *act, + const ACE_Time_Value &cur_time) { // Upcall to the <handler>s handle_timeout method if (handler->handle_timeout (cur_time, act) == -1) @@ -22,9 +24,9 @@ ACE_Event_Handler_Handle_Timeout_Upcall::timeout (TIMER_QUEUE &timer_queue, return 0; } -int -ACE_Event_Handler_Handle_Timeout_Upcall::cancellation (TIMER_QUEUE &timer_queue, - ACE_Event_Handler *handler) +template <class LOCK> int +ACE_Event_Handler_Handle_Timeout_Upcall<LOCK>::cancellation (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler) { ACE_UNUSED_ARG (timer_queue); @@ -34,6 +36,21 @@ ACE_Event_Handler_Handle_Timeout_Upcall::cancellation (TIMER_QUEUE &timer_queue, return 0; } +template <class LOCK> int +ACE_Event_Handler_Handle_Timeout_Upcall<LOCK>::deletion (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler, + const void *arg) +{ + ACE_UNUSED_ARG (timer_queue); + ACE_UNUSED_ARG (handler); + ACE_UNUSED_ARG (arg); + + // Does nothing + + return 0; +} + + #if defined (ACE_TEMPLATES_REQUIRE_SPECIALIZATION) template class ACE_Unbounded_Set<ACE_Timer_Node_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall, ACE_SYNCH_RECURSIVE_MUTEX> *>; template class ACE_Node<ACE_Timer_Node_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall, ACE_SYNCH_RECURSIVE_MUTEX> *>; @@ -47,4 +64,8 @@ template class ACE_Timer_Queue_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_T template class ACE_Timer_Queue_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall, ACE_SYNCH_RECURSIVE_MUTEX>; template class ACE_Timer_Wheel_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall, ACE_SYNCH_RECURSIVE_MUTEX>; template class ACE_Timer_Wheel_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall, ACE_SYNCH_RECURSIVE_MUTEX>; +template class ACE_Timer_Hash_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall, ACE_SYNCH_RECURSIVE_MUTEX>; +template class ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall, ACE_SYNCH_RECURSIVE_MUTEX>; #endif /* ACE_TEMPLATES_REQUIRE_SPECIALIZATION */ + +#endif /* ACE_TIMER_QUEUE_C */ diff --git a/ace/Timer_Queue.h b/ace/Timer_Queue.h index 42bf2fb5248..a0de5dbd5dc 100644 --- a/ace/Timer_Queue.h +++ b/ace/Timer_Queue.h @@ -1,5 +1,4 @@ /* -*- C++ -*- */ -// $Id$ // ============================================================================ // @@ -20,7 +19,8 @@ #include "ace/Synch.h" #include "ace/Timer_Queue_T.h" -class ACE_Export ACE_Event_Handler_Handle_Timeout_Upcall +template <class LOCK> +class ACE_Event_Handler_Handle_Timeout_Upcall // = TITLE // Functor for Timer_Queues. // @@ -30,8 +30,8 @@ class ACE_Export ACE_Event_Handler_Handle_Timeout_Upcall { public: typedef ACE_Timer_Queue_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, - ACE_SYNCH_RECURSIVE_MUTEX> + ACE_Event_Handler_Handle_Timeout_Upcall<LOCK>, + LOCK> TIMER_QUEUE; int timeout (TIMER_QUEUE &timer_queue, @@ -43,24 +43,37 @@ public: int cancellation (TIMER_QUEUE &timer_queue, ACE_Event_Handler *handler); // This method is called when the timer is canceled + + int deletion (TIMER_QUEUE &timer_queue, + ACE_Event_Handler *handler, + const void *arg); + // This method is called when the timer queue is destroyed and + // the timer is still contained in it }; // The following typedef are here for ease of use and backward // compatibility. -typedef ACE_Timer_Node_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, - ACE_SYNCH_RECURSIVE_MUTEX> +typedef ACE_Timer_Node_T<ACE_Event_Handler *> ACE_Timer_Node; typedef ACE_Timer_Queue_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_Queue; typedef ACE_Timer_Queue_Iterator_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_Queue_Iterator; + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Timer_Queue.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Timer_Queue.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + #endif /* ACE_TIMER_QUEUE_H */ diff --git a/ace/Timer_Queue.i b/ace/Timer_Queue.i new file mode 100644 index 00000000000..41e4324e61e --- /dev/null +++ b/ace/Timer_Queue.i @@ -0,0 +1,22 @@ +/* -*- C++ -*- */ + +template <class TYPE, class FUNCTOR> ACE_INLINE void +ACE_Timer_Queue_T<TYPE, FUNCTOR>::timer_skew (const ACE_Time_Value &skew) +{ + timer_skew_ = skew; +} + +template <class TYPE, class FUNCTOR> ACE_INLINE const ACE_Time_Value & +ACE_Timer_Queue_T<TYPE, FUNCTOR>::timer_skew (void) const +{ + return timer_skew_; +} + +template <class TYPE, class FUNCTOR> ACE_INLINE int +ACE_Timer_Queue_T<TYPE, FUNCTOR>::expire (void) +{ + if (!this->is_empty ()) + return this->expire (this->gettimeofday () + timer_skew_); + else + return 0; +} diff --git a/ace/Timer_Queue_T.cpp b/ace/Timer_Queue_T.cpp index cfe8060ddfa..c514a15b128 100644 --- a/ace/Timer_Queue_T.cpp +++ b/ace/Timer_Queue_T.cpp @@ -1,6 +1,3 @@ -// Timer_Queue_T.cpp -// $Id$ - #if !defined (ACE_TIMER_QUEUE_T_C) #define ACE_TIMER_QUEUE_T_C @@ -12,12 +9,10 @@ #include "ace/Timer_Queue_T.i" #endif /* __ACE_INLINE__ */ -ACE_ALLOC_HOOK_DEFINE(ACE_Timer_Node_T) - -template <class TYPE, class FUNCTOR, class LOCK> void -ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>::dump (void) const +template <class TYPE> void +ACE_Timer_Node_T<TYPE>::dump (void) const { - ACE_TRACE ("ACE_Timer_Node::dump"); + ACE_TRACE ("ACE_Timer_Node_T::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); // ACE_DEBUG ((LM_DEBUG, "\type_ = %x", this->type_)); ACE_DEBUG ((LM_DEBUG, "\nact_ = %x", this->act_)); @@ -29,50 +24,12 @@ ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>::dump (void) const ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } -template <class TYPE, class FUNCTOR, class LOCK> -ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Node_T (void) -{ - ACE_TRACE ("ACE_Timer_Node::ACE_Timer_Node"); -} - -template <class TYPE, class FUNCTOR, class LOCK> -ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Node_T (const TYPE &type, - const void *a, - const ACE_Time_Value &t, - const ACE_Time_Value &i, - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *n, - long timer_id) - : type_ (type), - act_ (a), - timer_value_ (t), - interval_ (i), - prev_ (0), - next_ (n), - timer_id_ (timer_id) -{ - ACE_TRACE ("ACE_Timer_Node::ACE_Timer_Node"); -} - -template <class TYPE, class FUNCTOR, class LOCK> -ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Node_T (const TYPE &type, - const void *a, - const ACE_Time_Value &t, - const ACE_Time_Value &i, - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *p, - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *n, - long timer_id) - : type_ (type), - act_ (a), - timer_value_ (t), - interval_ (i), - prev_ (p), - next_ (n), - timer_id_ (timer_id) +template <class TYPE> +ACE_Timer_Node_T<TYPE>::ACE_Timer_Node_T (void) { - ACE_TRACE ("ACE_Timer_Node::ACE_Timer_Node"); + ACE_TRACE ("ACE_Timer_Node_T::ACE_Timer_Node_T"); } - template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Queue_Iterator_T (void) { @@ -94,7 +51,7 @@ ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_Queue_Iterator_T (vo template <class TYPE, class FUNCTOR, class LOCK> ACE_Time_Value * ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::calculate_timeout (ACE_Time_Value *max_wait_time) { - ACE_TRACE ("ACE_Timer_List::calculate_timeout"); + ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout"); ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, max_wait_time)); if (this->is_empty ()) @@ -131,7 +88,7 @@ ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::calculate_timeout (ACE_Time_Value *max_w template <class TYPE, class FUNCTOR, class LOCK> void ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::dump (void) const { - ACE_TRACE ("ACE_Timer_Queue::dump"); + ACE_TRACE ("ACE_Timer_Queue_T::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); this->timeout_.dump (); this->timer_skew_.dump (); @@ -139,23 +96,41 @@ ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::dump (void) const } template <class TYPE, class FUNCTOR, class LOCK> -ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Queue_T (FUNCTOR *upcall_functor) +ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::ACE_Timer_Queue_T (FUNCTOR *upcall_functor, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist) : gettimeofday_ (ACE_OS::gettimeofday), - upcall_functor_ (upcall_functor == 0 ? *(new FUNCTOR) : *upcall_functor), + upcall_functor_ (upcall_functor == 0 ? new FUNCTOR : upcall_functor), delete_upcall_functor_ (upcall_functor == 0), - timer_skew_ (0, ACE_TIMER_SKEW) + timer_skew_ (0, ACE_TIMER_SKEW), + free_list_ (freelist == 0 ? new ACE_Locked_Free_List<ACE_Timer_Node_T <TYPE>, ACE_Null_Mutex> : freelist), + delete_free_list_ (freelist == 0) { - ACE_TRACE ("ACE_Timer_Queue::ACE_Timer_Queue"); + ACE_TRACE ("ACE_Timer_Queue_T::ACE_Timer_Queue_T"); } template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_Queue_T (void) { - // Cleanup the functor on the way out - if (delete_upcall_functor_) - delete &this->upcall_functor_; + ACE_TRACE ("ACE_Timer_Queue_T::~ACE_Timer_Queue_T"); + + // Cleanup the functor and free_list on the way out + if (this->delete_upcall_functor_) + delete this->upcall_functor_; + + if (this->delete_free_list_) + delete this->free_list_; +} + +template <class TYPE, class FUNCTOR, class LOCK> ACE_Timer_Node_T<TYPE> * +ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::alloc_node (void) +{ + return this->free_list_->remove (); +} - ACE_TRACE ("ACE_Timer_Queue::~ACE_Timer_Queue"); +template <class TYPE, class FUNCTOR, class LOCK> void +ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::free_node (ACE_Timer_Node_T<TYPE> *node) +{ + this->free_list_->add (node); } // Run the <handle_timeout> method for all Timers whose values are <= @@ -164,32 +139,31 @@ ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::~ACE_Timer_Queue_T (void) template <class TYPE, class FUNCTOR, class LOCK> int ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::expire (const ACE_Time_Value &cur_time) { - ACE_TRACE ("ACE_Timer_List::expire"); + ACE_TRACE ("ACE_Timer_Queue_T::expire"); ACE_MT (ACE_GUARD_RETURN (LOCK, ace_mon, this->mutex_, -1)); int number_of_timers_expired = 0; - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *expired; + ACE_Timer_Node_T<TYPE> *expired; // Keep looping while there are timers remaining and the earliest // timer is <= the <cur_time> passed in to the method. - for (ITERATOR &iter = this->iter (); - iter.next (expired, cur_time) != 0; - ) + while (this->earliest_time () <= cur_time) { - TYPE &type = expired->type_; - const void *act = expired->act_; + expired = this->remove_first (); + TYPE &type = expired->get_type (); + const void *act = expired->get_act (); int reclaim = 1; // Check if this is an interval timer. - if (expired->interval_ > ACE_Time_Value::zero) + if (expired->get_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); + 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. @@ -205,15 +179,12 @@ ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::expire (const ACE_Time_Value &cur_time) this->free_node (expired); number_of_timers_expired++; + + if (this->is_empty ()) + break; } return number_of_timers_expired; } -template <class TYPE, class FUNCTOR, class LOCK> LOCK & -ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::mutex (void) -{ - return this->mutex_; -} - #endif /* ACE_TIMER_QUEUE_T_C*/ diff --git a/ace/Timer_Queue_T.h b/ace/Timer_Queue_T.h index 538dd267c45..a2f3d978cd2 100644 --- a/ace/Timer_Queue_T.h +++ b/ace/Timer_Queue_T.h @@ -1,5 +1,4 @@ /* -*- C++ -*- */ -// $Id$ // ============================================================================ // @@ -10,7 +9,7 @@ // Timer_Queue_T.h // // = AUTHOR -// Doug Schmidt and Irfan Pyarali +// Doug Schmidt, Irfan Pyarali, and Darrell Brunsch // // ============================================================================ @@ -18,67 +17,85 @@ #define ACE_TIMER_QUEUE_T_H #include "ace/Time_Value.h" +#include "ace/Free_List.h" -// Forward declarations. -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_Queue_T; +// This should be nested within the ACE_Timer_Queue class but some C++ +// compilers still don't like this... -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_List_T; +template <class TYPE> +class ACE_Timer_Node_T + // = TITLE + // Maintains the state associated with a Timer entry. +{ +public: + ACE_Timer_Node_T (); + // Default constructor + + void set (const TYPE &type, + const void *a, + const ACE_Time_Value &t, + const ACE_Time_Value &i, + ACE_Timer_Node_T<TYPE> *n, + long timer_id); + // singly linked list + + void set (const TYPE &type, + const void *a, + const ACE_Time_Value &t, + const ACE_Time_Value &i, + ACE_Timer_Node_T<TYPE> *p, + ACE_Timer_Node_T<TYPE> *n, + long timer_id); + // doubly linked list version + + // = Accessors + + TYPE &get_type (void); + // get the type + + void set_type (TYPE &type); + // set the type -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_List_Iterator_T; + const void *get_act (void); + // get the act -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_Heap_T; + void set_act (void *act); + // set the act -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_Heap_Iterator_T; + ACE_Time_Value &get_timer_value (void); + // get the timer value -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_Wheel_T; + void set_timer_value (ACE_Time_Value timer_value); + // set the timer value -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_Wheel_Iterator_T; + ACE_Time_Value &get_interval (void); + // get the timer interval -// This should be nested within the ACE_Timer_Queue class but some C++ -// compilers still don't like this... + void set_interval (ACE_Time_Value interval); + // set the timer interval -template <class TYPE, class FUNCTOR, class LOCK> -class ACE_Timer_Node_T - // = TITLE - // Maintains the state associated with a Timer entry. -{ - // = The use of friends should be replaced with accessors... - friend class ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>; - friend class ACE_Timer_List_T<TYPE, FUNCTOR, LOCK>; - friend class ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, LOCK>; - friend class ACE_Timer_Heap_T<TYPE, FUNCTOR, LOCK>; - friend class ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, LOCK>; - friend class ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK>; - friend class ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>; - - // = Initialization methods. - ACE_Timer_Node_T (const TYPE &type, - const void *a, - const ACE_Time_Value &t, - const ACE_Time_Value &i, - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *n, - long timer_id); - // Constructor. + ACE_Timer_Node_T<TYPE> *get_prev (void); + // get the previous pointer + + void set_prev (ACE_Timer_Node_T<TYPE> *prev); + // set the previous pointer + + ACE_Timer_Node_T<TYPE> *get_next (void); + // get the next pointer - ACE_Timer_Node_T (const TYPE &type, - const void *a, - const ACE_Time_Value &t, - const ACE_Time_Value &i, - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *p, - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *n, - long timer_id); - // Constructor for the doubly linked list version. + void set_next (ACE_Timer_Node_T<TYPE> *next); + // set the next pointer + + long get_timer_id (void); + // get the timer_id + + void set_timer_id (long timer_id); + // set the timer_id + void dump (void) const; + // Dump the state of an TYPE. - ACE_Timer_Node_T (void); - // Default constructor. +private: TYPE type_; // Type of object stored in the Queue @@ -93,33 +110,29 @@ class ACE_Timer_Node_T // If this is a periodic timer this holds the time until the next // timeout. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *prev_; + ACE_Timer_Node_T<TYPE> *prev_; // Pointer to previous timer. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *next_; + ACE_Timer_Node_T<TYPE> *next_; // Pointer to next timer. long timer_id_; // Id of this timer (used to cancel timers before they expire). - - ACE_ALLOC_HOOK_DECLARE; - // Declare the dynamic allocation hooks. - - void dump (void) const; - // Dump the state of an TYPE. }; template <class TYPE, class FUNCTOR, class LOCK> class ACE_Timer_Queue_Iterator_T // = TITLE - // Generic interfae for iterating over a subclass of + // Generic interface for iterating over a subclass of // <ACE_Timer_Queue>. // // = DESCRIPTION - // This is a special type of iterator that "advances" by moving - // the head of the timer queue up by one every time. + // This is a generic iterator that can be used to visit every + // node of a timer queue. Be aware that it isn't guaranteed + // that the transversal will be in order of timeout values. { public: + // = Initialization and termination methods. ACE_Timer_Queue_Iterator_T (void); // Constructor. @@ -127,12 +140,17 @@ public: virtual ~ACE_Timer_Queue_Iterator_T (void); // Destructor. - virtual int next (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *&timer_node, - const ACE_Time_Value &cur_time) = 0; - // Pass back the next <timer_node> that hasn't been seen yet, if its - // <time_value_> <= <cur_time>. In addition, moves the timer queue - // forward by one node. Returns 0 when all <timer_nodes> have been - // seen, else 1. + virtual void first (void) = 0; + // Positions the iterator at the earliest node in the Timer Queue + + virtual void next (void) = 0; + // Positions the iterator at the next node in the Timer Queue + + virtual int isdone (void) = 0; + // Returns true when there are no more nodes in the sequence + + virtual ACE_Timer_Node_T<TYPE> *item (void) = 0; + // Returns the node at the current position in the sequence }; template <class TYPE, class FUNCTOR, class LOCK> @@ -146,14 +164,17 @@ class ACE_Timer_Queue_T // and <ACE_Timer_Heap>. { public: + typedef ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> ITERATOR; // Type of Iterator // = Initialization and termination methods. - ACE_Timer_Queue_T (FUNCTOR *upcall_functor = 0); + ACE_Timer_Queue_T (FUNCTOR *upcall_functor = 0, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); // Default constructor. <upcall_functor> is the instance of the // FUNCTOR to be used by the queue. If <upcall_functor> is 0, Timer - // Queue will create a default FUNCTOR. + // Queue will create a default FUNCTOR. <freelist> the freelist of + // timer nodes. If 0, then a default freelist will be created. virtual ~ACE_Timer_Queue_T (void); // Destructor - make virtual for proper destruction of inherited @@ -232,45 +253,51 @@ public: FUNCTOR &upcall_functor (void); // Accessor to the upcall functor + virtual ITERATOR &iter (void) = 0; + // Returns a pointer to this <ACE_Timer_Queue>'s iterator. + + virtual ACE_Timer_Node_T<TYPE> *remove_first (void) = 0; + // Removes the earliest node from the queue and returns it + virtual void dump (void) const; // Dump the state of a object. - ACE_ALLOC_HOOK_DECLARE; - // Declare the dynamic allocation hooks. - protected: - virtual void upcall (TYPE &type, const void *act, const ACE_Time_Value &cur_time); // This method will call the <functor> with the <type>, <act> and // <time> - virtual void reschedule (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *) = 0; + virtual void reschedule (ACE_Timer_Node_T<TYPE> *) = 0; // Reschedule an "interval" <ACE_Timer_Node>. - virtual ITERATOR &iter (void) = 0; - // Returns a pointer to this <ACE_Timer_Queue>'s iterator. - - virtual ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *alloc_node (void) = 0; + virtual ACE_Timer_Node_T<TYPE> *alloc_node (void); // Factory method that allocates a new node. - virtual void free_node (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *) = 0; + virtual void free_node (ACE_Timer_Node_T<TYPE> *); // Factory method that frees a previously allocated node. LOCK mutex_; // Synchronization variable for <ACE_Timer_Queue>. + ACE_Free_List<ACE_Timer_Node_T<TYPE> > *free_list_; + // Class that implements a free list + ACE_Time_Value (*gettimeofday_)(void); // Pointer to function that returns the current time of day. - FUNCTOR &upcall_functor_; + FUNCTOR *upcall_functor_; // Upcall functor int delete_upcall_functor_; // To delete or not to delete is the question? + int delete_free_list_; + // Flag to delete only if the class created the <free_list_> + private: + ACE_Time_Value timeout_; // Returned by <calculate_timeout>. diff --git a/ace/Timer_Queue_T.i b/ace/Timer_Queue_T.i index 752ae8c7d38..ad8ea45cdea 100644 --- a/ace/Timer_Queue_T.i +++ b/ace/Timer_Queue_T.i @@ -1,7 +1,122 @@ /* -*- C++ -*- */ -// $Id$ -// Timer_Queue_T.i +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set (const TYPE &type, + const void *a, + const ACE_Time_Value &t, + const ACE_Time_Value &i, + ACE_Timer_Node_T<TYPE> *n, + long timer_id) +{ + this->type_ = type; + this->act_ = a; + this->timer_value_ = t; + this->interval_ = i; + this->next_ = n; + this->timer_id_ = timer_id; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set (const TYPE &type, + const void *a, + const ACE_Time_Value &t, + const ACE_Time_Value &i, + ACE_Timer_Node_T<TYPE> *p, + ACE_Timer_Node_T<TYPE> *n, + long timer_id) +{ + this->type_ = type; + this->act_ = a; + this->timer_value_ = t; + this->interval_ = i; + this->prev_ = p; + this->next_ = n; + this->timer_id_ = timer_id; +} + +template <class TYPE> ACE_INLINE TYPE & +ACE_Timer_Node_T<TYPE>::get_type (void) +{ + return this->type_; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set_type (TYPE &type) +{ + this->type_ = type; +} + +template <class TYPE> ACE_INLINE const void * +ACE_Timer_Node_T<TYPE>::get_act (void) +{ + return this->act_; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set_act (void *act) +{ + this->act_ = act; +} + +template <class TYPE> ACE_INLINE ACE_Time_Value & +ACE_Timer_Node_T<TYPE>::get_timer_value (void) +{ + return this->timer_value_; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set_timer_value (ACE_Time_Value timer_value) +{ + this->timer_value_ = timer_value; +} + +template <class TYPE> ACE_INLINE ACE_Time_Value & +ACE_Timer_Node_T<TYPE>::get_interval (void) +{ + return this->interval_; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set_interval (ACE_Time_Value interval) +{ + this->interval_ = interval; +} + +template <class TYPE> ACE_INLINE ACE_Timer_Node_T<TYPE> * +ACE_Timer_Node_T<TYPE>::get_prev (void) +{ + return this->prev_; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set_prev (ACE_Timer_Node_T<TYPE> *prev) +{ + this->prev_ = prev; +} + +template <class TYPE> ACE_INLINE ACE_Timer_Node_T<TYPE> * +ACE_Timer_Node_T<TYPE>::get_next (void) +{ + return this->next_; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set_next (ACE_Timer_Node_T<TYPE> *next) +{ + this->next_ = next; +} + +template <class TYPE> ACE_INLINE long +ACE_Timer_Node_T<TYPE>::get_timer_id (void) +{ + return this->timer_id_; +} + +template <class TYPE> ACE_INLINE void +ACE_Timer_Node_T<TYPE>::set_timer_id (long timer_id) +{ + this->timer_id_ = timer_id; +} template <class TYPE, class FUNCTOR, class LOCK> ACE_INLINE void ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::timer_skew (const ACE_Time_Value &skew) @@ -29,7 +144,7 @@ ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::upcall (TYPE &type, const void *act, const ACE_Time_Value &cur_time) { - this->upcall_functor_.timeout (*this, type, act, cur_time); + this->upcall_functor ().timeout (*this, type, act, cur_time); } @@ -37,18 +152,23 @@ template <class TYPE, class FUNCTOR, class LOCK> ACE_INLINE ACE_Time_Value ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::gettimeofday (void) { // Invoke gettimeofday via pointer to function. - return gettimeofday_ (); + return this->gettimeofday_ (); } template <class TYPE, class FUNCTOR, class LOCK> ACE_INLINE void ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::gettimeofday (ACE_Time_Value (*gettimeofday)(void)) { - gettimeofday_ = gettimeofday; + this->gettimeofday_ = gettimeofday; +} + +template <class TYPE, class FUNCTOR, class LOCK> ACE_INLINE LOCK & +ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::mutex (void) +{ + return this->mutex_; } template <class TYPE, class FUNCTOR, class LOCK> ACE_INLINE FUNCTOR & ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK>::upcall_functor (void) { - return this->upcall_functor_; + return *this->upcall_functor_; } - diff --git a/ace/Timer_Wheel.h b/ace/Timer_Wheel.h index 8f988afe117..5bc61b9592c 100644 --- a/ace/Timer_Wheel.h +++ b/ace/Timer_Wheel.h @@ -22,12 +22,12 @@ // compatibility. typedef ACE_Timer_Wheel_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_Wheel; typedef ACE_Timer_Wheel_Iterator_T<ACE_Event_Handler *, - ACE_Event_Handler_Handle_Timeout_Upcall, + ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX> ACE_Timer_Wheel_Iterator; 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 */ diff --git a/ace/Timer_Wheel_T.h b/ace/Timer_Wheel_T.h index 28a2a089d3b..213d6a9c3c8 100644 --- a/ace/Timer_Wheel_T.h +++ b/ace/Timer_Wheel_T.h @@ -28,30 +28,35 @@ class ACE_Timer_Wheel_Iterator_T : public ACE_Timer_Queue_Iterator_T <TYPE, FUNC // Iterates over an <ACE_Timer_Wheel>. // // = DESCRIPTION - // This is a special type of iterator that "advances" by moving - // the head of the timer queue up by one every time. + // This is a generic iterator that can be used to visit every + // node of a timer queue. Be aware that it doesn't transverse + // in the order of timeout values. { public: ACE_Timer_Wheel_Iterator_T (ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK> &); - // Constructor. + // Constructor - virtual int next (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *&timer_node, - const ACE_Time_Value &cur_time); - // Pass back the next <timer_node> that hasn't been seen yet, if its - // <time_value_> <= <cur_time>. In addition, moves the timer queue - // forward by one node. Returns 0 when all <timer_nodes> have been - // seen, else 1. + virtual void first (void); + // Positions the iterator at the earliest node in the Timer Queue - void reset (void); - // Resets the iterator + virtual void next (void); + // Positions the iterator at the next node in the Timer Queue + + virtual int isdone (void); + // Returns true when there are no more nodes in the sequence + + virtual ACE_Timer_Node_T<TYPE> *item (void); + // Returns the node at the current position in the sequence protected: ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK> &timer_wheel_; // Pointer to the <ACE_Timer_List> that we are iterating over. -private: - size_t pos_; // Current position in the timing wheel - ACE_Time_Value time_; // Corresponding time of <pos_> + size_t pos_; + // Current position in the timing wheel + + ACE_Timer_Node_T<TYPE> *list_item_; + // Pointer to the position in the the <pos_>th list }; template <class TYPE, class FUNCTOR, class LOCK> @@ -76,19 +81,34 @@ public: // Type of iterator friend class ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK>; - // Iterator is a friend. + // Iterator is a friend typedef ACE_Timer_Queue_T<TYPE, FUNCTOR, LOCK> INHERITED; - // Type inherited from. + // Type inherited from - // = Initialization and termination methods. - ACE_Timer_Wheel_T (size_t wheelsize = ACE_DEFAULT_TIMER_WHEEL_SIZE, - size_t resolution = ACE_DEFAULT_TIMER_WHEEL_RESOLUTION, + // = Initialization and termination methods + + ACE_Timer_Wheel_T (size_t wheelsize, + size_t resolution, size_t prealloc = 0, - FUNCTOR *upcall_functor = 0); - // Constructor that takes in a size for the timing wheel and a - // resolution for placement in the timing wheel lists (in - // microseconds). + FUNCTOR *upcall_functor = 0, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); + // Constructor that takes in <wheelsize> - size of the timing wheel, + // <resolution> - resolution of time values the hashing function uses, + // and <upcall_functor> - a functor that will be used instead of creating + // a default functor. Also, when the freelist is created, <prealloc> nodes + // will be allocated. This can also take in a upcall functor and freelist + // (if 0, then defaults will be created) + + ACE_Timer_Wheel_T (FUNCTOR *upcall_functor = 0, + ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0); + // Default constructor. <upcall_functor> is the instance of the + // FUNCTOR to be used by the queue. If <upcall_functor> is 0, Timer + // Queue will create a default FUNCTOR. <freelist> the freelist of + // timer nodes. If 0, then a default freelist will be created. The + // defaults will be used for size and resolution and no preallocation + // (ACE_DEFAULT_TIMER_WHEEL_SIZE, ACE_DEFAULT_TIMER_WHEEL_RESOLUTION) + virtual ~ACE_Timer_Wheel_T (void); // Destructor @@ -107,14 +127,9 @@ public: // If it expires then <act> is passed in as the value to the // <functor>. If <interval> is != to <ACE_Time_Value::zero> then it // is used to reschedule the <type> automatically. This method - // returns a <timer_id> that uniquely identifies the the <type> - // entry in an internal list. This <timer_id> can be used to cancel - // the timer before it expires. The cancellation ensures that - // <timer_ids> are unique up to values of greater than 2 billion - // timers. As long as timers don't stay around longer than this - // there should be no problems with accidentally deleting the wrong - // timer. Returns -1 on failure (which is guaranteed never to be a - // valid <timer_id>). + // returns a <timer_id> that uniquely identifies the the timer. + // This <timer_id> can be used to cancel the timer before it expires. + // Returns -1 on failure. virtual int cancel (const TYPE &type, int dont_call_handle_close = 1); @@ -133,28 +148,25 @@ public: // 0 then the <functor> will be invoked. Returns 1 if cancellation // succeeded and 0 if the <timer_id> wasn't found. - virtual void dump (void) const; - // Dump the state of an object. + virtual int expire (const ACE_Time_Value ¤t_time); + // Run the <functor> for all timers whose values are <= <cur_time>. + // This does not account for <timer_skew>. Returns the number of + // timers canceled. -protected: - virtual ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *alloc_node (void); - // Factory method that allocates a new node (uses operator new). + virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> &iter (void); + // Returns a pointer to this <ACE_Timer_Queue_T>'s iterator. - virtual void free_node (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *); - // Factory method that frees a previously allocated node (uses - // operator delete). + virtual ACE_Timer_Node_T<TYPE> *remove_first (void); + // Removes the earliest node from the queue and returns it -private: - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *remove (void); - // Removes the earliest node and returns a pointer to it. + virtual void dump (void) const; + // Dump the state of an object. - virtual void reschedule (ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *); +private: + virtual void reschedule (ACE_Timer_Node_T<TYPE> *); // Reschedule an "interval" node - virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, LOCK> &iter (void); - // Returns a pointer to this <ACE_Timer_Queue_T>'s iterator. - - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> **wheel_; + ACE_Timer_Node_T<TYPE> **wheel_; // Timing Wheel. size_t wheel_size_; @@ -163,11 +175,8 @@ private: size_t resolution_; // Resolution (in microsoconds) of the timing wheel. - size_t current_pos_; - // Current position in the timing wheel. - - ACE_Time_Value current_time_; - // Keeps track of the previous time <current_pos_> was updated. + size_t earliest_pos_; + // Index of the list with the earliest time long size_; // Keeps track of the size of the queue @@ -175,8 +184,8 @@ private: ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, LOCK> iterator_; // Iterator used to expire timers. - ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK> *freelist_; - // Pointer to the freelist of <ACE_Timer_Node_T<TYPE, FUNCTOR, LOCK>>. + ACE_Timer_Node_T<TYPE> *freelist_; + // Pointer to the freelist of <ACE_Timer_Node_T<TYPE>>. // = Don't allow these operations for now. ACE_Timer_Wheel_T (const ACE_Timer_Wheel_T<TYPE, FUNCTOR, LOCK> &); diff --git a/tests/Timer_Queue_Test.cpp b/tests/Timer_Queue_Test.cpp index 3bb96018147..0d5cf9abf3e 100644 --- a/tests/Timer_Queue_Test.cpp +++ b/tests/Timer_Queue_Test.cpp @@ -1,5 +1,3 @@ -// $Id$ - // ============================================================================ // // = LIBRARY @@ -9,13 +7,13 @@ // Timer_Queue_Test.cpp // // = DESCRIPTION -// This is a simple test of <ACE_Timer_Queue> and two of its -// subclasses (<ACE_Timer_List> and <ACE_Timer_Heap>). The test -// sets up a bunch of timers and then adds them to a timer -// queue. The functionality of the timer queue is then tested. No -// command line arguments are needed to run the test. +// This is a simple test of <ACE_Timer_Queue> and four of its +// subclasses (<ACE_Timer_List>, <ACE_Timer_Heap>, <ACE_Timer_Wheel>, and +// <ACE_Timer_Hash>). The test sets up a bunch of timers and then adds +// them to a timer queue. The functionality of the timer queue is then +// tested. No command line arguments are needed to run the test. // -// = AUTHOR +// = AUTHORS // Douglas C. Schmidt, Prashant Jain, and Darrell Brunsch // // ============================================================================ @@ -24,21 +22,20 @@ #include "ace/Timer_List.h" #include "ace/Timer_Heap.h" #include "ace/Timer_Wheel.h" +#include "ace/Timer_Hash.h" #include "test_config.h" -static void -randomize_array (long array[], size_t size) +template <class T> static void +randomize_array (T array[], size_t size) { size_t i; - ACE_OS::srand (ACE_OS::time (0L)); - // Randomize the array. for (i = 0; i < size; i++) { int index = ACE_OS::rand() % size--; - long temp = array [index]; + T temp = array [index]; array [index] = array [size]; array [size] = temp; } @@ -86,13 +83,16 @@ test_functionality (ACE_Timer_Queue *tq) long timer_id; timer_id = tq->schedule (&eh, (const void *) 1, - ACE_OS::gettimeofday ()); + tq->gettimeofday ()); ACE_ASSERT (timer_id != -1); + ACE_ASSERT (tq->is_empty () == 0); //== ACE_ASSERT (tq->schedule (&eh, (const void *) 42, - ACE_OS::gettimeofday ()) != -1); + tq->gettimeofday ()) != -1); + ACE_ASSERT (tq->is_empty () == 0); //== ACE_ASSERT (tq->schedule (&eh, (const void *) 42, - ACE_OS::gettimeofday ()) != -1); + tq->gettimeofday ()) != -1); + ACE_ASSERT (tq->is_empty () == 0); //== // The following method will trigger a call to <handle_close>. ACE_ASSERT (tq->cancel (timer_id, 0, 0) == 1); ACE_ASSERT (tq->is_empty () == 0); @@ -100,23 +100,23 @@ test_functionality (ACE_Timer_Queue *tq) ACE_ASSERT (tq->expire () == 2); ACE_ASSERT (tq->schedule (&eh, (const void *) 4, - ACE_OS::gettimeofday ()) != -1); + tq->gettimeofday ()) != -1); ACE_ASSERT (tq->schedule (&eh, (const void *) 5, - ACE_OS::gettimeofday ()) != -1); - + tq->gettimeofday ()) != -1); + // The following method will trigger a call to <handle_close>. ACE_ASSERT (tq->cancel (&eh, 0) == 2); ACE_ASSERT (tq->is_empty ()); ACE_ASSERT (tq->expire () == 0); ACE_ASSERT (tq->schedule (&eh, (const void *) 007, - ACE_OS::gettimeofday ()) != -1); + tq->gettimeofday ()) != -1); ACE_ASSERT (tq->expire () == 1); timer_id = tq->schedule (&eh, (const void *) 6, - ACE_OS::gettimeofday ()); + tq->gettimeofday ()); ACE_ASSERT (timer_id != -1); ACE_ASSERT (tq->schedule (&eh, (const void *) 7, - ACE_OS::gettimeofday ()) != -1); + tq->gettimeofday ()) != -1); // The following method will *not* trigger a call to <handle_close>. ACE_ASSERT (tq->cancel (timer_id) == 1); @@ -138,13 +138,19 @@ test_performance (ACE_Timer_Queue *tq, // Test the amount of time required to schedule all the timers. + ACE_Time_Value *times; + ACE_NEW (times, ACE_Time_Value[max_iterations]); + + for (i = 0; i < max_iterations; i++) + times[i] = tq->gettimeofday (); + timer.start (); for (i = 0; i < max_iterations; i++) { timer_ids[i] = tq->schedule (&eh, (const void *) 42, - ACE_OS::gettimeofday ()); + times[i]); ACE_ASSERT (timer_ids[i] != -1); } @@ -166,9 +172,7 @@ test_performance (ACE_Timer_Queue *tq, "time per call = %f usecs\n", (et.user_time / double (max_iterations)) * 1000000)); - // Test the amount of time required to cancel all the timers. We - // start from the "back" in order to measure the worst case - // performance for the <ACE_Timer_List> (which uses linear search). + // Test the amount of time required to cancel all the timers. timer.start (); @@ -199,7 +203,7 @@ test_performance (ACE_Timer_Queue *tq, for (i = 0; i < max_iterations; i++) ACE_ASSERT (tq->schedule (&eh, (const void *) 42, - ACE_OS::gettimeofday ()) != -1); + tq->gettimeofday ()) != -1); ACE_ASSERT (tq->is_empty () == 0); @@ -215,25 +219,24 @@ test_performance (ACE_Timer_Queue *tq, max_iterations, test_name)); ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n", - et.real_time, et.user_time, et.system_time)); + et.real_time, et.user_time, et.system_time)); ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n", (et.user_time / double (max_iterations)) * 1000000)); - // Test the amount of time required to randomly expire all the + // Test the amount of time required to randomly cancel all the // timers. for (i = 0; i < max_iterations; i++) { - timer_ids[i] = tq->schedule (&eh, (const void *) 42, - ACE_OS::gettimeofday ()); + timer_ids[i] = tq->schedule (&eh, + (const void *) 42, + tq->gettimeofday ()); ACE_ASSERT (timer_ids[i] != -1); } ACE_ASSERT (tq->is_empty () == 0); - randomize_array (timer_ids, max_iterations); - timer.start (); for (i = max_iterations - 1; i >= 0; i--) @@ -245,34 +248,95 @@ test_performance (ACE_Timer_Queue *tq, timer.elapsed_time (et); - ACE_DEBUG ((LM_DEBUG, "time to randomly expire %d timers for %s\n", - max_iterations, test_name)); - ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n", - et.real_time, et.user_time, et.system_time)); - ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n", - (et.user_time / double (max_iterations)) * 1000000)); + ACE_DEBUG ((LM_DEBUG, + "time to randomly cancel %d timers for %s\n", + max_iterations, test_name)); + ACE_DEBUG ((LM_DEBUG, + "real time = %f secs, user time = %f secs, system time = %f secs\n", + et.real_time, et.user_time, et.system_time)); + ACE_DEBUG ((LM_DEBUG, + "time per call = %f usecs\n", + (et.user_time / double (max_iterations)) * 1000000)); + + // Test the amount of time required to randomly schedule all the timers. + + ACE_Time_Value now = tq->gettimeofday (); + + for (i = 0; i < max_iterations; i++) + times[i] = now + ACE_Time_Value (0, ACE_OS::rand () % 1000000); + + timer.start (); + + for (i = 0; i < max_iterations; i++) + { + timer_ids[i] = tq->schedule (&eh, + (const void *) 42, + times[i]); + ACE_ASSERT (timer_ids[i] != -1); + } + + ACE_ASSERT (tq->is_empty () == 0); + + timer.stop (); + + timer.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + "time to randomly schedule %d timers for %s\n", + max_iterations, test_name)); + ACE_DEBUG ((LM_DEBUG, + "real time = %f secs, user time = %f secs, system time = %f secs\n", + et.real_time, et.user_time, et.system_time)); + ACE_DEBUG ((LM_DEBUG, + "time per call = %f usecs\n", + (et.user_time / double (max_iterations)) * 1000000)); + + // Test the amount of time required to cancel all the timers. + + // Make sure everything is ready to be expired + + while (tq->gettimeofday () < now + ACE_Time_Value (1)) + continue; + + timer.start (); + + tq->expire (); + + ACE_ASSERT (tq->is_empty ()); + + timer.stop (); + + timer.elapsed_time (et); + + ACE_DEBUG ((LM_DEBUG, + "time to expire %d randomly scheduled timers for %s\n", + max_iterations, test_name)); + ACE_DEBUG ((LM_DEBUG, + "real time = %f secs, user time = %f secs, system time = %f secs\n", + et.real_time, et.user_time, et.system_time)); + ACE_DEBUG ((LM_DEBUG, + "time per call = %f usecs\n", + (et.user_time / double (max_iterations)) * 1000000)); + + delete times; } -struct Timer_Queues +struct Timer_Queue_List { + Timer_Queue_List (ACE_Timer_Queue *queue, const char *name, Timer_Queue_List *next = NULL) + : queue_ (queue), + name_ (name), + next_ (next) + {} + ACE_Timer_Queue *queue_; // Pointer to the subclass of <ACE_Timer_Queue> that we're testing. const char *name_; // Name of the Queue that we're testing. -}; - -// New Timer_Queue implementations should be added to the end of this -// table. -static Timer_Queues timer_queues[] = -{ - { 0, "ACE_Timer_Heap (preallocated)" }, - { 0, "ACE_Timer_Heap (non-preallocated)" }, - { 0, "ACE_Timer_Wheel (preallocated)" }, - { 0, "ACE_Timer_Wheel (non-preallocated)" }, - { new ACE_Timer_List, "ACE_Timer_List" }, - { 0, 0 }, + Timer_Queue_List *next_; + // Pointer to the next <Timer_Queues> structure }; int @@ -280,47 +344,104 @@ main (int argc, char *argv[]) { ACE_START_TEST ("Timer_Queue_Test"); + ACE_High_Res_Timer::get_env_global_scale_factor(); + + ACE_OS::srand (ACE_OS::time (0L)); + if (argc > 1) max_iterations = ACE_OS::atoi (argv[1]); // = Perform initializations. + + Timer_Queue_List *tq_list = NULL; - // Preallocate memory. - ACE_NEW_RETURN (timer_queues[0].queue_, - ACE_Timer_Heap (ACE_DEFAULT_TIMERS, 1), - -1); + // Add new Timer_Queue implementations here. + - // Don't preallocate memory. - ACE_NEW_RETURN (timer_queues[1].queue_, - ACE_Timer_Heap, - -1); + // Timer_Hash (Heap) - // Preallocate memory. - ACE_NEW_RETURN (timer_queues[2].queue_, - ACE_Timer_Wheel (ACE_DEFAULT_TIMER_WHEEL_SIZE, - ACE_DEFAULT_TIMER_WHEEL_RESOLUTION, - ACE_DEFAULT_TIMERS), + ACE_NEW_RETURN (tq_list, + Timer_Queue_List (new ACE_Timer_Hash_Heap, + "ACE_Timer_Hash (Heap)", + tq_list), + -1); + + // Timer_Hash + + ACE_NEW_RETURN (tq_list, + Timer_Queue_List (new ACE_Timer_Hash, + "ACE_Timer_Hash", + tq_list), + -1); + + // Timer_List + + ACE_NEW_RETURN (tq_list, + Timer_Queue_List (new ACE_Timer_List, + "ACE_Timer_List", + tq_list), + -1); + + // Timer_Wheel without preallocated memory + + ACE_NEW_RETURN (tq_list, + Timer_Queue_List (new ACE_Timer_Wheel, + "ACE_Timer_Wheel (non-preallocated)", + tq_list), + -1); + + // Timer_Wheel with preallocated memory. + + ACE_NEW_RETURN (tq_list, + Timer_Queue_List (new ACE_Timer_Wheel (ACE_DEFAULT_TIMER_WHEEL_SIZE, + ACE_DEFAULT_TIMER_WHEEL_RESOLUTION, + max_iterations), + "ACE_Timer_Wheel (preallocated)", + tq_list), -1); - // Don't preallocate memory. - ACE_NEW_RETURN (timer_queues[3].queue_, - ACE_Timer_Wheel, - -1); + + + // Timer_Heap without preallocated memory. + + ACE_NEW_RETURN (tq_list, + Timer_Queue_List (new ACE_Timer_Heap, + "ACE_Timer_Heap (non-preallocated)", + tq_list), + -1); + + // Timer_Heap with preallocate memory. + + ACE_NEW_RETURN (tq_list, + Timer_Queue_List (new ACE_Timer_Heap (max_iterations, 1), + "ACE_Timer_Heap (preallocated)", + tq_list), + -1); + + + + // Create the Timer ID array ACE_NEW_RETURN (timer_ids, long[max_iterations], -1); + + Timer_Queue_List *tq_ptr = tq_list; - for (int i = 0; timer_queues[i].name_ != 0; i++) + while (tq_ptr != NULL) { ACE_DEBUG ((LM_DEBUG, "**** starting test of %s\n", - timer_queues[i].name_)); - test_functionality (timer_queues[i].queue_); - test_performance (timer_queues[i].queue_, - timer_queues[i].name_); - delete timer_queues[i].queue_; + tq_ptr->name_)); + test_functionality (tq_ptr->queue_); + test_performance (tq_ptr->queue_, + tq_ptr->name_); + delete tq_ptr->queue_; + Timer_Queue_List *temp = tq_ptr; + tq_ptr = tq_ptr->next_; + delete temp; } + ACE_END_TEST; return 0; } |