The following IOCtls are defined and supported by the TIMER0$ device driver by way of the DosDevIOCtl call. The IOCtl category code is 80h (defined as HRT_IOCTL_CATEGORY).
The function codes within the HRT_IOCTL_CATEGORY are:
ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³Function ³Description ³ ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³00h ³Get Version ³ ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³01h ³Get Resolution ³ ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³02h ³Set Resolution ³ ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³03h ³Get Pointer to Clock Timer ³ ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³04h ³Free Pointer to Clock Timer ³ ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³05h ³Block Until Time Elapses ³ ÃÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³06h-7Fh ³Reserved ³ ÀÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
An example of the DosDevIOCtl calling convention for reading the current time follows:
#include "tmr0_ioc.h" APIRET rc = NO_ERROR; HFILE hfile = NULLHANDLE; ULONG ulAction = 0L; ULONG ulResolution = 1; ULONG ulSize1 = sizeof(ulResolution); ULONG * _Seg16 pulTimer16; // defines a 16:16 pointer ULONG ulSize2 = sizeof(pulTimer16); ULONG *pulTimer; rc=DosOpen( "TIMER0$ ", &hfile, &ulAction, 0,0, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL); if (rc) { printf("Couldn't open TIMER0$.\n"); return; } printf("TIMER0$ opened. File Handle is %lu\n",hfile); rc=DosDevIOCtl( hfile, HRT_IOCTL_CATEGORY, HRT_SET_RESOLUTION, &ulResolution, ulSize1, &ulSize1, NULL, 0, NULL); if (rc) { printf("Couldn't set resolution.\n"); DosClose(hfile); return; } rc=DosDevIOCtl( hfile, HRT_IOCTL_CATEGORY, HRT_GET_POINTER, NULL, 0, NULL, &pulTimer16, ulSize2, &ulSize2); if (rc) { printf("Couldn't get pointer.\n"); DosClose(hfile); return; } pulTimer = pulTimer16; // converts a 16:16 pointer to a 0:32 pointer if (!pulTimer) { printf("NULL pointer.\n"); DosClose(hfile); return; } // At this point, pulTimer is now a pointer to the timer 0 counter variable. rc=DosClose(hfile);
The DosOpen of TIMER0$ registers the application as a client. At this point, the high-resolution timer (HRT) is taking interrupts, so only open the driver when timer services are needed. The pointer is valid for the life of the process, and each call to HRT_GET_POINTER allocates another selector, so this call should only be made once.
While the HRT is taking interrupts, DOS sessions (VDMs) will not receive INT 8 or INT 1Ch calls. The reason for this is that OS/2 only allows one device driver to receive interrupts on a given IRQ, and VTIMER.SYS (the VDD that provides INT 8 and INT 1Ch services to VDM's) expects CLOCK0x.SYS to deliver IRQ 0 interrupts. When the HRT is active, it receives the IRQ 0 interrupts instead of CLOCK0x.SYS, and thus VTIMER.SYS never gets them either.
Note: Performance tools, such as C Set's DDE4XTRA.SYS and VisualAge's CPPOPA3.SYS, are incompatible with this driver. Performance analysis tools cannot be run while the high-resolution timer is active, and vice versa.
The following code segment illustrates how to block a time-critical thread until a certain time has eleapsed. Return code checking has been omitted for brevity. A time-critical thread should be used for this function.
ULONG ulDelay = 1; // Number of milliseconds to wait ULONG ulSize2 = sizeof(ulDelay); DosOpen("TIMER0$ ", &hfile, &ulAction,0,0,ulOpenFlag,ulOpenMode,NULL); DosSetPriority(0,PRTYC_TIMECRITICAL,0,0); DosDevIOCtl( hfile, HRT_IOCTL_CATEGORY, HRT_BLOCKUNTIL, &ulDelay, ulSize2, &ulSize2, NULL, 0, NULL);