1 #ifndef ACE_TIMER_WHEEL_T_CPP
2 #define ACE_TIMER_WHEEL_T_CPP
4 #if !defined (ACE_LACKS_PRAGMA_ONCE)
6 #endif /* ACE_LACKS_PRAGMA_ONCE */
8 #include "ace/OS_NS_sys_time.h"
9 #include "ace/Guard_T.h"
10 #include "ace/Timer_Wheel_T.h"
11 #include "ace/Log_Category.h"
12 #include "ace/Truncate.h"
14 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
16 // Design/implementation notes for ACE_Timer_Wheel_T.
18 // Each timer queue entry is represented by a ACE_Timer_Node.
19 // The timing wheel is divided into a number of "spokes"; there are
20 // spoke_count_ spokes in the wheel. Each timer is hashed into one of the
21 // spokes. Entries within each spoke are linked in a double-linked list
22 // in order of increasing expiration. The first ACE_Timer_Node in each
23 // spoke is a "dummy node" that marks the end of the list of ACE_Timer_Nodes
26 // The timer ID for a scheduled timer is formed by its spoke position in
27 // the wheel, and the number of timers that have been inserted in that spoke
28 // since the queue was initialized. N bits of the long timer_id are used
29 // to determine the spoke, and M bits are used as a counter.
30 // Each time a Node is inserted into a spoke, it's counter
31 // is incremented. The count is kept in the timer ID field
32 // of the dummy root Node. In the event of overflow of the counter, the spoke
33 // must be searched for each new id to make sure it's not already in use. To
34 // prevent having to do an exhaustive search each time, we keep extra data
35 // in the dummy root Node.
37 * Default Constructor that sets defaults for spoke_count_ and resolution_
38 * and doesn't do any preallocation.
40 * @param upcall_functor A pointer to a functor to use instead of the default
41 * @param freelist A pointer to a freelist to use instead of the default
43 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
44 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::ACE_Timer_Wheel_T
45 (FUNCTOR
* upcall_functor
47 , TIME_POLICY
const & time_policy
49 : Base_Timer_Queue (upcall_functor
, freelist
, time_policy
)
51 , spoke_count_(0) // calculated in open_i
58 ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T");
60 ACE_DEFAULT_TIMER_WHEEL_SIZE
,
61 ACE_DEFAULT_TIMER_WHEEL_RESOLUTION
);
65 * Constructor that sets up the timing wheel and also may preallocate
66 * some nodes on the free list
68 * @param spoke_count The number of lists in the timer wheel
69 * @param resolution The time resolution in milliseconds used by the hashing function
70 * @param prealloc The number of entries to prealloc in the free_list
71 * @param upcall_functor A pointer to a functor to use instead of the default
72 * @param freelist A pointer to a freelist to use instead of the default
74 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
75 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::ACE_Timer_Wheel_T
79 FUNCTOR
* upcall_functor
,
81 TIME_POLICY
const & time_policy
)
82 : Base_Timer_Queue (upcall_functor
, freelist
, time_policy
)
84 , spoke_count_ (0) // calculated in open_i
91 ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T");
92 this->open_i (prealloc
, spoke_count
, resolution
);
95 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
96 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::power2bits (int n
,
100 int max
= (1 << max_bits
) - 1;
104 // count the bits in n.
118 int a
= (1 << i
) - n
;
119 int b
= (1 << (i
- 1)) - n
;
128 * Initialize the queue. Uses the established members for all needed
131 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
132 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::open_i
133 (size_t prealloc
, u_int spokes
, u_int res
)
135 ACE_TRACE ("ACE_Timer_Wheel_T::open_i");
137 // Rather than waste bits in our timer id, we might as well round up
138 // the spoke count to the next power of two - 1 . (i.e 1,3,7,15,...127,etc.)
139 const int MIN_SPOKE_BITS
= 3; // Allow between 8 and 4096 spokes
140 const int MAX_SPOKE_BITS
= 12;
141 const int MAX_RES_BITS
= 20; // 20 is plenty, even on 64 bit platforms.
143 this->spoke_bits_
= power2bits (spokes
, MIN_SPOKE_BITS
, MAX_SPOKE_BITS
);
144 this->res_bits_
= power2bits (res
, 1, MAX_RES_BITS
);
146 this->spoke_count_
= 1 << this->spoke_bits_
;
148 this->free_list_
->resize (prealloc
+ this->spoke_count_
);
150 this->wheel_time_
.msec (1 << (this->res_bits_
));
152 ACE_NEW (this->spokes_
, ACE_Timer_Node_T
<TYPE
>* [this->spoke_count_
]);
154 // Create the root nodes. These will be treated specially
155 for (u_int i
= 0; i
< this->spoke_count_
; ++i
)
157 ACE_Timer_Node_T
<TYPE
>* root
= this->alloc_node ();
158 root
->set (0, 0, ACE_Time_Value::zero
, ACE_Time_Value::zero
, root
, root
, 0);
159 this->spokes_
[i
] = root
;
162 ACE_NEW (iterator_
, Iterator (*this));
165 /// Destructor just cleans up its memory
166 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
167 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::~ACE_Timer_Wheel_T ()
169 ACE_TRACE ("ACE_Timer_Wheel_T::~ACE_Timer_Wheel_T");
174 for (u_int i
= 0; i
< this->spoke_count_
; ++i
)
176 // Free all the nodes starting at the root
177 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[i
];
178 this->free_node (root
);
181 delete[] this->spokes_
;
184 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
185 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::close ()
187 ACE_TRACE ("ACE_Timer_Wheel_T::close");
189 // Remove any remaining nodes
190 for (u_int i
= 0; i
< this->spoke_count_
; ++i
)
192 // Free all the nodes starting at the root
193 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[i
];
194 for (ACE_Timer_Node_T
<TYPE
>* n
= root
->get_next (); n
!= root
;)
196 ACE_Timer_Node_T
<TYPE
>* next
= n
->get_next ();
197 this->upcall_functor ().deletion (*this,
205 // Leave rest for destructor
209 /// Searches for a node by timer_id within one spoke.
210 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
211 ACE_Timer_Node_T
<TYPE
>*
212 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::find_spoke_node
213 (u_int spoke
, long timer_id
) const
215 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[spoke
];
216 for (ACE_Timer_Node_T
<TYPE
>* n
= root
->get_next ();
220 if (n
->get_timer_id () == timer_id
)
226 /// Searches all spokes for a node matching the specified timer_id
227 /// Uses the spoke encoded in the timer_id as a starting place.
228 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
229 ACE_Timer_Node_T
<TYPE
>*
230 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::find_node (long timer_id
) const
235 // Search the spoke where timer_id was originally scheduled
236 u_int spoke_mask
= this->spoke_count_
- 1;
237 u_int start
= timer_id
& spoke_mask
;
238 ACE_Timer_Node_T
<TYPE
>* n
= this->find_spoke_node (start
, timer_id
);
242 //ACELIB_ERROR((LM_ERROR, "Node not found in original spoke.\n"));
244 // Search the rest of the spokes
245 for (u_int i
= 0; i
< this->spoke_count_
; ++i
)
248 { // already searched this one
249 n
= this->find_spoke_node (i
, timer_id
);
255 //ACELIB_ERROR((LM_ERROR, "Node not found.\n"));
260 * Check to see if the wheel is empty
262 * @return True if empty
264 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> bool
265 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::is_empty () const
267 ACE_TRACE ("ACE_Timer_Wheel_T::is_empty");
268 return timer_count_
== 0;
273 * @return First (earliest) node in the wheel_'s earliest_spoke_ list
275 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> const ACE_Time_Value
&
276 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::earliest_time () const
278 ACE_TRACE ("ACE_Timer_Wheel_T::earliest_time");
279 ACE_Timer_Node_T
<TYPE
>* n
= this->get_first_i ();
281 return n
->get_timer_value ();
282 return ACE_Time_Value::zero
;
285 /// Uses a simple hash to find which spoke to use based on when the
286 /// timer is due to expire. Hopefully the 64bit int operations avoid
287 /// any overflow problems.
288 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> u_int
289 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::calculate_spoke
290 (const ACE_Time_Value
& t
) const
292 return static_cast<u_int
> ((t
.msec () >> this->res_bits_
) & (this->spoke_count_
- 1));
295 /// Generates a unique timer_id for the given spoke. It should be pretty
296 /// fast until the point where the counter overflows. At that time you
297 /// have to do exhaustive searches within the spoke to ensure that a particular
298 /// timer id is not already in use. Some optimizations are in place so
299 /// that this hopefully doesn't have to happen often.
300 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> long
301 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::generate_timer_id (u_int spoke
)
303 int cnt_bits
= sizeof (long) * 8 - this->spoke_bits_
;
304 long max_cnt
= ((long)1 << cnt_bits
) - 1;
305 if (spoke
== this->spoke_count_
)
306 --max_cnt
; // Because -1 is used as a special invalid timer_id.
308 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[spoke
];
310 if (root
== root
->get_next ())
313 // This field is used as a counter instead of a timer_id.
314 long cnt
= root
->get_timer_id ();
318 root
->set_timer_id (cnt
+ 1);
319 return (cnt
<< this->spoke_bits_
) | spoke
;
322 // Count has overflowed its range.
323 if (root
== root
->get_next ())
325 // Special case when we overflow on an empty spoke. We can just
326 // wrap the count around without searching for duplicates. We only
327 // want to do this when the counter overflows, so that we return
328 // unique timer_id values as often as possible.
329 root
->set_timer_id (1);
333 // Overflowed count, and the spoke is not empty. Search for an unused
335 //ACELIB_ERROR((LM_ERROR, "Timer id overflow. We have to search now.\n"));
336 for (cnt
= 0; cnt
< max_cnt
- 1; ++cnt
)
338 // Look for an unused id. Yes, every new id on this spoke will result in a
339 // scan until all the spoke's timers get canceled/expired then the spoke will
340 // start over like new. So, when an empty spot is found, don't reset the
341 // root node's timer_id - it stays at max until the spoke clears out and
343 long id
= (cnt
<< this->spoke_bits_
) | spoke
;
344 if (0 == this->find_spoke_node (spoke
, id
))
348 return -1; // We did our best, but the spoke is full.
352 * Creates a ACE_Timer_Node_T based on the input parameters. Then inserts
353 * the node into the wheel using reschedule (). Then returns a timer_id.
355 * @param type The data of the timer node
356 * @param act Asynchronous Completion Token (AKA magic cookie)
357 * @param future_time The time the timer is scheduled for (absolute time)
358 * @param interval If not ACE_Time_Value::zero, then this is a periodic
359 * timer and interval is the time period
361 * @return Unique identifier (can be used to cancel the timer).
364 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> long
365 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::schedule_i (const TYPE
& type
,
367 const ACE_Time_Value
& future_time
,
368 const ACE_Time_Value
& interval
)
370 ACE_TRACE ("ACE_Timer_Wheel_T::schedule_i");
372 ACE_Timer_Node_T
<TYPE
>* n
= this->alloc_node ();
376 u_int spoke
= calculate_spoke (future_time
);
377 long id
= generate_timer_id (spoke
);
379 //ACELIB_ERROR((LM_ERROR, "Scheduling %x spoke:%d id:%d\n", (long) n, spoke, id));
383 n
->set (type
, act
, future_time
, interval
, 0, 0, id
);
384 this->schedule_i (n
, spoke
, future_time
);
399 * Takes an ACE_Timer_Node and inserts it into the correct position in
400 * the correct list. Also makes sure to update the earliest time.
402 * @param n The timer node to reschedule
404 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
405 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::reschedule (ACE_Timer_Node_T
<TYPE
>* n
)
407 ACE_TRACE ("ACE_Timer_Wheel_T::reschedule");
408 const ACE_Time_Value
& expire
= n
->get_timer_value ();
409 u_int spoke
= calculate_spoke (expire
);
410 this->schedule_i (n
, spoke
, expire
);
413 /// The shared scheduling functionality between schedule() and reschedule()
414 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
415 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::schedule_i
416 (ACE_Timer_Node_T
<TYPE
>* n
,
418 const ACE_Time_Value
& expire
)
420 // See if we need to update the earliest time
421 if (this->is_empty() || expire
< this->earliest_time ())
422 this->earliest_spoke_
= spoke
;
424 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[spoke
];
425 ACE_Timer_Node_T
<TYPE
>* last
= root
->get_prev ();
429 // If the spoke is empty
438 // We always want to search backwards from the tail of the list, because
439 // this minimizes the search in the extreme case when lots of timers are
440 // scheduled for exactly the same time
441 ACE_Timer_Node_T
<TYPE
>* p
= root
->get_prev ();
442 while (p
!= root
&& p
->get_timer_value () > expire
)
447 n
->set_next (p
->get_next ());
448 p
->get_next ()->set_prev (n
);
454 * Find the timer node by using the id as a pointer. Then use set_interval()
455 * on the node to update the interval.
457 * @param timer_id The timer identifier
458 * @param interval The new interval
460 * @return 0 if successful, -1 if no.
462 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
463 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::reset_interval (long timer_id
,
464 const ACE_Time_Value
&interval
467 ACE_TRACE ("ACE_Timer_Wheel_T::reset_interval");
468 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
469 ACE_Timer_Node_T
<TYPE
>* n
= this->find_node (timer_id
);
472 // The interval will take effect the next time this node is expired.
473 n
->set_interval (interval
);
481 * Goes through every list in the wheel and whenever we find one with the
482 * correct type value, we remove it and continue. At the end make sure
483 * we reset the earliest time value in case the earliest timers were
486 * @param type The value to search for.
487 * @param skip_close If this non-zero, the cancellation method of the
488 * functor will not be called for each cancelled timer.
490 * @return Number of timers cancelled
492 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
493 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::cancel (const TYPE
& type
, int skip_close
)
495 ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
497 int num_canceled
= 0; // Note : Technically this can overflow.
500 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
502 if (!this->is_empty ())
504 ACE_Timer_Node_T
<TYPE
>* first
= this->get_first ();
505 ACE_Time_Value last
= first
->get_timer_value ();
508 for (u_int i
= 0; i
< this->spoke_count_
; ++i
)
510 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[i
];
511 for (ACE_Timer_Node_T
<TYPE
>* n
= root
->get_next (); n
!= root
; )
513 if (n
->get_type () == type
)
519 ACE_Timer_Node_T
<TYPE
>* tmp
= n
;
522 this->cancel_i (tmp
);
532 this->recalc_earliest (last
);
535 // Call the close hooks.
537 // cancel_type() called once per <type>.
538 this->upcall_functor ().cancel_type (*this,
547 // cancel_timer() called once per <timer>.
548 this->upcall_functor ().cancel_timer (*this,
559 * Cancels the single timer that is specified by the timer_id. In this
560 * case the timer_id is actually a pointer to the node, so we cast it
561 * to the node. This can be dangerous if the timer_id is made up
562 * (or deleted twice) so we do a little sanity check. Finally we update
563 * the earliest time in case the earliest timer was removed.
565 * @param timer_id Timer Identifier
566 * @param act Asychronous Completion Token (AKA magic cookie):
567 * If this is non-zero, stores the magic cookie of
568 * the cancelled timer here.
569 * @param skip_close If this non-zero, the cancellation method of the
570 * functor will not be called.
572 * @return 1 for sucess and 0 if the timer_id wasn't found (or was
573 * found to be invalid)
575 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
576 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::cancel (long timer_id
,
580 ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
581 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
582 ACE_Timer_Node_T
<TYPE
>* n
= this->find_node (timer_id
);
585 ACE_Time_Value last
= n
->get_timer_value ();
587 int recalc
= (this->get_first_i () == n
);
589 // Call the close hooks.
592 // cancel_type() called once per <type>.
593 this->upcall_functor ().cancel_type (*this,
598 // cancel_timer() called once per <timer>.
599 this->upcall_functor ().cancel_timer (*this,
604 *act
= n
->get_act ();
609 this->recalc_earliest (last
);
616 /// Shared subset of the two cancel() methods.
617 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
618 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::cancel_i (ACE_Timer_Node_T
<TYPE
>* n
)
624 /// There are a few places where we have to figure out which timer
625 /// will expire next. This method makes the assumption that spokes
626 /// are always sorted, and that timers are always in the correct spoke
627 /// determined from their expiration time.
628 /// The last time is always passed in, even though you can often calculate
629 /// it as get_first()->get_timer_value().
630 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
631 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::recalc_earliest
632 (const ACE_Time_Value
& last
)
634 // This is possible because we use a count for is_empty()
635 if (this->is_empty ())
638 ACE_Time_Value et
= ACE_Time_Value::zero
;
640 u_int spoke
= this->earliest_spoke_
;
642 // We will have to go around the wheel at most one time.
643 for (u_int i
= 0; i
< this->spoke_count_
; ++i
)
645 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[spoke
];
646 ACE_Timer_Node_T
<TYPE
>* n
= root
->get_next ();
649 ACE_Time_Value t
= n
->get_timer_value ();
650 if (t
< last
+ this->wheel_time_
)
652 this->earliest_spoke_
= spoke
;
655 else if (et
== ACE_Time_Value::zero
|| t
< et
)
661 if (++spoke
>= this->spoke_count_
)
665 this->earliest_spoke_
= es
;
666 //ACELIB_ERROR((LM_ERROR, "We had to search the whole wheel.\n"));
670 * Dumps out the size of the wheel, the resolution, and the contents
673 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
674 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::dump () const
676 #if defined (ACE_HAS_DUMP)
677 ACE_TRACE ("ACE_Timer_Wheel_T::dump");
678 ACELIB_DEBUG ((LM_DEBUG
, ACE_BEGIN_DUMP
, this));
680 ACELIB_DEBUG ((LM_DEBUG
,
681 ACE_TEXT ("\nspoke_count_ = %d"), this->spoke_count_
));
682 ACELIB_DEBUG ((LM_DEBUG
,
683 ACE_TEXT ("\nresolution_ = %d"), 1 << this->res_bits_
));
684 ACELIB_DEBUG ((LM_DEBUG
,
685 ACE_TEXT ("\nwheel_ =\n")));
687 for (u_int i
= 0; i
< this->spoke_count_
; ++i
)
689 ACELIB_DEBUG ((LM_DEBUG
, ACE_TEXT ("%d\n"), i
));
690 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[i
];
691 for (ACE_Timer_Node_T
<TYPE
>* n
= root
->get_next ();
699 ACELIB_DEBUG ((LM_DEBUG
, ACE_END_DUMP
));
700 #endif /* ACE_HAS_DUMP */
705 * Removes the earliest node and then find the new <earliest_spoke_>
707 * @return The earliest timer node.
709 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Timer_Node_T
<TYPE
> *
710 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::remove_first ()
712 ACE_TRACE ("ACE_Timer_Wheel_T::remove_first");
713 return remove_first_expired (ACE_Time_Value::max_time
);
716 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
717 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::unlink (ACE_Timer_Node_T
<TYPE
>* n
)
719 ACE_TRACE ("ACE_Timer_Wheel_T::unlink");
721 n
->get_prev ()->set_next (n
->get_next ());
722 n
->get_next ()->set_prev (n
->get_prev ());
727 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Timer_Node_T
<TYPE
> *
728 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::remove_first_expired (const ACE_Time_Value
& now
)
730 ACE_Timer_Node_T
<TYPE
>* n
= this->get_first ();
731 if (n
!= 0 && n
->get_timer_value() <= now
)
734 this->recalc_earliest (n
->get_timer_value ());
741 * Returns the earliest node without removing it
743 * @return The earliest timer node.
745 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
746 ACE_Timer_Node_T
<TYPE
>*
747 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::get_first ()
749 ACE_TRACE ("ACE_Timer_Wheel_T::get_first");
750 return this->get_first_i ();
753 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
754 ACE_Timer_Node_T
<TYPE
>*
755 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::get_first_i () const
757 ACE_Timer_Node_T
<TYPE
>* root
= this->spokes_
[this->earliest_spoke_
];
758 ACE_Timer_Node_T
<TYPE
>* first
= root
->get_next ();
766 * @return The iterator
768 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
769 ACE_Timer_Queue_Iterator_T
<TYPE
> &
770 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::iter ()
772 this->iterator_
->first ();
773 return *this->iterator_
;
776 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
777 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire ()
779 return ACE_Timer_Queue_T
<TYPE
,FUNCTOR
,ACE_LOCK
,TIME_POLICY
>::expire ();
783 * This is a specialized version of expire that is more suited for the
784 * internal data representation.
786 * @param cur_time The time to expire timers up to.
788 * @return Number of timers expired
790 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
791 ACE_Timer_Wheel_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire (const ACE_Time_Value
& cur_time
)
793 ACE_TRACE ("ACE_Timer_Wheel_T::expire");
797 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
799 ACE_Timer_Node_T
<TYPE
>* n
= this->remove_first_expired (cur_time
);
805 //ACELIB_ERROR((LM_ERROR, "Expiring %x\n", (long) n));
807 ACE_Timer_Node_Dispatch_Info_T
<TYPE
> info
;
809 // Get the dispatch info
810 n
->get_dispatch_info (info
);
812 if (n
->get_interval () > ACE_Time_Value::zero
)
814 // Make sure that we skip past values that have already
816 this->recompute_next_abs_interval_time (n
, cur_time
);
818 this->reschedule (n
);
825 const void *upcall_act
= 0;
827 this->preinvoke (info
, cur_time
, upcall_act
);
829 this->upcall (info
, cur_time
);
831 this->postinvoke (info
, cur_time
, upcall_act
);
833 n
= this->remove_first_expired (cur_time
);
839 ///////////////////////////////////////////////////////////////////////////
840 // ACE_Timer_Wheel_Iterator_T
843 * Just initializes the iterator with a ACE_Timer_Wheel_T and then calls
844 * first() to initialize the rest of itself.
846 * @param wheel A reference for a timer queue to iterate over
848 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
849 ACE_Timer_Wheel_Iterator_T
<TYPE
,FUNCTOR
,ACE_LOCK
,TIME_POLICY
>::ACE_Timer_Wheel_Iterator_T
851 : timer_wheel_ (wheel
)
858 * Destructor, at this level does nothing.
860 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
861 ACE_Timer_Wheel_Iterator_T
<TYPE
,FUNCTOR
,ACE_LOCK
,TIME_POLICY
>::~ACE_Timer_Wheel_Iterator_T ()
867 * Positions the iterator at the first position in the timing wheel
868 * that contains something. spoke_ will be set to the spoke position of
869 * this entry and current_node_ will point to the first entry in that spoke.
871 * If the wheel is empty, spoke_ will be equal timer_wheel_.spoke_count_ and
872 * current_node_ would be 0.
874 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
875 ACE_Timer_Wheel_Iterator_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::first ()
882 * Positions the iterator at the next node.
884 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
885 ACE_Timer_Wheel_Iterator_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::next ()
890 ACE_Timer_Node_T
<TYPE
>* n
= this->current_node_
->get_next ();
891 ACE_Timer_Node_T
<TYPE
>* root
= this->timer_wheel_
.spokes_
[this->spoke_
];
893 this->goto_next (this->spoke_
+ 1);
895 this->current_node_
= n
;
898 /// Helper class for common functionality of next() and first()
899 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
900 ACE_Timer_Wheel_Iterator_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::goto_next (u_int start_spoke
)
902 // Find the first non-empty entry.
903 u_int sc
= this->timer_wheel_
.spoke_count_
;
904 for (u_int i
= start_spoke
; i
< sc
; ++i
)
906 ACE_Timer_Node_T
<TYPE
>* root
= this->timer_wheel_
.spokes_
[i
];
907 ACE_Timer_Node_T
<TYPE
>* n
= root
->get_next ();
911 this->current_node_
= n
;
917 this->current_node_
= 0;
921 * @return True when we there aren't any more items (when current_node_ == 0)
923 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> bool
924 ACE_Timer_Wheel_Iterator_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::isdone () const
926 return this->current_node_
== 0;
930 * @return The node at the current spokeition in the sequence or 0 if the wheel
933 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Timer_Node_T
<TYPE
> *
934 ACE_Timer_Wheel_Iterator_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::item ()
936 return this->current_node_
;
939 ACE_END_VERSIONED_NAMESPACE_DECL
941 #endif /* ACE_TIMER_WHEEL_T_CPP */