3 * Copyright (c) 1996-2002 Douglas E. Wegscheid. All rights reserved.
5 * Copyright (c) 2002,2003,2004,2005 Jarkko Hietaniemi. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the same terms as Perl itself.
14 #define PERL_NO_GET_CONTEXT
19 #if defined(__CYGWIN__) && defined(HAS_W32API_WINDOWS_H)
20 # include <w32api/windows.h>
21 # define CYGWIN_WITH_W32API
26 # include <sys/time.h>
30 # include <sys/select.h>
33 #if defined(TIME_HIRES_CLOCK_GETTIME_SYSCALL) || defined(TIME_HIRES_CLOCK_GETRES_SYSCALL)
40 #define IV_1E6 1000000L
41 #define IV_1E7 10000000L
42 #define IV_1E9 1000000000L
43 #define NV_1E6 1000000.0
44 #define NV_1E7 10000000.0
45 #define NV_1E9 1000000000.0
47 #ifndef PerlProc_pause
48 # define PerlProc_pause() Pause()
54 # undef Pause /* In case perl.h did it already. */
55 # define Pause() sleep(~0) /* Zzz for a long time. */
58 /* Though the cpp define ITIMER_VIRTUAL is available the functionality
59 * is not supported in Cygwin as of August 2004, ditto for Win32.
60 * Neither are ITIMER_PROF or ITIMER_REALPROF implemented. --jhi
62 #if defined(__CYGWIN__) || defined(WIN32)
63 # undef ITIMER_VIRTUAL
65 # undef ITIMER_REALPROF
68 /* 5.004 doesn't define PL_sv_undef */
69 #ifndef ATLEASTFIVEOHOHFIVE
71 # define PL_sv_undef sv_undef
75 #if defined(TIME_HIRES_CLOCK_GETTIME) && defined(_STRUCT_ITIMERSPEC)
77 /* HP-UX has CLOCK_XXX values but as enums, not as defines.
78 * The only way to detect these would be to test compile for each. */
80 # define CLOCK_REALTIME CLOCK_REALTIME
81 # define CLOCK_VIRTUAL CLOCK_VIRTUAL
82 # define CLOCK_PROFILE CLOCK_PROFILE
83 # endif /* # ifdef __hpux */
85 #endif /* #if defined(TIME_HIRES_CLOCK_GETTIME) && defined(_STRUCT_ITIMERSPEC) */
87 #if defined(WIN32) || defined(CYGWIN_WITH_W32API)
89 #ifndef HAS_GETTIMEOFDAY
90 # define HAS_GETTIMEOFDAY
93 /* shows up in winsock.h?
101 unsigned __int64 ft_i64;
105 #define MY_CXT_KEY "Time::HiRes_" XS_VERSION
108 unsigned long run_count;
109 unsigned __int64 base_ticks;
110 unsigned __int64 tick_frequency;
111 FT_t base_systime_as_filetime;
112 unsigned __int64 reset_time;
117 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
119 # define Const64(x) x##LL
121 # define Const64(x) x##i64
123 #define EPOCH_BIAS Const64(116444736000000000)
125 /* NOTE: This does not compute the timezone info (doing so can be expensive,
126 * and appears to be unsupported even by glibc) */
128 /* dMY_CXT needs a Perl context and we don't want to call PERL_GET_CONTEXT
129 for performance reasons */
132 #define gettimeofday(tp, not_used) _gettimeofday(aTHX_ tp, not_used)
134 /* If the performance counter delta drifts more than 0.5 seconds from the
135 * system time then we recalibrate to the system time. This means we may
136 * move *backwards* in time! */
137 #define MAX_PERF_COUNTER_SKEW Const64(5000000) /* 0.5 seconds */
139 /* Reset reading from the performance counter every five minutes.
140 * Many PC clocks just seem to be so bad. */
141 #define MAX_PERF_COUNTER_TICKS Const64(300000000) /* 300 seconds */
144 _gettimeofday(pTHX_ struct timeval *tp, void *not_used)
148 unsigned __int64 ticks;
151 if (MY_CXT.run_count++ == 0 ||
152 MY_CXT.base_systime_as_filetime.ft_i64 > MY_CXT.reset_time) {
153 QueryPerformanceFrequency((LARGE_INTEGER*)&MY_CXT.tick_frequency);
154 QueryPerformanceCounter((LARGE_INTEGER*)&MY_CXT.base_ticks);
155 GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val);
156 ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64;
157 MY_CXT.reset_time = ft.ft_i64 + MAX_PERF_COUNTER_TICKS;
161 QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
162 ticks -= MY_CXT.base_ticks;
163 ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64
164 + Const64(IV_1E7) * (ticks / MY_CXT.tick_frequency)
165 +(Const64(IV_1E7) * (ticks % MY_CXT.tick_frequency)) / MY_CXT.tick_frequency;
166 diff = ft.ft_i64 - MY_CXT.base_systime_as_filetime.ft_i64;
167 if (diff < -MAX_PERF_COUNTER_SKEW || diff > MAX_PERF_COUNTER_SKEW) {
168 MY_CXT.base_ticks += ticks;
169 GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val);
170 ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64;
174 /* seconds since epoch */
175 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(IV_1E7));
177 /* microseconds remaining */
178 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(IV_1E6));
184 #if defined(WIN32) && !defined(ATLEASTFIVEOHOHFIVE)
186 sleep(unsigned int t)
193 #if !defined(HAS_GETTIMEOFDAY) && defined(VMS)
194 #define HAS_GETTIMEOFDAY
197 #include <time.h> /* gettimeofday */
198 #include <stdlib.h> /* qdiv */
199 #include <starlet.h> /* sys$gettim */
202 #include <lib$routines.h> /* lib$ediv() */
206 VMS binary time is expressed in 100 nano-seconds since
207 system base time which is 17-NOV-1858 00:00:00.00
210 #define DIV_100NS_TO_SECS 10000000L
211 #define DIV_100NS_TO_USECS 10L
214 gettimeofday is supposed to return times since the epoch
215 so need to determine this in terms of VMS base time
217 static $DESCRIPTOR(dscepoch,"01-JAN-1970 00:00:00.00");
220 static long base_adjust[2]={0L,0L};
222 static __int64 base_adjust=0;
227 If we don't have gettimeofday, then likely we are on a VMS machine that
228 operates on local time rather than UTC...so we have to zone-adjust.
229 This code gleefully swiped from VMS.C
232 /* method used to handle UTC conversions:
233 * 1 == CRTL gmtime(); 2 == SYS$TIMEZONE_DIFFERENTIAL; 3 == no correction
235 static int gmtime_emulation_type;
236 /* number of secs to add to UTC POSIX-style time to get local time */
237 static long int utc_offset_secs;
238 static struct dsc$descriptor_s fildevdsc =
239 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
240 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
242 static time_t toutc_dst(time_t loc) {
245 if ((rsltmp = localtime(&loc)) == NULL) return -1;
246 loc -= utc_offset_secs;
247 if (rsltmp->tm_isdst) loc -= 3600;
251 static time_t toloc_dst(time_t utc) {
254 utc += utc_offset_secs;
255 if ((rsltmp = localtime(&utc)) == NULL) return -1;
256 if (rsltmp->tm_isdst) utc += 3600;
260 #define _toutc(secs) ((secs) == (time_t) -1 ? (time_t) -1 : \
261 ((gmtime_emulation_type || timezone_setup()), \
262 (gmtime_emulation_type == 1 ? toutc_dst(secs) : \
263 ((secs) - utc_offset_secs))))
265 #define _toloc(secs) ((secs) == (time_t) -1 ? (time_t) -1 : \
266 ((gmtime_emulation_type || timezone_setup()), \
267 (gmtime_emulation_type == 1 ? toloc_dst(secs) : \
268 ((secs) + utc_offset_secs))))
275 if (gmtime_emulation_type == 0) {
277 time_t base = 15 * 86400; /* 15jan71; to avoid month/year ends between */
278 /* results of calls to gmtime() and localtime() */
281 gmtime_emulation_type++;
282 if ((tm_p = gmtime(&base)) == NULL) { /* CRTL gmtime() is a fake */
283 char off[LNM$C_NAMLENGTH+1];;
285 gmtime_emulation_type++;
286 if (!Perl_vmstrnenv("SYS$TIMEZONE_DIFFERENTIAL",off,0,fildev,0)) {
287 gmtime_emulation_type++;
289 Perl_warn(aTHX_ "no UTC offset information; assuming local time is UTC");
291 else { utc_offset_secs = atol(off); }
293 else { /* We've got a working gmtime() */
294 struct tm gmt, local;
297 tm_p = localtime(&base);
299 utc_offset_secs = (local.tm_mday - gmt.tm_mday) * 86400;
300 utc_offset_secs += (local.tm_hour - gmt.tm_hour) * 3600;
301 utc_offset_secs += (local.tm_min - gmt.tm_min) * 60;
302 utc_offset_secs += (local.tm_sec - gmt.tm_sec);
310 gettimeofday (struct timeval *tp, void *tpz)
316 long div_100ns_to_secs;
317 long div_100ns_to_usecs;
325 In case of error, tv_usec = 0 and tv_sec = VMS condition code.
326 The return from function is also set to -1.
327 This is not exactly as per the manual page.
333 if (base_adjust[0]==0 && base_adjust[1]==0) {
335 if (base_adjust==0) { /* Need to determine epoch adjustment */
337 ret=sys$bintim(&dscepoch,&base_adjust);
338 if (1 != (ret &&1)) {
344 ret=sys$gettim(&quad); /* Get VMS system time */
345 if ((1 && ret) == 1) {
347 quad[0] -= base_adjust[0]; /* convert to epoch offset */
348 quad[1] -= base_adjust[1]; /* convert 2nd half of quadword */
349 div_100ns_to_secs = DIV_100NS_TO_SECS;
350 div_100ns_to_usecs = DIV_100NS_TO_USECS;
351 lib$ediv(&div_100ns_to_secs,&quad,&quo,&rem);
354 lib$ediv(&div_100ns_to_usecs,&quad1,&quo1,&rem1);
355 tp->tv_sec = quo; /* Whole seconds */
356 tp->tv_usec = quo1; /* Micro-seconds */
358 quad -= base_adjust; /* convert to epoch offset */
359 ans1=qdiv(quad,DIV_100NS_TO_SECS);
360 ans2=qdiv(ans1.rem,DIV_100NS_TO_USECS);
361 tp->tv_sec = ans1.quot; /* Whole seconds */
362 tp->tv_usec = ans2.quot; /* Micro-seconds */
370 if (VMSISH_TIME) tp->tv_sec = _toloc(tp->tv_sec);
372 if (!VMSISH_TIME) tp->tv_sec = _toutc(tp->tv_sec);
380 /* Do not use H A S _ N A N O S L E E P
381 * so that Perl Configure doesn't scan for it (and pull in -lrt and
382 * the like which are not usually good ideas for the default Perl).
383 * (We are part of the core perl now.)
384 * The TIME_HIRES_NANOSLEEP is set by Makefile.PL. */
385 #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP)
387 #define usleep hrt_nanosleep /* could conflict with ncurses for static build */
390 hrt_nanosleep(unsigned long usec) /* This is used to emulate usleep. */
393 res.tv_sec = usec / IV_1E6;
394 res.tv_nsec = ( usec - res.tv_sec * IV_1E6 ) * 1000;
395 nanosleep(&res, NULL);
398 #endif /* #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP) */
400 #if !defined(HAS_USLEEP) && defined(HAS_SELECT)
401 #ifndef SELECT_IS_BROKEN
403 #define usleep hrt_usleep /* could conflict with ncurses for static build */
406 hrt_usleep(unsigned long usec)
411 select(0, (Select_fd_set_t)NULL, (Select_fd_set_t)NULL,
412 (Select_fd_set_t)NULL, &tv);
415 #endif /* #if !defined(HAS_USLEEP) && defined(HAS_SELECT) */
417 #if !defined(HAS_USLEEP) && defined(WIN32)
419 #define usleep hrt_usleep /* could conflict with ncurses for static build */
422 hrt_usleep(unsigned long usec)
428 #endif /* #if !defined(HAS_USLEEP) && defined(WIN32) */
430 #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP)
432 #define usleep hrt_usleep /* could conflict with ncurses for static build */
435 hrt_usleep(unsigned long usec)
438 ts1.tv_sec = usec * 1000; /* Ignoring wraparound. */
440 nanosleep(&ts1, NULL);
443 #endif /* #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP) */
445 #if !defined(HAS_USLEEP) && defined(HAS_POLL)
447 #define usleep hrt_usleep /* could conflict with ncurses for static build */
450 hrt_usleep(unsigned long usec)
452 int msec = usec / 1000;
456 #endif /* #if !defined(HAS_USLEEP) && defined(HAS_POLL) */
458 #if !defined(HAS_UALARM) && defined(HAS_SETITIMER)
460 #define ualarm hrt_ualarm /* could conflict with ncurses for static build */
463 hrt_ualarm(int usec, int interval)
465 struct itimerval itv;
466 itv.it_value.tv_sec = usec / IV_1E6;
467 itv.it_value.tv_usec = usec % IV_1E6;
468 itv.it_interval.tv_sec = interval / IV_1E6;
469 itv.it_interval.tv_usec = interval % IV_1E6;
470 return setitimer(ITIMER_REAL, &itv, 0);
472 #endif /* #if !defined(HAS_UALARM) && defined(HAS_SETITIMER) */
474 #if !defined(HAS_UALARM) && defined(VMS)
476 #define ualarm vms_ualarm
478 #include <lib$routines.h>
486 #define VMSERR(s) (!((s)&1))
489 us_to_VMS(useconds_t mseconds, unsigned long v[])
498 iss = lib$addx(qq,qq,qq);
499 if (VMSERR(iss)) lib$signal(iss);
500 iss = lib$subx(v,qq,v);
501 if (VMSERR(iss)) lib$signal(iss);
502 iss = lib$addx(qq,qq,qq);
503 if (VMSERR(iss)) lib$signal(iss);
504 iss = lib$subx(v,qq,v);
505 if (VMSERR(iss)) lib$signal(iss);
506 iss = lib$subx(v,qq,v);
507 if (VMSERR(iss)) lib$signal(iss);
511 VMS_to_us(unsigned long v[])
514 unsigned long div=10,quot, rem;
516 iss = lib$ediv(&div,v,",&rem);
517 if (VMSERR(iss)) lib$signal(iss);
522 typedef unsigned short word;
523 typedef struct _ualarm {
526 unsigned long delay[2];
527 unsigned long interval[2];
528 unsigned long remain[2];
533 static Alarm *a0, alarm_base;
538 static void ualarm_AST(Alarm *a);
541 vms_ualarm(int mseconds, int interval)
550 static struct item_list3 itmlst[2];
551 static int first = 1;
557 itmlst[0].code = JPI$_ASTEN;
558 itmlst[0].length = sizeof(asten);
559 itmlst[0].retlenaddr = NULL;
561 itmlst[1].length = 0;
562 itmlst[1].bufaddr = NULL;
563 itmlst[1].retlenaddr = NULL;
565 iss = lib$get_ef(&alarm_ef);
566 if (VMSERR(iss)) lib$signal(iss);
569 a0->function = UAL_NULL;
571 itmlst[0].bufaddr = &asten;
573 iss = sys$getjpiw(0,0,0,itmlst,0,0,0);
574 if (VMSERR(iss)) lib$signal(iss);
575 if (!(asten&0x08)) return -1;
579 a->function = UAL_SET;
581 a->function = UAL_CLEAR;
584 us_to_VMS(mseconds, a->delay);
586 us_to_VMS(interval, a->interval);
591 iss = sys$clref(alarm_ef);
592 if (VMSERR(iss)) lib$signal(iss);
594 iss = sys$dclast(ualarm_AST,a,0);
595 if (VMSERR(iss)) lib$signal(iss);
597 iss = sys$waitfr(alarm_ef);
598 if (VMSERR(iss)) lib$signal(iss);
600 if (a->function == UAL_ACTIVE)
601 return VMS_to_us(a->remain);
612 unsigned long now[2];
614 iss = sys$gettim(now);
615 if (VMSERR(iss)) lib$signal(iss);
617 if (a->function == UAL_SET || a->function == UAL_CLEAR) {
618 if (a0->function == UAL_ACTIVE) {
619 iss = sys$cantim(a0,PSL$C_USER);
620 if (VMSERR(iss)) lib$signal(iss);
622 iss = lib$subx(a0->remain, now, a->remain);
623 if (VMSERR(iss)) lib$signal(iss);
625 if (a->remain[1] & 0x80000000)
626 a->remain[0] = a->remain[1] = 0;
629 if (a->function == UAL_SET) {
630 a->function = a0->function;
631 a0->function = UAL_ACTIVE;
632 a0->repeat = a->repeat;
634 a0->interval[0] = a->interval[0];
635 a0->interval[1] = a->interval[1];
637 a0->delay[0] = a->delay[0];
638 a0->delay[1] = a->delay[1];
640 iss = lib$subx(now, a0->delay, a0->remain);
641 if (VMSERR(iss)) lib$signal(iss);
643 iss = sys$setimr(0,a0->delay,ualarm_AST,a0);
644 if (VMSERR(iss)) lib$signal(iss);
646 a->function = a0->function;
647 a0->function = UAL_NULL;
649 iss = sys$setef(alarm_ef);
650 if (VMSERR(iss)) lib$signal(iss);
651 } else if (a->function == UAL_ACTIVE) {
653 iss = lib$subx(now, a->interval, a->remain);
654 if (VMSERR(iss)) lib$signal(iss);
656 iss = sys$setimr(0,a->interval,ualarm_AST,a);
657 if (VMSERR(iss)) lib$signal(iss);
659 a->function = UAL_NULL;
662 if (VMSERR(iss)) lib$signal(iss);
663 lib$signal(SS$_ASTFLT);
665 lib$signal(SS$_BADPARAM);
669 #endif /* #if !defined(HAS_UALARM) && defined(VMS) */
671 #ifdef HAS_GETTIMEOFDAY
674 myU2time(pTHX_ UV *ret)
678 status = gettimeofday (&Tp, NULL);
692 status = gettimeofday (&Tp, NULL);
693 return status == 0 ? Tp.tv_sec + (Tp.tv_usec / NV_1E6) : -1.0;
696 #endif /* #ifdef HAS_GETTIMEOFDAY */
698 #include "const-c.inc"
700 MODULE = Time::HiRes PACKAGE = Time::HiRes
709 #ifdef ATLEASTFIVEOHOHFIVE
710 #ifdef HAS_GETTIMEOFDAY
712 hv_store(PL_modglobal, "Time::NVtime", 12, newSViv(PTR2IV(myNVtime)), 0);
713 hv_store(PL_modglobal, "Time::U2time", 12, newSViv(PTR2IV(myU2time)), 0);
719 #if defined(USE_ITHREADS) && defined(MY_CXT_KEY)
728 INCLUDE: const-xs.inc
730 #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY)
736 struct timeval Ta, Tb;
738 gettimeofday(&Ta, NULL);
740 if (useconds > 1E6) {
741 IV seconds = (IV) (useconds / 1E6);
742 /* If usleep() has been implemented using setitimer()
743 * then this contortion is unnecessary-- but usleep()
744 * may be implemented in some other way, so let's contort. */
747 useconds -= 1E6 * seconds;
749 } else if (useconds < 0.0)
750 croak("Time::HiRes::usleep(%"NVgf"): negative time not invented yet", useconds);
751 usleep((U32)useconds);
754 gettimeofday(&Tb, NULL);
756 printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec);
758 RETVAL = 1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec);
763 #if defined(TIME_HIRES_NANOSLEEP)
770 struct timeval Ta, Tb;
772 gettimeofday(&Ta, NULL);
776 IV sec = (IV) (nsec / 1E9);
781 } else if (nsec < 0.0)
782 croak("Time::HiRes::nanosleep(%"NVgf"): negative time not invented yet", nsec);
783 ts1.tv_sec = (IV) (nsec / 1E9);
784 ts1.tv_nsec = (IV) nsec - (IV) (ts1.tv_sec * NV_1E9);
785 status = nanosleep(&ts1, NULL);
790 gettimeofday(&Tb, NULL);
791 RETVAL = status == 0 ? 1E3*(1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec)) : -1;
796 #else /* #if defined(TIME_HIRES_NANOSLEEP) */
802 croak("Time::HiRes::nanosleep(): unimplemented in this platform");
805 #endif /* #if defined(TIME_HIRES_NANOSLEEP) */
810 struct timeval Ta, Tb;
812 gettimeofday(&Ta, NULL);
814 NV seconds = SvNV(ST(0));
815 if (seconds >= 0.0) {
816 UV useconds = (UV)(1E6 * (seconds - (UV)seconds));
819 if ((IV)useconds < 0) {
820 #if defined(__sparc64__) && defined(__GNUC__)
821 /* Sparc64 gcc 2.95.3 (e.g. on NetBSD) has a bug
822 * where (0.5 - (UV)(0.5)) will under certain
823 * circumstances (if the double is cast to UV more
824 * than once?) evaluate to -0.5, instead of 0.5. */
825 useconds = -(IV)useconds;
826 #endif /* #if defined(__sparc64__) && defined(__GNUC__) */
827 if ((IV)useconds < 0)
828 croak("Time::HiRes::sleep(%"NVgf"): internal error: useconds < 0 (unsigned %"UVuf" signed %"IVdf")", seconds, useconds, (IV)useconds);
832 croak("Time::HiRes::sleep(%"NVgf"): negative time not invented yet", seconds);
835 gettimeofday(&Tb, NULL);
837 printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec);
839 RETVAL = (NV)(Tb.tv_sec-Ta.tv_sec)+0.000001*(NV)(Tb.tv_usec-Ta.tv_usec);
844 #else /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */
850 croak("Time::HiRes::usleep(): unimplemented in this platform");
853 #endif /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */
858 ualarm(useconds,interval=0)
862 if (useconds < 0 || interval < 0)
863 croak("Time::HiRes::ualarm(%d, %d): negative time not invented yet", useconds, interval);
864 RETVAL = ualarm(useconds, interval);
870 alarm(seconds,interval=0)
874 if (seconds < 0.0 || interval < 0.0)
875 croak("Time::HiRes::alarm(%"NVgf", %"NVgf"): negative time not invented yet", seconds, interval);
876 RETVAL = (NV)ualarm((IV)(seconds * IV_1E6),
877 (IV)(interval * IV_1E6)) / NV_1E6;
885 ualarm(useconds,interval=0)
889 croak("Time::HiRes::ualarm(): unimplemented in this platform");
893 alarm(seconds,interval=0)
897 croak("Time::HiRes::alarm(): unimplemented in this platform");
900 #endif /* #ifdef HAS_UALARM */
902 #ifdef HAS_GETTIMEOFDAY
903 # ifdef MACOS_TRADITIONAL /* fix epoch TZ and use unsigned time_t */
911 status = gettimeofday (&Tp, &Tz);
914 Tp.tv_sec += Tz.tz_minuteswest * 60; /* adjust for TZ */
915 if (GIMME == G_ARRAY) {
917 /* Mac OS (Classic) has unsigned time_t */
918 PUSHs(sv_2mortal(newSVuv(Tp.tv_sec)));
919 PUSHs(sv_2mortal(newSViv(Tp.tv_usec)));
922 PUSHs(sv_2mortal(newSVnv(Tp.tv_sec + (Tp.tv_usec / NV_1E6))));
933 status = gettimeofday (&Tp, &Tz);
935 Tp.tv_sec += Tz.tz_minuteswest * 60; /* adjust for TZ */
936 RETVAL = Tp.tv_sec + (Tp.tv_usec / NV_1E6);
943 # else /* MACOS_TRADITIONAL */
950 status = gettimeofday (&Tp, NULL);
952 if (GIMME == G_ARRAY) {
954 PUSHs(sv_2mortal(newSViv(Tp.tv_sec)));
955 PUSHs(sv_2mortal(newSViv(Tp.tv_usec)));
958 PUSHs(sv_2mortal(newSVnv(Tp.tv_sec + (Tp.tv_usec / NV_1E6))));
968 status = gettimeofday (&Tp, NULL);
970 RETVAL = Tp.tv_sec + (Tp.tv_usec / NV_1E6);
977 # endif /* MACOS_TRADITIONAL */
978 #endif /* #ifdef HAS_GETTIMEOFDAY */
980 #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER)
982 #define TV2NV(tv) ((NV)((tv).tv_sec) + 0.000001 * (NV)((tv).tv_usec))
985 setitimer(which, seconds, interval = 0)
990 struct itimerval newit;
991 struct itimerval oldit;
993 if (seconds < 0.0 || interval < 0.0)
994 croak("Time::HiRes::setitimer(%"IVdf", %"NVgf", %"NVgf"): negative time not invented yet", (IV)which, seconds, interval);
995 newit.it_value.tv_sec = (IV)seconds;
996 newit.it_value.tv_usec =
997 (IV)((seconds - (NV)newit.it_value.tv_sec) * NV_1E6);
998 newit.it_interval.tv_sec = (IV)interval;
999 newit.it_interval.tv_usec =
1000 (IV)((interval - (NV)newit.it_interval.tv_sec) * NV_1E6);
1001 if (setitimer(which, &newit, &oldit) == 0) {
1003 PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_value))));
1004 if (GIMME == G_ARRAY) {
1006 PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_interval))));
1014 struct itimerval nowit;
1016 if (getitimer(which, &nowit) == 0) {
1018 PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_value))));
1019 if (GIMME == G_ARRAY) {
1021 PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_interval))));
1025 #endif /* #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER) */
1027 #if defined(TIME_HIRES_CLOCK_GETTIME)
1030 clock_gettime(clock_id = CLOCK_REALTIME)
1036 #ifdef TIME_HIRES_CLOCK_GETTIME_SYSCALL
1037 status = syscall(SYS_clock_gettime, clock_id, &ts);
1039 status = clock_gettime(clock_id, &ts);
1041 RETVAL = status == 0 ? ts.tv_sec + (NV) ts.tv_nsec / (NV) 1e9 : -1;
1046 #else /* if defined(TIME_HIRES_CLOCK_GETTIME) */
1049 clock_gettime(clock_id = 0)
1052 croak("Time::HiRes::clock_gettime(): unimplemented in this platform");
1055 #endif /* #if defined(TIME_HIRES_CLOCK_GETTIME) */
1057 #if defined(TIME_HIRES_CLOCK_GETRES)
1060 clock_getres(clock_id = CLOCK_REALTIME)
1066 #ifdef TIME_HIRES_CLOCK_GETRES_SYSCALL
1067 status = syscall(SYS_clock_getres, clock_id, &ts);
1069 status = clock_getres(clock_id, &ts);
1071 RETVAL = status == 0 ? ts.tv_sec + (NV) ts.tv_nsec / (NV) 1e9 : -1;
1076 #else /* if defined(TIME_HIRES_CLOCK_GETRES) */
1079 clock_getres(clock_id = 0)
1082 croak("Time::HiRes::clock_getres(): unimplemented in this platform");
1085 #endif /* #if defined(TIME_HIRES_CLOCK_GETRES) */
1087 #if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME)
1090 clock_nanosleep(clock_id = CLOCK_REALTIME, sec = 0.0, flags = 0)
1097 struct timeval Ta, Tb;
1099 gettimeofday(&Ta, NULL);
1101 ts.tv_sec = (IV) sec;
1102 ts.tv_nsec = (sec - (NV) ts.tv_sec) * (NV) 1E9;
1103 status = clock_nanosleep(clock_id, flags, &ts, NULL);
1108 gettimeofday(&Tb, NULL);
1109 RETVAL = status == 0 ? 1E3*(1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec)) : -1;
1114 #else /* if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) */
1119 croak("Time::HiRes::clock_nanosleep(): unimplemented in this platform");
1122 #endif /* #if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) */
1124 #if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC)
1132 RETVAL = clocks == -1 ? -1 : (NV)clocks / (NV)CLOCKS_PER_SEC;
1137 #else /* if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC) */
1142 croak("Time::HiRes::clock(): unimplemented in this platform");
1145 #endif /* #if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC) */