delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/04/29/00:40:34

From: sandmann AT clio DOT rice DOT edu (Charles Sandmann)
Message-Id: <10304290440.AA26174@clio.rice.edu>
Subject: uclock proposed patch
To: djgpp-workers AT delorie DOT com (DJGPP developers)
Date: Mon, 28 Apr 2003 23:40:04 -0500 (CDT)
X-Mailer: ELM [version 2.5 PL2]
Mime-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

For Windows 2000 and XP; I'll try a test on NT4 and on a 486 running NT 3.1
if I get a chance.  Autocalibrates as needed to always keep the tic 
counter aligned.  This might cause some jitter due to the inaccuracy of
the NT tic counter, but since it's not a real time OS and multitasking
who knows what really happened.  Installs signal handler, should never
been seen in real life (no one is running Windows NT 3.5 or earlier 
which were the last versions to support 486s which didn't have rdtsc).
If they are, it falls back to tic accuracy.

Comments?

--- uclock.c_	Tue Dec 11 21:28:06 2001
+++ uclock.c	Mon Apr 28 23:25:18 2003
@@ -11,4 +11,21 @@
 #include <dpmi.h>
 #include <libc/bss.h>
+#include <dos.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/exceptn.h>
+
+/* Catch rdtsc exception and always return 0LL */
+static void catch_rdtsc(int val)
+{
+  short *eip = (short *)__djgpp_exception_state->__eip;
+  if(*eip == 0x310f) {
+    __djgpp_exception_state->__eip += 2;
+    __djgpp_exception_state->__edx = 0;
+    longjmp(__djgpp_exception_state, 0);
+  }
+  return;
+}
+
 
 static int uclock_bss = -1;
@@ -30,4 +47,32 @@
   uclock_t rv;
 
+  _farsetsel(_dos_ds);
+
+  if(_os_trueversion == 0x532) {	/* Windows NT, 2000, XP */
+    static double multiplier;
+    static unsigned long btics;
+    uclock_t rval;
+
+    if (uclock_bss != __bss_count) {
+      signal(SIGILL, catch_rdtsc);
+      tics = _farnspeekl(0x46c);
+      while ( (btics = _farnspeekl(0x46c)) == tics);
+      base = _rdtsc();
+      if (base == 0) base = -1LL;
+      while ( (tics = _farnspeekl(0x46c)) == btics);
+      if (tics < btics) tics = btics + 1;		/* Midnight */
+      multiplier = ((tics - btics)*65536) / (double)(_rdtsc() - base);
+      uclock_bss = __bss_count;
+    }
+    rval = (_rdtsc() - base) * multiplier;
+    tics = _farnspeekl(0x46c) - btics;
+    while (tics <= 0) tics += 0x1800b0;			/* Midnight */
+    if( (unsigned long)(rval >> 16) != tics) {		/* Recalibrate */
+      rval = ((uclock_t)tics) << 16;
+      multiplier = (tics*65536) / (double)(_rdtsc() - base);
+    }
+    return rval;
+  }
+
   if (uclock_bss != __bss_count)
   {
@@ -52,5 +97,4 @@
        if the timer worked in mode 3.  So we simply wait for one clock
        tick when we run on Windows.  */
-    _farsetsel(_dos_ds);
     otics = _farnspeekl(0x46c);
     do {
@@ -63,9 +107,9 @@
   /* Make sure the numbers we get are consistent */
   do {
-    otics = _farpeekl(_dos_ds, 0x46c);
+    otics = _farnspeekl(0x46c);
     outportb(0x43, 0x00);
     lsb = inportb(0x40);
     msb = inportb(0x40);
-    tics = _farpeekl(_dos_ds, 0x46c);
+    tics = _farnspeekl(0x46c);
   } while (otics != tics);
 

- Raw text -


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