delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2002/12/07/00:53:43

Message-ID: <001a01c29db4$6ee30100$0100a8c0@p4>
From: "Andrew Cottrell" <acottrel AT ihug DOT com DOT au>
To: <djgpp-workers AT delorie DOT com>
Subject: XP delay() again - potential solution
Date: Sat, 7 Dec 2002 16:49:08 +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 have ran it through some tests and it is 1000% better than the exisitng
code, here is an output from a sample test run:-

DJGPP_204 C:\dj204\testing>delay 500 500 500 500 250 250 250 250 1000 1000
Time = 07Dec2002 16:45:03
Wait for 500 milli seconds.
Wait for 500 milli seconds.
Wait for 500 milli seconds.
Wait for 500 milli seconds.
Wait for 250 milli seconds.
Wait for 250 milli seconds.
Wait for 250 milli seconds.
Wait for 250 milli seconds.
Wait for 1000 milli seconds.
Wait for 1000 milli seconds.
Time = 07Dec2002 16:45:08

I have not created a patch for this as this may not the final solution and
the full file is easier to read and it's small.

Does anyone have any other suggestions to try to put forward a solution for
Win 2000 and XP only. I will need to test them to see if they work.

Anyone got any problems with the code below?  I have included RB's info so
people don't need to look it up.

/* 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 delay(unsigned msec)
{
  if(_os_trueversion == 0x532)
  {
    unsigned long start_tick;
    unsigned long end_tick;
    __dpmi_regs r;

    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))
    {
        end_tick++;
    }
    if (end_tick > tick_per_day)
    {
        while (r.h.al == 0)
        {
            r.h.ah = 0x00;
           __dpmi_int(0x1A, &r);
        }
        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);
    }
  }
  else
  {
    __dpmi_regs r;

    while (msec)
    {
       unsigned usec;
       unsigned msec_this = msec;
       if (msec_this > 4000)
         msec_this = 4000;
       usec = msec_this * 1000;
       r.h.ah = 0x86;
       r.x.cx = usec>>16;
       r.x.dx = usec & 0xffff;
       __dpmi_int(0x15, &r);
       msec -= msec_this;
    }
  }
}


- Raw text -


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