delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2002/12/08/03:08:19

Message-ID: <004401c29e90$dc1ccf30$0100a8c0@p4>
From: "Andrew Cottrell" <acottrel AT ihug DOT com DOT au>
To: <djgpp-workers AT delorie DOT com>
References: <10212071847 DOT AA13093 AT clio DOT rice DOT edu>
Subject: Re: XP delay() again - potential solution
Date: Sun, 8 Dec 2002 19:07:01 +1100
MIME-Version: 1.0
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2800.1123
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1123
Reply-To: djgpp-workers AT delorie DOT com

> > This was discussed a while ago and I cannot remember if there was a
solution
> > proposed, except one I worked on.  Below is a modified delay.c that
works on
> > XP. It does have some problems in that it is only accuate to approx 27
> > milliseconds as the TOD tick is updated every 54.9 millisends and I do a
> > manual rounding check in the code in order to try to make the delay a
bit
> > more accurate.
>
> I also worked on something similar - my WIP from last year is attached at
> the bottom.  I was trying to get more accuracy, but due to the unsync
> between the counter and tick rollover, I think there were bugs I hadn't
> fixed in the stuff below (it didn't work?).  I also tried to call the
> int15 call and checked for success, just in case they fixed it some day.
>
> Yours looks fine, and I think we ought to get it into the library for the
next
> release.  Maybe document the accuracy issue. Maybe do some yields in the
busy
> loop.  Thanks for working on this, I'm just completely swamped.
Charles,

I modified the code to try the int 15 and if it failed then use the TOD tick
time as you indicated if MS fix it down the tack. I added the yields,
hopefully in the right spots and modified the txh file. I do not know what
to put in the docs so any help is appreciated even if it is I don't
understand it.

Below are the patches, one for delay.c and the other for delay.txh.

Any more comments on the delay.c mods?
*** \djgppcvs\src\libc\dos\dos\delay.c Tue Mar 21 18:35:38 1995
--- .\src\libc\dos\dos\delay.c Sun Dec  8 18:59:16 2002
***************
*** 1,10 ****
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  #include <dos.h>
  #include <dpmi.h>

! void delay(unsigned msec)
  {
    __dpmi_regs r;
    while (msec)
    {
      unsigned usec;
--- 1,54 ----
+ /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+
  #include <dos.h>
  #include <dpmi.h>

! /*--------------------------------------------------
! INT 15 - BIOS - WAIT (AT,PS)
!    AH = 86h
!    CX:DX = interval in microseconds
! Return: CF clear if successful (wait interval elapsed)
!    CF set on error or AH=83h wait already in progress
!    AH = status (see #00496)
! Note: the resolution of the wait period is 977 microseconds on many
systems
!    because many BIOSes use the 1/1024 second fast interrupt from the AT
!    real-time clock chip which is available on INT 70; because newer
!    BIOSes may have much more precise timers available, it is not
!    possible to use this function accurately for very short delays unless
!    the precise behavior of the BIOS is known (or found through testing)
! SeeAlso: AH=41h,AH=83h,INT 1A/AX=FF01h,INT 70
! Note: Does not work on Win 2K or XP!!!!
! --------------------------------------------------
! INT 1A - TIME - GET SYSTEM TIME
!  AH = 00h
! Return: CX:DX = number of clock ticks since midnight
!  AL = midnight flag, nonzero if midnight passed since time last read
! Notes: there are approximately 18.2 clock ticks per second, 1800B0h per 24
! hrs
!    (except on Tandy 2000, where the clock runs at 20 ticks per second)
!  IBM and many clone BIOSes set the flag for AL rather than incrementing
!    it, leading to loss of a day if two consecutive midnights pass
!    without a request for the time (e.g. if the system is on but idle)
!  since the midnight flag is cleared, if an application calls this
!    function after midnight before DOS does, DOS will not receive the
!    midnight flag and will fail to advance the date
!  Modern releases of MS-DOS/PC DOS (5.0+???) assume that AL is a day
!    rollover counter rather than a flag, as expected by older releases.
!    DOS 5 - 7.10 (Windows 98 SE) provide an undocumented CONFIG.SYS
!    SWITCHES=/T option to force the old behaviour of the day advancing
!    code, that is using a flag instead of a counter.
!  DR DOS 3.31 - DR-DOS 7.03 handle AL as a flag.
! SeeAlso: AH=01h,AH=02h,INT 21/AH=2Ch,INT 55"Tandy 2000",INT 4E/AH=02h"TI"
! SeeAlso: INT 62/AX=0099h,MEM 0040h:006Ch,MEM 0040h:0070h
! --------------------------------------------------*/
!
! #define tick_per_day (24*60*60*10000/182)
!
! void ac_delay(unsigned msec)
  {
      __dpmi_regs r;
+
      while (msec)
      {
          unsigned usec;
***************
*** 16,21 ****
--- 60,104 ----
          r.x.cx = usec>>16;
          r.x.dx = usec & 0xffff;
          __dpmi_int(0x15, &r);
+         if ((r.x.flags & 1) || (r.h.ah == 0x83))
+         {
+             /* INT 15 FAILED, so fall back to the Time Of Day Tick */
+             unsigned long start_tick;
+             unsigned long end_tick;
+
+             r.h.ah = 0x00;
+             __dpmi_int(0x1A, &r);
+
+             start_tick = (r.x.cx << 16) + (r.x.dx & 0xffff);
+             end_tick = (msec*182)/10000 + start_tick;
+
+             if ((msec%10000/182) > (5000/182)) /* Manual round ticks */
+             {
+                 end_tick++;
+             }
+             if (end_tick > tick_per_day)  /* Tick time past midnight */
+             {
+                 /* check for midnight */
+                 while (r.h.al == 0)
+                 {
+                     r.h.ah = 0x00;
+                     __dpmi_int(0x1A, &r);
+                     __dpmi_yield();
+                 }
+                 end_tick = end_tick - tick_per_day;
+             }
+
+             while (((r.x.cx << 16) + (r.x.dx & 0xffff)) <= end_tick)
+             {
+                 r.h.ah = 0x00;
+                 __dpmi_int(0x1A, &r);
+                 __dpmi_yield();
+             }
+             msec = 0;  /* waited the required time */
+         }
+         else
+         {
              msec -= msec_this;
          }
      }
+ }

*** \djgppcvs\src\libc\dos\dos\delay.txh Mon Sep  6 22:39:32 1999
--- .\src\libc\dos\dos\delay.txh Sun Dec  8 18:54:14 2002
***************
*** 13,22 ****
  It uses the @code{int 15h} delay function to relinquish the CPU to other
  programs that might need it.

! Some operating systems that emulate DOS, such as OS/2 and Windows/NT,
! hang the DOS session when the @key{Pause} key is pressed during the call
! to @code{delay}.  Plain DOS and Windows 3.X and 9X are known to not have
! this bug.

  @subheading Return Value

--- 13,26 ----
  It uses the @code{int 15h} delay function to relinquish the CPU to other
  programs that might need it.

! Some operating systems that emulate DOS, such as OS/2, Windows/NT, Windows
2000
! and Windows XP hang the DOS session when the @key{Pause} key is pressed
during
! the call to @code{delay}.  Plain DOS and Windows 3.X and 9X are known to
! not have this bug. On Windows 2000 and XP to exit the pause press any key.
!
! Windows 2000 and XP delay resolution is 54.9 millisecond. Under Windows
! 2000 and XP the delay function uses the Time Of Day Tick which occurs
! 18.2 times per second.

  @subheading Return Value




- Raw text -


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