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. */
6 * This module implements the operating system specific routines
10 #define ___INCLUDED_FROM_OS_TIME
11 #define ___VERSION 406003
18 /*---------------------------------------------------------------------------*/
21 ___time_module ___time_mod
=
30 #ifdef ___TIME_MODULE_INIT
36 /*---------------------------------------------------------------------------*/
38 /* Time management. */
41 void ___time_from_nsecs
52 #ifdef ___FLOAT_TIME_REPRESENTATION
53 *tim
= secs
+ nsecs
/ 1000000000.0;
56 #ifdef ___INT_TIME_REPRESENTATION
57 tim
->secs
= secs
+ nsecs
/ 1000000000;
58 tim
->nsecs
= nsecs
% 1000000000;
71 #ifdef ___FLOAT_TIME_REPRESENTATION
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;
92 #ifdef ___FLOAT_TIME_REPRESENTATION
96 #ifdef ___INT_TIME_REPRESENTATION
99 if (tim2
.nsecs
> tim1
->nsecs
)
101 tim1
->secs
-= tim2
.secs
+ 1;
102 tim1
->nsecs
+= 1000000000 - tim2
.nsecs
;
106 tim1
->secs
-= tim2
.secs
;
107 tim1
->nsecs
-= tim2
.nsecs
;
113 ___BOOL ___time_equal
121 #ifdef ___FLOAT_TIME_REPRESENTATION
122 return (tim1
== tim2
);
125 #ifdef ___INT_TIME_REPRESENTATION
126 return (tim1
.secs
== tim2
.secs
&& tim1
.nsecs
== tim2
.nsecs
);
139 #ifdef ___FLOAT_TIME_REPRESENTATION
140 return (tim1
< tim2
);
143 #ifdef ___INT_TIME_REPRESENTATION
144 return (tim1
.secs
< tim2
.secs
||
145 (tim1
.secs
== tim2
.secs
&& tim1
.nsecs
< tim2
.nsecs
));
150 ___BOOL ___time_positive
155 #ifdef ___FLOAT_TIME_REPRESENTATION
159 #ifdef ___INT_TIME_REPRESENTATION
160 return (tim
.secs
> 0 ||
161 (tim
.secs
== 0 && tim
.nsecs
> 0));
166 void ___time_get_current_time
171 #ifndef USE_clock_gettime
173 #ifndef USE_GetSystemTime
174 #ifndef USE_gettimeofday
177 #ifndef USE_CLASSIC_MACOS
179 *tim
= ___time_mod
.time_neg_infinity
;
189 #ifdef USE_clock_gettime
191 /* The clock_gettime function is in POSIX.1b (realtime programming). */
194 if (clock_gettime (CLOCK_REALTIME
, &ts
) == 0)
195 ___time_from_nsecs (tim
, ts
.tv_sec
-JAN_1(1970), ts
.tv_nsec
);
197 *tim
= ___time_mod
.time_neg_infinity
;
203 /* The getclock function is in the Tru64 UNIX standard C library. */
206 if (getclock (TIMEOFDAY
, &ts
) == 0)
207 ___time_from_nsecs (tim
, ts
.tv_sec
-JAN_1(1970), ts
.tv_nsec
);
209 *tim
= ___time_mod
.time_neg_infinity
;
213 #ifdef USE_GetSystemTime
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
);
226 *tim
= ___time_mod
.time_neg_infinity
;
230 #ifdef USE_gettimeofday
233 if (gettimeofday (&tv
, NULL
) == 0)
234 ___time_from_nsecs (tim
, tv
.tv_sec
-JAN_1(1970), tv
.tv_usec
*1000);
236 *tim
= ___time_mod
.time_neg_infinity
;
244 ___time_from_nsecs (tim
, tb
.time
-JAN_1(1970), tb
.millitm
*1000000);
252 ___time_from_nsecs (tim
, t
-JAN_1(1970), 0);
256 #ifdef USE_CLASSIC_MACOS
258 if (has_GetUTCDateTime
)
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));
268 *tim
= ___time_mod
.time_neg_infinity
;
270 else if (has_GetDateTime
)
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
;
283 ReadLocation (&here
);
284 offset
= here
.u
.gmtDelta
& 0x00ffffff;
285 if (offset
& 0x00800000)
286 offset
|= 0xff000000;
290 ___time_from_nsecs (tim
, t
-JAN_1(1904), 0);
293 *tim
= ___time_mod
.time_neg_infinity
;
299 void ___time_to_seconds
307 #ifdef ___FLOAT_TIME_REPRESENTATION
311 #ifdef ___INT_TIME_REPRESENTATION
312 *seconds
= tim
.secs
+ tim
.nsecs
/ 1000000000.0;
317 void ___time_from_seconds
325 #ifdef ___FLOAT_TIME_REPRESENTATION
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
;
336 ___SM32 secs
= seconds
;
337 ___SM32 nsecs
= (seconds
- secs
) * 1000000000.0;
350 void ___absolute_time_to_relative_time
358 if (___time_less (tim
, ___time_mod
.time_pos_infinity
))
362 ___time_get_current_time (&now
);
363 ___time_subtract (rtim
, now
);
366 *rtim
= ___time_mod
.time_pos_infinity
;
370 #ifndef LINEEDITOR_WITH_NONBLOCKING_IO
373 void ___absolute_time_sleep
378 ___absolute_time_to_relative_time (tim
, &tim
);
380 if (___time_positive (tim
))
384 #ifdef ___FLOAT_TIME_REPRESENTATION
388 nsecs
= ___CAST(___SM32
,tim
* 1000000000.0);
391 #ifdef ___INT_TIME_REPRESENTATION
395 nsecs
= tim
.secs
* 1000000000 + tim
.nsecs
;
398 #ifndef USE_nanosleep
401 #ifndef USE_CLASSIC_MACOS
402 /* Can't sleep... so stay awake! */
410 /* The nanosleep function is in POSIX.1b (realtime programming). */
412 ts
.tv_sec
= nsecs
/ 1000000000;
414 nanosleep (&ts
, NULL
);
419 Sleep (nsecs
/ 1000000);
423 sleep (nsecs
/ 1000000000);
426 #ifdef USE_CLASSIC_MACOS
428 ___U32 ticks
= nsecs
/ 16666666;
431 if (has_WaitNextEvent
)
434 WaitNextEvent (0, &er
, ticks
, NULL
);
437 Delay (ticks
, &ticks
);
450 #ifdef ___TIMEVAL_NOT_LIMITED
451 #define ___TIMEVAL_SEC_LIMIT 2147483647 /* in seconds = 68 years */
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 */
459 void ___absolute_time_to_nonnegative_timeval
461 struct timeval
**tv
),
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
;
481 t
->tv_sec
= ___CAST(int,tim
);
482 t
->tv_usec
= ___CAST(int,(tim
- t
->tv_sec
) * 1000000.0);
486 #ifdef ___INT_TIME_REPRESENTATION
487 if (tim
.secs
> ___TIMEVAL_SEC_LIMIT
)
489 t
->tv_sec
= ___TIMEVAL_SEC_LIMIT
;
494 t
->tv_sec
= tim
.secs
;
495 t
->tv_usec
= tim
.nsecs
/ 1000;
513 #ifdef USE_MsgWaitForMultipleObjects
516 void ___absolute_time_to_nonnegative_msecs
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 */
535 *ms
= ___CAST(DWORD
,msecs
);
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 */
545 *ms
= tim
.secs
* 1000 + tim
.nsecs
/ 1000000;
560 /*---------------------------------------------------------------------------*/
562 /* Measurement of process times. */
565 void ___process_times
576 #ifndef USE_GetProcessTimes
577 #ifndef USE_getrusage
580 #ifndef USE_DosQuerySysInfo
581 #ifndef USE_CLASSIC_MACOS
583 *user
= 0.0; /* can't get time... result is 0 */
593 #ifdef USE_GetProcessTimes
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
);;
607 *user
= 0.0; /* can't get time... result is 0 */
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
;
624 *user
= 0.0; /* can't get time... result is 0 */
633 #define CLOCK_TICKS_PER_SEC CLK_TCK
637 #define CLOCK_TICKS_PER_SEC sysconf (_SC_CLK_TCK)
639 #ifdef _SC_CLOCKS_PER_SEC
640 #define CLOCK_TICKS_PER_SEC sysconf (_SC_CLOCKS_PER_SEC)
646 #ifndef CLOCK_TICKS_PER_SEC
647 @error Cannot find a definition
for CLOCK_TICKS_PER_SEC
652 static long clock_ticks_per_sec
= 0;
654 if (clock_ticks_per_sec
== 0)
655 clock_ticks_per_sec
= CLOCK_TICKS_PER_SEC
;
659 *user
= ___CAST(___F64
,t
.tms_utime
) / clock_ticks_per_sec
;
660 *sys
= ___CAST(___F64
,t
.tms_stime
) / clock_ticks_per_sec
;
666 *user
= ___CAST(___F64
,clock ()) / CLOCKS_PER_SEC
;
667 *sys
= 0.0; /* fake system time */
671 #ifdef USE_DosQuerySysInfo
673 static ___U32 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 */
686 #ifdef USE_CLASSIC_MACOS
688 static ___U32 origin
= 0;
692 origin
= TickCount ();
696 *user
= ___CAST(___F64
,(now
-origin
)) / 60;
697 *sys
= 0.0; /* fake system time */
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
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
737 #ifndef USE_CreateThread
740 ___F64 ___set_heartbeat_interval
741 ___P((___F64 seconds
),
745 ___time_mod
.current_heartbeat_interval
= seconds
;
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
781 ___HIDDEN
void heartbeat_interrupt_handler
787 ___set_signal_handler (HEARTBEAT_SIG
, heartbeat_interrupt_handler
);
790 ___time_mod
.heartbeat_interrupt_handler ();
794 ___F64 ___set_heartbeat_interval
795 ___P((___F64 seconds
),
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);
817 if (seconds
>= 2147483648.0) /* upper bound is 68 years! */
824 secs
= ___CAST(int,seconds
);
825 usecs
= ___CAST(int,(seconds
- secs
) * 1000000.0);
826 if (secs
<= 0 && usecs
< 1) /* use smallest interval */
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
;
850 ___set_signal_handler (HEARTBEAT_SIG
, SIG_IGN
);
855 void ___enable_heartbeat_interrupts ___PVOID
857 ___set_heartbeat_interval (___time_mod
.current_heartbeat_interval
);
859 ___set_signal_handler (HEARTBEAT_SIG
, heartbeat_interrupt_handler
);
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 ();
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
),
905 ___time_mod
.current_heartbeat_interval
= seconds
;
907 if (seconds
< 0.0) /* turn heartbeat off */
909 _dos_setvect (0x1C, prev_vector_1Ch
);
914 ___F64 ticks
= seconds
* 18.2; /* 18.2 ticks/sec */
917 if (ticks
>= 2147483648.0) /* upper bound is 3.7 years! */
922 if (t
<= 0) /* use smallest interval */
926 ___time_mod
.heartbeat_interval
= t
;
927 ___time_mod
.heartbeat_countdown
= ___time_mod
.heartbeat_interval
;
928 _dos_setvect (0x1C, ___time_mod
.heartbeat_interrupt_handler
);
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;
965 #ifdef USE_DosStartTimer
968 ___HIDDEN
void APIENTRY heartbeat_thread_code
976 DosWaitEventSem (___time_mod
.hev
, SEM_INDEFINITE_WAIT
);
977 DosResetEventSem (___time_mod
.hev
, &pc
);
978 if (___time_mod
.heartbeat_enabled
)
981 ___time_mod
.heartbeat_interrupt_handler ();
988 ___F64 ___set_heartbeat_interval
989 ___P((___F64 seconds
),
993 ___time_mod
.current_heartbeat_interval
= seconds
;
995 if (!___time_mod
.heartbeat_hev
|| !___time_mod
.heartbeat_tid
)
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 */
1006 ___F64 msecs
= seconds
* 1000.0;
1009 if (msecs
>= 4294967295.0) /* upper bound is 49.7 days! */
1014 if (m
== 0) /* use smallest interval */
1018 if (DosStartTimer (m
, ___CAST(HSEM
,___time_mod
.hev
), &___time_mod
.htimer
)
1021 ___time_mod
.heartbeat_htimer
= 1;
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
,
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;
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
;
1109 #define heartbeat_task_proc heartbeat_task_code
1113 ___HIDDEN
asm void heartbeat_task_proc ___PVOID
1117 jsr heartbeat_task_code
1125 ___F64 ___set_heartbeat_interval
1126 ___P((___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;
1139 if (seconds
< 0.0) /* turn heartbeat off */
1143 ___F64 ticks
= seconds
* 60.0; /* 60 ticks/sec */
1146 if (ticks
>= 32767.0) /* upper bound is 9 minutes! */
1151 if (t
<= 0) /* use smallest interval */
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;
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;
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
),
1217 DWORD interval
= ___time_mod
.heartbeat_interval
;
1221 DWORD n
= WaitForSingleObject (___time_mod
.heartbeat_update
, interval
);
1223 interval
= ___time_mod
.heartbeat_interval
;
1230 case WAIT_ABANDONED
:
1235 if (___time_mod
.heartbeat_enabled
)
1236 ___time_mod
.heartbeat_interrupt_handler ();
1239 default: /* WAIT_FAILED */
1248 ___F64 ___set_heartbeat_interval
1249 ___P((___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 */
1263 ___F64 msecs
= seconds
* 1000.0;
1266 if (msecs
>= 4294967294.0) /* upper bound is 49.6 days! */
1267 m
= 4294967294UL; /* note that INFINITE = 4294967295 */
1270 m
= ___CAST(DWORD
,msecs
);
1271 if (m
== 0) /* use smallest interval */
1275 ___time_mod
.heartbeat_interval
= m
;
1276 SetEvent (___time_mod
.heartbeat_update
); /* ignore error */
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
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 */
1309 e
= err_code_from_GetLastError ();
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 */
1321 e
= err_code_from_GetLastError ();
1324 ___time_mod
.heartbeat_thread
= thread
;
1326 if (!SetThreadPriority (thread
, HEARTBEAT_PRIORITY
))
1327 e
= err_code_from_GetLastError ();
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 */
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
;
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
;)
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
))
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 /*---------------------------------------------------------------------------*/