server/dep/ACE_wrappers/ace/Timer_Wheel_T.cpp

964 lines
29 KiB
C++

// $Id: Timer_Wheel_T.cpp 89254 2010-02-25 22:10:39Z cleeland $
#ifndef ACE_TIMER_WHEEL_T_CPP
#define ACE_TIMER_WHEEL_T_CPP
#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */
#include "ace/OS_NS_sys_time.h"
#include "ace/Guard_T.h"
#include "ace/Timer_Wheel_T.h"
#include "ace/Log_Msg.h"
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
// Design/implementation notes for ACE_Timer_Wheel_T.
//
// Each timer queue entry is represented by a ACE_Timer_Node.
// The timing wheel is divided into a number of "spokes"; there are
// spoke_count_ spokes in the wheel. Each timer is hashed into one of the
// spokes. Entries within each spoke are linked in a double-linked list
// in order of increasing expiration. The first ACE_Timer_Node in each
// spoke is a "dummy node" that marks the end of the list of ACE_Timer_Nodes
// in that spoke.
//
// The timer ID for a scheduled timer is formed by its spoke position in
// the wheel, and the number of timers that have been inserted in that spoke
// since the queue was initialized. N bits of the long timer_id are used
// to determine the spoke, and M bits are used as a counter.
// Each time a Node is inserted into a spoke, it's counter
// is incremented. The count is kept in the timer ID field
// of the dummy root Node. In the event of overflow of the counter, the spoke
// must be searched for each new id to make sure it's not already in use. To
// prevent having to do an exhaustive search each time, we keep extra data
// in the dummy root Node.
/**
* Default Constructor that sets defaults for spoke_count_ and resolution_
* and doesn't do any preallocation.
*
* @param upcall_functor A pointer to a functor to use instead of the default
* @param freelist A pointer to a freelist to use instead of the default
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Wheel_T
(FUNCTOR* upcall_functor
, FreeList* freelist
)
: Base (upcall_functor, freelist)
, spokes_(0)
, spoke_count_(0) // calculated in open_i
, spoke_bits_(0)
, res_bits_ (0)
, earliest_spoke_ (0)
, iterator_(0)
, timer_count_(0)
{
ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T");
this->open_i (0,
ACE_DEFAULT_TIMER_WHEEL_SIZE,
ACE_DEFAULT_TIMER_WHEEL_RESOLUTION);
}
/**
* Constructor that sets up the timing wheel and also may preallocate
* some nodes on the free list
*
* @param spoke_count The number of lists in the timer wheel
* @param resolution The time resolution in milliseconds used by the hashing function
* @param prealloc The number of entries to prealloc in the free_list
* @param upcall_functor A pointer to a functor to use instead of the default
* @param freelist A pointer to a freelist to use instead of the default
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Wheel_T
(u_int spoke_count,
u_int resolution,
size_t prealloc,
FUNCTOR* upcall_functor,
FreeList* freelist)
: Base (upcall_functor, freelist)
, spokes_ (0)
, spoke_count_ (0) // calculated in open_i
, spoke_bits_ (0)
, res_bits_ (0)
, earliest_spoke_ (0)
, iterator_ (0)
, timer_count_ (0)
{
ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T");
this->open_i (prealloc, spoke_count, resolution);
}
template <class TYPE, class FUNCTOR, class ACE_LOCK> int
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::power2bits (int n,
int min_bits,
int max_bits)
{
int max = (1 << max_bits) - 1;
if (n > max)
return max_bits;
// count the bits in n.
int i = 0;
int tmp = n;
do
{
tmp >>= 1;
++i;
}
while (tmp != 0);
if (i <= min_bits)
return min_bits;
// Which is nearest?
int a = (1 << i) - n;
int b = (1 << (i - 1)) - n;
if (b < 0)
b = -b;
if (b < a)
return i - 1;
return i;
}
/**
* Initialize the queue. Uses the established members for all needed
* information.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::open_i
(size_t prealloc, u_int spokes, u_int res)
{
ACE_TRACE ("ACE_Timer_Wheel_T::open_i");
this->gettimeofday (ACE_OS::gettimeofday);
// Rather than waste bits in our timer id, we might as well round up
// the spoke count to the next power of two - 1 . (i.e 1,3,7,15,...127,etc.)
const int MIN_SPOKE_BITS = 3; // Allow between 8 and 4096 spokes
const int MAX_SPOKE_BITS = 12;
const int MAX_RES_BITS = 20; // 20 is plenty, even on 64 bit platforms.
this->spoke_bits_ = power2bits (spokes, MIN_SPOKE_BITS, MAX_SPOKE_BITS);
this->res_bits_ = power2bits (res, 1, MAX_RES_BITS);
this->spoke_count_ = 1 << this->spoke_bits_;
this->free_list_->resize (prealloc + this->spoke_count_);
this->wheel_time_.msec (1 << (this->res_bits_));
ACE_NEW (this->spokes_, ACE_Timer_Node_T<TYPE>* [this->spoke_count_]);
// Create the root nodes. These will be treated specially
for (u_int i = 0; i < this->spoke_count_; ++i)
{
ACE_Timer_Node_T<TYPE>* root = this->alloc_node ();
root->set (0, 0, ACE_Time_Value::zero, ACE_Time_Value::zero, root, root, 0);
this->spokes_[i] = root;
}
ACE_NEW (iterator_, Iterator (*this));
}
/// Destructor just cleans up its memory
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Wheel_T (void)
{
ACE_TRACE ("ACE_Timer_Wheel_T::~ACE_Timer_Wheel_T");
delete iterator_;
for (u_int i = 0; i < this->spoke_count_; ++i)
{
// Free all the nodes starting at the root
ACE_Timer_Node_T<TYPE>* root = this->spokes_[i];
for (ACE_Timer_Node_T<TYPE>* n = root->get_next (); n != root;)
{
ACE_Timer_Node_T<TYPE>* next = n->get_next ();
this->upcall_functor ().deletion (*this,
n->get_type (),
n->get_act ());
this->free_node (n);
n = next;
}
delete root;
}
delete[] this->spokes_;
}
/// Searches for a node by timer_id within one spoke.
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Node_T<TYPE>*
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::find_spoke_node
(u_int spoke, long timer_id) const
{
ACE_Timer_Node_T<TYPE>* root = this->spokes_[spoke];
for (ACE_Timer_Node_T<TYPE>* n = root->get_next ();
n != root;
n = n->get_next ())
{
if (n->get_timer_id () == timer_id)
return n;
}
return 0;
}
/// Searches all spokes for a node matching the specified timer_id
/// Uses the spoke encoded in the timer_id as a starting place.
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Node_T<TYPE>*
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::find_node (long timer_id) const
{
if (timer_id == -1)
return 0;
// Search the spoke where timer_id was originally scheduled
u_int spoke_mask = this->spoke_count_ - 1;
u_int start = timer_id & spoke_mask;
ACE_Timer_Node_T<TYPE>* n = this->find_spoke_node (start, timer_id);
if (n != 0)
return n;
//ACE_ERROR((LM_ERROR, "Node not found in original spoke.\n"));
// Search the rest of the spokes
for (u_int i = 0; i < this->spoke_count_; ++i)
{
if (i != start)
{ // already searched this one
n = this->find_spoke_node (i, timer_id);
if (n != 0)
return n;
}
}
//ACE_ERROR((LM_ERROR, "Node not found.\n"));
return 0;
}
/**
* Check to see if the wheel is empty
*
* @return True if empty
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> bool
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::is_empty (void) const
{
ACE_TRACE ("ACE_Timer_Wheel_T::is_empty");
return timer_count_ == 0;
}
/**
* @return First (earliest) node in the wheel_'s earliest_spoke_ list
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> const ACE_Time_Value &
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::earliest_time (void) const
{
ACE_TRACE ("ACE_Timer_Wheel_T::earliest_time");
ACE_Timer_Node_T<TYPE>* n = this->get_first_i ();
if (n != 0)
return n->get_timer_value ();
return ACE_Time_Value::zero;
}
/// Uses a simple hash to find which spoke to use based on when the
/// timer is due to expire. Hopefully the 64bit int operations avoid
/// any overflow problems.
template <class TYPE, class FUNCTOR, class ACE_LOCK> u_int
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::calculate_spoke
(const ACE_Time_Value& t) const
{
return static_cast<u_int> ((t.msec () >> this->res_bits_) & (this->spoke_count_ - 1));
}
/// Generates a unique timer_id for the given spoke. It should be pretty
/// fast until the point where the counter overflows. At that time you
/// have to do exhaustive searches within the spoke to ensure that a particular
/// timer id is not already in use. Some optimizations are in place so
/// that this hopefully doesn't have to happen often.
template <class TYPE, class FUNCTOR, class ACE_LOCK> long
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::generate_timer_id (u_int spoke)
{
int cnt_bits = sizeof (long) * 8 - this->spoke_bits_;
long max_cnt = ((long)1 << cnt_bits) - 1;
if (spoke == this->spoke_count_)
--max_cnt; // Because -1 is used as a special invalid timer_id.
ACE_Timer_Node_T<TYPE>* root = this->spokes_[spoke];
if (root == root->get_next ())
root->set_act(0);
// We use this field to keep track of the next counter value that
// may be in use. Of course it may have expired, so we just use
// this field so that we know when we don't have to check for duplicates
#if defined (ACE_WIN64)
// The cast below is legit... we know that long is shorter than a
// pointer, but are only using it as a 'long' storage area.
# pragma warning(push)
# pragma warning(disable : 4311)
#endif /* ACE_WIN64 */
long next_cnt = reinterpret_cast<long> (root->get_act ());
#if defined (ACE_WIN64)
# pragma warning(pop)
#endif /* ACE_WIN64 */
// This field is used as a counter instead of a timer_id.
long cnt = root->get_timer_id ();
if (cnt >= max_cnt && root == root->get_next ())
{
// Special case when we overflow on an empty spoke. We can just
// wrap the count around without searching for duplicates. We only
// want to do this when the counter overflows, so that we return
// unique timer_id values as often as possible.
root->set_timer_id (1);
return spoke;
}
else if (cnt >= max_cnt)
{ // overflow
cnt = 0; // try again starting at zero
}
else if (next_cnt == 0 || cnt < next_cnt)
{
root->set_timer_id (cnt + 1);
return (cnt << this->spoke_bits_) | spoke;
}
//ACE_ERROR((LM_ERROR, "Timer id overflow. We have to search now.\n"));
// We've run out of consecutive id numbers so now we have to search
// for a unique id.
// We'll try increasing numbers until we find one that is not in use,
// and we'll record the next highest number so that we can avoid this
// search as often as possible.
for (; cnt < max_cnt - 1; ++cnt)
{
long id = (cnt << this->spoke_bits_) | spoke;
ACE_Timer_Node_T<TYPE>* n = this->find_spoke_node (spoke, id);
if (n == 0)
{
root->set_timer_id (cnt + 1);
// Now we need to find the next highest cnt in use
next_cnt = 0;
for (; n != root; n = n->get_next ())
{
long tmp = n->get_timer_id () >> this->spoke_bits_;
if (tmp > cnt && (tmp < next_cnt || next_cnt == 0))
next_cnt = tmp;
}
#if defined (ACE_WIN64)
// The cast below is legit... we know we're storing a long in
// a pointer, but are only using it as a 'long' storage area.
# pragma warning(push)
# pragma warning(disable : 4312)
#endif /* ACE_WIN64 */
root->set_act (reinterpret_cast<void*> (next_cnt));
#if defined (ACE_WIN64)
# pragma warning(pop)
#endif /* ACE_WIN64 */
return id;
}
}
return -1; // We did our best, but the spoke is full.
}
/**
* Creates a ACE_Timer_Node_T based on the input parameters. Then inserts
* the node into the wheel using reschedule (). Then returns a timer_id.
*
* @param type The data of the timer node
* @param act Asynchronous Completion Token (AKA magic cookie)
* @param future_time The time the timer is scheduled for (absolute time)
* @param interval If not ACE_Time_Value::zero, then this is a periodic
* timer and interval is the time period
*
* @return Unique identifier (can be used to cancel the timer).
* -1 on failure.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> long
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::schedule_i (const TYPE& type,
const void* act,
const ACE_Time_Value& future_time,
const ACE_Time_Value& interval)
{
ACE_TRACE ("ACE_Timer_Wheel_T::schedule_i");
ACE_Timer_Node_T<TYPE>* n = this->alloc_node ();
if (n != 0)
{
u_int spoke = calculate_spoke (future_time);
long id = generate_timer_id (spoke);
//ACE_ERROR((LM_ERROR, "Scheduling %x spoke:%d id:%d\n", (long) n, spoke, id));
if (id != -1)
{
n->set (type, act, future_time, interval, 0, 0, id);
this->schedule_i (n, spoke, future_time);
}
return id;
}
// Failure return
errno = ENOMEM;
return -1;
}
/**
* Takes an ACE_Timer_Node and inserts it into the correct position in
* the correct list. Also makes sure to update the earliest time.
*
* @param n The timer node to reschedule
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::reschedule (ACE_Timer_Node_T<TYPE>* n)
{
ACE_TRACE ("ACE_Timer_Wheel_T::reschedule");
const ACE_Time_Value& expire = n->get_timer_value ();
u_int spoke = calculate_spoke (expire);
this->schedule_i (n, spoke, expire);
}
/// The shared scheduling functionality between schedule() and reschedule()
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::schedule_i
(ACE_Timer_Node_T<TYPE>* n,
u_int spoke,
const ACE_Time_Value& expire)
{
// See if we need to update the earliest time
if (this->is_empty() || expire < this->earliest_time ())
this->earliest_spoke_ = spoke;
ACE_Timer_Node_T<TYPE>* root = this->spokes_[spoke];
ACE_Timer_Node_T<TYPE>* last = root->get_prev ();
++timer_count_;
// If the spoke is empty
if (last == root) {
n->set_prev (root);
n->set_next (root);
root->set_prev (n);
root->set_next (n);
return;
}
// We always want to search backwards from the tail of the list, because
// this minimizes the search in the extreme case when lots of timers are
// scheduled for exactly the same time
ACE_Timer_Node_T<TYPE>* p = root->get_prev ();
while (p != root && p->get_timer_value () > expire)
p = p->get_prev ();
// insert after
n->set_prev (p);
n->set_next (p->get_next ());
p->get_next ()->set_prev (n);
p->set_next (n);
}
/**
* Find the timer node by using the id as a pointer. Then use set_interval()
* on the node to update the interval.
*
* @param timer_id The timer identifier
* @param interval The new interval
*
* @return 0 if successful, -1 if no.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> int
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::reset_interval (long timer_id,
const ACE_Time_Value &interval
)
{
ACE_TRACE ("ACE_Timer_Wheel_T::reset_interval");
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
ACE_Timer_Node_T<TYPE>* n = this->find_node (timer_id);
if (n != 0)
{
// The interval will take effect the next time this node is expired.
n->set_interval (interval);
return 0;
}
return -1;
}
/**
* Goes through every list in the wheel and whenever we find one with the
* correct type value, we remove it and continue. At the end make sure
* we reset the earliest time value in case the earliest timers were
* removed.
*
* @param type The value to search for.
* @param skip_close If this non-zero, the cancellation method of the
* functor will not be called for each cancelled timer.
*
* @return Number of timers cancelled
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> int
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (const TYPE& type, int skip_close)
{
ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
int num_canceled = 0; // Note : Technically this can overflow.
int cookie = 0;
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
if (!this->is_empty ())
{
ACE_Timer_Node_T<TYPE>* first = this->get_first ();
ACE_Time_Value last = first->get_timer_value ();
int recalc = 0;
for (u_int i = 0; i < this->spoke_count_; ++i)
{
ACE_Timer_Node_T<TYPE>* root = this->spokes_[i];
for (ACE_Timer_Node_T<TYPE>* n = root->get_next (); n != root; )
{
if (n->get_type () == type)
{
++num_canceled;
if (n == first)
recalc = 1;
ACE_Timer_Node_T<TYPE>* tmp = n;
n = n->get_next ();
this->cancel_i (tmp);
}
else
{
n = n->get_next ();
}
}
}
if (recalc)
this->recalc_earliest (last);
}
// Call the close hooks.
// cancel_type() called once per <type>.
this->upcall_functor ().cancel_type (*this,
type,
skip_close,
cookie);
for (int i = 0;
i < num_canceled;
++i)
{
// cancel_timer() called once per <timer>.
this->upcall_functor ().cancel_timer (*this,
type,
skip_close,
cookie);
}
return num_canceled;
}
/**
* Cancels the single timer that is specified by the timer_id. In this
* case the timer_id is actually a pointer to the node, so we cast it
* to the node. This can be dangerous if the timer_id is made up
* (or deleted twice) so we do a little sanity check. Finally we update
* the earliest time in case the earliest timer was removed.
*
* @param timer_id Timer Identifier
* @param act Asychronous Completion Token (AKA magic cookie):
* If this is non-zero, stores the magic cookie of
* the cancelled timer here.
* @param skip_close If this non-zero, the cancellation method of the
* functor will not be called.
*
* @return 1 for sucess and 0 if the timer_id wasn't found (or was
* found to be invalid)
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> int
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (long timer_id,
const void **act,
int skip_close)
{
ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
ACE_Timer_Node_T<TYPE>* n = this->find_node (timer_id);
if (n != 0)
{
ACE_Time_Value last = n->get_timer_value ();
int recalc = (this->get_first_i () == n);
// Call the close hooks.
int cookie = 0;
// cancel_type() called once per <type>.
this->upcall_functor ().cancel_type (*this,
n->get_type (),
skip_close,
cookie);
// cancel_timer() called once per <timer>.
this->upcall_functor ().cancel_timer (*this,
n->get_type (),
skip_close,
cookie);
if (act != 0)
*act = n->get_act ();
this->cancel_i (n);
if (recalc)
this->recalc_earliest (last);
return 1;
}
return 0;
}
/// Shared subset of the two cancel() methods.
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::cancel_i (ACE_Timer_Node_T<TYPE>* n)
{
this->unlink (n);
this->free_node (n);
}
/// There are a few places where we have to figure out which timer
/// will expire next. This method makes the assumption that spokes
/// are always sorted, and that timers are always in the correct spoke
/// determined from their expiration time.
/// The last time is always passed in, even though you can often calculate
/// it as get_first()->get_timer_value().
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::recalc_earliest
(const ACE_Time_Value& last)
{
// This is possible because we use a count for is_empty()
if (this->is_empty ())
return;
ACE_Time_Value et = ACE_Time_Value::zero;
u_int es = 0;
u_int spoke = this->earliest_spoke_;
// We will have to go around the wheel at most one time.
for (u_int i = 0; i < this->spoke_count_; ++i)
{
ACE_Timer_Node_T<TYPE>* root = this->spokes_[spoke];
ACE_Timer_Node_T<TYPE>* n = root->get_next ();
if (n != root)
{
ACE_Time_Value t = n->get_timer_value ();
if (t < last + this->wheel_time_)
{
this->earliest_spoke_ = spoke;
return;
}
else if (et == ACE_Time_Value::zero || t < et)
{
et = t;
es = spoke;
}
}
if (++spoke >= this->spoke_count_)
spoke = 0;
}
this->earliest_spoke_ = es;
//ACE_ERROR((LM_ERROR, "We had to search the whole wheel.\n"));
}
/**
* Dumps out the size of the wheel, the resolution, and the contents
* of the wheel.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::dump (void) const
{
#if defined (ACE_HAS_DUMP)
ACE_TRACE ("ACE_Timer_Wheel_T::dump");
ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("\nspoke_count_ = %d"), this->spoke_count_));
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("\nresolution_ = %d"), 1 << this->res_bits_));
ACE_DEBUG ((LM_DEBUG,
ACE_TEXT ("\nwheel_ =\n")));
for (u_int i = 0; i < this->spoke_count_; ++i)
{
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d\n"), i));
ACE_Timer_Node_T<TYPE>* root = this->spokes_[i];
for (ACE_Timer_Node_T<TYPE>* n = root->get_next ();
n != root;
n = n->get_next ())
{
n->dump ();
}
}
ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
#endif /* ACE_HAS_DUMP */
}
/**
* Removes the earliest node and then find the new <earliest_spoke_>
*
* @return The earliest timer node.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::remove_first (void)
{
ACE_TRACE ("ACE_Timer_Wheel_T::remove_first");
return remove_first_expired (ACE_Time_Value::max_time);
}
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::unlink (ACE_Timer_Node_T<TYPE>* n)
{
ACE_TRACE ("ACE_Timer_Wheel_T::unlink");
--timer_count_;
n->get_prev ()->set_next (n->get_next ());
n->get_next ()->set_prev (n->get_prev ());
n->set_prev (0);
n->set_next (0);
}
template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::remove_first_expired (const ACE_Time_Value& now)
{
ACE_Timer_Node_T<TYPE>* n = this->get_first ();
if (n != 0 && n->get_timer_value() <= now)
{
this->unlink (n);
this->recalc_earliest (n->get_timer_value ());
return n;
}
return 0;
}
/**
* Returns the earliest node without removing it
*
* @return The earliest timer node.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Node_T<TYPE>*
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::get_first (void)
{
ACE_TRACE ("ACE_Timer_Wheel_T::get_first");
return this->get_first_i ();
}
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Node_T<TYPE>*
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::get_first_i (void) const
{
ACE_Timer_Node_T<TYPE>* root = this->spokes_[this->earliest_spoke_];
ACE_Timer_Node_T<TYPE>* first = root->get_next ();
if (first != root)
return first;
return 0;
}
/**
* @return The iterator
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>&
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::iter (void)
{
this->iterator_->first ();
return *this->iterator_;
}
/**
* Dummy version of expire to get rid of warnings in Sun CC 4.2
* Just call the expire of the base class.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> int
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::expire ()
{
return ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK>::expire ();
}
/**
* This is a specialized version of expire that is more suited for the
* internal data representation.
*
* @param cur_time The time to expire timers up to.
*
* @return Number of timers expired
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> int
ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::expire (const ACE_Time_Value& cur_time)
{
ACE_TRACE ("ACE_Timer_Wheel_T::expire");
int expcount = 0;
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
ACE_Timer_Node_T<TYPE>* n = this->remove_first_expired (cur_time);
while (n != 0)
{
++expcount;
//ACE_ERROR((LM_ERROR, "Expiring %x\n", (long) n));
ACE_Timer_Node_Dispatch_Info_T<TYPE> info;
// Get the dispatch info
n->get_dispatch_info (info);
if (n->get_interval () > ACE_Time_Value::zero)
{
// Make sure that we skip past values that have already
// "expired".
this->recompute_next_abs_interval_time (n, cur_time);
this->reschedule (n);
}
else
{
this->free_node (n);
}
const void *upcall_act = 0;
this->preinvoke (info, cur_time, upcall_act);
this->upcall (info, cur_time);
this->postinvoke (info, cur_time, upcall_act);
n = this->remove_first_expired (cur_time);
}
return expcount;
}
///////////////////////////////////////////////////////////////////////////
// ACE_Timer_Wheel_Iterator_T
/**
* Just initializes the iterator with a ACE_Timer_Wheel_T and then calls
* first() to initialize the rest of itself.
*
* @param wheel A reference for a timer queue to iterate over
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Wheel_Iterator_T<TYPE,FUNCTOR,ACE_LOCK>::ACE_Timer_Wheel_Iterator_T
(Wheel& wheel)
: timer_wheel_ (wheel)
{
this->first();
}
/**
* Destructor, at this level does nothing.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK>
ACE_Timer_Wheel_Iterator_T<TYPE,
FUNCTOR,
ACE_LOCK>::~ACE_Timer_Wheel_Iterator_T (void)
{
}
/**
* Positions the iterator at the first position in the timing wheel
* that contains something. spoke_ will be set to the spoke position of
* this entry and current_node_ will point to the first entry in that spoke.
*
* If the wheel is empty, spoke_ will be equal timer_wheel_.spoke_count_ and
* current_node_ would be 0.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::first (void)
{
this->goto_next(0);
}
/**
* Positions the iterator at the next node.
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::next (void)
{
if (this->isdone())
return;
ACE_Timer_Node_T<TYPE>* n = this->current_node_->get_next ();
ACE_Timer_Node_T<TYPE>* root = this->timer_wheel_.spokes_[this->spoke_];
if (n == root)
this->goto_next (this->spoke_ + 1);
else
this->current_node_ = n;
}
/// Helper class for common functionality of next() and first()
template <class TYPE, class FUNCTOR, class ACE_LOCK> void
ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::goto_next (u_int start_spoke)
{
// Find the first non-empty entry.
u_int sc = this->timer_wheel_.spoke_count_;
for (u_int i = start_spoke; i < sc; ++i)
{
ACE_Timer_Node_T<TYPE>* root = this->timer_wheel_.spokes_[i];
ACE_Timer_Node_T<TYPE>* n = root->get_next ();
if (n != root)
{
this->spoke_ = i;
this->current_node_ = n;
return;
}
}
// empty
this->spoke_ = sc;
this->current_node_ = 0;
}
/**
* @return True when we there aren't any more items (when current_node_ == 0)
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> bool
ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::isdone (void) const
{
return this->current_node_ == 0;
}
/**
* @return The node at the current spokeition in the sequence or 0 if the wheel
* is empty
*/
template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::item (void)
{
return this->current_node_;
}
ACE_END_VERSIONED_NAMESPACE_DECL
#endif /* ACE_TIMER_WHEEL_T_CPP */