From acac02cf678b99e52baa4ef71c66b2cc6f06ff6f Mon Sep 17 00:00:00 2001 From: Chaskiel M Grundman Date: Sun, 3 Apr 2005 21:01:46 +0000 Subject: [PATCH] STABLE14-rx-clock-rollover-fix-20050403 FIXES 17990 itimer rollover comes faster now; handle it. (cherry picked from commit c5c9bf0a7896047381d2d07ddaa954b231b7f356) --- src/rx/rx_clock.c | 90 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/src/rx/rx_clock.c b/src/rx/rx_clock.c index a455419f3a..9d7ca30731 100644 --- a/src/rx/rx_clock.c +++ b/src/rx/rx_clock.c @@ -37,6 +37,9 @@ RCSID #endif /* !UKERNEL */ #else /* KERNEL */ #include +#ifdef HAVE_SIGNAL_H +#include +#endif #include #include #include @@ -49,8 +52,9 @@ RCSID #ifndef KERNEL -#define STARTVALUE 100000000 /* Max number of seconds setitimer allows, for some reason */ -static int startvalue = STARTVALUE; +#define STARTVALUE 3600 +static struct clock startvalue; +static struct clock relclock_epoch; /* The elapsed time of the last itimer reset */ struct clock clock_now; /* The last elapsed time ready by clock_GetTimer */ @@ -60,28 +64,52 @@ int clock_haveCurrentTime; int clock_nUpdates; /* The actual number of clock updates */ static int clockInitialized = 0; +static void +clock_Sync(void) +{ + struct itimerval itimer, otimer; + itimer.it_value.tv_sec = STARTVALUE; + itimer.it_value.tv_usec = 0; + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = 0; + + signal(SIGALRM, SIG_IGN); + if (setitimer(ITIMER_REAL, &itimer, &otimer) != 0) { + fprintf(stderr, "clock: could not set interval timer; \ + aborted(errno=%d)\n", errno); + fflush(stderr); + exit(1); + } + if (relclock_epoch.usec + startvalue.usec >= otimer.it_value.tv_usec) { + relclock_epoch.sec = relclock_epoch.sec + + startvalue.sec - otimer.it_value.tv_sec; + relclock_epoch.usec = relclock_epoch.usec + + startvalue.usec - otimer.it_value.tv_usec; + } else { + relclock_epoch.sec = relclock_epoch.sec + + startvalue.sec - 1 - otimer.it_value.tv_sec; + relclock_epoch.usec = relclock_epoch.usec + + startvalue.usec + 1000000 - otimer.it_value.tv_usec; + } + if (relclock_epoch.usec >= 1000000) + relclock_epoch.usec -= 1000000, relclock_epoch.sec++; + /* the initial value of the interval timer may not be exactly the same + * as the arg passed to setitimer. POSIX allows the implementation to + * round it up slightly, and some nonconformant implementations truncate + * it */ + getitimer(ITIMER_REAL, &itimer); + startvalue.sec = itimer.it_value.tv_sec; + startvalue.usec = itimer.it_value.tv_usec; +} + /* Initialize the clock */ void clock_Init(void) { - struct itimerval itimer, otimer; - if (!clockInitialized) { - itimer.it_value.tv_sec = STARTVALUE; - itimer.it_value.tv_usec = 0; - itimer.it_interval.tv_sec = 0; - itimer.it_interval.tv_usec = 0; - - if (setitimer(ITIMER_REAL, &itimer, &otimer) != 0) { - fprintf(stderr, "clock: could not set interval timer; \ - aborted(errno=%d)\n", errno); - fflush(stderr); - exit(1); - } - getitimer(ITIMER_REAL, &itimer); - startvalue = itimer.it_value.tv_sec; - if (itimer.it_value.tv_usec > 0) - startvalue++; + relclock_epoch.sec = relclock_epoch.usec = 0; + startvalue.sec = startvalue.usec = 0; + clock_Sync(); clockInitialized = 1; } @@ -101,11 +129,27 @@ void clock_UpdateTime(void) { struct itimerval itimer; + struct clock offset; + struct clock new; + getitimer(ITIMER_REAL, &itimer); - clock_now.sec = startvalue - 1 - itimer.it_value.tv_sec; /* The "-1" makes up for adding 1000000 usec, on the next line */ - clock_now.usec = 1000000 - itimer.it_value.tv_usec; - if (clock_now.usec == 1000000) - clock_now.usec = 0, clock_now.sec++; + + if (startvalue.usec >= itimer.it_value.tv_usec) { + offset.sec = startvalue.sec - itimer.it_value.tv_sec; + offset.usec = startvalue.usec - itimer.it_value.tv_usec; + } else { + /* The "-1" makes up for adding 1000000 usec, on the next line */ + offset.sec = startvalue.sec - 1 - itimer.it_value.tv_sec; + offset.usec = startvalue.usec + 1000000 - itimer.it_value.tv_usec; + } + new.sec = relclock_epoch.sec + offset.sec; + new.usec = relclock_epoch.usec + offset.usec; + if (new.usec >= 1000000) + new.usec -= 1000000, new.sec++; + clock_now.sec = new.sec; + clock_now.usec = new.usec; + if (itimer.it_value.tv_sec < startvalue.sec / 2) + clock_Sync(); clock_haveCurrentTime = 1; clock_nUpdates++; }