Watt-32 tcp/ip  2.2 dev-rel.10
timer.c
Go to the documentation of this file.
1 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <limits.h>
21 #include <signal.h>
22 #include <time.h>
23 #include <math.h>
24 #include <errno.h>
25 #include <sys/wtime.h>
26 
27 #include "wattcp.h"
28 #include "ioport.h"
29 #include "strings.h"
30 #include "gettod.h"
31 #include "pcdbug.h"
32 #include "pcqueue.h"
33 #include "language.h"
34 #include "cpumodel.h"
35 #include "powerpak.h"
36 #include "wdpmi.h"
37 #include "x32vm.h"
38 #include "rs232.h"
39 #include "misc.h"
40 #include "run.h"
41 #include "timer.h"
42 
43 #if (DOSX & PHARLAP)
44 #include <mw/exc.h> /* _dx_alloc_rmode_wrapper_iret() */
45 #endif
46 
47 DWORD start_time = 0;
48 DWORD start_day = 0;
50 #if defined(WIN32)
51  static int num_cpus = 1;
52  BOOL has_rdtsc = TRUE;
53  BOOL use_rdtsc = TRUE;
55 #else
56  BOOL has_8254 = FALSE;
57  BOOL has_rdtsc = FALSE;
58  BOOL use_rdtsc = FALSE;
59  BOOL using_int8 = FALSE;
60 #endif
61 
62 DWORD clocks_per_usec = 0L;
63 time_t user_tick_base = 0UL; /* time() when user-tick started */
64 DWORD user_tick_msec = 0UL; /* milli-sec user-tick counter */
65 BOOL user_tick_active = FALSE;
66 
67 static DWORD date = 0;
68 static DWORD date_ms = 0;
69 
70 /*
71  * Things for the user installable timer ISR.
72  */
73 #if !(DOSX & DJGPP)
74  #define TIMER_ISR_PERIOD 10UL /* 10 msec between interrupts */
75  #define TIMER_INTR 8
76 #endif
77 
78 #if (DOSX == 0) || (DOSX & DOS4GW)
79  #define HAVE_TIMER_ISR
80 
81  static W32_IntrHandler old_int_8 = NULL;
82 
83 #elif (DOSX & (PHARLAP|X32VM))
84  #define HAVE_TIMER_ISR
85 
86  static REALPTR old_int_8, int8_cback;
87 /*static FARPTR old_int_8_pm; */
88  static RMC_BLK rmBlock_int8;
89 
90 #elif (DOSX & DJGPP)
91  #define HAVE_TIMER_ISR
92 
93  static DWORD itimer_resolution = 0UL; /* in usec */
94  static void (*old_sigalrm)(int);
95  static struct itimerval old_itimer;
96 #endif
97 
98 #if defined(HAVE_TIMER_ISR) && !(DOSX & DJGPP)
99  static DWORD tick_timer_8254 = 0UL;
100 
101  /* 1193181 = 4.77MHz/4 pulses per sec.
102  */
103  #define TIMER_8254_COUNT ((1193181UL * TIMER_ISR_PERIOD) / 1000UL)
104 #endif
105 
106 
111 void init_timers (void)
112 {
113 #if defined(WIN32)
114  SYSTEM_INFO sys_info;
115 
116  memset (&sys_info, 0, sizeof(sys_info));
117  GetSystemInfo (&sys_info);
118  num_cpus = sys_info.dwNumberOfProcessors;
119  clocks_per_usec = (DWORD) (get_cpu_speed() / S64_SUFFIX(1000000));
120 
121 #else
122  #if (DOSX) /* problems using 64-bit types in small/large models */
123  hires_timer (TRUE);
124  #endif
125 
126  #if defined(HAVE_UINT64)
127  if (use_rdtsc && has_rdtsc)
128  {
129  clocks_per_usec = (DWORD) (get_cpu_speed() / S64_SUFFIX(1000000));
130  if (clocks_per_usec == 0UL)
131  {
132  outsnl ("CPU speed is 0?");
133  use_rdtsc = FALSE;
134  has_rdtsc = FALSE;
135  }
136  }
137  set_utc_offset(); /* don't pull in gettod.c unneccesary */
138  #endif
139 #endif
140 
141  chk_timeout (0UL); /* init 'date' variables */
142 
143  start_time = set_timeout (0);
145 }
146 
156 void W32_CALL init_userSuppliedTimerTick (void)
157 {
158  SIO_TRACE (("init_userSuppliedTimerTick"));
159  user_tick_active = TRUE;
160  user_tick_base = time (NULL);
161 #ifdef __MSDOS__
162  has_8254 = FALSE;
163 #endif
164 }
165 
166 /*
167  * Disable stack-checking here
168  */
169 #if defined(__HIGHC__)
170  #pragma off(Call_trace)
171  #pragma off(Prolog_trace)
172  #pragma off(Epilog_trace)
173 #endif
174 
175 #include "nochkstk.h"
176 
186 void W32_CALL userTimerTick (DWORD elapsed_time_msec)
187 {
188  user_tick_msec += elapsed_time_msec;
189 }
190 
191 #if defined(HAVE_TIMER_ISR)
192 
195 #if (DOSX & (DJGPP|PHARLAP|X32VM))
196  static void new_int_8 (void) /* not really an intr-handler */
197 #else
198  static INTR_PROTOTYPE new_int_8 (void)
199 #endif
200 {
201 #if !(DOSX & DJGPP)
202  tick_timer_8254 += TIMER_8254_COUNT;
203 
204  if (tick_timer_8254 >= 0x10000)
205  {
206  tick_timer_8254 -= 0x10000;
207 
208 #if defined(__WATCOMC__)
209  _chain_intr (old_int_8); /* chain now */
210 #elif (DOSX & (PHARLAP|X32VM))
211  _dx_call_real (old_int_8, &rmBlock_int8, 1);
212 #else
213  (*old_int_8)();
214 #endif
215  }
216  else
217  _outportb (0x20, 0x60); /* specific EOI for IRQ 0 */
218 
219  userTimerTick (TIMER_ISR_PERIOD);
220 
221 #else
222  userTimerTick (itimer_resolution / 1000UL);
223 #endif /* !(DOSX & DJGPP) */
224 
225 #if (DOSX & DJGPP)
226  /* BEEP(); */ /* !! test */
227 #endif
228 }
229 
230 void exit_timer_isr (void)
231 {
232  if (!using_int8)
233  return;
234 
235 #if (DOSX & DJGPP)
236  signal (SIGALRM, old_sigalrm);
237  setitimer (ITIMER_REAL, &old_itimer, NULL);
238 #else
239  if (old_int_8)
240  {
241  _outportb (0x43, 0x34); /* restore default timer rate */
242  _outportb (0x40, 0);
243  _outportb (0x40, 0);
244 
245  PUSHF_CLI();
246 
247 #if (DOSX & (PHARLAP|X32VM))
248  _dx_rmiv_set (TIMER_INTR, old_int_8);
249  if (int8_cback)
250  _dx_free_rmode_wrapper (int8_cback);
251  old_int_8 = 0;
252  int8_cback = 0;
253 #else
254  _dos_setvect (TIMER_INTR, old_int_8);
255  old_int_8 = NULL;
256 #endif
257 
258  POPF();
259  }
260 #endif /* DJGPP */
261 
262  /* This causes timeout calculations for timers started earlier
263  * to go wrong.
264  */
265  user_tick_active = FALSE;
266  using_int8 = FALSE;
267 }
268 
269 /*
270  * DOS/djgpp: Hook INT 8 and modify rate of timer channel 0 for 55 msec period.
271  * DOS/others: Hook INT 8 and modify rate of timer channel 0 for 10 msec period.
272  * Win32: N/A.
273  */
274 void init_timer_isr (void)
275 {
276  /* Caller must do exit_timer_isr() before doing this again
277  */
278  if (using_int8)
279  return;
280 
281 #if (DOSX & DJGPP)
282  {
283  struct itimerval tim;
284 
285  memset (&tim, 0, sizeof(tim));
286  tim.it_interval.tv_usec = 1;
287  setitimer (ITIMER_REAL, &tim, NULL);
288  setitimer (ITIMER_REAL, NULL, &tim);
289  itimer_resolution = 1000000UL * tim.it_interval.tv_sec + /* should become 55000 */
290  tim.it_interval.tv_usec;
291  tim.it_value.tv_sec = tim.it_interval.tv_sec;
292  tim.it_value.tv_usec = tim.it_interval.tv_usec;
293 
294  memset (&old_itimer, 0, sizeof(old_itimer));
295  old_sigalrm = signal (SIGALRM, (W32_IntrHandler)new_int_8);
296  setitimer (ITIMER_REAL, &tim, &old_itimer);
297  }
298 
299 #elif (DOSX & (PHARLAP|X32VM))
300  #if 1
301  int8_cback = _dx_alloc_rmode_wrapper_iret ((pmodeHook)new_int_8, 256);
302  if (!int8_cback)
303  {
304  outsnl (_LANG("Cannot allocate real-mode timer callback"));
305  return;
306  }
307  _dx_rmiv_get (8, &old_int_8);
308  _dx_rmiv_set (8, int8_cback);
309  #else
310  {
311  FARPTR fp;
312  FP_SET (fp, new_int_8, MY_CS());
313  _dx_pmiv_get (8, &old_int_8_pm);
314  _dx_apmiv_set (8, fp);
315  }
316  #endif
317 #else
318  old_int_8 = _dos_getvect (8);
319  _dos_setvect (8, new_int_8);
320 #endif
321 
322 #if !(DOSX & DJGPP)
323  _outportb (0x43, 0x34);
324  _outportb (0x40, loBYTE(TIMER_8254_COUNT));
325  _outportb (0x40, hiBYTE(TIMER_8254_COUNT));
326 #endif
327 
329  using_int8 = TRUE;
330 
331  /* release it very early */
332  RUNDOWN_ADD (exit_timer_isr, -2);
333 }
334 
335 #else
336 
337 void init_timer_isr (void)
338 {
339 #if defined(USE_DEBUG)
340  if (debug_on)
341  outsnl ("No timer-ISR in this environment");
342 #endif
343 }
344 
345 void exit_timer_isr (void)
346 {
347 }
348 #endif /* HAVE_TIMER_ISR */
349 
359 int W32_CALL cmp_timers (DWORD t1, DWORD t2)
360 {
361  if (t1 == t2)
362  return (0);
363  return (t1 < t2 ? -1 : +1);
364 }
365 
366 #if defined(__MSDOS__)
367 
377 int hires_timer (int on)
378 {
379  int old = has_8254;
380 
381  SIO_TRACE (("hires_timer %s", on ? "on" : "off"));
382  has_8254 = on;
383  chk_timeout (0UL);
384  return (old);
385 }
386 
387 
388 /*
389  * The following 2 routines are modified versions from KA9Q NOS
390  * by Phil Karn.
391  *
392  * clockbits() - Read low order bits of timer 0 (the TOD clock)
393  * This works only for the 8254 chips used in ATs and 386+.
394  *
395  * Old version:
396  * The timer 0 runs in mode 3 (square wave mode), counting down
397  * by 2s, twice for each cycle. So it is necessary to read back the
398  * OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT
399  * pin forms the most significant bit of the count. Unfortunately,
400  * the 8253 in the PC/XT lacks a command to read the OUTPUT pin...
401  *
402  * Now simply:
403  * The timer 0 runs in mode 2 (rate generator), counting down.
404  * We don't compare the OUTPUT pin to see what cycle we're in.
405  * A bit lower precision, but a bit faster.
406  *
407  * WARNING!: This can cause serious trouble if anything else is also using
408  * timer interrupts. In that case use the above "userSuppliedTimerTick()".
409  * The reading of I/O registers gives bad precision under Windows.
410  */
411 DWORD clockbits (void)
412 {
413  static VOLATILE DWORD count; /* static because of PUSHF_CLI() */
414 
415 #if 1
416  /*
417  * The following version was suggested by Andrew Paulsen
418  * <andrew.paulsen@ndsu.nodak.edu>. Seem to work fine.
419  */
420  static BOOL started = FALSE;
421 
422  PUSHF_CLI();
423 
424  if (!started) /* Initialize once, it is periodic */
425  {
426  _outportb (0x43, 0x34); /* Set timer 0, mode 2 */
427  _outportb (0x40, 0x00); /* Count is decremented, then compared to 0 */
428  _outportb (0x40, 0x00); /* so set count to 0 to get 65536 */
429  started = TRUE;
430  }
431 
432  _outportb (0x43, 0x04); /* Latch present counter value command */
433  count = _inportb (0x40); /* LSB of count */
434  count |= _inportb (0x40) << 8; /* MSB of count */
435 
436  POPF();
437 
438  return (count);
439 
440 #else
441  static VOLATILE DWORD stat, count; /* static because of PUSHF_CLI() */
442 
443  do
444  {
445  PUSHF_CLI();
446  _outportb (0x43, 0xC2); /* Read Back Command (timer 0, 8254 only) */
447  stat = _inportb (0x40); /* get status of timer 0 */
448  count = _inportb (0x40); /* LSB of count */
449  count |= _inportb (0x40) << 8; /* MSB of count */
450  POPF();
451  }
452  while (stat & 0x40); /* reread if NULL COUNT bit set */
453 
454  stat = (stat & 0x80) << 8; /* Shift OUTPUT to MSB of 16-bit word */
455  count >>= 1; /* count = count/2 */
456  if (count == 0)
457  return (stat ^ 0x8000UL); /* return complement of OUTPUT bit */
458  return (count | stat); /* Combine OUTPUT with counter */
459 #endif
460 }
461 
462 #if !defined(W32_NO_8087)
463 /*
464  * Return hardware time-of-day in milliseconds. Resolution is improved
465  * beyond 55 ms (the clock tick interval) by reading back the instantaneous
466  * 8254 counter value and combining it with the clock tick counter.
467  *
468  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
469  * between the two reads in clockbits(). The tick counter is examined before
470  * and after the hardware counter is read. If the tick counter changes, try
471  * again.
472  *
473  * \note The hardware counter (lo) counts down from 65536 at a rate of
474  * 1.193181 MHz (4.77/4). System tick count (hi) counts up.
475  */
476 DWORD millisec_clock (void)
477 {
478  DWORD hi;
479  WORD lo;
480  double x;
481 
482  do
483  {
484  hi = PEEKL (0, BIOS_CLK);
485  lo = clockbits();
486  }
487  while (hi != PEEKL(0, BIOS_CLK)); /* tick count changed, try again */
488  lo = 0 - lo;
489 
490  /* Emulating this would be slow. We'd better have a math-processor
491  */
492  x = ldexp ((double)hi, 16) + (double)lo; /* x = hi*2^16 + lo */
493  return (DWORD) (x * 4.0 / 4770.0);
494 }
495 #endif /* !W32_NO_8087 */
496 #endif /* __MSDOS__ */
497 
498 
503 DWORD W32_CALL set_timeout (DWORD msec)
504 {
505  DWORD ret;
506 
507  if (user_tick_active) /* using timer ISR or user-timer */
508  {
509  ret = user_tick_msec + msec;
510  }
511 #if defined(HAVE_UINT64) /* CPU-clock, 8254 PIT or 55msec ticks */ || \
512  defined(WIN32) /* GetSystemTimeAsFileTime() */
513  else
514  {
515  struct timeval now;
516 
517  gettimeofday2 (&now, NULL);
518  ret = msec + 1000 * (DWORD)now.tv_sec + (DWORD)(now.tv_usec / 1000);
519  }
520 #else
521 
522 #if !defined(W32_NO_8087)
523  else if (has_8254) /* high-resolution PIT */
524  {
525  ret = msec + date_ms + millisec_clock();
526  }
527 #endif
528  else /* fallback to 55msec ticks */
529  {
530  DWORD ticks = 1;
531 
532  if (msec > 55)
533  ticks = msec / 55UL;
534  /* ret = ticks + ms_clock(); !!!! try this */
535  ret = ticks + date + PEEKL (0,BIOS_CLK);
536  }
537 #endif /* HAVE_UINT64 || WIN32 */
538 
539  return (ret == 0 ? 1 : ret);
540 }
541 
547 BOOL W32_CALL chk_timeout (DWORD value)
548 {
549  if (user_tick_active) /* using timer ISR or user-timer */
550  {
551  if (value == 0)
552  return (0);
553  return (user_tick_msec >= value);
554  }
555 
556 #if defined(HAVE_UINT64) || defined(WIN32)
557  if (value == 0UL)
558  return (0);
559  return (set_timeout(0) >= value);
560 
561 #else
562  {
563  static char oldHour = -1;
564 #if !defined(W32_NO_8087)
565  static DWORD now_ms;
566 #endif
567  static DWORD now;
568  char hour;
569 
570  now = (DWORD) PEEKL (0, BIOS_CLK);
571 #if 1
572  hour = (char)(now >> 16U);
573 #else
574  hour = (char)(now/65543.33496093); /* Jan De Geeter 17.12.01 */
575 #endif
576 
577  if (hour != oldHour)
578  {
579  if (hour < oldHour) /* midnight passed */
580  {
581 #define CORR 290UL /* experimental correction */
582  date += 1572750UL + CORR; /* Update date (0x1800B0UL) */
583  date_ms += 3600UL*24UL*1000UL; /* ~2^26 */
584  }
585  oldHour = hour;
586  }
587 
588  if (value == 0L) /* timer not initialised */
589  return (0); /* (or stopped) */
590 
591 #if !defined(W32_NO_8087)
592  if (has_8254)
593  {
594  now_ms = millisec_clock();
595  return (now_ms + date_ms >= value);
596  }
597 #endif
598  now += date; /* date extend current time */
599  return (now >= value); /* return true if expired */
600  }
601 #endif /* HAVE_UINT64 || WIN32 */
602 }
603 
608 int W32_CALL set_timediff (long msec)
609 {
610  date_ms -= msec;
611  date -= msec/55;
612  return (0);
613 }
614 
621 long W32_CALL get_timediff (DWORD now, DWORD tim)
622 {
623 #if defined(HAVE_UINT64) || defined(WIN32)
624  return (long)(now - tim);
625 #else
626  long dt = (long)(now - tim);
627 
628  if (has_8254)
629  dt = dt % (3600L*24L*1000L);
630  else dt = dt % (1572750L + CORR);
631  return (dt);
632 #endif
633 }
634 
635 #if !defined(W32_NO_8087)
636 /*
637  * Return difference (in micro-sec) between timevals `*newer' and `*older'
638  */
639 double W32_CALL timeval_diff (const struct timeval *newer, const struct timeval *older)
640 {
641  long d_sec = (long)newer->tv_sec - (long)older->tv_sec;
642  long d_usec = newer->tv_usec - older->tv_usec;
643 
644  while (d_usec < 0)
645  {
646  d_usec += 1000000L;
647  d_sec -= 1;
648  }
649  return ((1E6 * (double)d_sec) + (double)d_usec);
650 }
651 #endif
652 
653 struct timeval W32_CALL timeval_diff2 (struct timeval *ta, struct timeval *tb)
654 {
655  struct timeval tv;
656 
657  if (tb->tv_usec > ta->tv_usec)
658  {
659  ta->tv_sec--;
660  ta->tv_usec += 1000000L;
661  }
662  tv.tv_sec = ta->tv_sec - tb->tv_sec;
663  tv.tv_usec = ta->tv_usec - tb->tv_usec;
664  if (tv.tv_usec >= 1000000L)
665  {
666  tv.tv_usec -= 1000000L;
667  tv.tv_sec++;
668  }
669  return (tv);
670 }
671 
672 #if defined(USE_DEBUG)
673 /*
674  * Return string "x.xx" for timeout value.
675  * 'val' is always in milli-sec units if we're using the 8254 PIT,
676  * RDTSC timestamps, timer ISR or user-supplied timer.
677  * 'val' is always in milli-sec units on Win32.
678  */
679 const char *time_str (DWORD val)
680 {
681  static char buf[30];
682  char fmt[6];
683  double flt_val;
684 
685 #if defined(WIN32)
686  flt_val = (double)val / 1000.0F;
687  strcpy (fmt, "%.3f");
688 
689 #else
690 
691  if (has_8254 || has_rdtsc || user_tick_active)
692  {
693  flt_val = (double)val / 1000.0F;
694  strcpy (fmt, "%.3f");
695  }
696  else
697  {
698  flt_val = (double)val / 18.2F;
699  strcpy (fmt, "%.2f");
700  }
701 #endif
702 
703 #if defined(SNPRINTF)
704  SNPRINTF (buf, sizeof(buf), fmt, flt_val);
705 #else
706  sprintf (buf, sizeof(buf), fmt, flt_val);
707 #endif
708  return (buf);
709 }
710 
711 /*
712  * Return string "HH:MM:SS" for a time in seconds.
713  */
714 const char *hms_str (DWORD sec)
715 {
716  static char buf[30];
717  WORD hour = (WORD) (sec / 3600UL);
718  WORD min = (WORD) (sec / 60) - (60 * hour);
719 
720  sprintf (buf, "%02u:%02u:%02u", hour, min, (UINT)(sec % 60UL));
721  return (buf);
722 }
723 
724 /*
725  * Return string "xx:xx" for time elapsed since started.
726  * Handles max 24 days. Or max 49 days with user_tick_active.
727  */
728 const char *elapsed_str (DWORD val)
729 {
730  static char buf[30];
731  WORD hour, min, msec;
732  DWORD sec;
733  BOOL msec_clock = 1;
734 
735 #ifdef __MSDOS__
736  msec_clock = (has_8254 || has_rdtsc);
737 #endif
738 
739  if (val == 0UL)
740  return ("00:00:00.000");
741 
742 #if 0
743  if (!user_tick_active && val < start_time) /* wrapped? */
744  val = ULONG_MAX - val + start_time;
745 #endif
746 
747  /* If user-ticks is used, 'val' should be correct msec count
748  * since init_userSuppliedTimerTick() was called.
749  */
750  if (user_tick_active)
751  {
752  sec = val / 1000UL;
753  msec = (WORD) (val % 1000UL);
754  }
755  else if (msec_clock)
756  {
757  val -= start_time;
758  sec = val / 1000UL;
759  msec = (WORD) (val % 1000UL);
760  }
761  else
762  {
763  val -= start_time;
764  sec = val / 18;
765  msec = 55 * (WORD)(val % 18UL);
766  }
767 
768  hour = (WORD) (sec / 3600UL);
769  min = (WORD) (sec / 60UL) - 60 * hour;
770  sec = sec % 60UL;
771  sprintf (buf, "%02u:%02u:%02lu.%03u", hour, min, sec, msec);
772  return (buf);
773 }
774 #endif /* USE_DEBUG */
775 
776 
777 #if defined(__MSDOS__)
778 /*
779  * The following was contributed by
780  * "Alain" <alainm@pobox.com>
781  */
782 #define TICKS_DAY 1573067UL /* Number of ticks in one day */
783 
784 DWORD ms_clock (void)
785 {
786  static DWORD lastTick, tickOffset;
787  static char firstTime = 1;
788  DWORD tick = PEEKL (0, 0x46C);
789 
790  if (firstTime)
791  {
792  firstTime = 0;
793  lastTick = tickOffset = tick;
794  return (0);
795  }
796  if (lastTick > tick) /* day changed */
797  tickOffset -= TICKS_DAY;
798  lastTick = tick;
799  return (tick - tickOffset);
800 }
801 
802 #if defined(__HIGHC__) || defined(__DMC__)
803 void delay (unsigned int msec)
804 {
805  for (; msec; msec--)
806  {
807  DWORD now = ms_clock();
808  while (ms_clock() == now) /* wait 1msec */
809  ;
810  }
811 }
812 #endif
813 
814 #if (DOSX) && defined(HAVE_UINT64)
815 /*
816  * Wait for BIOS timer-tick to change 'num' times.
817  */
818 static void Wait_N_ticks (int num)
819 {
820  while (num--)
821  {
822  DWORD time = PEEKL (0, BIOS_CLK);
823 
824  while (time == PEEKL(0,BIOS_CLK))
825  {
826 #ifdef __DJGPP__
827  ENABLE(); /* CWSDPMI requires this! */
828 #else
829  ((void)0);
830 #endif
831  }
832  }
833 }
834 
839 {
840  #define NUM_SAMPLES 3
841  #define WAIT_TICKS 2
842 
843  uint64 speed;
844  uint64 sample [NUM_SAMPLES];
845  int i;
846 
847  Wait_N_ticks (1);
848 
849  for (i = 0; i < NUM_SAMPLES; i++)
850  {
851  uint64 start = GET_RDTSC();
852 
853  Wait_N_ticks (WAIT_TICKS);
854  sample[i] = 1000 * (GET_RDTSC() - start) / (WAIT_TICKS*55);
855  }
856 
857  speed = 0;
858  for (i = 0; i < NUM_SAMPLES; i++)
859  speed += sample[i];
860  return (speed / NUM_SAMPLES);
861 }
862 #endif /* DOSX && HAVE_UINT64 */
863 
864 #elif defined(WIN32)
865 
866 #if 0
867 /*
868  * Wait for timer-ticks to change 'num' times.
869  */
870 static void Wait_N_ticks (int num)
871 {
872  DWORD tim;
873 
874  while (num--)
875  {
876  tim = GetTickCount() + 55;
877  while (GetTickCount() < tim)
878  Sleep (0);
879  }
880 }
881 #endif
882 
886 uint64 get_cpu_speed (void)
887 {
888  LARGE_INTEGER rc;
889 
890  if (QueryPerformanceFrequency(&rc))
891  return (rc.QuadPart);
892  return (0);
893 }
894 
895 uint64 win_get_perf_count (void)
896 {
897  LARGE_INTEGER rc;
898  DWORD am = 0UL;
899  HANDLE ct = INVALID_HANDLE_VALUE;
900 
901  if (num_cpus > 1)
902  {
903  ct = GetCurrentThread();
904  am = SetThreadAffinityMask (ct, 1);
905  }
906  QueryPerformanceCounter (&rc);
907  if (num_cpus > 1)
908  SetThreadAffinityMask (ct, am);
909  return (rc.QuadPart);
910 }
911 
912 #if defined(NOT_USED)
913 /*
914  * Make sure RDTSC is returned from the 1st CPU on a multi (or hyper-threading)
915  * CPU system.
916  */
917 uint64 win_get_rdtsc (void)
918 {
919  DWORD am = 0UL;
920  HANDLE ct = INVALID_HANDLE_VALUE;
921  uint64 rc;
922 
923  if (num_cpus > 1)
924  {
925  ct = GetCurrentThread();
926  am = SetThreadAffinityMask (ct, 1);
927  }
928  rc = get_rdtsc();
929  if (num_cpus > 1)
930  SetThreadAffinityMask (ct, am);
931  return (rc);
932 }
933 #endif /* NOT_USED */
934 #endif /* __MSDOS__ */
935 
static void new_int_8(void)
User defined 10 (or 55) milli-sec counter ISR.
Definition: timer.c:196
void W32_CALL userTimerTick(DWORD elapsed_time_msec)
Provide timer-ticks from an application.
Definition: timer.c:186
int W32_CALL set_timediff(long msec)
Must be called by user right before or after a time change occurs.
Definition: timer.c:608
DWORD start_day
Start-day of watt_sock_init()
Definition: timer.c:48
BOOL has_rdtsc
Never set in Watt-32.
Definition: timer.c:52
void init_timers(void)
Setup timer stuff and measure CPU speed.
Definition: timer.c:111
DWORD clocks_per_usec
Measured CPU speed (MHz)
Definition: timer.c:62
DWORD get_day_num(void)
Simplified method of getting days since 1970-01-01.
Definition: misc.c:200
Core definitions.
uint64 get_cpu_speed(void)
Return estimated CPU speed in Hz.
Definition: timer.c:838
BOOL use_rdtsc
Ditto.
Definition: timer.c:53
Definition: x32vm.h:30
void W32_CALL init_userSuppliedTimerTick(void)
init_userSuppliedTimerTick() - setup timer handling for programs that are already running a periodic ...
Definition: timer.c:156
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
BOOL using_int8
init_timer_isr() called
Definition: timer.c:59
unsigned long long uint64
our unsigned "long long" type
Definition: wattcp.h:60
void set_utc_offset(void)
Called from init_timers() once.
Definition: gettod.c:146
Definition: wtime.h:38
BOOL has_8254
Do we have a working 8254 timer chip?
Definition: timer.c:56
DWORD start_time
Start-time of watt_sock_init() (in msec)
Definition: timer.c:47
int W32_CALL cmp_timers(DWORD t1, DWORD t2)
Compare two timers with expirary at 't1' and 't2'.
Definition: timer.c:359
int hires_timer(int on)
Control use of high-resolution timer.
Definition: timer.c:377
long W32_CALL get_timediff(DWORD now, DWORD tim)
Return time difference between timers 'now' and 'tim'.
Definition: timer.c:621
BOOL W32_CALL chk_timeout(DWORD value)
Check if milli-sec value has expired:
Definition: timer.c:547