Improve GambitREPL iOS example.
[gambit-c.git] / lib / os_time.c
blob795c0c25e0502ad744161292f4c5ace1ef1266d0
1 /* File: "os_time.c", Time-stamp: <2011-03-22 14:38:49 feeley> */
3 /* Copyright (c) 1994-2008 by Marc Feeley, All Rights Reserved. */
5 /*
6 * This module implements the operating system specific routines
7 * related to time.
8 */
10 #define ___INCLUDED_FROM_OS_TIME
11 #define ___VERSION 406003
12 #include "gambit.h"
14 #include "os_base.h"
15 #include "os_time.h"
18 /*---------------------------------------------------------------------------*/
21 ___time_module ___time_mod =
24 TIME_POS_INFINITY,
25 TIME_NEG_INFINITY,
26 0.0,
27 -1.0,
28 NULL
30 #ifdef ___TIME_MODULE_INIT
31 ___TIME_MODULE_INIT
32 #endif
36 /*---------------------------------------------------------------------------*/
38 /* Time management. */
41 void ___time_from_nsecs
42 ___P((___time *tim,
43 ___SM32 secs,
44 ___SM32 nsecs),
45 (tim,
46 secs,
47 nsecs)
48 ___time *tim;
49 ___SM32 secs;
50 ___SM32 nsecs;)
52 #ifdef ___FLOAT_TIME_REPRESENTATION
53 *tim = secs + nsecs / 1000000000.0;
54 #endif
56 #ifdef ___INT_TIME_REPRESENTATION
57 tim->secs = secs + nsecs / 1000000000;
58 tim->nsecs = nsecs % 1000000000;
59 #endif
63 void ___time_add
64 ___P((___time *tim1,
65 ___time tim2),
66 (tim1,
67 tim2)
68 ___time *tim1;
69 ___time tim2;)
71 #ifdef ___FLOAT_TIME_REPRESENTATION
72 *tim1 += tim2;
73 #endif
75 #ifdef ___INT_TIME_REPRESENTATION
76 ___SM32 total_secs = tim1->secs + tim2.secs;
77 ___SM32 total_nsecs = tim1->nsecs + tim2.nsecs;
78 tim1->secs += tim2.secs + total_nsecs / 1000000000;
79 tim1->nsecs = total_nsecs % 1000000000;
80 #endif
84 void ___time_subtract
85 ___P((___time *tim1,
86 ___time tim2),
87 (tim1,
88 tim2)
89 ___time *tim1;
90 ___time tim2;)
92 #ifdef ___FLOAT_TIME_REPRESENTATION
93 *tim1 -= tim2;
94 #endif
96 #ifdef ___INT_TIME_REPRESENTATION
97 ___SM32 total_nsecs;
99 if (tim2.nsecs > tim1->nsecs)
101 tim1->secs -= tim2.secs + 1;
102 tim1->nsecs += 1000000000 - tim2.nsecs;
104 else
106 tim1->secs -= tim2.secs;
107 tim1->nsecs -= tim2.nsecs;
109 #endif
113 ___BOOL ___time_equal
114 ___P((___time tim1,
115 ___time tim2),
116 (tim1,
117 tim2)
118 ___time tim1;
119 ___time tim2;)
121 #ifdef ___FLOAT_TIME_REPRESENTATION
122 return (tim1 == tim2);
123 #endif
125 #ifdef ___INT_TIME_REPRESENTATION
126 return (tim1.secs == tim2.secs && tim1.nsecs == tim2.nsecs);
127 #endif
131 ___BOOL ___time_less
132 ___P((___time tim1,
133 ___time tim2),
134 (tim1,
135 tim2)
136 ___time tim1;
137 ___time tim2;)
139 #ifdef ___FLOAT_TIME_REPRESENTATION
140 return (tim1 < tim2);
141 #endif
143 #ifdef ___INT_TIME_REPRESENTATION
144 return (tim1.secs < tim2.secs ||
145 (tim1.secs == tim2.secs && tim1.nsecs < tim2.nsecs));
146 #endif
150 ___BOOL ___time_positive
151 ___P((___time tim),
152 (tim)
153 ___time tim;)
155 #ifdef ___FLOAT_TIME_REPRESENTATION
156 return (tim > 0.0);
157 #endif
159 #ifdef ___INT_TIME_REPRESENTATION
160 return (tim.secs > 0 ||
161 (tim.secs == 0 && tim.nsecs > 0));
162 #endif
166 void ___time_get_current_time
167 ___P((___time *tim),
168 (tim)
169 ___time *tim;)
171 #ifndef USE_clock_gettime
172 #ifndef USE_getclock
173 #ifndef USE_GetSystemTime
174 #ifndef USE_gettimeofday
175 #ifndef USE_ftime
176 #ifndef USE_time
177 #ifndef USE_CLASSIC_MACOS
179 *tim = ___time_mod.time_neg_infinity;
181 #endif
182 #endif
183 #endif
184 #endif
185 #endif
186 #endif
187 #endif
189 #ifdef USE_clock_gettime
191 /* The clock_gettime function is in POSIX.1b (realtime programming). */
193 struct timespec ts;
194 if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
195 ___time_from_nsecs (tim, ts.tv_sec-JAN_1(1970), ts.tv_nsec);
196 else
197 *tim = ___time_mod.time_neg_infinity;
199 #endif
201 #ifdef USE_getclock
203 /* The getclock function is in the Tru64 UNIX standard C library. */
205 struct timespec ts;
206 if (getclock (TIMEOFDAY, &ts) == 0)
207 ___time_from_nsecs (tim, ts.tv_sec-JAN_1(1970), ts.tv_nsec);
208 else
209 *tim = ___time_mod.time_neg_infinity;
211 #endif
213 #ifdef USE_GetSystemTime
215 SYSTEMTIME st;
216 FILETIME ft;
217 GetSystemTime (&st);
218 if (SystemTimeToFileTime (&st, &ft))
220 LONGLONG x = *___CAST(LONGLONG*,&ft);
221 ___SM32 secs = x / 10000000 - JAN_1(1601LL);
222 ___SM32 nsecs = x % 10000000 * 100;
223 ___time_from_nsecs (tim, secs, nsecs);
225 else
226 *tim = ___time_mod.time_neg_infinity;
228 #endif
230 #ifdef USE_gettimeofday
232 struct timeval tv;
233 if (gettimeofday (&tv, NULL) == 0)
234 ___time_from_nsecs (tim, tv.tv_sec-JAN_1(1970), tv.tv_usec*1000);
235 else
236 *tim = ___time_mod.time_neg_infinity;
238 #endif
240 #ifdef USE_ftime
242 struct timeb tb;
243 ftime (&tb);
244 ___time_from_nsecs (tim, tb.time-JAN_1(1970), tb.millitm*1000000);
246 #endif
248 #ifdef USE_time
250 time_t t;
251 time (&t);
252 ___time_from_nsecs (tim, t-JAN_1(1970), 0);
254 #endif
256 #ifdef USE_CLASSIC_MACOS
258 if (has_GetUTCDateTime)
260 UTCDateTime dt;
262 if (GetUTCDateTime (&dt, kUTCDefaultOptions) == noErr)
263 ___time_from_nsecs (tim,
264 dt.lowSeconds-JAN_1(1904),
265 ___CAST(___SM32,dt.fraction)*15258 +
266 ((___CAST(___SM32,dt.fraction)*101)>>7));
267 else
268 *tim = ___time_mod.time_neg_infinity;
270 else if (has_GetDateTime)
272 unsigned long t;
274 GetDateTime (&t); /* Get seconds since 01-01-1904 in local time. */
276 if (has_ReadLocation)
278 /* Adjust to UTC based on machine location. */
280 MachineLocation here;
281 long offset;
283 ReadLocation (&here);
284 offset = here.u.gmtDelta & 0x00ffffff;
285 if (offset & 0x00800000)
286 offset |= 0xff000000;
287 t -= offset;
290 ___time_from_nsecs (tim, t-JAN_1(1904), 0);
292 else
293 *tim = ___time_mod.time_neg_infinity;
295 #endif
299 void ___time_to_seconds
300 ___P((___time tim,
301 ___F64 *seconds),
302 (tim,
303 seconds)
304 ___time tim;
305 ___F64 *seconds;)
307 #ifdef ___FLOAT_TIME_REPRESENTATION
308 *seconds = tim;
309 #endif
311 #ifdef ___INT_TIME_REPRESENTATION
312 *seconds = tim.secs + tim.nsecs / 1000000000.0;
313 #endif
317 void ___time_from_seconds
318 ___P((___time *tim,
319 ___F64 seconds),
320 (tim,
321 seconds)
322 ___time *tim;
323 ___F64 seconds;)
325 #ifdef ___FLOAT_TIME_REPRESENTATION
326 *tim = seconds;
327 #endif
329 #ifdef ___INT_TIME_REPRESENTATION
330 if (seconds >= 2147483648.0) /* more than 68 years is pos infinity! */
331 *tim = ___time_mod.time_pos_infinity;
332 else if (seconds < -2147483648.0) /* less than -68 years is neg infinity! */
333 *tim = ___time_mod.time_neg_infinity;
334 else
336 ___SM32 secs = seconds;
337 ___SM32 nsecs = (seconds - secs) * 1000000000.0;
338 if (nsecs < 0)
340 secs--;
341 nsecs += 1000000000;
343 tim->secs = secs;
344 tim->nsecs = nsecs;
346 #endif
350 void ___absolute_time_to_relative_time
351 ___P((___time tim,
352 ___time *rtim),
353 (tim,
354 rtim)
355 ___time tim;
356 ___time *rtim;)
358 if (___time_less (tim, ___time_mod.time_pos_infinity))
360 ___time now;
361 *rtim = tim;
362 ___time_get_current_time (&now);
363 ___time_subtract (rtim, now);
365 else
366 *rtim = ___time_mod.time_pos_infinity;
370 #ifndef LINEEDITOR_WITH_NONBLOCKING_IO
373 void ___absolute_time_sleep
374 ___P((___time tim),
375 (tim)
376 ___time tim;)
378 ___absolute_time_to_relative_time (tim, &tim);
380 if (___time_positive (tim))
382 ___SM32 nsecs;
384 #ifdef ___FLOAT_TIME_REPRESENTATION
385 if (tim > 2.0)
386 nsecs = 2000000000;
387 else
388 nsecs = ___CAST(___SM32,tim * 1000000000.0);
389 #endif
391 #ifdef ___INT_TIME_REPRESENTATION
392 if (tim.secs > 2)
393 nsecs = 2000000000;
394 else
395 nsecs = tim.secs * 1000000000 + tim.nsecs;
396 #endif
398 #ifndef USE_nanosleep
399 #ifndef USE_Sleep
400 #ifndef USE_sleep
401 #ifndef USE_CLASSIC_MACOS
402 /* Can't sleep... so stay awake! */
403 #endif
404 #endif
405 #endif
406 #endif
408 #ifdef USE_nanosleep
410 /* The nanosleep function is in POSIX.1b (realtime programming). */
411 struct timespec ts;
412 ts.tv_sec = nsecs / 1000000000;
413 ts.tv_nsec = nsecs;
414 nanosleep (&ts, NULL);
416 #endif
418 #ifdef USE_Sleep
419 Sleep (nsecs / 1000000);
420 #endif
422 #ifdef USE_sleep
423 sleep (nsecs / 1000000000);
424 #endif
426 #ifdef USE_CLASSIC_MACOS
428 ___U32 ticks = nsecs / 16666666;
429 if (has_IdleUpdate)
430 IdleUpdate ();
431 if (has_WaitNextEvent)
433 EventRecord er;
434 WaitNextEvent (0, &er, ticks, NULL);
436 else if (has_Delay)
437 Delay (ticks, &ticks);
439 #endif
444 #endif
447 #ifdef USE_select
450 #ifdef ___TIMEVAL_NOT_LIMITED
451 #define ___TIMEVAL_SEC_LIMIT 2147483647 /* in seconds = 68 years */
452 #else
453 /* Mac OS X gives an error when the seconds > 100000000 (3.2 years) */
454 /* We'll be conservative in case other systems have limits */
455 #define ___TIMEVAL_SEC_LIMIT 9999999 /* in seconds = 118 days */
456 #endif
459 void ___absolute_time_to_nonnegative_timeval
460 ___P((___time tim,
461 struct timeval **tv),
462 (tim,
464 ___time tim;
465 struct timeval **tv;)
467 if (___time_less (tim, ___time_mod.time_pos_infinity))
469 struct timeval *t = *tv;
471 if (___time_positive (tim))
473 #ifdef ___FLOAT_TIME_REPRESENTATION
474 if (tim >= (___TIMEVAL_SEC_LIMIT+1.0))
476 t->tv_sec = ___TIMEVAL_SEC_LIMIT;
477 t->tv_usec = 999999;
479 else
481 t->tv_sec = ___CAST(int,tim);
482 t->tv_usec = ___CAST(int,(tim - t->tv_sec) * 1000000.0);
484 #endif
486 #ifdef ___INT_TIME_REPRESENTATION
487 if (tim.secs > ___TIMEVAL_SEC_LIMIT)
489 t->tv_sec = ___TIMEVAL_SEC_LIMIT;
490 t->tv_usec = 999999;
492 else
494 t->tv_sec = tim.secs;
495 t->tv_usec = tim.nsecs / 1000;
497 #endif
499 else
501 t->tv_sec = 0;
502 t->tv_usec = 0;
505 else
506 *tv = NULL;
510 #endif
513 #ifdef USE_MsgWaitForMultipleObjects
516 void ___absolute_time_to_nonnegative_msecs
517 ___P((___time tim,
518 DWORD *ms),
519 (tim,
521 ___time tim;
522 DWORD *ms;)
524 if (___time_less (tim, ___time_mod.time_pos_infinity))
526 if (___time_positive (tim))
528 #ifdef ___FLOAT_TIME_REPRESENTATION
530 ___F64 msecs = tim * 1000.0;
532 if (msecs >= 4294967294.0) /* upper bound is 49.6 days! */
533 *ms = 4294967294UL; /* note that INFINITE = 4294967295 */
534 else
535 *ms = ___CAST(DWORD,msecs);
537 #endif
539 #ifdef ___INT_TIME_REPRESENTATION
541 if (tim.secs > 4294968 || /* upper bound is 49.6 days! */
542 (tim.secs == 4294967 && tim.nsecs >= 294000000))
543 *ms = 4294967294UL; /* note that INFINITE = 4294967295 */
544 else
545 *ms = tim.secs * 1000 + tim.nsecs / 1000000;
547 #endif
549 else
550 *ms = 0;
552 else
553 *ms = INFINITE;
557 #endif
560 /*---------------------------------------------------------------------------*/
562 /* Measurement of process times. */
565 void ___process_times
566 ___P((___F64 *user,
567 ___F64 *sys,
568 ___F64 *real),
569 (user,
570 sys,
571 real)
572 ___F64 *user;
573 ___F64 *sys;
574 ___F64 *real;)
576 #ifndef USE_GetProcessTimes
577 #ifndef USE_getrusage
578 #ifndef USE_times
579 #ifndef USE_clock
580 #ifndef USE_DosQuerySysInfo
581 #ifndef USE_CLASSIC_MACOS
583 *user = 0.0; /* can't get time... result is 0 */
584 *sys = 0.0;
586 #endif
587 #endif
588 #endif
589 #endif
590 #endif
591 #endif
593 #ifdef USE_GetProcessTimes
595 HANDLE p;
596 FILETIME creation_time, exit_time, sys_time, user_time;
598 p = GetCurrentProcess ();
600 if (GetProcessTimes (p, &creation_time, &exit_time, &sys_time, &user_time))
602 *user = FILETIME_TO_SECONDS(user_time);
603 *sys = FILETIME_TO_SECONDS(sys_time);;
605 else
607 *user = 0.0; /* can't get time... result is 0 */
608 *sys = 0.0;
611 #endif
613 #ifdef USE_getrusage
615 struct rusage ru;
617 if (getrusage (RUSAGE_SELF, &ru) == 0)
619 *user = ru.ru_utime.tv_sec + ___CAST(___F64,ru.ru_utime.tv_usec) / 1.0e6;
620 *sys = ru.ru_stime.tv_sec + ___CAST(___F64,ru.ru_stime.tv_usec) / 1.0e6;
622 else
624 *user = 0.0; /* can't get time... result is 0 */
625 *sys = 0.0;
628 #endif
630 #ifdef USE_times
632 #ifdef CLK_TCK
633 #define CLOCK_TICKS_PER_SEC CLK_TCK
634 #else
635 #ifdef USE_sysconf
636 #ifdef _SC_CLK_TCK
637 #define CLOCK_TICKS_PER_SEC sysconf (_SC_CLK_TCK)
638 #else
639 #ifdef _SC_CLOCKS_PER_SEC
640 #define CLOCK_TICKS_PER_SEC sysconf (_SC_CLOCKS_PER_SEC)
641 #endif
642 #endif
643 #endif
644 #endif
646 #ifndef CLOCK_TICKS_PER_SEC
647 @error Cannot find a definition for CLOCK_TICKS_PER_SEC
648 #endif
650 struct tms t;
652 static long clock_ticks_per_sec = 0;
654 if (clock_ticks_per_sec == 0)
655 clock_ticks_per_sec = CLOCK_TICKS_PER_SEC;
657 times (&t);
659 *user = ___CAST(___F64,t.tms_utime) / clock_ticks_per_sec;
660 *sys = ___CAST(___F64,t.tms_stime) / clock_ticks_per_sec;
662 #endif
664 #ifdef USE_clock
666 *user = ___CAST(___F64,clock ()) / CLOCKS_PER_SEC;
667 *sys = 0.0; /* fake system time */
669 #endif
671 #ifdef USE_DosQuerySysInfo
673 static ___U32 origin = 0;
674 ___U32 now;
676 while (origin == 0)
677 DosQuerySysInfo (QSV_MS_COUNT, QSV_MS_COUNT, &origin, sizeof (origin));
679 DosQuerySysInfo (QSV_MS_COUNT, QSV_MS_COUNT, &now, sizeof (now));
681 *user = ___CAST(___F64,(now-origin)) / 1.0e3; /* are the units right? */
682 *sys = 0.0; /* fake system time */
684 #endif
686 #ifdef USE_CLASSIC_MACOS
688 static ___U32 origin = 0;
689 ___U32 now;
691 while (origin == 0)
692 origin = TickCount ();
694 now = TickCount ();
696 *user = ___CAST(___F64,(now-origin)) / 60;
697 *sys = 0.0; /* fake system time */
699 #endif
702 ___time now;
703 ___F64 seconds;
705 ___time_get_current_time (&now);
706 ___time_to_seconds (now, &seconds);
708 *real = seconds - ___time_mod.process_start_seconds;
713 ___HIDDEN void setup_process_times ___PVOID
715 ___F64 user, sys;
717 ___time_mod.process_start_seconds = 0.0;
718 ___process_times (&user, &sys, &___time_mod.process_start_seconds);
723 ___HIDDEN void cleanup_process_times ___PVOID
728 /*---------------------------------------------------------------------------*/
730 /* Heartbeat interrupt handling. */
733 #ifndef USE_setitimer
734 #ifndef USE_dos_setvect_1Ch
735 #ifndef USE_DosStartTimer
736 #ifndef USE_VInstall
737 #ifndef USE_CreateThread
740 ___F64 ___set_heartbeat_interval
741 ___P((___F64 seconds),
742 (seconds)
743 ___F64 seconds;)
745 ___time_mod.current_heartbeat_interval = seconds;
746 return 0.0;
750 void ___disable_heartbeat_interrupts ___PVOID
755 void ___enable_heartbeat_interrupts ___PVOID
760 ___SCMOBJ ___setup_heartbeat_interrupt_handling ___PVOID
762 return ___FIX(___NO_ERR);
766 void ___cleanup_heartbeat_interrupt_handling ___PVOID
771 #endif
772 #endif
773 #endif
774 #endif
775 #endif
778 #ifdef USE_setitimer
781 ___HIDDEN void heartbeat_interrupt_handler
782 ___P((int sig),
783 (sig)
784 int sig;)
786 #ifdef USE_signal
787 ___set_signal_handler (HEARTBEAT_SIG, heartbeat_interrupt_handler);
788 #endif
790 ___time_mod.heartbeat_interrupt_handler ();
794 ___F64 ___set_heartbeat_interval
795 ___P((___F64 seconds),
796 (seconds)
797 ___F64 seconds;)
799 struct itimerval tv;
801 ___time_mod.current_heartbeat_interval = seconds;
803 if (seconds < 0.0) /* turn heartbeat off */
805 tv.it_interval.tv_sec = 0;
806 tv.it_interval.tv_usec = 0;
807 tv.it_value.tv_sec = 0;
808 tv.it_value.tv_usec = 0;
809 setitimer (HEARTBEAT_ITIMER, &tv, 0);
810 return 0.0;
812 else
814 int secs;
815 int usecs;
817 if (seconds >= 2147483648.0) /* upper bound is 68 years! */
819 secs = 2147483647;
820 usecs = 999999;
822 else
824 secs = ___CAST(int,seconds);
825 usecs = ___CAST(int,(seconds - secs) * 1000000.0);
826 if (secs <= 0 && usecs < 1) /* use smallest interval */
828 secs = 0;
829 usecs = 1;
833 tv.it_interval.tv_sec = secs;
834 tv.it_interval.tv_usec = usecs;
835 tv.it_value.tv_sec = secs;
836 tv.it_value.tv_usec = usecs;
837 setitimer (HEARTBEAT_ITIMER, &tv, 0);
838 getitimer (HEARTBEAT_ITIMER, &tv);
839 return tv.it_interval.tv_sec + tv.it_interval.tv_usec / 1000000.0;
844 void ___disable_heartbeat_interrupts ___PVOID
846 ___F64 save_heartbeat_interval = ___time_mod.current_heartbeat_interval;
847 ___set_heartbeat_interval (-1.0);
848 ___time_mod.current_heartbeat_interval = save_heartbeat_interval;
849 #ifdef USE_POSIX
850 ___set_signal_handler (HEARTBEAT_SIG, SIG_IGN);
851 #endif
855 void ___enable_heartbeat_interrupts ___PVOID
857 ___set_heartbeat_interval (___time_mod.current_heartbeat_interval);
858 #ifdef USE_POSIX
859 ___set_signal_handler (HEARTBEAT_SIG, heartbeat_interrupt_handler);
860 #endif
864 ___SCMOBJ ___setup_heartbeat_interrupt_handling ___PVOID
866 ___enable_heartbeat_interrupts ();
867 return ___FIX(___NO_ERR);
871 void ___cleanup_heartbeat_interrupt_handling ___PVOID
873 ___disable_heartbeat_interrupts ();
877 #endif
880 #ifdef USE_dos_setvect_1Ch
883 /* 1Ch = timer tick vector */
886 ___HIDDEN void __interrupt __far heartbeat_interrupt_handler ___PVOID
888 if (___time_mod.heartbeat_countdown > 1)
889 ___time_mod.heartbeat_countdown--;
890 else if (___time_mod.heartbeat_countdown == 1
891 && ___time_mod.heartbeat_enabled)
893 ___time_mod.heartbeat_countdown = ___time_mod.heartbeat_interval;
894 ___time_mod.heartbeat_interrupt_handler ();
896 _chain_intr (prev_vector_1Ch);
900 ___F64 ___set_heartbeat_interval
901 ___P((___F64 seconds),
902 (seconds)
903 ___F64 seconds;)
905 ___time_mod.current_heartbeat_interval = seconds;
907 if (seconds < 0.0) /* turn heartbeat off */
909 _dos_setvect (0x1C, prev_vector_1Ch);
910 return 0.0;
912 else
914 ___F64 ticks = seconds * 18.2; /* 18.2 ticks/sec */
915 int t;
917 if (ticks >= 2147483648.0) /* upper bound is 3.7 years! */
918 t = 2147483647;
919 else
921 t = ticks;
922 if (t <= 0) /* use smallest interval */
923 t = 1;
926 ___time_mod.heartbeat_interval = t;
927 ___time_mod.heartbeat_countdown = ___time_mod.heartbeat_interval;
928 _dos_setvect (0x1C, ___time_mod.heartbeat_interrupt_handler);
929 return t / 18.2;
934 void ___disable_heartbeat_interrupts ___PVOID
936 ___time_mod.heartbeat_enabled = 0;
940 void ___enable_heartbeat_interrupts ___PVOID
942 ___time_mod.heartbeat_enabled = 1;
946 ___SCMOBJ ___setup_heartbeat_interrupt_handling ___PVOID
948 prev_vector_1Ch = _dos_getvect (0x1C);
949 ___time_mod.heartbeat_enabled = 1;
950 ___set_heartbeat_interval (-1.0);
951 return ___FIX(___NO_ERR);
955 void ___cleanup_heartbeat_interrupt_handling ___PVOID
957 ___set_heartbeat_interval (-1.0);
958 ___time_mod.heartbeat_enabled = 0;
962 #endif
965 #ifdef USE_DosStartTimer
968 ___HIDDEN void APIENTRY heartbeat_thread_code
969 ___P((ULONG param),
970 (param)
971 ULONG param;)
973 ULONG pc = 0;
974 for (;;)
976 DosWaitEventSem (___time_mod.hev, SEM_INDEFINITE_WAIT);
977 DosResetEventSem (___time_mod.hev, &pc);
978 if (___time_mod.heartbeat_enabled)
980 DosEnterCritSec ();
981 ___time_mod.heartbeat_interrupt_handler ();
982 DosExitCritSec ();
988 ___F64 ___set_heartbeat_interval
989 ___P((___F64 seconds),
990 (seconds)
991 ___F64 seconds;)
993 ___time_mod.current_heartbeat_interval = seconds;
995 if (!___time_mod.heartbeat_hev || !___time_mod.heartbeat_tid)
996 return 0.0;
997 if (___time_mod.heartbeat_htimer)
999 DosStopTimer (___time_mod.htimer);
1000 ___time_mod.heartbeat_htimer = 0;
1002 if (seconds < 0.0) /* turn heartbeat off */
1003 return 0.0;
1004 else
1006 ___F64 msecs = seconds * 1000.0;
1007 ULONG m;
1009 if (msecs >= 4294967295.0) /* upper bound is 49.7 days! */
1010 m = 4294967295;
1011 else
1013 m = msecs;
1014 if (m == 0) /* use smallest interval */
1015 m = 1;
1018 if (DosStartTimer (m, ___CAST(HSEM,___time_mod.hev), &___time_mod.htimer)
1019 == NO_ERROR)
1021 ___time_mod.heartbeat_htimer = 1;
1022 return m / 1000.0;
1024 else
1025 return 0.0;
1030 void ___disable_heartbeat_interrupts ___PVOID
1032 ___time_mod.heartbeat_enabled = 0;
1036 void ___enable_heartbeat_interrupts ___PVOID
1038 ___time_mod.heartbeat_enabled = 1;
1042 ___SCMOBJ ___setup_heartbeat_interrupt_handling ___PVOID
1044 ___time_mod.heartbeat_enabled = 0;
1045 ___time_mod.heartbeat_hev = 0;
1046 ___time_mod.heartbeat_tid = 0;
1047 ___time_mod.heartbeat_htimer = 0;
1048 if (DosCreateEventSem (0, &___time_mod.hev, DC_SEM_SHARED, FALSE) != NO_ERROR)
1049 return ___FIX(___UNKNOWN_ERR);
1050 ___time_mod.heartbeat_hev = 1;
1051 if (DosCreateThread (&___time_mod.tid,
1052 heartbeat_thread_code,
1054 CREATE_READY|STACK_COMMITTED,
1055 4096)
1056 != NO_ERROR)
1057 return ___FIX(___UNKNOWN_ERR);
1058 ___time_mod.heartbeat_tid = 1;
1059 DosSetPriority (PRTYS_THREAD, PRTYC_NOCHANGE, PRTYD_MAXIMUM, ___time_mod.tid);
1060 ___time_mod.heartbeat_enabled = 1;
1062 return ___FIX(___NO_ERR);
1066 void ___cleanup_heartbeat_interrupt_handling ___PVOID
1068 ___time_mod.heartbeat_enabled = 0;
1069 if (___time_mod.heartbeat_htimer)
1071 DosStopTimer (___time_mod.htimer);
1072 ___time_mod.heartbeat_htimer = 0;
1074 if (___time_mod.heartbeat_tid)
1076 DosKillThread (___time_mod.tid);
1077 ___time_mod.heartbeat_tid = 0;
1079 if (___time_mod.heartbeat_hev)
1081 DosCloseEventSem (___time_mod.hev);
1082 ___time_mod.heartbeat_hev = 0;
1087 #endif
1090 #ifdef USE_VInstall
1093 ___HIDDEN ___BOOL heartbeat_task_installed;
1094 ___HIDDEN short heartbeat_task_ticks;
1095 ___HIDDEN VBLTask heartbeat_task;
1096 ___HIDDEN ___BOOL heartbeat_enabled;
1099 ___HIDDEN void heartbeat_task_code ___PVOID
1101 if (___time_mod.heartbeat_enabled)
1102 ___time_mod.heartbeat_interrupt_handler ();
1103 ___time_mod.heartbeat_task.vblCount = ___time_mod.heartbeat_task_ticks;
1107 #ifdef __POWERPC__
1109 #define heartbeat_task_proc heartbeat_task_code
1111 #else
1113 ___HIDDEN asm void heartbeat_task_proc ___PVOID
1115 move.l a5,-(sp)
1116 move.l 0x904,a5
1117 jsr heartbeat_task_code
1118 move.l (sp)+,a5
1122 #endif
1125 ___F64 ___set_heartbeat_interval
1126 ___P((___F64 seconds),
1127 (seconds)
1128 ___F64 seconds;)
1130 ___time_mod.current_heartbeat_interval = seconds;
1132 if (___time_mod.heartbeat_task_installed)
1133 if (VRemove (___CAST(QElemPtr,&___time_mod.heartbeat_task)) != noErr)
1135 ___time_mod.heartbeat_task_installed = 0;
1136 return 0.0;
1139 if (seconds < 0.0) /* turn heartbeat off */
1140 return 0.0;
1141 else
1143 ___F64 ticks = seconds * 60.0; /* 60 ticks/sec */
1144 short t;
1146 if (ticks >= 32767.0) /* upper bound is 9 minutes! */
1147 t = 32767;
1148 else
1150 t = ticks;
1151 if (t <= 0) /* use smallest interval */
1152 t = 1;
1155 ___time_mod.heartbeat_task_ticks = t;
1156 ___time_mod.heartbeat_task.qType = vType;
1157 ___time_mod.heartbeat_task.vblAddr = NewVBLProc (heartbeat_task_proc);
1158 ___time_mod.heartbeat_task.vblCount = t;
1159 ___time_mod.heartbeat_task.vblPhase = 0;
1160 if (VInstall (___CAST(QElemPtr,&___time_mod.heartbeat_task)) == noErr)
1162 ___time_mod.heartbeat_task_installed = 1;
1163 return t / 60.0;
1165 else
1166 return 0.0;
1171 void ___disable_heartbeat_interrupts ___PVOID
1173 ___time_mod.heartbeat_enabled = 0;
1177 void ___enable_heartbeat_interrupts ___PVOID
1179 ___time_mod.heartbeat_enabled = 1;
1183 ___SCMOBJ ___setup_heartbeat_interrupt_handling ___PVOID
1185 ___time_mod.heartbeat_enabled = 1;
1186 ___time_mod.heartbeat_task_installed = 0;
1187 return ___FIX(___NO_ERR);
1191 void ___cleanup_heartbeat_interrupt_handling ___PVOID
1193 ___set_heartbeat_interval (-1.0);
1194 ___time_mod.heartbeat_enabled = 0;
1198 #endif
1201 #ifdef USE_CreateThread
1205 * The HEARTBEAT_PRIORITY should be high so that heartbeats will occur
1206 * as close as possible to the correct time.
1209 #define HEARTBEAT_PRIORITY THREAD_PRIORITY_HIGHEST
1212 ___HIDDEN DWORD WINAPI heartbeat_thread_proc
1213 ___P((LPVOID param),
1214 (param)
1215 LPVOID param;)
1217 DWORD interval = ___time_mod.heartbeat_interval;
1219 for (;;)
1221 DWORD n = WaitForSingleObject (___time_mod.heartbeat_update, interval);
1223 interval = ___time_mod.heartbeat_interval;
1225 if (interval == 0)
1226 return 0;
1228 switch (n)
1230 case WAIT_ABANDONED:
1231 case WAIT_OBJECT_0:
1232 break;
1234 case WAIT_TIMEOUT:
1235 if (___time_mod.heartbeat_enabled)
1236 ___time_mod.heartbeat_interrupt_handler ();
1237 break;
1239 default: /* WAIT_FAILED */
1240 return 0;
1244 return 0;
1248 ___F64 ___set_heartbeat_interval
1249 ___P((___F64 seconds),
1250 (seconds)
1251 ___F64 seconds;)
1253 ___time_mod.current_heartbeat_interval = seconds;
1255 if (seconds < 0.0) /* turn heartbeat off */
1257 ___time_mod.heartbeat_interval = INFINITE;
1258 SetEvent (___time_mod.heartbeat_update); /* ignore error */
1259 return 0.0;
1261 else
1263 ___F64 msecs = seconds * 1000.0;
1264 DWORD m;
1266 if (msecs >= 4294967294.0) /* upper bound is 49.6 days! */
1267 m = 4294967294UL; /* note that INFINITE = 4294967295 */
1268 else
1270 m = ___CAST(DWORD,msecs);
1271 if (m == 0) /* use smallest interval */
1272 m = 1;
1275 ___time_mod.heartbeat_interval = m;
1276 SetEvent (___time_mod.heartbeat_update); /* ignore error */
1277 return m / 1000.0;
1282 void ___disable_heartbeat_interrupts ___PVOID
1284 ___time_mod.heartbeat_enabled = 0;
1288 void ___enable_heartbeat_interrupts ___PVOID
1290 ___time_mod.heartbeat_enabled = 1;
1294 ___SCMOBJ ___setup_heartbeat_interrupt_handling ___PVOID
1296 ___SCMOBJ e;
1297 DWORD thread_id;
1298 HANDLE thread;
1299 HANDLE update;
1301 ___time_mod.heartbeat_enabled = 1;
1302 ___time_mod.heartbeat_interval = INFINITE;
1304 if ((update = CreateEvent (NULL, /* can't inherit */
1305 FALSE, /* auto reset */
1306 FALSE, /* not signaled */
1307 NULL)) /* no name */
1308 == NULL)
1309 e = err_code_from_GetLastError ();
1310 else
1312 ___time_mod.heartbeat_update = update;
1314 if ((thread = CreateThread (NULL, /* no security attributes */
1315 65536, /* committed stack size */
1316 heartbeat_thread_proc,
1317 0, /* argument to thread function */
1318 0, /* use default creation flags */
1319 &thread_id))
1320 == NULL)
1321 e = err_code_from_GetLastError ();
1322 else
1324 ___time_mod.heartbeat_thread = thread;
1326 if (!SetThreadPriority (thread, HEARTBEAT_PRIORITY))
1327 e = err_code_from_GetLastError ();
1328 else
1329 return ___FIX(___NO_ERR);
1331 ___time_mod.heartbeat_interval = 0;
1332 SetEvent (update); /* ignore error */
1333 WaitForSingleObject (thread, INFINITE); /* ignore error */
1334 CloseHandle (thread); /* ignore error */
1337 CloseHandle (update); /* ignore error */
1340 return e;
1344 void ___cleanup_heartbeat_interrupt_handling ___PVOID
1346 if (___time_mod.heartbeat_thread != NULL)
1348 ___time_mod.heartbeat_enabled = 0;
1349 ___time_mod.heartbeat_interval = 0;
1350 SetEvent (___time_mod.heartbeat_update); /* ignore error */
1351 WaitForSingleObject (___time_mod.heartbeat_thread, INFINITE); /* ignore error */
1352 CloseHandle (___time_mod.heartbeat_thread); /* ignore error */
1353 CloseHandle (___time_mod.heartbeat_update); /* ignore error */
1354 ___time_mod.heartbeat_update = NULL;
1355 ___time_mod.heartbeat_thread = NULL;
1360 #endif
1363 /*---------------------------------------------------------------------------*/
1365 /* Time module initialization/finalization. */
1368 ___SCMOBJ ___setup_time_module
1369 ___P((void (*heartbeat_interrupt_handler) ___PVOID),
1370 (heartbeat_interrupt_handler)
1371 void (*heartbeat_interrupt_handler) ___PVOID;)
1373 ___SCMOBJ e;
1374 if (!___time_mod.setup)
1376 ___time_mod.heartbeat_interrupt_handler = heartbeat_interrupt_handler;
1377 setup_process_times ();
1378 if ((e = ___setup_heartbeat_interrupt_handling ()) != ___FIX(___NO_ERR))
1379 return e;
1380 ___time_mod.setup = 1;
1381 return ___FIX(___NO_ERR);
1384 return ___FIX(___UNKNOWN_ERR);
1388 void ___cleanup_time_module ___PVOID
1390 if (___time_mod.setup)
1392 ___cleanup_heartbeat_interrupt_handling ();
1393 cleanup_process_times ();
1394 ___time_mod.setup = 0;
1399 /*---------------------------------------------------------------------------*/