Annotation of coherent/f/etc/conf/streams/src/hr_timer.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * This file contains routines which define a simple high-precision timer
                      3:  * for PC systems, with appropriate definitions for working under a variety
                      4:  * of different operating environments.
                      5:  *
                      6:  * The basic idea, which is discussed in (among other places)
                      7:  *     "Accurately Timing Windows Events Without Timer Reprogramming"
                      8:  *     Jerry Jongerius,
                      9:  *     Microsoft Systems Journal,
                     10:  *     July 1991.
                     11:  * is to read the count register of counter/timer channel 0 on the PC, which
                     12:  * is normally set up to generate a divide-by-65536 signal from a 1.19318MHz
                     13:  * timebase, ie. the infamous 18.2Hz timer tick.
                     14:  *
                     15:  * While it is possible to read this value with low overhead if you have some
                     16:  * cooperation from the timer tick handler, it's not too tough for normal
                     17:  * application code to get at this, as long as it is possible to disable
                     18:  * interrupts for a short time. This is only necessary to prevent disruption
                     19:  * to the technique from other subsystems that use it as well.
                     20:  */
                     21: 
                     22: /*
                     23:  * Locate the system-dependent header files we need depending on the
                     24:  * operating environment we are being compiled under.
                     25:  */
                     26: 
                     27: #include <ccompat.h>
                     28: 
                     29: #define        INT_FLAG_BIT_MASK               0x200
                     30: 
                     31: #if    defined (__GNUC__) && defined (GNUDOS)
                     32: 
                     33: #include <pc.h>
                     34: #include <dos.h>
                     35: 
                     36: #define        INPUT_BYTE(port)        inportb (port)
                     37: #define        OUTPUT_BYTE(port,byte)  outportb (port, byte)
                     38: 
                     39: static inline unsigned short SPL7 (void) {
                     40:         register unsigned short temp;
                     41:         asm ("pushf; pop %0; cli" : "=r" (temp));
                     42:         return temp;
                     43: }
                     44: 
                     45: static inline void SPLX (unsigned short prev) {
                     46:         if ((prev & INT_FLAG_BIT_MASK) != 0)
                     47:                 asm ("sti");
                     48: }
                     49: 
                     50: #define        BIOS_CLOCK_INT  0x1A
                     51: 
                     52: static inline unsigned short GETTICKCOUNT (void) {
                     53:        union REGS in;
                     54:         in.h.ah = 0;
                     55:         int86 (BIOS_CLOCK_INT, & in, & in);
                     56:         return in.x.dx;
                     57: }
                     58: 
                     59: #elif  __BORLANDC__
                     60: 
                     61: #include <dos.h>
                     62: #include <conio.h>
                     63: 
                     64: #define        INPUT_BYTE(port)        inportb (port)
                     65: #define        OUTPUT_BYTE(port,byte)  outportb (port, byte)
                     66: 
                     67: #define SPL7()         (_AX = _FLAGS, disable (), _AX)
                     68: #define SPLX(s)                ((s & INT_FLAG_BIT_MASK) != 0 ? enable () : (void) 0)
                     69: 
                     70: #define        BIOS_DATA_SEGMENT       0x40
                     71: #define        BIOS_TICK_COUNT_LOW     0x6C
                     72: #define        GETTICKCOUNT()          * (unsigned short far *) MK_FP (BIOS_DATA_SEGMENT, BIOS_TICK_COUNT_LOW)
                     73: 
                     74: #else
                     75: #error unknown system type
                     76: #endif
                     77: 
                     78: /*
                     79:  * Returns a 32-bit unsigned value which combines the BIOS tick count with
                     80:  * the current count value from the CTC. Since we do not have the cooperation
                     81:  * of the tick interrupt handler, we detect overflows by reading the BIOS
                     82:  * count before and after; we examine the sign of the value we read from the
                     83:  * CRTC to decide which side of the fence we fell on.
                     84:  *
                     85:  * The BIOS tick count is actually 32-bit, but the low 16-bit part only
                     86:  * overflows about once per hour, so who cares?
                     87:  */
                     88: 
                     89: #define        CTC_PORT_CMD    0x43
                     90: #define        CTC_PORT_0      0x40
                     91: #define        CTC_READ_CMD    0xC2
                     92: 
                     93: #ifdef __USE_PROTO
                     94: unsigned long getTickCount (void)
                     95: #else
                     96: unsigned long
                     97: getTickCount ()
                     98: #endif
                     99: {
                    100:        register unsigned short microcount;
                    101:         unsigned short tickcount, tickcount2;
                    102:         register short s;
                    103: 
                    104:         tickcount = GETTICKCOUNT ();
                    105: 
                    106:         /*
                    107:          * Once we are in a critical section, issue the read (which locks the
                    108:          * current values in the registers until the read completes).
                    109:          */
                    110: 
                    111:         s = SPL7 ();
                    112: 
                    113:         OUTPUT_BYTE (CTC_PORT_CMD, CTC_READ_CMD);
                    114:         microcount = (INPUT_BYTE (CTC_PORT_0) & 0x80) != 0 ? 0x8000 : 0;
                    115:         microcount |= INPUT_BYTE (CTC_PORT_0) >> 1;
                    116:         microcount |= INPUT_BYTE (CTC_PORT_0) << 7;
                    117: 
                    118:        SPLX (s);
                    119: 
                    120:         if ((microcount & 0x7FFF) == 0)
                    121:                microcount |= 0x7FFF;
                    122: 
                    123:         /*
                    124:          * Turn the count-down into a count-up.
                    125:          */
                    126: 
                    127:         microcount = ~ microcount;
                    128: 
                    129:         /*
                    130:          * See if we need to cope with a timer wraparound condition.
                    131:          */
                    132: 
                    133:         if ((tickcount2 = GETTICKCOUNT ()) != tickcount) {
                    134:                /*
                    135:                  * OK, now which BIOS tick did our measurement fall into?
                    136:                  * Since the CTC is a upcount from zero, if the value we
                    137:                  * read has the high bit clear, go with the new value,
                    138:                 * otherwise use the old one.
                    139:                  */
                    140: 
                    141:                 if ((microcount & 0x8000) == 0)
                    142:                        tickcount = tickcount2;
                    143:         }
                    144: 
                    145:         return ((unsigned long) tickcount << 16) | microcount;
                    146: }
                    147: 
                    148: /*
                    149:  * Sit in a loop making sure that the values returned from the timer code
                    150:  * monotonically increase.
                    151:  */
                    152: 
                    153: #include <stdio.h>
                    154: 
                    155: #ifdef __USE_PROTO
                    156: void main (void)
                    157: #else
                    158: void
                    159: main ()
                    160: #endif
                    161: {
                    162:        unsigned long last, current;
                    163: 
                    164:         current = getTickCount ();
                    165:         while (! kbhit ()) {
                    166:                last = current;
                    167:                 current = getTickCount ();
                    168:                 if ((long) (current - last) <= 0) {
                    169:                        break;
                    170:                 }
                    171:         }
                    172:        printf ("At end : %lx <= %lx\n", current, last);
                    173: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.