delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2007/02/28/17:37:10

X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f
Subject: Final version of gettimeofday() patch
To: djgpp-workers AT delorie DOT com
X-Mailer: Lotus Notes Release 7.0.2 September 26, 2006
Message-ID: <OF797A29F0.37D3281E-ON87257290.007B2DAD-87257290.007C2A0C@seagate.com>
From: Gordon DOT Schumacher AT seagate DOT com
Date: Wed, 28 Feb 2007 15:36:12 -0700
X-MIMETrack: Serialize by Router on SV-GW1/Seagate Internet(Release 7.0.1 HF29|March 07, 2006) at
02/28/2007 02:36:15 PM
MIME-Version: 1.0
X-Proofpoint-FWRule: outbound2
X-Proofpoint-Virus-Version: vendor=fsecure engine=4.65.5502:2.3.11,1.2.37,4.0.164 definitions=2007-02-28_06:2007-02-28,2007-02-27,2007-02-28 signatures=0
Reply-To: djgpp-workers AT delorie DOT com

I've now got what I believe to be a finalized version of my proposed
changes to gettimeofday().  I'm running it to good effect here, and
you can feel free to try compiling it with -DTEST to build a sample
application that should check for drift against what the time that
DOS int21 reports.  On my test systems the drift was negligible.

(And yes, I realize that I'm defining the clock frequency to far
more digits than necessary; better too many than too few, though.)

The include of <sys/gcc.h> is simply to pick up the macro definitions
for likely() and unlikely(); you can compile it just fine without
that header (which is new in my testing) by commenting out that
header include and adding the following instead:
#define likely(x) x
#define unlikely(x) x

I will include my proposal for <sys/gcc.h> in another message.


--- src/libc/dos/dos/gettimeo.c.orig      1995-03-11 03:42:42.000000000
-0700
+++ src/libc/dos/dos/gettimeo.c     2007-02-28 15:28:57.156250000 -0700
@@ -1,44 +1,164 @@
+/* Copyright (C) 2007 Gordon Schumacher, see COPYING.DJ for details */
 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
 #include <libc/stubs.h>
 #include <time.h>
 #include <dpmi.h>
+#include <limits.h>
+#include <math.h>
+#include <sys/gcc.h>
+
+#undef CLOCKS_PER_SEC
+/*
+Thanks to Rod Pemberton for the math for the clock frequency.
+The exact calculation is as follows:
+   4 * ((4.5Mhz * 455) / 572) = 14.31818... MHz
+(4.5Mhz US TV bandwith/channel, 455 colorburst phase changes/line,
+ 572 total lines/frame including sync)
+
+   14.318Mhz / 12 = 1.1931818... Mhz
+(The clock has a divisor of 12)
+
+   1.1931818... Mhz / 65536 ~= 18.2065Hz
+(65536 cycles per tick)
+
+Remember that clock() multiplies by 5!
+*/
+//#define CLOCKS_PER_SEC  ((4 * ((4.5 * 455) / 572)) / (12 * 65536))
+#define CLOCKS_PER_SEC  91.032548384232954545454545454545F
+#define CLOCK_T_MAX     INT_MAX

 int gettimeofday(struct timeval *tv, struct timezone *tz)
 {
-  __dpmi_regs r;
-  struct tm tmblk;
-  struct timeval tv_tmp;
-
-
-  if (!tv)
-    tv = &tv_tmp;
-
-  r.h.ah = 0x2c;
-  __dpmi_int(0x21, &r);
-
-  tv->tv_usec = r.h.dl * 10000;
-  tmblk.tm_sec = r.h.dh;
-  tmblk.tm_min = r.h.cl;
-  tmblk.tm_hour = r.h.ch;
-
-  r.h.ah = 0x2a;
-  __dpmi_int(0x21, &r);
-
-  tmblk.tm_mday = r.h.dl;
-  tmblk.tm_mon = r.h.dh - 1;
-  tmblk.tm_year = (r.x.cx & 0x7ff) - 1900;
-
-  tmblk.tm_wday = tmblk.tm_yday = tmblk.tm_gmtoff = 0;
-  tmblk.tm_zone = 0;
-  tmblk.tm_isdst = -1;
-
-  tv->tv_sec = mktime(&tmblk);
-
-  if(tz)
-  {
-    struct tm *tmloc = localtime(&(tv->tv_sec));
-    tz->tz_minuteswest = - tmloc->tm_gmtoff / 60;
-    tz->tz_dsttime = tmloc->tm_isdst;
-  }
-  return 0;
+   static clock_t startclock = 0;
+   static struct timeval starttime;
+   struct timeval tv_tmp;
+
+   if (!tv)
+      tv = &tv_tmp;
+
+   if (unlikely(startclock == 0))
+   {
+      __dpmi_regs r;
+      struct tm tmblk;
+
+      startclock = clock();
+
+      r.h.ah = 0x2c;
+      __dpmi_int(0x21, &r);
+      starttime.tv_usec = r.h.dl * 10000;
+      tmblk.tm_sec = r.h.dh;
+      tmblk.tm_min = r.h.cl;
+      tmblk.tm_hour = r.h.ch;
+
+      r.h.ah = 0x2a;
+      __dpmi_int(0x21, &r);
+
+      tmblk.tm_mday = r.h.dl;
+      tmblk.tm_mon = r.h.dh - 1;
+      tmblk.tm_year = (r.x.cx & 0x7ff) - 1900;
+
+      tmblk.tm_wday = tmblk.tm_yday = tmblk.tm_gmtoff = 0;
+      tmblk.tm_zone = 0;
+      tmblk.tm_isdst = -1;
+
+      starttime.tv_sec = mktime(&tmblk);
+
+      tv->tv_sec  = starttime.tv_sec;
+      tv->tv_usec = starttime.tv_usec;
+   }
+   else
+   {
+      double secs;
+      clock_t curclock = clock();
+      unsigned long clockdiff;
+
+      if (likely(curclock >= startclock))
+         clockdiff = (unsigned long) (curclock - startclock);
+      else
+      {
+         clockdiff = ((unsigned long) CLOCK_T_MAX + curclock) -
startclock;
+         startclock = 0;   // Recalibrate now...
+      }
+
+      secs = clockdiff / CLOCKS_PER_SEC;
+      tv->tv_sec  = starttime.tv_sec  + secs;
+      tv->tv_usec = starttime.tv_usec + ((secs - (long) secs) * 1000000);
+      if (unlikely(tv->tv_usec >= 1000000))
+      {
+         tv->tv_sec++;
+         tv->tv_usec -= 1000000;
+      }
+
+      // Recalibrate against the RTC about once an hour
+      // This should keep any error within one tick
+      if (unlikely(clockdiff > 65535))
+         startclock = 0;
+   }
+
+   if (tz)
+   {
+      struct tm *tmloc = localtime(&(tv->tv_sec));
+      tz->tz_minuteswest = - tmloc->tm_gmtoff / 60;
+      tz->tz_dsttime = tmloc->tm_isdst;
+   }
+   return 0;
 }
+
+#if defined(TEST)
+   #include <stdio.h>
+
+int main()
+{
+   int start, end, i;
+   struct tm tmblk;
+   struct timeval rtc, tod;
+   time_t rtc_secs, tod_secs;
+   char timestr[25];
+   unsigned long maxusec = 0;
+   __dpmi_regs r;
+   double maxposerror = 0.0F, maxnegerror = 0.0F;
+
+   while (!kbhit())
+   {
+      double curerror;
+
+      r.h.ah = 0x2c;
+      __dpmi_int(0x21, &r);
+      rtc.tv_usec    = r.h.dl * 10000;
+      tmblk.tm_sec  = r.h.dh;
+      tmblk.tm_min  = r.h.cl;
+      tmblk.tm_hour = r.h.ch;
+
+      r.h.ah = 0x2a;
+      __dpmi_int(0x21, &r);
+
+      tmblk.tm_mday = r.h.dl;
+      tmblk.tm_mon = r.h.dh - 1;
+      tmblk.tm_year = (r.x.cx & 0x7ff) - 1900;
+
+      tmblk.tm_wday = tmblk.tm_yday = tmblk.tm_gmtoff = 0;
+      tmblk.tm_zone = 0;
+      tmblk.tm_isdst = -1;
+      rtc_secs = rtc.tv_sec = mktime(&tmblk);
+
+      gettimeofday(&tod, NULL);
+      tod_secs = tod.tv_sec;
+
+      if (tod.tv_usec > maxusec)
+         maxusec = tod.tv_usec;
+      curerror = difftime(rtc_secs, tod_secs) + ((rtc.tv_usec -
tod.tv_usec) / 1000000.0F);
+      if (curerror > maxposerror)
+         maxposerror = curerror;
+      if (curerror < maxnegerror)
+         maxnegerror = curerror;
+
+      strftime(timestr, sizeof(timestr), "%m/%d/%y %H:%M:%S",
localtime(&tod_secs));
+      printf("\rThe time now is %s.%ld      ", timestr, tod.tv_usec);
+   }
+   printf("\nMaximum value of usec is %ld\n", maxusec);
+   printf("Maximum errors are %f and %f\n", maxposerror, maxnegerror);
+   return 0;
+}
+#endif
+
+

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019