summaryrefslogtreecommitdiff
path: root/ACE/ace/Timer_Queue_T.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/Timer_Queue_T.cpp')
-rw-r--r--ACE/ace/Timer_Queue_T.cpp65
1 files changed, 61 insertions, 4 deletions
diff --git a/ACE/ace/Timer_Queue_T.cpp b/ACE/ace/Timer_Queue_T.cpp
index 2ac9a29e9aa..23d2628970d 100644
--- a/ACE/ace/Timer_Queue_T.cpp
+++ b/ACE/ace/Timer_Queue_T.cpp
@@ -283,6 +283,66 @@ ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::expire (const ACE_Time_Value &cur_ti
return number_of_timers_expired;
}
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::recompute_next_abs_interval_time
+ (ACE_Timer_Node_T<TYPE> *expired,
+ const ACE_Time_Value &cur_time)
+{
+ if ( expired->get_timer_value () <= cur_time )
+ {
+ /*
+ * Somehow the current time is past when this time was
+ * supposed to expire (e.g., timer took too long,
+ * somebody changed system time, etc.). There used to
+ * be a simple loop here that skipped ahead one timer
+ * interval at a time, but that was horribly inefficient
+ * (an O(n) algorithm) when the timer duration was small
+ * relative to the amount of time skipped.
+ *
+ * So, we replace the loop with a simple computation,
+ * which also happens to be O(1). All times get
+ * normalized in the computation to microseconds.
+ *
+ * For reference, the loop looked like this:
+ *
+ * do
+ * expired->set_timer_value (expired->get_timer_value () +
+ * expired->get_interval ());
+ * while (expired->get_timer_value () <= cur_time);
+ *
+ */
+
+ // Compute the duration of the timer's interval
+ ACE_UINT64 interval_usec;
+ expired->get_interval ().to_usec (interval_usec);
+
+ // Compute the span between the current time and when
+ // the timer would have expired in the past (and
+ // normalize to microseconds).
+ ACE_Time_Value old_diff = cur_time - expired->get_timer_value ();
+ ACE_UINT64 old_diff_usec;
+ old_diff.to_usec (old_diff_usec);
+
+ // Compute the delta time in the future when the timer
+ // should fire as if it had advanced incrementally. The
+ // modulo arithmetic accomodates the likely case that
+ // the current time doesn't fall precisely on a timer
+ // firing interval.
+ ACE_UINT64 new_timer_usec =
+ interval_usec - (old_diff_usec % interval_usec);
+
+ // Compute the absolute time in the future when this
+ // interval timer should expire.
+ ACE_Time_Value new_timer_value
+ (cur_time.sec ()
+ + static_cast<time_t>(new_timer_usec / ACE_ONE_SECOND_IN_USECS),
+ cur_time.usec ()
+ + static_cast<suseconds_t>(new_timer_usec % ACE_ONE_SECOND_IN_USECS));
+
+ expired->set_timer_value (new_timer_value);
+ }
+}
+
template <class TYPE, class FUNCTOR, class ACE_LOCK> int
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::dispatch_info_i (const ACE_Time_Value &cur_time,
ACE_Timer_Node_Dispatch_Info_T<TYPE> &info)
@@ -306,10 +366,7 @@ ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::dispatch_info_i (const ACE_Time_Valu
{
// 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);
+ this->recompute_next_abs_interval_time (expired, cur_time);
// Since this is an interval timer, we need to reschedule
// it.