Message-ID: <004401c29e90$dc1ccf30$0100a8c0@p4> From: "Andrew Cottrell" To: 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 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit 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 #include ! 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 #include ! /*-------------------------------------------------- ! 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