Message-ID: <001a01c29db4$6ee30100$0100a8c0@p4> From: "Andrew Cottrell" To: Subject: XP delay() again - potential solution Date: Sat, 7 Dec 2002 16:49:08 +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 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 #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 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; } } }