Subject: kern/10699: microtime() is not monotomically increasing using Cyrix MediaGX i8254
To: None <>
From: None <>
List: netbsd-bugs
Date: 07/27/2000 21:13:14
>Number:         10699
>Category:       kern
>Synopsis:       microtime() is not monotomically increasing using Cyrix MediaGX i8254
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul 27 21:14:01 PDT 2000
>Originator:     Jesse Off
>Release:        1.4.2
NewMonics, Inc.
NetBSD cypher 1.4.2 NetBSD 1.4.2 (GENERIC) #3: Wed Mar 15 23:41:54 PST 2000 i386

Cyrix MediaGX 266mx.

microtime() (and hence, the gettimeofday() syscall) uses the buggy Cyrix
MediaGX i8254 with the broken LATCH command.  The result is that 
gettimeofday() sometimes goes backward in time on sequential calls 
therefore causing havoc on applications (and drivers, if any) 
that depend on a monotomically increasing microtime(). (which is what is 
documented in the microtime manpage)

Run the following on a MediaGX system.  You will get an assertion
failure somewhere between 0-500 iterations.


int main(void) {
  struct timeval tv[2];
  struct timeval *now, *prev;
  int iterations = 0;

  now = &tv[0];
  prev = &tv[1];
  gettimeofday(prev, NULL);

  for(;;) {
    struct timeval *tmp;

    gettimeofday(now, NULL);
    assert((now->tv_sec > prev->tv_sec) ||
           (now->tv_sec == prev->tv_sec && now->tv_usec >= prev->tv_usec));
    tmp = prev;
    prev = now;
    now = tmp;


arch/i386/isa/clock.c has a decent workaround which reads the 8254 
multiple times, but microtime.s does not use this and only reads the 
8254 once.  There are a number of potential fixes:
  *) Blow it off  (Not really a fix, but MediaGX's aren't being
     manufactured anymore.)
  *) use Pentium RDTSC for microtime like OpenBSD does. 
  *) Don't even use the 8254 latch for microtime.  Just take the timeval from
     the last clock tick.  Sure, low resolution and the potential
     for reading the same value twice, but at least 
     gettimeofday() won't go backward in time.