https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=ea99e9fdda42141ef1c2273943a33d3191d72844

commit ea99e9fdda42141ef1c2273943a33d3191d72844
Author: Corinna Vinschen <[email protected]>
Date:   Mon Jan 21 11:14:16 2019 +0100

    Cygwin: timerfd: fix overrun computation
    
    - Drop erroneous initial computation of overrun count in settime
      for absolute non-realtime clocks.  It's repeated in thread_func
      and thus counted twice.
    
    - Fix overrun computation for timestamp offsets being a multiple of
      the timer interval.  The timestamp has to be corrected after the
      first offset, otherwise the correction loop counts the intervals
      again.
    
    Signed-off-by: Corinna Vinschen <[email protected]>

Diff:
---
 winsup/cygwin/timerfd.cc | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/winsup/cygwin/timerfd.cc b/winsup/cygwin/timerfd.cc
index 64836b0..0a04241 100644
--- a/winsup/cygwin/timerfd.cc
+++ b/winsup/cygwin/timerfd.cc
@@ -155,13 +155,18 @@ timerfd_tracker::thread_func ()
              /* Make concessions for unexact realtime clock */
              if (ts > now)
                ts = now - 1;
-             increment_overrun_count ((now - ts + get_interval () - 1)
-                                      / get_interval ());
+             LONG64 ov_cnt = (now - ts + get_interval () - 1)
+                             / get_interval ();
+             increment_overrun_count (ov_cnt);
+             ts += get_interval () * ov_cnt;
              /* Set exp_ts to current timestamp.  Make sure exp_ts ends up
                 bigger than "now" and fix overrun count as required */
-             while ((ts += get_interval ()) <= (now = get_clock_now ()))
-               increment_overrun_count ((now - ts + get_interval () - 1)
-                                        / get_interval ());
+             while (ts <= (now = get_clock_now ()))
+               {
+                 increment_overrun_count ((now - ts + get_interval () - 1)
+                                          / get_interval ());
+                 ts += get_interval ();
+               }
              set_exp_ts (ts);
              /* NtSetTimer allows periods of up to 24 days only.  If the time
                 is longer, we set the timer up as one-shot timer for each
@@ -536,11 +541,7 @@ timerfd_shared::arm_timer (int flags, const struct 
itimerspec *new_value)
          /* If the timestamp was earlier than now, compute number
             of overruns and offset DueTime to expire immediately. */
          if (DueTime.QuadPart >= 0)
-           {
-             LONG64 num_intervals = DueTime.QuadPart / _interval;
-             increment_overrun_count (num_intervals);
-             DueTime.QuadPart = -1LL;
-           }
+           DueTime.QuadPart = -1LL;
        }
     }
   else

Reply via email to