diff options
Diffstat (limited to 'ACE/ace/Timer_Queue_T.cpp')
-rw-r--r-- | ACE/ace/Timer_Queue_T.cpp | 65 |
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. |