GitHub Actions: Try MSVC builds with /std:c++17 and 20
[ACE_TAO.git] / ACE / ace / Timer_Wheel_T.cpp
blob5c55346187c179d8140b4a57a73f132fbb8580d1
1 #ifndef ACE_TIMER_WHEEL_T_CPP
2 #define ACE_TIMER_WHEEL_T_CPP
4 #if !defined (ACE_LACKS_PRAGMA_ONCE)
5 # 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
24 // in that spoke.
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.
36 /**
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
46 , FreeList* freelist
47 , TIME_POLICY const & time_policy
49 : Base_Timer_Queue (upcall_functor, freelist, time_policy)
50 , spokes_(0)
51 , spoke_count_(0) // calculated in open_i
52 , spoke_bits_(0)
53 , res_bits_ (0)
54 , earliest_spoke_ (0)
55 , iterator_(0)
56 , timer_count_(0)
58 ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T");
59 this->open_i (0,
60 ACE_DEFAULT_TIMER_WHEEL_SIZE,
61 ACE_DEFAULT_TIMER_WHEEL_RESOLUTION);
64 /**
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
76 (u_int spoke_count,
77 u_int resolution,
78 size_t prealloc,
79 FUNCTOR* upcall_functor,
80 FreeList* freelist,
81 TIME_POLICY const & time_policy)
82 : Base_Timer_Queue (upcall_functor, freelist, time_policy)
83 , spokes_ (0)
84 , spoke_count_ (0) // calculated in open_i
85 , spoke_bits_ (0)
86 , res_bits_ (0)
87 , earliest_spoke_ (0)
88 , iterator_ (0)
89 , timer_count_ (0)
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,
97 int min_bits,
98 int max_bits)
100 int max = (1 << max_bits) - 1;
101 if (n > max)
102 return max_bits;
104 // count the bits in n.
105 int i = 0;
106 int tmp = n;
109 tmp >>= 1;
110 ++i;
112 while (tmp != 0);
114 if (i <= min_bits)
115 return min_bits;
117 // Which is nearest?
118 int a = (1 << i) - n;
119 int b = (1 << (i - 1)) - n;
120 if (b < 0)
121 b = -b;
122 if (b < a)
123 return i - 1;
124 return i;
128 * Initialize the queue. Uses the established members for all needed
129 * information.
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 (void)
169 ACE_TRACE ("ACE_Timer_Wheel_T::~ACE_Timer_Wheel_T");
171 delete iterator_;
173 this->close ();
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 (void)
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,
198 n->get_type (),
199 n->get_act ());
200 this->free_node (n);
201 n = next;
205 // Leave rest for destructor
206 return 0;
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 ();
217 n != root;
218 n = n->get_next ())
220 if (n->get_timer_id () == timer_id)
221 return n;
223 return 0;
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
232 if (timer_id == -1)
233 return 0;
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);
239 if (n != 0)
240 return n;
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)
247 if (i != start)
248 { // already searched this one
249 n = this->find_spoke_node (i, timer_id);
250 if (n != 0)
251 return n;
255 //ACELIB_ERROR((LM_ERROR, "Node not found.\n"));
256 return 0;
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 (void) 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 (void) const
278 ACE_TRACE ("ACE_Timer_Wheel_T::earliest_time");
279 ACE_Timer_Node_T<TYPE>* n = this->get_first_i ();
280 if (n != 0)
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)
304 int cnt_bits = sizeof (long) * 8 - this->spoke_bits_;
305 long max_cnt = ((long)1 << cnt_bits) - 1;
306 if (spoke == this->spoke_count_)
307 --max_cnt; // Because -1 is used as a special invalid timer_id.
309 ACE_Timer_Node_T<TYPE>* root = this->spokes_[spoke];
311 if (root == root->get_next ())
312 root->set_act(0);
314 // This field is used as a counter instead of a timer_id.
315 long cnt = root->get_timer_id ();
317 if (cnt < max_cnt)
319 root->set_timer_id (cnt + 1);
320 return (cnt << this->spoke_bits_) | spoke;
323 // Count has overflowed its range.
324 if (root == root->get_next ())
326 // Special case when we overflow on an empty spoke. We can just
327 // wrap the count around without searching for duplicates. We only
328 // want to do this when the counter overflows, so that we return
329 // unique timer_id values as often as possible.
330 root->set_timer_id (1);
331 return spoke;
334 // Overflowed count, and the spoke is not empty. Search for an unused
335 // id value.
336 //ACELIB_ERROR((LM_ERROR, "Timer id overflow. We have to search now.\n"));
337 for (cnt = 0; cnt < max_cnt - 1; ++cnt)
339 // Look for an unused id. Yes, every new id on this spoke will result in a
340 // scan until all the spoke's timers get canceled/expired then the spoke will
341 // start over like new. So, when an empty spot is found, don't reset the
342 // root node's timer_id - it stays at max until the spoke clears out and
343 // starts over.
344 long id = (cnt << this->spoke_bits_) | spoke;
345 if (0 == this->find_spoke_node (spoke, id))
346 return id;
349 return -1; // We did our best, but the spoke is full.
353 * Creates a ACE_Timer_Node_T based on the input parameters. Then inserts
354 * the node into the wheel using reschedule (). Then returns a timer_id.
356 * @param type The data of the timer node
357 * @param act Asynchronous Completion Token (AKA magic cookie)
358 * @param future_time The time the timer is scheduled for (absolute time)
359 * @param interval If not ACE_Time_Value::zero, then this is a periodic
360 * timer and interval is the time period
362 * @return Unique identifier (can be used to cancel the timer).
363 * -1 on failure.
365 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> long
366 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::schedule_i (const TYPE& type,
367 const void* act,
368 const ACE_Time_Value& future_time,
369 const ACE_Time_Value& interval)
371 ACE_TRACE ("ACE_Timer_Wheel_T::schedule_i");
373 ACE_Timer_Node_T<TYPE>* n = this->alloc_node ();
375 if (n != 0)
377 u_int spoke = calculate_spoke (future_time);
378 long id = generate_timer_id (spoke);
380 //ACELIB_ERROR((LM_ERROR, "Scheduling %x spoke:%d id:%d\n", (long) n, spoke, id));
382 if (id != -1)
384 n->set (type, act, future_time, interval, 0, 0, id);
385 this->schedule_i (n, spoke, future_time);
387 else
389 this->free_node (n);
391 return id;
394 // Failure return
395 errno = ENOMEM;
396 return -1;
400 * Takes an ACE_Timer_Node and inserts it into the correct position in
401 * the correct list. Also makes sure to update the earliest time.
403 * @param n The timer node to reschedule
405 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
406 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reschedule (ACE_Timer_Node_T<TYPE>* n)
408 ACE_TRACE ("ACE_Timer_Wheel_T::reschedule");
409 const ACE_Time_Value& expire = n->get_timer_value ();
410 u_int spoke = calculate_spoke (expire);
411 this->schedule_i (n, spoke, expire);
414 /// The shared scheduling functionality between schedule() and reschedule()
415 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
416 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::schedule_i
417 (ACE_Timer_Node_T<TYPE>* n,
418 u_int spoke,
419 const ACE_Time_Value& expire)
421 // See if we need to update the earliest time
422 if (this->is_empty() || expire < this->earliest_time ())
423 this->earliest_spoke_ = spoke;
425 ACE_Timer_Node_T<TYPE>* root = this->spokes_[spoke];
426 ACE_Timer_Node_T<TYPE>* last = root->get_prev ();
428 ++timer_count_;
430 // If the spoke is empty
431 if (last == root) {
432 n->set_prev (root);
433 n->set_next (root);
434 root->set_prev (n);
435 root->set_next (n);
436 return;
439 // We always want to search backwards from the tail of the list, because
440 // this minimizes the search in the extreme case when lots of timers are
441 // scheduled for exactly the same time
442 ACE_Timer_Node_T<TYPE>* p = root->get_prev ();
443 while (p != root && p->get_timer_value () > expire)
444 p = p->get_prev ();
446 // insert after
447 n->set_prev (p);
448 n->set_next (p->get_next ());
449 p->get_next ()->set_prev (n);
450 p->set_next (n);
455 * Find the timer node by using the id as a pointer. Then use set_interval()
456 * on the node to update the interval.
458 * @param timer_id The timer identifier
459 * @param interval The new interval
461 * @return 0 if successful, -1 if no.
463 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
464 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reset_interval (long timer_id,
465 const ACE_Time_Value &interval
468 ACE_TRACE ("ACE_Timer_Wheel_T::reset_interval");
469 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
470 ACE_Timer_Node_T<TYPE>* n = this->find_node (timer_id);
471 if (n != 0)
473 // The interval will take effect the next time this node is expired.
474 n->set_interval (interval);
475 return 0;
477 return -1;
482 * Goes through every list in the wheel and whenever we find one with the
483 * correct type value, we remove it and continue. At the end make sure
484 * we reset the earliest time value in case the earliest timers were
485 * removed.
487 * @param type The value to search for.
488 * @param skip_close If this non-zero, the cancellation method of the
489 * functor will not be called for each cancelled timer.
491 * @return Number of timers cancelled
493 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
494 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::cancel (const TYPE& type, int skip_close)
496 ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
498 int num_canceled = 0; // Note : Technically this can overflow.
499 int cookie = 0;
501 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
503 if (!this->is_empty ())
505 ACE_Timer_Node_T<TYPE>* first = this->get_first ();
506 ACE_Time_Value last = first->get_timer_value ();
507 int recalc = 0;
509 for (u_int i = 0; i < this->spoke_count_; ++i)
511 ACE_Timer_Node_T<TYPE>* root = this->spokes_[i];
512 for (ACE_Timer_Node_T<TYPE>* n = root->get_next (); n != root; )
514 if (n->get_type () == type)
516 ++num_canceled;
517 if (n == first)
518 recalc = 1;
520 ACE_Timer_Node_T<TYPE>* tmp = n;
521 n = n->get_next ();
523 this->cancel_i (tmp);
525 else
527 n = n->get_next ();
532 if (recalc)
533 this->recalc_earliest (last);
536 // Call the close hooks.
538 // cancel_type() called once per <type>.
539 this->upcall_functor ().cancel_type (*this,
540 type,
541 skip_close,
542 cookie);
544 for (int i = 0;
545 i < num_canceled;
546 ++i)
548 // cancel_timer() called once per <timer>.
549 this->upcall_functor ().cancel_timer (*this,
550 type,
551 skip_close,
552 cookie);
555 return num_canceled;
560 * Cancels the single timer that is specified by the timer_id. In this
561 * case the timer_id is actually a pointer to the node, so we cast it
562 * to the node. This can be dangerous if the timer_id is made up
563 * (or deleted twice) so we do a little sanity check. Finally we update
564 * the earliest time in case the earliest timer was removed.
566 * @param timer_id Timer Identifier
567 * @param act Asychronous Completion Token (AKA magic cookie):
568 * If this is non-zero, stores the magic cookie of
569 * the cancelled timer here.
570 * @param skip_close If this non-zero, the cancellation method of the
571 * functor will not be called.
573 * @return 1 for sucess and 0 if the timer_id wasn't found (or was
574 * found to be invalid)
576 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
577 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::cancel (long timer_id,
578 const void **act,
579 int skip_close)
581 ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
582 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
583 ACE_Timer_Node_T<TYPE>* n = this->find_node (timer_id);
584 if (n != 0)
586 ACE_Time_Value last = n->get_timer_value ();
588 int recalc = (this->get_first_i () == n);
590 // Call the close hooks.
591 int cookie = 0;
593 // cancel_type() called once per <type>.
594 this->upcall_functor ().cancel_type (*this,
595 n->get_type (),
596 skip_close,
597 cookie);
599 // cancel_timer() called once per <timer>.
600 this->upcall_functor ().cancel_timer (*this,
601 n->get_type (),
602 skip_close,
603 cookie);
604 if (act != 0)
605 *act = n->get_act ();
607 this->cancel_i (n);
609 if (recalc)
610 this->recalc_earliest (last);
612 return 1;
614 return 0;
617 /// Shared subset of the two cancel() methods.
618 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
619 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::cancel_i (ACE_Timer_Node_T<TYPE>* n)
621 this->unlink (n);
622 this->free_node (n);
625 /// There are a few places where we have to figure out which timer
626 /// will expire next. This method makes the assumption that spokes
627 /// are always sorted, and that timers are always in the correct spoke
628 /// determined from their expiration time.
629 /// The last time is always passed in, even though you can often calculate
630 /// it as get_first()->get_timer_value().
631 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
632 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::recalc_earliest
633 (const ACE_Time_Value& last)
635 // This is possible because we use a count for is_empty()
636 if (this->is_empty ())
637 return;
639 ACE_Time_Value et = ACE_Time_Value::zero;
640 u_int es = 0;
641 u_int spoke = this->earliest_spoke_;
643 // We will have to go around the wheel at most one time.
644 for (u_int i = 0; i < this->spoke_count_; ++i)
646 ACE_Timer_Node_T<TYPE>* root = this->spokes_[spoke];
647 ACE_Timer_Node_T<TYPE>* n = root->get_next ();
648 if (n != root)
650 ACE_Time_Value t = n->get_timer_value ();
651 if (t < last + this->wheel_time_)
653 this->earliest_spoke_ = spoke;
654 return;
656 else if (et == ACE_Time_Value::zero || t < et)
658 et = t;
659 es = spoke;
662 if (++spoke >= this->spoke_count_)
663 spoke = 0;
666 this->earliest_spoke_ = es;
667 //ACELIB_ERROR((LM_ERROR, "We had to search the whole wheel.\n"));
671 * Dumps out the size of the wheel, the resolution, and the contents
672 * of the wheel.
674 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
675 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::dump (void) const
677 #if defined (ACE_HAS_DUMP)
678 ACE_TRACE ("ACE_Timer_Wheel_T::dump");
679 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
681 ACELIB_DEBUG ((LM_DEBUG,
682 ACE_TEXT ("\nspoke_count_ = %d"), this->spoke_count_));
683 ACELIB_DEBUG ((LM_DEBUG,
684 ACE_TEXT ("\nresolution_ = %d"), 1 << this->res_bits_));
685 ACELIB_DEBUG ((LM_DEBUG,
686 ACE_TEXT ("\nwheel_ =\n")));
688 for (u_int i = 0; i < this->spoke_count_; ++i)
690 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("%d\n"), i));
691 ACE_Timer_Node_T<TYPE>* root = this->spokes_[i];
692 for (ACE_Timer_Node_T<TYPE>* n = root->get_next ();
693 n != root;
694 n = n->get_next ())
696 n->dump ();
700 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
701 #endif /* ACE_HAS_DUMP */
706 * Removes the earliest node and then find the new <earliest_spoke_>
708 * @return The earliest timer node.
710 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Timer_Node_T<TYPE> *
711 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::remove_first (void)
713 ACE_TRACE ("ACE_Timer_Wheel_T::remove_first");
714 return remove_first_expired (ACE_Time_Value::max_time);
717 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
718 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::unlink (ACE_Timer_Node_T<TYPE>* n)
720 ACE_TRACE ("ACE_Timer_Wheel_T::unlink");
721 --timer_count_;
722 n->get_prev ()->set_next (n->get_next ());
723 n->get_next ()->set_prev (n->get_prev ());
724 n->set_prev (0);
725 n->set_next (0);
728 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Timer_Node_T<TYPE> *
729 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::remove_first_expired (const ACE_Time_Value& now)
731 ACE_Timer_Node_T<TYPE>* n = this->get_first ();
732 if (n != 0 && n->get_timer_value() <= now)
734 this->unlink (n);
735 this->recalc_earliest (n->get_timer_value ());
736 return n;
738 return 0;
742 * Returns the earliest node without removing it
744 * @return The earliest timer node.
746 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
747 ACE_Timer_Node_T<TYPE>*
748 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::get_first (void)
750 ACE_TRACE ("ACE_Timer_Wheel_T::get_first");
751 return this->get_first_i ();
754 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
755 ACE_Timer_Node_T<TYPE>*
756 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::get_first_i (void) const
758 ACE_Timer_Node_T<TYPE>* root = this->spokes_[this->earliest_spoke_];
759 ACE_Timer_Node_T<TYPE>* first = root->get_next ();
760 if (first != root)
761 return first;
762 return 0;
767 * @return The iterator
769 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
770 ACE_Timer_Queue_Iterator_T<TYPE> &
771 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::iter (void)
773 this->iterator_->first ();
774 return *this->iterator_;
777 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
778 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire ()
780 return ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK,TIME_POLICY>::expire ();
784 * This is a specialized version of expire that is more suited for the
785 * internal data representation.
787 * @param cur_time The time to expire timers up to.
789 * @return Number of timers expired
791 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
792 ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire (const ACE_Time_Value& cur_time)
794 ACE_TRACE ("ACE_Timer_Wheel_T::expire");
796 int expcount = 0;
798 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
800 ACE_Timer_Node_T<TYPE>* n = this->remove_first_expired (cur_time);
802 while (n != 0)
804 ++expcount;
806 //ACELIB_ERROR((LM_ERROR, "Expiring %x\n", (long) n));
808 ACE_Timer_Node_Dispatch_Info_T<TYPE> info;
810 // Get the dispatch info
811 n->get_dispatch_info (info);
813 if (n->get_interval () > ACE_Time_Value::zero)
815 // Make sure that we skip past values that have already
816 // "expired".
817 this->recompute_next_abs_interval_time (n, cur_time);
819 this->reschedule (n);
821 else
823 this->free_node (n);
826 const void *upcall_act = 0;
828 this->preinvoke (info, cur_time, upcall_act);
830 this->upcall (info, cur_time);
832 this->postinvoke (info, cur_time, upcall_act);
834 n = this->remove_first_expired (cur_time);
837 return expcount;
840 ///////////////////////////////////////////////////////////////////////////
841 // ACE_Timer_Wheel_Iterator_T
844 * Just initializes the iterator with a ACE_Timer_Wheel_T and then calls
845 * first() to initialize the rest of itself.
847 * @param wheel A reference for a timer queue to iterate over
849 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
850 ACE_Timer_Wheel_Iterator_T<TYPE,FUNCTOR,ACE_LOCK,TIME_POLICY>::ACE_Timer_Wheel_Iterator_T
851 (Wheel& wheel)
852 : timer_wheel_ (wheel)
854 this->first();
859 * Destructor, at this level does nothing.
861 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
862 ACE_Timer_Wheel_Iterator_T<TYPE,FUNCTOR,ACE_LOCK,TIME_POLICY>::~ACE_Timer_Wheel_Iterator_T (void)
868 * Positions the iterator at the first position in the timing wheel
869 * that contains something. spoke_ will be set to the spoke position of
870 * this entry and current_node_ will point to the first entry in that spoke.
872 * If the wheel is empty, spoke_ will be equal timer_wheel_.spoke_count_ and
873 * current_node_ would be 0.
875 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
876 ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::first (void)
878 this->goto_next(0);
883 * Positions the iterator at the next node.
885 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
886 ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::next (void)
888 if (this->isdone())
889 return;
891 ACE_Timer_Node_T<TYPE>* n = this->current_node_->get_next ();
892 ACE_Timer_Node_T<TYPE>* root = this->timer_wheel_.spokes_[this->spoke_];
893 if (n == root)
894 this->goto_next (this->spoke_ + 1);
895 else
896 this->current_node_ = n;
899 /// Helper class for common functionality of next() and first()
900 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
901 ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::goto_next (u_int start_spoke)
903 // Find the first non-empty entry.
904 u_int sc = this->timer_wheel_.spoke_count_;
905 for (u_int i = start_spoke; i < sc; ++i)
907 ACE_Timer_Node_T<TYPE>* root = this->timer_wheel_.spokes_[i];
908 ACE_Timer_Node_T<TYPE>* n = root->get_next ();
909 if (n != root)
911 this->spoke_ = i;
912 this->current_node_ = n;
913 return;
916 // empty
917 this->spoke_ = sc;
918 this->current_node_ = 0;
922 * @return True when we there aren't any more items (when current_node_ == 0)
924 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> bool
925 ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::isdone (void) const
927 return this->current_node_ == 0;
931 * @return The node at the current spokeition in the sequence or 0 if the wheel
932 * is empty
934 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Timer_Node_T<TYPE> *
935 ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::item (void)
937 return this->current_node_;
940 ACE_END_VERSIONED_NAMESPACE_DECL
942 #endif /* ACE_TIMER_WHEEL_T_CPP */