1b8851fccSafresh1 /*
2b8851fccSafresh1  *
3b8851fccSafresh1  * Copyright (c) 1996-2002 Douglas E. Wegscheid.  All rights reserved.
4b8851fccSafresh1  *
5b8851fccSafresh1  * Copyright (c) 2002-2010 Jarkko Hietaniemi.
6b8851fccSafresh1  * All rights reserved.
7b8851fccSafresh1  *
8b8851fccSafresh1  * Copyright (C) 2011, 2012, 2013 Andrew Main (Zefram) <zefram@fysh.org>
9b8851fccSafresh1  *
10b8851fccSafresh1  * This program is free software; you can redistribute it and/or modify
11b8851fccSafresh1  * it under the same terms as Perl itself.
12b8851fccSafresh1  */
13b8851fccSafresh1 
14b8851fccSafresh1 #define PERL_NO_GET_CONTEXT
15b8851fccSafresh1 #include "EXTERN.h"
16b8851fccSafresh1 #include "perl.h"
17b8851fccSafresh1 #include "XSUB.h"
18eac174f2Safresh1 #include "reentr.h"
19*e0680481Safresh1 #if !defined(IS_SAFE_PATHNAME) && defined(TIME_HIRES_UTIME) && defined(HAS_UTIMENSAT)
20eac174f2Safresh1 #define NEED_ck_warner
21b46d8ef2Safresh1 #endif
22*e0680481Safresh1 #include "ppport.h"
23b8851fccSafresh1 #if defined(__CYGWIN__) && defined(HAS_W32API_WINDOWS_H)
24b8851fccSafresh1 #  include <w32api/windows.h>
25b8851fccSafresh1 #  define CYGWIN_WITH_W32API
26b8851fccSafresh1 #endif
27b8851fccSafresh1 #ifdef WIN32
28b8851fccSafresh1 #  include <time.h>
29b8851fccSafresh1 #else
30b8851fccSafresh1 #  include <sys/time.h>
31b8851fccSafresh1 #endif
32b8851fccSafresh1 #ifdef HAS_SELECT
33b8851fccSafresh1 #  ifdef I_SYS_SELECT
34b8851fccSafresh1 #    include <sys/select.h>
35b8851fccSafresh1 #  endif
36b8851fccSafresh1 #endif
37b8851fccSafresh1 #if defined(TIME_HIRES_CLOCK_GETTIME_SYSCALL) || defined(TIME_HIRES_CLOCK_GETRES_SYSCALL)
38b8851fccSafresh1 #  include <syscall.h>
39b8851fccSafresh1 #endif
40b8851fccSafresh1 
419f11ffb7Safresh1 #ifndef GCC_DIAG_IGNORE
429f11ffb7Safresh1 #  define GCC_DIAG_IGNORE(x)
439f11ffb7Safresh1 #  define GCC_DIAG_RESTORE
449f11ffb7Safresh1 #endif
459f11ffb7Safresh1 #ifndef GCC_DIAG_IGNORE_STMT
469f11ffb7Safresh1 #  define GCC_DIAG_IGNORE_STMT(x) GCC_DIAG_IGNORE(x) NOOP
479f11ffb7Safresh1 #  define GCC_DIAG_RESTORE_STMT GCC_DIAG_RESTORE NOOP
489f11ffb7Safresh1 #endif
499f11ffb7Safresh1 
50b8851fccSafresh1 #if PERL_VERSION_GE(5,7,3) && !PERL_VERSION_GE(5,10,1)
51b8851fccSafresh1 #  undef SAVEOP
52b8851fccSafresh1 #  define SAVEOP() SAVEVPTR(PL_op)
53b8851fccSafresh1 #endif
54b8851fccSafresh1 
55b8851fccSafresh1 #define IV_1E6 1000000
56b8851fccSafresh1 #define IV_1E7 10000000
57b8851fccSafresh1 #define IV_1E9 1000000000
58b8851fccSafresh1 
59b8851fccSafresh1 #define NV_1E6 1000000.0
60b8851fccSafresh1 #define NV_1E7 10000000.0
61b8851fccSafresh1 #define NV_1E9 1000000000.0
62b8851fccSafresh1 
63b8851fccSafresh1 #ifndef PerlProc_pause
64b8851fccSafresh1 #  define PerlProc_pause() Pause()
65b8851fccSafresh1 #endif
66b8851fccSafresh1 
67b8851fccSafresh1 #ifdef HAS_PAUSE
68b8851fccSafresh1 #  define Pause   pause
69b8851fccSafresh1 #else
70b8851fccSafresh1 #  undef Pause /* In case perl.h did it already. */
71b8851fccSafresh1 #  define Pause() sleep(~0) /* Zzz for a long time. */
72b8851fccSafresh1 #endif
73b8851fccSafresh1 
74b8851fccSafresh1 /* Though the cpp define ITIMER_VIRTUAL is available the functionality
75b8851fccSafresh1  * is not supported in Cygwin as of August 2004, ditto for Win32.
76b8851fccSafresh1  * Neither are ITIMER_PROF or ITIMER_REALPROF implemented.  --jhi
77b8851fccSafresh1  */
78b8851fccSafresh1 #if defined(__CYGWIN__) || defined(WIN32)
79b8851fccSafresh1 #  undef ITIMER_VIRTUAL
80b8851fccSafresh1 #  undef ITIMER_PROF
81b8851fccSafresh1 #  undef ITIMER_REALPROF
82b8851fccSafresh1 #endif
83b8851fccSafresh1 
84c0dd97bfSafresh1 #ifndef TIME_HIRES_CLOCKID_T
85c0dd97bfSafresh1 typedef int clockid_t;
86c0dd97bfSafresh1 #endif
87c0dd97bfSafresh1 
88b8851fccSafresh1 #if defined(TIME_HIRES_CLOCK_GETTIME) && defined(_STRUCT_ITIMERSPEC)
89b8851fccSafresh1 
90b8851fccSafresh1 /* HP-UX has CLOCK_XXX values but as enums, not as defines.
91b8851fccSafresh1  * The only way to detect these would be to test compile for each. */
92b8851fccSafresh1 #  ifdef __hpux
93b8851fccSafresh1 /* However, it seems that at least in HP-UX 11.31 ia64 there *are*
94b8851fccSafresh1  * defines for these, so let's try detecting them. */
95b8851fccSafresh1 #    ifndef CLOCK_REALTIME
96b8851fccSafresh1 #      define CLOCK_REALTIME CLOCK_REALTIME
97b8851fccSafresh1 #      define CLOCK_VIRTUAL  CLOCK_VIRTUAL
98b8851fccSafresh1 #      define CLOCK_PROFILE  CLOCK_PROFILE
99b8851fccSafresh1 #    endif
100b8851fccSafresh1 #  endif /* # ifdef __hpux */
101b8851fccSafresh1 
102b8851fccSafresh1 #endif /* #if defined(TIME_HIRES_CLOCK_GETTIME) && defined(_STRUCT_ITIMERSPEC) */
103b8851fccSafresh1 
104b8851fccSafresh1 #if defined(WIN32) || defined(CYGWIN_WITH_W32API)
105b8851fccSafresh1 
106b8851fccSafresh1 #  ifndef HAS_GETTIMEOFDAY
107b8851fccSafresh1 #    define HAS_GETTIMEOFDAY
108b8851fccSafresh1 #  endif
109b8851fccSafresh1 
110b8851fccSafresh1 /* shows up in winsock.h?
111b8851fccSafresh1 struct timeval {
112b8851fccSafresh1     long tv_sec;
113b8851fccSafresh1     long tv_usec;
114b8851fccSafresh1 }
115b8851fccSafresh1 */
116b8851fccSafresh1 
117b8851fccSafresh1 typedef union {
118b8851fccSafresh1     unsigned __int64    ft_i64;
119b8851fccSafresh1     FILETIME            ft_val;
120b8851fccSafresh1 } FT_t;
121b8851fccSafresh1 
122b8851fccSafresh1 #  define MY_CXT_KEY "Time::HiRes_" XS_VERSION
123b8851fccSafresh1 
124b8851fccSafresh1 typedef struct {
125b8851fccSafresh1     unsigned long run_count;
126b8851fccSafresh1     unsigned __int64 base_ticks;
127b8851fccSafresh1     unsigned __int64 tick_frequency;
128b8851fccSafresh1     FT_t base_systime_as_filetime;
129b8851fccSafresh1     unsigned __int64 reset_time;
130b8851fccSafresh1 } my_cxt_t;
131b8851fccSafresh1 
132eac174f2Safresh1 /* Visual C++ 2013 and older don't have the timespec structure.
133eac174f2Safresh1  * Neither do mingw.org compilers with MinGW runtimes older than 3.22. */
134eac174f2Safresh1 #  if((defined(_MSC_VER) && _MSC_VER < 1900) || \
135eac174f2Safresh1       (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && \
136eac174f2Safresh1       defined(__MINGW32_MAJOR_VERSION) && (__MINGW32_MAJOR_VERSION < 3 || \
137eac174f2Safresh1       (__MINGW32_MAJOR_VERSION == 3 && __MINGW32_MINOR_VERSION < 22))))
13856d68f1eSafresh1 struct timespec {
13956d68f1eSafresh1     time_t tv_sec;
14056d68f1eSafresh1     long   tv_nsec;
14156d68f1eSafresh1 };
14256d68f1eSafresh1 #  endif
14356d68f1eSafresh1 
144b8851fccSafresh1 START_MY_CXT
145b8851fccSafresh1 
146b8851fccSafresh1 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
147b8851fccSafresh1 #  ifdef __GNUC__
148b8851fccSafresh1 #    define Const64(x) x##LL
149b8851fccSafresh1 #  else
150b8851fccSafresh1 #    define Const64(x) x##i64
151b8851fccSafresh1 #  endif
152b8851fccSafresh1 #  define EPOCH_BIAS  Const64(116444736000000000)
153b8851fccSafresh1 
154b8851fccSafresh1 #  ifdef Const64
155b8851fccSafresh1 #    ifdef __GNUC__
156b8851fccSafresh1 #      define IV_1E6LL  1000000LL /* Needed because of Const64() ##-appends LL (or i64). */
157b8851fccSafresh1 #      define IV_1E7LL  10000000LL
158b8851fccSafresh1 #      define IV_1E9LL  1000000000LL
159b8851fccSafresh1 #    else
160b8851fccSafresh1 #      define IV_1E6i64 1000000i64
161b8851fccSafresh1 #      define IV_1E7i64 10000000i64
162b8851fccSafresh1 #      define IV_1E9i64 1000000000i64
163b8851fccSafresh1 #    endif
164b8851fccSafresh1 #  endif
165b8851fccSafresh1 
166b8851fccSafresh1 /* NOTE: This does not compute the timezone info (doing so can be expensive,
167b8851fccSafresh1  * and appears to be unsupported even by glibc) */
168b8851fccSafresh1 
169b8851fccSafresh1 /* dMY_CXT needs a Perl context and we don't want to call PERL_GET_CONTEXT
170b8851fccSafresh1    for performance reasons */
171b8851fccSafresh1 
172b8851fccSafresh1 #  undef gettimeofday
173b8851fccSafresh1 #  define gettimeofday(tp, not_used) _gettimeofday(aTHX_ tp, not_used)
174b8851fccSafresh1 
17556d68f1eSafresh1 #  undef GetSystemTimePreciseAsFileTime
17656d68f1eSafresh1 #  define GetSystemTimePreciseAsFileTime(out) _GetSystemTimePreciseAsFileTime(aTHX_ out)
17756d68f1eSafresh1 
17856d68f1eSafresh1 #  undef clock_gettime
17956d68f1eSafresh1 #  define clock_gettime(clock_id, tp) _clock_gettime(aTHX_ clock_id, tp)
18056d68f1eSafresh1 
18156d68f1eSafresh1 #  undef clock_getres
18256d68f1eSafresh1 #  define clock_getres(clock_id, tp) _clock_getres(clock_id, tp)
18356d68f1eSafresh1 
18456d68f1eSafresh1 #  ifndef CLOCK_REALTIME
18556d68f1eSafresh1 #    define CLOCK_REALTIME  1
18656d68f1eSafresh1 #    define CLOCK_MONOTONIC 2
18756d68f1eSafresh1 #  endif
18856d68f1eSafresh1 
189b8851fccSafresh1 /* If the performance counter delta drifts more than 0.5 seconds from the
190b8851fccSafresh1  * system time then we recalibrate to the system time.  This means we may
191b8851fccSafresh1  * move *backwards* in time! */
192b8851fccSafresh1 #  define MAX_PERF_COUNTER_SKEW Const64(5000000) /* 0.5 seconds */
193b8851fccSafresh1 
194b8851fccSafresh1 /* Reset reading from the performance counter every five minutes.
195b8851fccSafresh1  * Many PC clocks just seem to be so bad. */
196b8851fccSafresh1 #  define MAX_PERF_COUNTER_TICKS Const64(300000000) /* 300 seconds */
197b8851fccSafresh1 
19856d68f1eSafresh1 /*
19956d68f1eSafresh1  * Windows 8 introduced GetSystemTimePreciseAsFileTime(), but currently we have
20056d68f1eSafresh1  * to support older systems, so for now we provide our own implementation.
20156d68f1eSafresh1  * In the future we will switch to the real deal.
20256d68f1eSafresh1  */
20356d68f1eSafresh1 static void
_GetSystemTimePreciseAsFileTime(pTHX_ FILETIME * out)20456d68f1eSafresh1 _GetSystemTimePreciseAsFileTime(pTHX_ FILETIME *out)
205b8851fccSafresh1 {
206b8851fccSafresh1     dMY_CXT;
207b8851fccSafresh1     FT_t ft;
208b8851fccSafresh1 
209b8851fccSafresh1     if (MY_CXT.run_count++ == 0 ||
210b8851fccSafresh1         MY_CXT.base_systime_as_filetime.ft_i64 > MY_CXT.reset_time) {
21156d68f1eSafresh1 
212b8851fccSafresh1         QueryPerformanceFrequency((LARGE_INTEGER*)&MY_CXT.tick_frequency);
213b8851fccSafresh1         QueryPerformanceCounter((LARGE_INTEGER*)&MY_CXT.base_ticks);
214b8851fccSafresh1         GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val);
215b8851fccSafresh1         ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64;
216b8851fccSafresh1         MY_CXT.reset_time = ft.ft_i64 + MAX_PERF_COUNTER_TICKS;
217b8851fccSafresh1     }
218b8851fccSafresh1     else {
219b8851fccSafresh1         __int64 diff;
22056d68f1eSafresh1         unsigned __int64 ticks;
221b8851fccSafresh1         QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
222b8851fccSafresh1         ticks -= MY_CXT.base_ticks;
223b8851fccSafresh1         ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64
224b8851fccSafresh1                     + Const64(IV_1E7) * (ticks / MY_CXT.tick_frequency)
225b8851fccSafresh1                     +(Const64(IV_1E7) * (ticks % MY_CXT.tick_frequency)) / MY_CXT.tick_frequency;
226b8851fccSafresh1         diff = ft.ft_i64 - MY_CXT.base_systime_as_filetime.ft_i64;
227b8851fccSafresh1         if (diff < -MAX_PERF_COUNTER_SKEW || diff > MAX_PERF_COUNTER_SKEW) {
228b8851fccSafresh1             MY_CXT.base_ticks += ticks;
229b8851fccSafresh1             GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val);
230b8851fccSafresh1             ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64;
231b8851fccSafresh1         }
232b8851fccSafresh1     }
233b8851fccSafresh1 
23456d68f1eSafresh1     *out = ft.ft_val;
23556d68f1eSafresh1 
23656d68f1eSafresh1     return;
23756d68f1eSafresh1 }
23856d68f1eSafresh1 
23956d68f1eSafresh1 static int
_gettimeofday(pTHX_ struct timeval * tp,void * not_used)24056d68f1eSafresh1 _gettimeofday(pTHX_ struct timeval *tp, void *not_used)
24156d68f1eSafresh1 {
24256d68f1eSafresh1     FT_t ft;
24356d68f1eSafresh1 
24456d68f1eSafresh1     PERL_UNUSED_ARG(not_used);
24556d68f1eSafresh1 
24656d68f1eSafresh1     GetSystemTimePreciseAsFileTime(&ft.ft_val);
24756d68f1eSafresh1 
248b8851fccSafresh1     /* seconds since epoch */
249b8851fccSafresh1     tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(IV_1E7));
250b8851fccSafresh1 
251b8851fccSafresh1     /* microseconds remaining */
252b8851fccSafresh1     tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(IV_1E6));
253b8851fccSafresh1 
254b8851fccSafresh1     return 0;
255b8851fccSafresh1 }
256b8851fccSafresh1 
25756d68f1eSafresh1 static int
_clock_gettime(pTHX_ clockid_t clock_id,struct timespec * tp)25856d68f1eSafresh1 _clock_gettime(pTHX_ clockid_t clock_id, struct timespec *tp)
259b8851fccSafresh1 {
26056d68f1eSafresh1     switch (clock_id) {
26156d68f1eSafresh1     case CLOCK_REALTIME: {
26256d68f1eSafresh1         FT_t ft;
26356d68f1eSafresh1 
26456d68f1eSafresh1         GetSystemTimePreciseAsFileTime(&ft.ft_val);
26556d68f1eSafresh1         tp->tv_sec = (time_t)((ft.ft_i64 - EPOCH_BIAS) / IV_1E7);
26656d68f1eSafresh1         tp->tv_nsec = (long)((ft.ft_i64 % IV_1E7) * 100);
26756d68f1eSafresh1         break;
26856d68f1eSafresh1     }
26956d68f1eSafresh1     case CLOCK_MONOTONIC: {
27056d68f1eSafresh1         unsigned __int64 freq, ticks;
27156d68f1eSafresh1 
27256d68f1eSafresh1         QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
27356d68f1eSafresh1         QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
27456d68f1eSafresh1 
27556d68f1eSafresh1         tp->tv_sec = (time_t)(ticks / freq);
27656d68f1eSafresh1         tp->tv_nsec = (long)((IV_1E9 * (ticks % freq)) / freq);
27756d68f1eSafresh1         break;
27856d68f1eSafresh1     }
27956d68f1eSafresh1     default:
28056d68f1eSafresh1         errno = EINVAL;
28156d68f1eSafresh1         return 1;
28256d68f1eSafresh1     }
28356d68f1eSafresh1 
284b8851fccSafresh1     return 0;
285b8851fccSafresh1 }
28656d68f1eSafresh1 
28756d68f1eSafresh1 static int
_clock_getres(clockid_t clock_id,struct timespec * tp)28856d68f1eSafresh1 _clock_getres(clockid_t clock_id, struct timespec *tp)
28956d68f1eSafresh1 {
29056d68f1eSafresh1     unsigned __int64 freq, qpc_res_ns;
29156d68f1eSafresh1 
29256d68f1eSafresh1     QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
29356d68f1eSafresh1     qpc_res_ns = IV_1E9 > freq ? IV_1E9 / freq : 1;
29456d68f1eSafresh1 
29556d68f1eSafresh1     switch (clock_id) {
29656d68f1eSafresh1     case CLOCK_REALTIME:
29756d68f1eSafresh1         tp->tv_sec = 0;
29856d68f1eSafresh1         /* the resolution can't be smaller than 100ns because our implementation
29956d68f1eSafresh1          * of CLOCK_REALTIME is using FILETIME internally */
30056d68f1eSafresh1         tp->tv_nsec = (long)(qpc_res_ns > 100 ? qpc_res_ns : 100);
30156d68f1eSafresh1         break;
30256d68f1eSafresh1 
30356d68f1eSafresh1     case CLOCK_MONOTONIC:
30456d68f1eSafresh1         tp->tv_sec = 0;
30556d68f1eSafresh1         tp->tv_nsec = (long)qpc_res_ns;
30656d68f1eSafresh1         break;
30756d68f1eSafresh1 
30856d68f1eSafresh1     default:
30956d68f1eSafresh1         errno = EINVAL;
31056d68f1eSafresh1         return 1;
31156d68f1eSafresh1     }
31256d68f1eSafresh1 
31356d68f1eSafresh1     return 0;
31456d68f1eSafresh1 }
31556d68f1eSafresh1 
31656d68f1eSafresh1 #endif /* #if defined(WIN32) || defined(CYGWIN_WITH_W32API) */
317b8851fccSafresh1 
318b8851fccSafresh1  /* Do not use H A S _ N A N O S L E E P
319b8851fccSafresh1   * so that Perl Configure doesn't scan for it (and pull in -lrt and
320b8851fccSafresh1   * the like which are not usually good ideas for the default Perl).
321b8851fccSafresh1   * (We are part of the core perl now.)
322b8851fccSafresh1   * The TIME_HIRES_NANOSLEEP is set by Makefile.PL. */
323b8851fccSafresh1 #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP)
324b8851fccSafresh1 #  define HAS_USLEEP
325b8851fccSafresh1 #  define usleep hrt_usleep  /* could conflict with ncurses for static build */
326b8851fccSafresh1 
327b8851fccSafresh1 static void
hrt_usleep(unsigned long usec)328b8851fccSafresh1 hrt_usleep(unsigned long usec) /* This is used to emulate usleep. */
329b8851fccSafresh1 {
330b8851fccSafresh1     struct timespec res;
331b8851fccSafresh1     res.tv_sec = usec / IV_1E6;
332b8851fccSafresh1     res.tv_nsec = ( usec - res.tv_sec * IV_1E6 ) * 1000;
333b8851fccSafresh1     nanosleep(&res, NULL);
334b8851fccSafresh1 }
335b8851fccSafresh1 
336b8851fccSafresh1 #endif /* #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP) */
337b8851fccSafresh1 
338b8851fccSafresh1 #if !defined(HAS_USLEEP) && defined(HAS_SELECT)
339b8851fccSafresh1 #  ifndef SELECT_IS_BROKEN
340b8851fccSafresh1 #    define HAS_USLEEP
341b8851fccSafresh1 #    define usleep hrt_usleep  /* could conflict with ncurses for static build */
342b8851fccSafresh1 
343b8851fccSafresh1 static void
hrt_usleep(unsigned long usec)344b8851fccSafresh1 hrt_usleep(unsigned long usec)
345b8851fccSafresh1 {
346b8851fccSafresh1     struct timeval tv;
347b8851fccSafresh1     tv.tv_sec = 0;
348b8851fccSafresh1     tv.tv_usec = usec;
349b8851fccSafresh1     select(0, (Select_fd_set_t)NULL, (Select_fd_set_t)NULL,
350b8851fccSafresh1         (Select_fd_set_t)NULL, &tv);
351b8851fccSafresh1 }
352b8851fccSafresh1 #  endif
353b8851fccSafresh1 #endif /* #if !defined(HAS_USLEEP) && defined(HAS_SELECT) */
354b8851fccSafresh1 
355b8851fccSafresh1 #if !defined(HAS_USLEEP) && defined(WIN32)
356b8851fccSafresh1 #  define HAS_USLEEP
357b8851fccSafresh1 #  define usleep hrt_usleep  /* could conflict with ncurses for static build */
358b8851fccSafresh1 
359b8851fccSafresh1 static void
hrt_usleep(unsigned long usec)360b8851fccSafresh1 hrt_usleep(unsigned long usec)
361b8851fccSafresh1 {
362b8851fccSafresh1     long msec;
363b8851fccSafresh1     msec = usec / 1000;
364b8851fccSafresh1     Sleep (msec);
365b8851fccSafresh1 }
366b8851fccSafresh1 #endif /* #if !defined(HAS_USLEEP) && defined(WIN32) */
367b8851fccSafresh1 
368b8851fccSafresh1 #if !defined(HAS_USLEEP) && defined(HAS_POLL)
369b8851fccSafresh1 #  define HAS_USLEEP
370b8851fccSafresh1 #  define usleep hrt_usleep  /* could conflict with ncurses for static build */
371b8851fccSafresh1 
372b8851fccSafresh1 static void
hrt_usleep(unsigned long usec)373b8851fccSafresh1 hrt_usleep(unsigned long usec)
374b8851fccSafresh1 {
375b8851fccSafresh1     int msec = usec / 1000;
376b8851fccSafresh1     poll(0, 0, msec);
377b8851fccSafresh1 }
378b8851fccSafresh1 
379b8851fccSafresh1 #endif /* #if !defined(HAS_USLEEP) && defined(HAS_POLL) */
380b8851fccSafresh1 
381b8851fccSafresh1 #if defined(HAS_SETITIMER) && defined(ITIMER_REAL)
382b8851fccSafresh1 
383b8851fccSafresh1 static int
hrt_ualarm_itimero(struct itimerval * oitv,int usec,int uinterval)384b8851fccSafresh1 hrt_ualarm_itimero(struct itimerval *oitv, int usec, int uinterval)
385b8851fccSafresh1 {
386b8851fccSafresh1     struct itimerval itv;
387b8851fccSafresh1     itv.it_value.tv_sec = usec / IV_1E6;
388b8851fccSafresh1     itv.it_value.tv_usec = usec % IV_1E6;
389b8851fccSafresh1     itv.it_interval.tv_sec = uinterval / IV_1E6;
390b8851fccSafresh1     itv.it_interval.tv_usec = uinterval % IV_1E6;
391b8851fccSafresh1     return setitimer(ITIMER_REAL, &itv, oitv);
392b8851fccSafresh1 }
393b8851fccSafresh1 
394b8851fccSafresh1 #endif /* #if !defined(HAS_UALARM) && defined(HAS_SETITIMER) */
395b8851fccSafresh1 
396b8851fccSafresh1 #if !defined(HAS_UALARM) && defined(HAS_SETITIMER)
397b8851fccSafresh1 #  define HAS_UALARM
398b8851fccSafresh1 #  define ualarm hrt_ualarm_itimer  /* could conflict with ncurses for static build */
399b8851fccSafresh1 #endif
400b8851fccSafresh1 
401b8851fccSafresh1 #if !defined(HAS_UALARM) && defined(VMS)
402b8851fccSafresh1 #  define HAS_UALARM
403b8851fccSafresh1 #  define ualarm vms_ualarm
404b8851fccSafresh1 
405b8851fccSafresh1 #  include <lib$routines.h>
406b8851fccSafresh1 #  include <ssdef.h>
407b8851fccSafresh1 #  include <starlet.h>
408b8851fccSafresh1 #  include <descrip.h>
409b8851fccSafresh1 #  include <signal.h>
410b8851fccSafresh1 #  include <jpidef.h>
411b8851fccSafresh1 #  include <psldef.h>
412b8851fccSafresh1 
413b8851fccSafresh1 #  define VMSERR(s)   (!((s)&1))
414b8851fccSafresh1 
415b8851fccSafresh1 static void
us_to_VMS(useconds_t mseconds,unsigned long v[])416b8851fccSafresh1 us_to_VMS(useconds_t mseconds, unsigned long v[])
417b8851fccSafresh1 {
418b8851fccSafresh1     int iss;
419b8851fccSafresh1     unsigned long qq[2];
420b8851fccSafresh1 
421b8851fccSafresh1     qq[0] = mseconds;
422b8851fccSafresh1     qq[1] = 0;
423b8851fccSafresh1     v[0] = v[1] = 0;
424b8851fccSafresh1 
425b8851fccSafresh1     iss = lib$addx(qq,qq,qq);
426b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
427b8851fccSafresh1     iss = lib$subx(v,qq,v);
428b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
429b8851fccSafresh1     iss = lib$addx(qq,qq,qq);
430b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
431b8851fccSafresh1     iss = lib$subx(v,qq,v);
432b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
433b8851fccSafresh1     iss = lib$subx(v,qq,v);
434b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
435b8851fccSafresh1 }
436b8851fccSafresh1 
437b8851fccSafresh1 static int
VMS_to_us(unsigned long v[])438b8851fccSafresh1 VMS_to_us(unsigned long v[])
439b8851fccSafresh1 {
440b8851fccSafresh1     int iss;
441b8851fccSafresh1     unsigned long div=10,quot, rem;
442b8851fccSafresh1 
443b8851fccSafresh1     iss = lib$ediv(&div,v,&quot,&rem);
444b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
445b8851fccSafresh1 
446b8851fccSafresh1     return quot;
447b8851fccSafresh1 }
448b8851fccSafresh1 
449b8851fccSafresh1 typedef unsigned short word;
450b8851fccSafresh1 typedef struct _ualarm {
451b8851fccSafresh1     int function;
452b8851fccSafresh1     int repeat;
453b8851fccSafresh1     unsigned long delay[2];
454b8851fccSafresh1     unsigned long interval[2];
455b8851fccSafresh1     unsigned long remain[2];
456b8851fccSafresh1 } Alarm;
457b8851fccSafresh1 
458b8851fccSafresh1 
459b8851fccSafresh1 static int alarm_ef;
460b8851fccSafresh1 static Alarm *a0, alarm_base;
461b8851fccSafresh1 #  define UAL_NULL   0
462b8851fccSafresh1 #  define UAL_SET    1
463b8851fccSafresh1 #  define UAL_CLEAR  2
464b8851fccSafresh1 #  define UAL_ACTIVE 4
465b8851fccSafresh1 static void ualarm_AST(Alarm *a);
466b8851fccSafresh1 
467b8851fccSafresh1 static int
vms_ualarm(int mseconds,int interval)468b8851fccSafresh1 vms_ualarm(int mseconds, int interval)
469b8851fccSafresh1 {
470b8851fccSafresh1     Alarm *a, abase;
471b8851fccSafresh1     struct item_list3 {
472b8851fccSafresh1         word length;
473b8851fccSafresh1         word code;
474b8851fccSafresh1         void *bufaddr;
475b8851fccSafresh1         void *retlenaddr;
476b8851fccSafresh1     } ;
477b8851fccSafresh1     static struct item_list3 itmlst[2];
478b8851fccSafresh1     static int first = 1;
479b8851fccSafresh1     unsigned long asten;
480b8851fccSafresh1     int iss, enabled;
481b8851fccSafresh1 
482b8851fccSafresh1     if (first) {
483b8851fccSafresh1         first = 0;
484b8851fccSafresh1         itmlst[0].code       = JPI$_ASTEN;
485b8851fccSafresh1         itmlst[0].length     = sizeof(asten);
486b8851fccSafresh1         itmlst[0].retlenaddr = NULL;
487b8851fccSafresh1         itmlst[1].code       = 0;
488b8851fccSafresh1         itmlst[1].length     = 0;
489b8851fccSafresh1         itmlst[1].bufaddr    = NULL;
490b8851fccSafresh1         itmlst[1].retlenaddr = NULL;
491b8851fccSafresh1 
492b8851fccSafresh1         iss = lib$get_ef(&alarm_ef);
493b8851fccSafresh1         if (VMSERR(iss)) lib$signal(iss);
494b8851fccSafresh1 
495b8851fccSafresh1         a0 = &alarm_base;
496b8851fccSafresh1         a0->function = UAL_NULL;
497b8851fccSafresh1     }
498b8851fccSafresh1     itmlst[0].bufaddr    = &asten;
499b8851fccSafresh1 
500b8851fccSafresh1     iss = sys$getjpiw(0,0,0,itmlst,0,0,0);
501b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
502b8851fccSafresh1     if (!(asten&0x08)) return -1;
503b8851fccSafresh1 
504b8851fccSafresh1     a = &abase;
505b8851fccSafresh1     if (mseconds) {
506b8851fccSafresh1         a->function = UAL_SET;
507b8851fccSafresh1     } else {
508b8851fccSafresh1         a->function = UAL_CLEAR;
509b8851fccSafresh1     }
510b8851fccSafresh1 
511b8851fccSafresh1     us_to_VMS(mseconds, a->delay);
512b8851fccSafresh1     if (interval) {
513b8851fccSafresh1         us_to_VMS(interval, a->interval);
514b8851fccSafresh1         a->repeat = 1;
515b8851fccSafresh1     } else
516b8851fccSafresh1         a->repeat = 0;
517b8851fccSafresh1 
518b8851fccSafresh1     iss = sys$clref(alarm_ef);
519b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
520b8851fccSafresh1 
521b8851fccSafresh1     iss = sys$dclast(ualarm_AST,a,0);
522b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
523b8851fccSafresh1 
524b8851fccSafresh1     iss = sys$waitfr(alarm_ef);
525b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
526b8851fccSafresh1 
527b8851fccSafresh1     if (a->function == UAL_ACTIVE)
528b8851fccSafresh1         return VMS_to_us(a->remain);
529b8851fccSafresh1     else
530b8851fccSafresh1         return 0;
531b8851fccSafresh1 }
532b8851fccSafresh1 
533b8851fccSafresh1 
534b8851fccSafresh1 
535b8851fccSafresh1 static void
ualarm_AST(Alarm * a)536b8851fccSafresh1 ualarm_AST(Alarm *a)
537b8851fccSafresh1 {
538b8851fccSafresh1     int iss;
539b8851fccSafresh1     unsigned long now[2];
540b8851fccSafresh1 
541b8851fccSafresh1     iss = sys$gettim(now);
542b8851fccSafresh1     if (VMSERR(iss)) lib$signal(iss);
543b8851fccSafresh1 
544b8851fccSafresh1     if (a->function == UAL_SET || a->function == UAL_CLEAR) {
545b8851fccSafresh1         if (a0->function == UAL_ACTIVE) {
546b8851fccSafresh1             iss = sys$cantim(a0,PSL$C_USER);
547b8851fccSafresh1             if (VMSERR(iss)) lib$signal(iss);
548b8851fccSafresh1 
549b8851fccSafresh1             iss = lib$subx(a0->remain, now, a->remain);
550b8851fccSafresh1             if (VMSERR(iss)) lib$signal(iss);
551b8851fccSafresh1 
552b8851fccSafresh1             if (a->remain[1] & 0x80000000)
553b8851fccSafresh1                 a->remain[0] = a->remain[1] = 0;
554b8851fccSafresh1         }
555b8851fccSafresh1 
556b8851fccSafresh1         if (a->function == UAL_SET) {
557b8851fccSafresh1             a->function = a0->function;
558b8851fccSafresh1             a0->function = UAL_ACTIVE;
559b8851fccSafresh1             a0->repeat = a->repeat;
560b8851fccSafresh1             if (a0->repeat) {
561b8851fccSafresh1                 a0->interval[0] = a->interval[0];
562b8851fccSafresh1                 a0->interval[1] = a->interval[1];
563b8851fccSafresh1             }
564b8851fccSafresh1             a0->delay[0] = a->delay[0];
565b8851fccSafresh1             a0->delay[1] = a->delay[1];
566b8851fccSafresh1 
567b8851fccSafresh1             iss = lib$subx(now, a0->delay, a0->remain);
568b8851fccSafresh1             if (VMSERR(iss)) lib$signal(iss);
569b8851fccSafresh1 
570b8851fccSafresh1             iss = sys$setimr(0,a0->delay,ualarm_AST,a0);
571b8851fccSafresh1             if (VMSERR(iss)) lib$signal(iss);
572b8851fccSafresh1         } else {
573b8851fccSafresh1             a->function = a0->function;
574b8851fccSafresh1             a0->function = UAL_NULL;
575b8851fccSafresh1         }
576b8851fccSafresh1         iss = sys$setef(alarm_ef);
577b8851fccSafresh1         if (VMSERR(iss)) lib$signal(iss);
578b8851fccSafresh1     } else if (a->function == UAL_ACTIVE) {
579b8851fccSafresh1         if (a->repeat) {
580b8851fccSafresh1             iss = lib$subx(now, a->interval, a->remain);
581b8851fccSafresh1             if (VMSERR(iss)) lib$signal(iss);
582b8851fccSafresh1 
583b8851fccSafresh1             iss = sys$setimr(0,a->interval,ualarm_AST,a);
584b8851fccSafresh1             if (VMSERR(iss)) lib$signal(iss);
585b8851fccSafresh1         } else {
586b8851fccSafresh1             a->function = UAL_NULL;
587b8851fccSafresh1         }
588b8851fccSafresh1         iss = sys$wake(0,0);
589b8851fccSafresh1         if (VMSERR(iss)) lib$signal(iss);
590b8851fccSafresh1         lib$signal(SS$_ASTFLT);
591b8851fccSafresh1     } else {
592b8851fccSafresh1         lib$signal(SS$_BADPARAM);
593b8851fccSafresh1     }
594b8851fccSafresh1 }
595b8851fccSafresh1 
596b8851fccSafresh1 #endif /* #if !defined(HAS_UALARM) && defined(VMS) */
597b8851fccSafresh1 
598b8851fccSafresh1 #ifdef HAS_GETTIMEOFDAY
599b8851fccSafresh1 
600b8851fccSafresh1 static int
myU2time(pTHX_ UV * ret)601b8851fccSafresh1 myU2time(pTHX_ UV *ret)
602b8851fccSafresh1 {
603b8851fccSafresh1     struct timeval Tp;
604b8851fccSafresh1     int status;
605b8851fccSafresh1     status = gettimeofday (&Tp, NULL);
606b8851fccSafresh1     ret[0] = Tp.tv_sec;
607b8851fccSafresh1     ret[1] = Tp.tv_usec;
608b8851fccSafresh1     return status;
609b8851fccSafresh1 }
610b8851fccSafresh1 
611b8851fccSafresh1 static NV
myNVtime()612b8851fccSafresh1 myNVtime()
613b8851fccSafresh1 {
614b8851fccSafresh1 #  ifdef WIN32
615b8851fccSafresh1     dTHX;
616b8851fccSafresh1 #  endif
617b8851fccSafresh1     struct timeval Tp;
618b8851fccSafresh1     int status;
619b8851fccSafresh1     status = gettimeofday (&Tp, NULL);
620b8851fccSafresh1     return status == 0 ? Tp.tv_sec + (Tp.tv_usec / NV_1E6) : -1.0;
621b8851fccSafresh1 }
622b8851fccSafresh1 
623b8851fccSafresh1 #endif /* #ifdef HAS_GETTIMEOFDAY */
624b8851fccSafresh1 
625b8851fccSafresh1 static void
hrstatns(UV * atime_nsec,UV * mtime_nsec,UV * ctime_nsec)626b8851fccSafresh1 hrstatns(UV *atime_nsec, UV *mtime_nsec, UV *ctime_nsec)
627b8851fccSafresh1 {
628b8851fccSafresh1     dTHX;
629b8851fccSafresh1 #if TIME_HIRES_STAT == 1
630b8851fccSafresh1     *atime_nsec = PL_statcache.st_atimespec.tv_nsec;
631b8851fccSafresh1     *mtime_nsec = PL_statcache.st_mtimespec.tv_nsec;
632b8851fccSafresh1     *ctime_nsec = PL_statcache.st_ctimespec.tv_nsec;
633b8851fccSafresh1 #elif TIME_HIRES_STAT == 2
634b8851fccSafresh1     *atime_nsec = PL_statcache.st_atimensec;
635b8851fccSafresh1     *mtime_nsec = PL_statcache.st_mtimensec;
636b8851fccSafresh1     *ctime_nsec = PL_statcache.st_ctimensec;
637b8851fccSafresh1 #elif TIME_HIRES_STAT == 3
638b8851fccSafresh1     *atime_nsec = PL_statcache.st_atime_n;
639b8851fccSafresh1     *mtime_nsec = PL_statcache.st_mtime_n;
640b8851fccSafresh1     *ctime_nsec = PL_statcache.st_ctime_n;
641b8851fccSafresh1 #elif TIME_HIRES_STAT == 4
642b8851fccSafresh1     *atime_nsec = PL_statcache.st_atim.tv_nsec;
643b8851fccSafresh1     *mtime_nsec = PL_statcache.st_mtim.tv_nsec;
644b8851fccSafresh1     *ctime_nsec = PL_statcache.st_ctim.tv_nsec;
645b8851fccSafresh1 #elif TIME_HIRES_STAT == 5
646b8851fccSafresh1     *atime_nsec = PL_statcache.st_uatime * 1000;
647b8851fccSafresh1     *mtime_nsec = PL_statcache.st_umtime * 1000;
648b8851fccSafresh1     *ctime_nsec = PL_statcache.st_uctime * 1000;
649b8851fccSafresh1 #else /* !TIME_HIRES_STAT */
650b8851fccSafresh1     *atime_nsec = 0;
651b8851fccSafresh1     *mtime_nsec = 0;
652b8851fccSafresh1     *ctime_nsec = 0;
653b8851fccSafresh1 #endif /* !TIME_HIRES_STAT */
654b8851fccSafresh1 }
655b8851fccSafresh1 
656014083a1Safresh1 /* Until Apple implements clock_gettime()
657014083a1Safresh1  * (ditto clock_getres() and clock_nanosleep())
658014083a1Safresh1  * we will emulate them using the Mach kernel interfaces. */
659014083a1Safresh1 #if defined(PERL_DARWIN) && \
660014083a1Safresh1   (defined(TIME_HIRES_CLOCK_GETTIME_EMULATION)   || \
661014083a1Safresh1    defined(TIME_HIRES_CLOCK_GETRES_EMULATION)    || \
662014083a1Safresh1    defined(TIME_HIRES_CLOCK_NANOSLEEP_EMULATION))
663b8851fccSafresh1 
664014083a1Safresh1 #  ifndef CLOCK_REALTIME
665de18eedbSafresh1 #    define CLOCK_REALTIME  0x01
666de18eedbSafresh1 #    define CLOCK_MONOTONIC 0x02
667014083a1Safresh1 #  endif
668de18eedbSafresh1 
669014083a1Safresh1 #  ifndef TIMER_ABSTIME
670de18eedbSafresh1 #    define TIMER_ABSTIME   0x01
671014083a1Safresh1 #  endif
672de18eedbSafresh1 
673de18eedbSafresh1 #  ifdef USE_ITHREADS
674014083a1Safresh1 #    define PERL_DARWIN_MUTEX
675014083a1Safresh1 #  endif
676014083a1Safresh1 
677014083a1Safresh1 #  ifdef PERL_DARWIN_MUTEX
678de18eedbSafresh1 STATIC perl_mutex darwin_time_mutex;
679de18eedbSafresh1 #  endif
680de18eedbSafresh1 
681014083a1Safresh1 #  include <mach/mach_time.h>
682014083a1Safresh1 
683b8851fccSafresh1 static uint64_t absolute_time_init;
684b8851fccSafresh1 static mach_timebase_info_data_t timebase_info;
685b8851fccSafresh1 static struct timespec timespec_init;
686b8851fccSafresh1 
darwin_time_init()687b8851fccSafresh1 static int darwin_time_init() {
688b8851fccSafresh1     struct timeval tv;
689b8851fccSafresh1     int success = 1;
690014083a1Safresh1 #  ifdef PERL_DARWIN_MUTEX
691b8851fccSafresh1     MUTEX_LOCK(&darwin_time_mutex);
692b8851fccSafresh1 #  endif
693b8851fccSafresh1     if (absolute_time_init == 0) {
694b8851fccSafresh1         /* mach_absolute_time() cannot fail */
695b8851fccSafresh1         absolute_time_init = mach_absolute_time();
696b8851fccSafresh1         success = mach_timebase_info(&timebase_info) == KERN_SUCCESS;
697b8851fccSafresh1         if (success) {
698b8851fccSafresh1             success = gettimeofday(&tv, NULL) == 0;
699b8851fccSafresh1             if (success) {
700b8851fccSafresh1                 timespec_init.tv_sec  = tv.tv_sec;
701b8851fccSafresh1                 timespec_init.tv_nsec = tv.tv_usec * 1000;
702b8851fccSafresh1             }
703b8851fccSafresh1         }
704b8851fccSafresh1     }
705014083a1Safresh1 #  ifdef PERL_DARWIN_MUTEX
706b8851fccSafresh1     MUTEX_UNLOCK(&darwin_time_mutex);
707b8851fccSafresh1 #  endif
708b8851fccSafresh1     return success;
709b8851fccSafresh1 }
710b8851fccSafresh1 
711014083a1Safresh1 #  ifdef TIME_HIRES_CLOCK_GETTIME_EMULATION
th_clock_gettime(clockid_t clock_id,struct timespec * ts)712c0dd97bfSafresh1 static int th_clock_gettime(clockid_t clock_id, struct timespec *ts) {
713b8851fccSafresh1     if (darwin_time_init() && timebase_info.denom) {
714b8851fccSafresh1         switch (clock_id) {
715b8851fccSafresh1         case CLOCK_REALTIME:
716b8851fccSafresh1             {
717b8851fccSafresh1                 uint64_t nanos =
718b8851fccSafresh1                     ((mach_absolute_time() - absolute_time_init) *
719b8851fccSafresh1                     (uint64_t)timebase_info.numer) / (uint64_t)timebase_info.denom;
720b8851fccSafresh1                 ts->tv_sec  = timespec_init.tv_sec  + nanos / IV_1E9;
721b8851fccSafresh1                 ts->tv_nsec = timespec_init.tv_nsec + nanos % IV_1E9;
722b8851fccSafresh1                 return 0;
723b8851fccSafresh1             }
724b8851fccSafresh1 
725b8851fccSafresh1         case CLOCK_MONOTONIC:
726b8851fccSafresh1             {
727b8851fccSafresh1                 uint64_t nanos =
728b8851fccSafresh1                     (mach_absolute_time() *
729b8851fccSafresh1                     (uint64_t)timebase_info.numer) / (uint64_t)timebase_info.denom;
730b8851fccSafresh1                 ts->tv_sec  = nanos / IV_1E9;
731b8851fccSafresh1                 ts->tv_nsec = nanos - ts->tv_sec * IV_1E9;
732b8851fccSafresh1                 return 0;
733b8851fccSafresh1             }
734b8851fccSafresh1 
735b8851fccSafresh1         default:
736b8851fccSafresh1             break;
737b8851fccSafresh1         }
738b8851fccSafresh1     }
739b8851fccSafresh1 
740b8851fccSafresh1     SETERRNO(EINVAL, LIB_INVARG);
741b8851fccSafresh1     return -1;
742b8851fccSafresh1 }
743c0dd97bfSafresh1 
744c0dd97bfSafresh1 #    define clock_gettime(clock_id, ts) th_clock_gettime((clock_id), (ts))
745c0dd97bfSafresh1 
746014083a1Safresh1 #  endif /* TIME_HIRES_CLOCK_GETTIME_EMULATION */
747b8851fccSafresh1 
748014083a1Safresh1 #  ifdef TIME_HIRES_CLOCK_GETRES_EMULATION
th_clock_getres(clockid_t clock_id,struct timespec * ts)749c0dd97bfSafresh1 static int th_clock_getres(clockid_t clock_id, struct timespec *ts) {
750b8851fccSafresh1     if (darwin_time_init() && timebase_info.denom) {
751b8851fccSafresh1         switch (clock_id) {
752b8851fccSafresh1         case CLOCK_REALTIME:
753b8851fccSafresh1         case CLOCK_MONOTONIC:
754b8851fccSafresh1             ts->tv_sec  = 0;
755b8851fccSafresh1             /* In newer kernels both the numer and denom are one,
756b8851fccSafresh1              * resulting in conversion factor of one, which is of
757b8851fccSafresh1              * course unrealistic. */
758b8851fccSafresh1             ts->tv_nsec = timebase_info.numer / timebase_info.denom;
759b8851fccSafresh1             return 0;
760b8851fccSafresh1         default:
761b8851fccSafresh1             break;
762b8851fccSafresh1         }
763b8851fccSafresh1     }
764b8851fccSafresh1 
765b8851fccSafresh1     SETERRNO(EINVAL, LIB_INVARG);
766b8851fccSafresh1     return -1;
767b8851fccSafresh1 }
768c0dd97bfSafresh1 
769c0dd97bfSafresh1 #    define clock_getres(clock_id, ts) th_clock_getres((clock_id), (ts))
770014083a1Safresh1 #  endif /* TIME_HIRES_CLOCK_GETRES_EMULATION */
771b8851fccSafresh1 
772014083a1Safresh1 #  ifdef TIME_HIRES_CLOCK_NANOSLEEP_EMULATION
th_clock_nanosleep(clockid_t clock_id,int flags,const struct timespec * rqtp,struct timespec * rmtp)773c0dd97bfSafresh1 static int th_clock_nanosleep(clockid_t clock_id, int flags,
774b8851fccSafresh1                            const struct timespec *rqtp,
775b8851fccSafresh1                            struct timespec *rmtp) {
776b8851fccSafresh1     if (darwin_time_init()) {
777b8851fccSafresh1         switch (clock_id) {
778b8851fccSafresh1         case CLOCK_REALTIME:
779b8851fccSafresh1         case CLOCK_MONOTONIC:
780b8851fccSafresh1             {
781b8851fccSafresh1                 uint64_t nanos = rqtp->tv_sec * IV_1E9 + rqtp->tv_nsec;
782b8851fccSafresh1                 int success;
783b8851fccSafresh1                 if ((flags & TIMER_ABSTIME)) {
784b8851fccSafresh1                     uint64_t back =
785b8851fccSafresh1                         timespec_init.tv_sec * IV_1E9 + timespec_init.tv_nsec;
786b8851fccSafresh1                     nanos = nanos > back ? nanos - back : 0;
787b8851fccSafresh1                 }
788b8851fccSafresh1                 success =
789b8851fccSafresh1                     mach_wait_until(mach_absolute_time() + nanos) == KERN_SUCCESS;
790b8851fccSafresh1 
791b8851fccSafresh1                 /* In the relative sleep, the rmtp should be filled in with
792b8851fccSafresh1                  * the 'unused' part of the rqtp in case the sleep gets
793b8851fccSafresh1                  * interrupted by a signal.  But it is unknown how signals
794b8851fccSafresh1                  * interact with mach_wait_until().  In the absolute sleep,
795b8851fccSafresh1                  * the rmtp should stay untouched. */
796b8851fccSafresh1                 rmtp->tv_sec  = 0;
797b8851fccSafresh1                 rmtp->tv_nsec = 0;
798b8851fccSafresh1 
799b8851fccSafresh1                 return success;
800b8851fccSafresh1             }
801b8851fccSafresh1 
802b8851fccSafresh1         default:
803b8851fccSafresh1             break;
804b8851fccSafresh1         }
805b8851fccSafresh1     }
806b8851fccSafresh1 
807b8851fccSafresh1     SETERRNO(EINVAL, LIB_INVARG);
808b8851fccSafresh1     return -1;
809b8851fccSafresh1 }
810c0dd97bfSafresh1 
811c0dd97bfSafresh1 #    define clock_nanosleep(clock_id, flags, rqtp, rmtp) \
812c0dd97bfSafresh1   th_clock_nanosleep((clock_id), (flags), (rqtp), (rmtp))
813c0dd97bfSafresh1 
814014083a1Safresh1 #  endif /* TIME_HIRES_CLOCK_NANOSLEEP_EMULATION */
815b8851fccSafresh1 
816b8851fccSafresh1 #endif /* PERL_DARWIN */
817b8851fccSafresh1 
8189f11ffb7Safresh1 /* The macOS headers warn about using certain interfaces in
8199f11ffb7Safresh1  * OS-release-ignorant manner, for example:
8209f11ffb7Safresh1  *
8219f11ffb7Safresh1  * warning: 'futimens' is only available on macOS 10.13 or newer
8229f11ffb7Safresh1  *       [-Wunguarded-availability-new]
8239f11ffb7Safresh1  *
8249f11ffb7Safresh1  * (ditto for utimensat)
8259f11ffb7Safresh1  *
8269f11ffb7Safresh1  * There is clang __builtin_available() *runtime* check for this.
8279f11ffb7Safresh1  * The gotchas are that neither __builtin_available() nor __has_builtin()
8289f11ffb7Safresh1  * are always available.
8299f11ffb7Safresh1  */
8309f11ffb7Safresh1 #ifndef __has_builtin
8319f11ffb7Safresh1 #  define __has_builtin(x) 0 /* non-clang */
8329f11ffb7Safresh1 #endif
8339f11ffb7Safresh1 #ifdef HAS_FUTIMENS
8349f11ffb7Safresh1 #  if defined(PERL_DARWIN) && __has_builtin(__builtin_available)
8359f11ffb7Safresh1 #    define FUTIMENS_AVAILABLE __builtin_available(macOS 10.13, *)
8369f11ffb7Safresh1 #  else
8379f11ffb7Safresh1 #    define FUTIMENS_AVAILABLE 1
8389f11ffb7Safresh1 #  endif
8399f11ffb7Safresh1 #else
8409f11ffb7Safresh1 #  define FUTIMENS_AVAILABLE 0
8419f11ffb7Safresh1 #endif
8429f11ffb7Safresh1 #ifdef HAS_UTIMENSAT
8439f11ffb7Safresh1 #  if defined(PERL_DARWIN) && __has_builtin(__builtin_available)
8449f11ffb7Safresh1 #    define UTIMENSAT_AVAILABLE __builtin_available(macOS 10.13, *)
8459f11ffb7Safresh1 #  else
8469f11ffb7Safresh1 #    define UTIMENSAT_AVAILABLE 1
8479f11ffb7Safresh1 #  endif
8489f11ffb7Safresh1 #else
8499f11ffb7Safresh1 #  define UTIMENSAT_AVAILABLE 0
8509f11ffb7Safresh1 #endif
8519f11ffb7Safresh1 
852b8851fccSafresh1 #include "const-c.inc"
853b8851fccSafresh1 
854b8851fccSafresh1 #if (defined(TIME_HIRES_NANOSLEEP)) || \
855b8851fccSafresh1     (defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME))
856b8851fccSafresh1 
857b8851fccSafresh1 static void
nanosleep_init(NV nsec,struct timespec * sleepfor,struct timespec * unslept)858b8851fccSafresh1 nanosleep_init(NV nsec,
859b8851fccSafresh1                     struct timespec *sleepfor,
860b8851fccSafresh1                     struct timespec *unslept) {
861b8851fccSafresh1   sleepfor->tv_sec = (Time_t)(nsec / NV_1E9);
862b8851fccSafresh1   sleepfor->tv_nsec = (long)(nsec - ((NV)sleepfor->tv_sec) * NV_1E9);
863b8851fccSafresh1   unslept->tv_sec = 0;
864b8851fccSafresh1   unslept->tv_nsec = 0;
865b8851fccSafresh1 }
866b8851fccSafresh1 
867b8851fccSafresh1 static NV
nsec_without_unslept(struct timespec * sleepfor,const struct timespec * unslept)868b8851fccSafresh1 nsec_without_unslept(struct timespec *sleepfor,
869b8851fccSafresh1                      const struct timespec *unslept) {
870b8851fccSafresh1     if (sleepfor->tv_sec >= unslept->tv_sec) {
871b8851fccSafresh1         sleepfor->tv_sec -= unslept->tv_sec;
872b8851fccSafresh1         if (sleepfor->tv_nsec >= unslept->tv_nsec) {
873b8851fccSafresh1             sleepfor->tv_nsec -= unslept->tv_nsec;
874b8851fccSafresh1         } else if (sleepfor->tv_sec > 0) {
875b8851fccSafresh1             sleepfor->tv_sec--;
876b8851fccSafresh1             sleepfor->tv_nsec += IV_1E9;
877b8851fccSafresh1             sleepfor->tv_nsec -= unslept->tv_nsec;
878b8851fccSafresh1         } else {
879b8851fccSafresh1             sleepfor->tv_sec = 0;
880b8851fccSafresh1             sleepfor->tv_nsec = 0;
881b8851fccSafresh1         }
882b8851fccSafresh1     } else {
883b8851fccSafresh1         sleepfor->tv_sec = 0;
884b8851fccSafresh1         sleepfor->tv_nsec = 0;
885b8851fccSafresh1     }
886b8851fccSafresh1     return ((NV)sleepfor->tv_sec) * NV_1E9 + ((NV)sleepfor->tv_nsec);
887b8851fccSafresh1 }
888b8851fccSafresh1 
889b8851fccSafresh1 #endif
890b8851fccSafresh1 
891014083a1Safresh1 /* In case Perl and/or Devel::PPPort are too old, minimally emulate
892014083a1Safresh1  * IS_SAFE_PATHNAME() (which looks for zero bytes in the pathname). */
893014083a1Safresh1 #ifndef IS_SAFE_PATHNAME
894eac174f2Safresh1 #  if PERL_VERSION_GE(5,12,0) /* Perl_ck_warner is 5.10.0 -> */
895014083a1Safresh1 #    ifdef WARN_SYSCALLS
896014083a1Safresh1 #      define WARNEMUCAT WARN_SYSCALLS /* 5.22.0 -> */
897014083a1Safresh1 #    else
898014083a1Safresh1 #      define WARNEMUCAT WARN_MISC
899014083a1Safresh1 #    endif
900014083a1Safresh1 #    define WARNEMU(opname) Perl_ck_warner(aTHX_ packWARN(WARNEMUCAT), "Invalid \\0 character in pathname for %s",opname)
901014083a1Safresh1 #  else
902014083a1Safresh1 #    define WARNEMU(opname) Perl_warn(aTHX_ "Invalid \\0 character in pathname for %s",opname)
903014083a1Safresh1 #  endif
904014083a1Safresh1 #  define IS_SAFE_PATHNAME(pv, len, opname) (((len)>1)&&memchr((pv), 0, (len)-1)?(SETERRNO(ENOENT, LIB_INVARG),WARNEMU(opname),FALSE):(TRUE))
905014083a1Safresh1 #endif
906014083a1Safresh1 
907b8851fccSafresh1 MODULE = Time::HiRes            PACKAGE = Time::HiRes
908b8851fccSafresh1 
909b8851fccSafresh1 PROTOTYPES: ENABLE
910b8851fccSafresh1 
911b8851fccSafresh1 BOOT:
912b8851fccSafresh1     {
913b8851fccSafresh1 #ifdef MY_CXT_KEY
914b8851fccSafresh1         MY_CXT_INIT;
915b8851fccSafresh1 #endif
916b8851fccSafresh1 #ifdef HAS_GETTIMEOFDAY
917b8851fccSafresh1         {
918b8851fccSafresh1             (void) hv_store(PL_modglobal, "Time::NVtime", 12,
919b8851fccSafresh1                             newSViv(PTR2IV(myNVtime)), 0);
920b8851fccSafresh1             (void) hv_store(PL_modglobal, "Time::U2time", 12,
921b8851fccSafresh1                             newSViv(PTR2IV(myU2time)), 0);
922b8851fccSafresh1         }
923b8851fccSafresh1 #endif
924b8851fccSafresh1 #if defined(PERL_DARWIN)
925014083a1Safresh1 #  if defined(USE_ITHREADS) && defined(PERL_DARWIN_MUTEX)
926b8851fccSafresh1         MUTEX_INIT(&darwin_time_mutex);
927b8851fccSafresh1 #  endif
928b8851fccSafresh1 #endif
929b8851fccSafresh1     }
930b8851fccSafresh1 
931b8851fccSafresh1 #if defined(USE_ITHREADS) && defined(MY_CXT_KEY)
932b8851fccSafresh1 
933b8851fccSafresh1 void
934b8851fccSafresh1 CLONE(...)
935b8851fccSafresh1     CODE:
936b8851fccSafresh1         MY_CXT_CLONE;
937b8851fccSafresh1 
938b8851fccSafresh1 #endif
939b8851fccSafresh1 
940b8851fccSafresh1 INCLUDE: const-xs.inc
941b8851fccSafresh1 
942b8851fccSafresh1 #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY)
943b8851fccSafresh1 
944b8851fccSafresh1 NV
945b8851fccSafresh1 usleep(useconds)
946b8851fccSafresh1     NV useconds
947b8851fccSafresh1     PREINIT:
948b8851fccSafresh1         struct timeval Ta, Tb;
949b8851fccSafresh1     CODE:
950b8851fccSafresh1         gettimeofday(&Ta, NULL);
951b8851fccSafresh1         if (items > 0) {
952b8851fccSafresh1             if (useconds >= NV_1E6) {
953b8851fccSafresh1                 IV seconds = (IV) (useconds / NV_1E6);
954b8851fccSafresh1                 /* If usleep() has been implemented using setitimer()
955b8851fccSafresh1                  * then this contortion is unnecessary-- but usleep()
956b8851fccSafresh1                  * may be implemented in some other way, so let's contort. */
957b8851fccSafresh1                 if (seconds) {
958b8851fccSafresh1                     sleep(seconds);
959b8851fccSafresh1                     useconds -= NV_1E6 * seconds;
960b8851fccSafresh1                 }
961b8851fccSafresh1             } else if (useconds < 0.0)
962c0dd97bfSafresh1                 croak("Time::HiRes::usleep(%" NVgf
963c0dd97bfSafresh1                       "): negative time not invented yet", useconds);
96456d68f1eSafresh1 
965b8851fccSafresh1             usleep((U32)useconds);
966b8851fccSafresh1         } else
967b8851fccSafresh1             PerlProc_pause();
96856d68f1eSafresh1 
969b8851fccSafresh1         gettimeofday(&Tb, NULL);
970b8851fccSafresh1 #  if 0
971b8851fccSafresh1         printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec);
972b8851fccSafresh1 #  endif
973b8851fccSafresh1         RETVAL = NV_1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec);
974b8851fccSafresh1 
975b8851fccSafresh1     OUTPUT:
976b8851fccSafresh1         RETVAL
977b8851fccSafresh1 
978b8851fccSafresh1 #  if defined(TIME_HIRES_NANOSLEEP)
979b8851fccSafresh1 
980b8851fccSafresh1 NV
981b8851fccSafresh1 nanosleep(nsec)
982b8851fccSafresh1     NV nsec
983b8851fccSafresh1     PREINIT:
984b8851fccSafresh1         struct timespec sleepfor, unslept;
985b8851fccSafresh1     CODE:
986b8851fccSafresh1         if (nsec < 0.0)
987c0dd97bfSafresh1             croak("Time::HiRes::nanosleep(%" NVgf
988c0dd97bfSafresh1                   "): negative time not invented yet", nsec);
989b8851fccSafresh1         nanosleep_init(nsec, &sleepfor, &unslept);
990b8851fccSafresh1         if (nanosleep(&sleepfor, &unslept) == 0) {
991b8851fccSafresh1             RETVAL = nsec;
992b8851fccSafresh1         } else {
993b8851fccSafresh1             RETVAL = nsec_without_unslept(&sleepfor, &unslept);
994b8851fccSafresh1         }
995b8851fccSafresh1     OUTPUT:
996b8851fccSafresh1         RETVAL
997b8851fccSafresh1 
998b8851fccSafresh1 #  else  /* #if defined(TIME_HIRES_NANOSLEEP) */
999b8851fccSafresh1 
1000b8851fccSafresh1 NV
1001b8851fccSafresh1 nanosleep(nsec)
1002b8851fccSafresh1     NV nsec
1003b8851fccSafresh1     CODE:
1004b8851fccSafresh1         PERL_UNUSED_ARG(nsec);
1005b8851fccSafresh1         croak("Time::HiRes::nanosleep(): unimplemented in this platform");
1006b8851fccSafresh1         RETVAL = 0.0;
1007b8851fccSafresh1     OUTPUT:
1008b8851fccSafresh1         RETVAL
1009b8851fccSafresh1 
1010b8851fccSafresh1 #  endif /* #if defined(TIME_HIRES_NANOSLEEP) */
1011b8851fccSafresh1 
1012b8851fccSafresh1 NV
1013b8851fccSafresh1 sleep(...)
1014b8851fccSafresh1     PREINIT:
1015b8851fccSafresh1         struct timeval Ta, Tb;
1016b8851fccSafresh1     CODE:
1017b8851fccSafresh1         gettimeofday(&Ta, NULL);
1018b8851fccSafresh1         if (items > 0) {
1019b8851fccSafresh1             NV seconds  = SvNV(ST(0));
1020b8851fccSafresh1             if (seconds >= 0.0) {
1021b8851fccSafresh1                 UV useconds = (UV)(1E6 * (seconds - (UV)seconds));
1022b8851fccSafresh1                 if (seconds >= 1.0)
1023b8851fccSafresh1                     sleep((U32)seconds);
1024b8851fccSafresh1                 if ((IV)useconds < 0) {
1025b8851fccSafresh1 #  if defined(__sparc64__) && defined(__GNUC__)
1026b8851fccSafresh1                     /* Sparc64 gcc 2.95.3 (e.g. on NetBSD) has a bug
1027b8851fccSafresh1                      * where (0.5 - (UV)(0.5)) will under certain
1028b8851fccSafresh1                      * circumstances (if the double is cast to UV more
1029b8851fccSafresh1                      * than once?) evaluate to -0.5, instead of 0.5. */
1030b8851fccSafresh1                     useconds = -(IV)useconds;
1031b8851fccSafresh1 #  endif /* #if defined(__sparc64__) && defined(__GNUC__) */
1032b8851fccSafresh1                     if ((IV)useconds < 0)
1033c0dd97bfSafresh1                         croak("Time::HiRes::sleep(%" NVgf
1034c0dd97bfSafresh1                               "): internal error: useconds < 0 (unsigned %" UVuf
1035c0dd97bfSafresh1                               " signed %" IVdf ")",
1036c0dd97bfSafresh1                               seconds, useconds, (IV)useconds);
1037b8851fccSafresh1                 }
1038b8851fccSafresh1                 usleep(useconds);
1039b8851fccSafresh1             } else
1040c0dd97bfSafresh1                 croak("Time::HiRes::sleep(%" NVgf
1041c0dd97bfSafresh1                       "): negative time not invented yet", seconds);
1042b8851fccSafresh1         } else
1043b8851fccSafresh1             PerlProc_pause();
104456d68f1eSafresh1 
1045b8851fccSafresh1         gettimeofday(&Tb, NULL);
1046b8851fccSafresh1 #  if 0
1047b8851fccSafresh1         printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec);
1048b8851fccSafresh1 #  endif
1049b8851fccSafresh1         RETVAL = (NV)(Tb.tv_sec-Ta.tv_sec)+0.000001*(NV)(Tb.tv_usec-Ta.tv_usec);
1050b8851fccSafresh1 
1051b8851fccSafresh1     OUTPUT:
1052b8851fccSafresh1         RETVAL
1053b8851fccSafresh1 
1054b8851fccSafresh1 #else  /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */
1055b8851fccSafresh1 
1056b8851fccSafresh1 NV
1057b8851fccSafresh1 usleep(useconds)
1058b8851fccSafresh1     NV useconds
1059b8851fccSafresh1     CODE:
1060b8851fccSafresh1         PERL_UNUSED_ARG(useconds);
1061b8851fccSafresh1         croak("Time::HiRes::usleep(): unimplemented in this platform");
1062b8851fccSafresh1         RETVAL = 0.0;
1063b8851fccSafresh1     OUTPUT:
1064b8851fccSafresh1         RETVAL
1065b8851fccSafresh1 
1066b8851fccSafresh1 #endif /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */
1067b8851fccSafresh1 
1068b8851fccSafresh1 #ifdef HAS_UALARM
1069b8851fccSafresh1 
1070b8851fccSafresh1 IV
1071b8851fccSafresh1 ualarm(useconds,uinterval=0)
1072b8851fccSafresh1     int useconds
1073b8851fccSafresh1     int uinterval
1074b8851fccSafresh1     CODE:
1075b8851fccSafresh1         if (useconds < 0 || uinterval < 0)
1076b8851fccSafresh1             croak("Time::HiRes::ualarm(%d, %d): negative time not invented yet", useconds, uinterval);
1077b8851fccSafresh1 #  if defined(HAS_SETITIMER) && defined(ITIMER_REAL)
1078b8851fccSafresh1         {
1079b8851fccSafresh1             struct itimerval itv;
1080b8851fccSafresh1             if (hrt_ualarm_itimero(&itv, useconds, uinterval)) {
1081b8851fccSafresh1                 /* To conform to ualarm's interface, we're actually ignoring
1082b8851fccSafresh1                    an error here.  */
1083b8851fccSafresh1                 RETVAL = 0;
1084b8851fccSafresh1             } else {
1085b8851fccSafresh1                 RETVAL = itv.it_value.tv_sec * IV_1E6 + itv.it_value.tv_usec;
1086b8851fccSafresh1             }
1087b8851fccSafresh1         }
1088b8851fccSafresh1 #  else
1089b8851fccSafresh1         if (useconds >= IV_1E6 || uinterval >= IV_1E6)
1090c0dd97bfSafresh1             croak("Time::HiRes::ualarm(%d, %d): useconds or uinterval"
1091c0dd97bfSafresh1                   " equal to or more than %" IVdf,
1092c0dd97bfSafresh1                   useconds, uinterval, IV_1E6);
109356d68f1eSafresh1 
1094b8851fccSafresh1         RETVAL = ualarm(useconds, uinterval);
1095b8851fccSafresh1 #  endif
1096b8851fccSafresh1 
1097b8851fccSafresh1     OUTPUT:
1098b8851fccSafresh1         RETVAL
1099b8851fccSafresh1 
1100b8851fccSafresh1 NV
1101b8851fccSafresh1 alarm(seconds,interval=0)
1102b8851fccSafresh1     NV seconds
1103b8851fccSafresh1     NV interval
1104b8851fccSafresh1     CODE:
1105b8851fccSafresh1         if (seconds < 0.0 || interval < 0.0)
1106c0dd97bfSafresh1             croak("Time::HiRes::alarm(%" NVgf ", %" NVgf
1107c0dd97bfSafresh1                   "): negative time not invented yet", seconds, interval);
110856d68f1eSafresh1 
1109b8851fccSafresh1         {
1110b8851fccSafresh1             IV iseconds = (IV)seconds;
1111b8851fccSafresh1             IV iinterval = (IV)interval;
1112b8851fccSafresh1             NV fseconds = seconds - iseconds;
1113b8851fccSafresh1             NV finterval = interval - iinterval;
1114b8851fccSafresh1             IV useconds, uinterval;
1115b8851fccSafresh1             if (fseconds >= 1.0 || finterval >= 1.0)
1116c0dd97bfSafresh1                 croak("Time::HiRes::alarm(%" NVgf ", %" NVgf
1117c0dd97bfSafresh1                       "): seconds or interval too large to split correctly",
1118c0dd97bfSafresh1                       seconds, interval);
111956d68f1eSafresh1 
1120b8851fccSafresh1             useconds = IV_1E6 * fseconds;
1121b8851fccSafresh1             uinterval = IV_1E6 * finterval;
1122b8851fccSafresh1 #  if defined(HAS_SETITIMER) && defined(ITIMER_REAL)
1123b8851fccSafresh1             {
1124b8851fccSafresh1                 struct itimerval nitv, oitv;
1125b8851fccSafresh1                 nitv.it_value.tv_sec = iseconds;
1126b8851fccSafresh1                 nitv.it_value.tv_usec = useconds;
1127b8851fccSafresh1                 nitv.it_interval.tv_sec = iinterval;
1128b8851fccSafresh1                 nitv.it_interval.tv_usec = uinterval;
1129b8851fccSafresh1                 if (setitimer(ITIMER_REAL, &nitv, &oitv)) {
1130b8851fccSafresh1                     /* To conform to alarm's interface, we're actually ignoring
1131b8851fccSafresh1                        an error here.  */
1132b8851fccSafresh1                     RETVAL = 0;
1133b8851fccSafresh1                 } else {
1134b8851fccSafresh1                     RETVAL = oitv.it_value.tv_sec + ((NV)oitv.it_value.tv_usec) / NV_1E6;
1135b8851fccSafresh1                 }
1136b8851fccSafresh1             }
1137b8851fccSafresh1 #  else
1138b8851fccSafresh1             if (iseconds || iinterval)
1139c0dd97bfSafresh1                 croak("Time::HiRes::alarm(%" NVgf ", %" NVgf
1140c0dd97bfSafresh1                       "): seconds or interval equal to or more than 1.0 ",
1141c0dd97bfSafresh1                       seconds, interval);
114256d68f1eSafresh1 
1143b8851fccSafresh1             RETVAL = (NV)ualarm( useconds, uinterval ) / NV_1E6;
1144b8851fccSafresh1 #  endif
1145b8851fccSafresh1         }
1146b8851fccSafresh1 
1147b8851fccSafresh1     OUTPUT:
1148b8851fccSafresh1         RETVAL
1149b8851fccSafresh1 
115056d68f1eSafresh1 #else /* #ifdef HAS_UALARM */
1151b8851fccSafresh1 
1152b8851fccSafresh1 int
1153b8851fccSafresh1 ualarm(useconds,interval=0)
1154b8851fccSafresh1     int useconds
1155b8851fccSafresh1     int interval
1156b8851fccSafresh1     CODE:
1157b8851fccSafresh1         PERL_UNUSED_ARG(useconds);
1158b8851fccSafresh1         PERL_UNUSED_ARG(interval);
1159b8851fccSafresh1         croak("Time::HiRes::ualarm(): unimplemented in this platform");
1160b8851fccSafresh1         RETVAL = -1;
1161b8851fccSafresh1     OUTPUT:
1162b8851fccSafresh1         RETVAL
1163b8851fccSafresh1 
1164b8851fccSafresh1 NV
1165b8851fccSafresh1 alarm(seconds,interval=0)
1166b8851fccSafresh1     NV seconds
1167b8851fccSafresh1     NV interval
1168b8851fccSafresh1     CODE:
1169b8851fccSafresh1         PERL_UNUSED_ARG(seconds);
1170b8851fccSafresh1         PERL_UNUSED_ARG(interval);
1171b8851fccSafresh1         croak("Time::HiRes::alarm(): unimplemented in this platform");
1172b8851fccSafresh1         RETVAL = 0.0;
1173b8851fccSafresh1     OUTPUT:
1174b8851fccSafresh1         RETVAL
1175b8851fccSafresh1 
1176b8851fccSafresh1 #endif /* #ifdef HAS_UALARM */
1177b8851fccSafresh1 
1178b8851fccSafresh1 #ifdef HAS_GETTIMEOFDAY
1179b8851fccSafresh1 
1180b8851fccSafresh1 void
1181b8851fccSafresh1 gettimeofday()
1182b8851fccSafresh1     PREINIT:
1183b8851fccSafresh1         struct timeval Tp;
1184b8851fccSafresh1     PPCODE:
1185b8851fccSafresh1         int status;
1186b8851fccSafresh1         status = gettimeofday (&Tp, NULL);
1187b8851fccSafresh1         if (status == 0) {
1188*e0680481Safresh1             if (GIMME_V == G_LIST) {
1189b8851fccSafresh1                 EXTEND(sp, 2);
1190b8851fccSafresh1                 PUSHs(sv_2mortal(newSViv(Tp.tv_sec)));
1191b8851fccSafresh1                 PUSHs(sv_2mortal(newSViv(Tp.tv_usec)));
1192b8851fccSafresh1             } else {
1193b8851fccSafresh1                 EXTEND(sp, 1);
1194b8851fccSafresh1                 PUSHs(sv_2mortal(newSVnv(Tp.tv_sec + (Tp.tv_usec / NV_1E6))));
1195b8851fccSafresh1             }
1196b8851fccSafresh1         }
1197b8851fccSafresh1 
1198b8851fccSafresh1 NV
1199b8851fccSafresh1 time()
1200b8851fccSafresh1     PREINIT:
1201b8851fccSafresh1         struct timeval Tp;
1202b8851fccSafresh1     CODE:
1203b8851fccSafresh1         int status;
1204b8851fccSafresh1         status = gettimeofday (&Tp, NULL);
1205b8851fccSafresh1         if (status == 0) {
1206b8851fccSafresh1             RETVAL = Tp.tv_sec + (Tp.tv_usec / NV_1E6);
1207b8851fccSafresh1         } else {
1208b8851fccSafresh1             RETVAL = -1.0;
1209b8851fccSafresh1         }
1210b8851fccSafresh1     OUTPUT:
1211b8851fccSafresh1         RETVAL
1212b8851fccSafresh1 
1213b8851fccSafresh1 #endif /* #ifdef HAS_GETTIMEOFDAY */
1214b8851fccSafresh1 
1215b8851fccSafresh1 #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER)
1216b8851fccSafresh1 
1217b8851fccSafresh1 #  define TV2NV(tv) ((NV)((tv).tv_sec) + 0.000001 * (NV)((tv).tv_usec))
1218b8851fccSafresh1 
1219b8851fccSafresh1 void
1220b8851fccSafresh1 setitimer(which, seconds, interval = 0)
1221b8851fccSafresh1     int which
1222b8851fccSafresh1     NV seconds
1223b8851fccSafresh1     NV interval
1224b8851fccSafresh1     PREINIT:
1225b8851fccSafresh1         struct itimerval newit;
1226b8851fccSafresh1         struct itimerval oldit;
1227b8851fccSafresh1     PPCODE:
1228b8851fccSafresh1         if (seconds < 0.0 || interval < 0.0)
1229c0dd97bfSafresh1             croak("Time::HiRes::setitimer(%" IVdf ", %" NVgf ", %" NVgf
1230c0dd97bfSafresh1                   "): negative time not invented yet",
1231c0dd97bfSafresh1                   (IV)which, seconds, interval);
1232b8851fccSafresh1         newit.it_value.tv_sec  = (IV)seconds;
1233b8851fccSafresh1         newit.it_value.tv_usec =
1234b8851fccSafresh1           (IV)((seconds  - (NV)newit.it_value.tv_sec)    * NV_1E6);
1235b8851fccSafresh1         newit.it_interval.tv_sec  = (IV)interval;
1236b8851fccSafresh1         newit.it_interval.tv_usec =
1237b8851fccSafresh1           (IV)((interval - (NV)newit.it_interval.tv_sec) * NV_1E6);
1238b8851fccSafresh1         /* on some platforms the 1st arg to setitimer is an enum, which
1239b8851fccSafresh1          * causes -Wc++-compat to complain about passing an int instead
1240b8851fccSafresh1          */
12419f11ffb7Safresh1         GCC_DIAG_IGNORE_STMT(-Wc++-compat);
1242b8851fccSafresh1         if (setitimer(which, &newit, &oldit) == 0) {
1243b8851fccSafresh1             EXTEND(sp, 1);
1244b8851fccSafresh1             PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_value))));
1245*e0680481Safresh1             if (GIMME_V == G_LIST) {
1246b8851fccSafresh1                 EXTEND(sp, 1);
1247b8851fccSafresh1                 PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_interval))));
1248b8851fccSafresh1             }
1249b8851fccSafresh1         }
12509f11ffb7Safresh1         GCC_DIAG_RESTORE_STMT;
1251b8851fccSafresh1 
1252b8851fccSafresh1 void
1253b8851fccSafresh1 getitimer(which)
1254b8851fccSafresh1     int which
1255b8851fccSafresh1     PREINIT:
1256b8851fccSafresh1         struct itimerval nowit;
1257b8851fccSafresh1     PPCODE:
1258b8851fccSafresh1         /* on some platforms the 1st arg to getitimer is an enum, which
1259b8851fccSafresh1          * causes -Wc++-compat to complain about passing an int instead
1260b8851fccSafresh1          */
12619f11ffb7Safresh1         GCC_DIAG_IGNORE_STMT(-Wc++-compat);
1262b8851fccSafresh1         if (getitimer(which, &nowit) == 0) {
1263b8851fccSafresh1             EXTEND(sp, 1);
1264b8851fccSafresh1             PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_value))));
1265*e0680481Safresh1             if (GIMME_V == G_LIST) {
1266b8851fccSafresh1                 EXTEND(sp, 1);
1267b8851fccSafresh1                 PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_interval))));
1268b8851fccSafresh1             }
1269b8851fccSafresh1         }
12709f11ffb7Safresh1         GCC_DIAG_RESTORE_STMT;
1271b8851fccSafresh1 
1272b8851fccSafresh1 #endif /* #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER) */
1273b8851fccSafresh1 
1274014083a1Safresh1 #if defined(TIME_HIRES_UTIME)
1275014083a1Safresh1 
1276014083a1Safresh1 I32
1277014083a1Safresh1 utime(accessed, modified, ...)
1278014083a1Safresh1 PROTOTYPE: $$@
1279014083a1Safresh1     PREINIT:
1280014083a1Safresh1         SV* accessed;
1281014083a1Safresh1         SV* modified;
1282014083a1Safresh1         SV* file;
1283014083a1Safresh1 
1284014083a1Safresh1         struct timespec utbuf[2];
1285014083a1Safresh1         struct timespec *utbufp = utbuf;
1286014083a1Safresh1         int tot;
1287014083a1Safresh1 
1288014083a1Safresh1     CODE:
1289014083a1Safresh1         accessed = ST(0);
1290014083a1Safresh1         modified = ST(1);
1291014083a1Safresh1         items -= 2;
1292014083a1Safresh1         tot = 0;
1293014083a1Safresh1 
1294014083a1Safresh1         if ( accessed == &PL_sv_undef && modified == &PL_sv_undef )
1295014083a1Safresh1             utbufp = NULL;
1296014083a1Safresh1         else {
1297014083a1Safresh1             if (SvNV(accessed) < 0.0 || SvNV(modified) < 0.0)
1298c0dd97bfSafresh1                 croak("Time::HiRes::utime(%" NVgf ", %" NVgf
1299c0dd97bfSafresh1                       "): negative time not invented yet",
1300c0dd97bfSafresh1                           SvNV(accessed), SvNV(modified));
1301014083a1Safresh1             Zero(&utbuf, sizeof utbuf, char);
1302b46d8ef2Safresh1 
1303014083a1Safresh1             utbuf[0].tv_sec = (Time_t)SvNV(accessed);  /* time accessed */
1304b46d8ef2Safresh1             utbuf[0].tv_nsec = (long)(
1305b46d8ef2Safresh1                 (SvNV(accessed) - (NV)utbuf[0].tv_sec)
1306b46d8ef2Safresh1                 * NV_1E9 + (NV)0.5);
1307b46d8ef2Safresh1 
1308014083a1Safresh1             utbuf[1].tv_sec = (Time_t)SvNV(modified);  /* time modified */
1309b46d8ef2Safresh1             utbuf[1].tv_nsec = (long)(
1310b46d8ef2Safresh1                 (SvNV(modified) - (NV)utbuf[1].tv_sec)
1311b46d8ef2Safresh1                 * NV_1E9 + (NV)0.5);
1312014083a1Safresh1         }
1313014083a1Safresh1 
1314014083a1Safresh1         while (items > 0) {
1315014083a1Safresh1             file = POPs; items--;
1316014083a1Safresh1 
1317014083a1Safresh1             if (SvROK(file) && GvIO(SvRV(file)) && IoIFP(sv_2io(SvRV(file)))) {
1318014083a1Safresh1 	        int fd =  PerlIO_fileno(IoIFP(sv_2io(file)));
13199f11ffb7Safresh1                 if (fd < 0) {
1320014083a1Safresh1                     SETERRNO(EBADF,RMS_IFI);
13219f11ffb7Safresh1                 } else {
1322014083a1Safresh1 #  ifdef HAS_FUTIMENS
13239f11ffb7Safresh1                     if (FUTIMENS_AVAILABLE) {
13249f11ffb7Safresh1                         if (futimens(fd, utbufp) == 0) {
1325014083a1Safresh1                             tot++;
13269f11ffb7Safresh1                         }
13279f11ffb7Safresh1                     } else {
1328014083a1Safresh1                         croak("futimens unimplemented in this platform");
13299f11ffb7Safresh1                     }
13309f11ffb7Safresh1 #  else  /* HAS_FUTIMENS */
13319f11ffb7Safresh1                     croak("futimens unimplemented in this platform");
13329f11ffb7Safresh1 #  endif /* HAS_FUTIMENS */
13339f11ffb7Safresh1                 }
1334014083a1Safresh1             }
1335014083a1Safresh1             else {
1336014083a1Safresh1 #  ifdef HAS_UTIMENSAT
13379f11ffb7Safresh1                 if (UTIMENSAT_AVAILABLE) {
1338014083a1Safresh1                     STRLEN len;
1339014083a1Safresh1                     char * name = SvPV(file, len);
1340014083a1Safresh1                     if (IS_SAFE_PATHNAME(name, len, "utime") &&
13419f11ffb7Safresh1                         utimensat(AT_FDCWD, name, utbufp, 0) == 0) {
134256d68f1eSafresh1 
1343014083a1Safresh1                         tot++;
13449f11ffb7Safresh1                     }
13459f11ffb7Safresh1                 } else {
13469f11ffb7Safresh1                     croak("utimensat unimplemented in this platform");
13479f11ffb7Safresh1                 }
1348014083a1Safresh1 #  else  /* HAS_UTIMENSAT */
1349014083a1Safresh1                 croak("utimensat unimplemented in this platform");
1350014083a1Safresh1 #  endif /* HAS_UTIMENSAT */
1351014083a1Safresh1             }
1352014083a1Safresh1         } /* while items */
1353014083a1Safresh1         RETVAL = tot;
1354014083a1Safresh1 
1355014083a1Safresh1     OUTPUT:
1356014083a1Safresh1         RETVAL
1357014083a1Safresh1 
1358014083a1Safresh1 #else  /* #if defined(TIME_HIRES_UTIME) */
1359014083a1Safresh1 
1360014083a1Safresh1 I32
1361014083a1Safresh1 utime(accessed, modified, ...)
1362014083a1Safresh1     CODE:
1363014083a1Safresh1         croak("Time::HiRes::utime(): unimplemented in this platform");
1364014083a1Safresh1         RETVAL = 0;
1365014083a1Safresh1     OUTPUT:
1366014083a1Safresh1         RETVAL
1367014083a1Safresh1 
1368014083a1Safresh1 #endif /* #if defined(TIME_HIRES_UTIME) */
1369014083a1Safresh1 
1370b8851fccSafresh1 #if defined(TIME_HIRES_CLOCK_GETTIME)
1371b8851fccSafresh1 
1372b8851fccSafresh1 NV
1373b8851fccSafresh1 clock_gettime(clock_id = CLOCK_REALTIME)
1374c0dd97bfSafresh1     clockid_t clock_id
1375b8851fccSafresh1     PREINIT:
1376b8851fccSafresh1         struct timespec ts;
1377b8851fccSafresh1         int status = -1;
1378b8851fccSafresh1     CODE:
1379b8851fccSafresh1 #  ifdef TIME_HIRES_CLOCK_GETTIME_SYSCALL
1380b8851fccSafresh1         status = syscall(SYS_clock_gettime, clock_id, &ts);
1381b8851fccSafresh1 #  else
1382b8851fccSafresh1         status = clock_gettime(clock_id, &ts);
1383b8851fccSafresh1 #  endif
1384b8851fccSafresh1         RETVAL = status == 0 ? ts.tv_sec + (NV) ts.tv_nsec / NV_1E9 : -1;
1385b8851fccSafresh1 
1386b8851fccSafresh1     OUTPUT:
1387b8851fccSafresh1         RETVAL
1388b8851fccSafresh1 
1389b8851fccSafresh1 #else  /* if defined(TIME_HIRES_CLOCK_GETTIME) */
1390b8851fccSafresh1 
1391b8851fccSafresh1 NV
1392b8851fccSafresh1 clock_gettime(clock_id = 0)
1393c0dd97bfSafresh1     clockid_t clock_id
1394b8851fccSafresh1     CODE:
1395b8851fccSafresh1         PERL_UNUSED_ARG(clock_id);
1396b8851fccSafresh1         croak("Time::HiRes::clock_gettime(): unimplemented in this platform");
1397b8851fccSafresh1         RETVAL = 0.0;
1398b8851fccSafresh1     OUTPUT:
1399b8851fccSafresh1         RETVAL
1400b8851fccSafresh1 
1401b8851fccSafresh1 #endif /*  #if defined(TIME_HIRES_CLOCK_GETTIME) */
1402b8851fccSafresh1 
1403b8851fccSafresh1 #if defined(TIME_HIRES_CLOCK_GETRES)
1404b8851fccSafresh1 
1405b8851fccSafresh1 NV
1406b8851fccSafresh1 clock_getres(clock_id = CLOCK_REALTIME)
1407c0dd97bfSafresh1     clockid_t clock_id
1408b8851fccSafresh1     PREINIT:
1409b8851fccSafresh1         int status = -1;
1410b8851fccSafresh1         struct timespec ts;
1411b8851fccSafresh1     CODE:
1412b8851fccSafresh1 #  ifdef TIME_HIRES_CLOCK_GETRES_SYSCALL
1413b8851fccSafresh1         status = syscall(SYS_clock_getres, clock_id, &ts);
1414b8851fccSafresh1 #  else
1415b8851fccSafresh1         status = clock_getres(clock_id, &ts);
1416b8851fccSafresh1 #  endif
1417b8851fccSafresh1         RETVAL = status == 0 ? ts.tv_sec + (NV) ts.tv_nsec / NV_1E9 : -1;
1418b8851fccSafresh1 
1419b8851fccSafresh1     OUTPUT:
1420b8851fccSafresh1         RETVAL
1421b8851fccSafresh1 
1422b8851fccSafresh1 #else  /* if defined(TIME_HIRES_CLOCK_GETRES) */
1423b8851fccSafresh1 
1424b8851fccSafresh1 NV
1425b8851fccSafresh1 clock_getres(clock_id = 0)
1426c0dd97bfSafresh1     clockid_t clock_id
1427b8851fccSafresh1     CODE:
1428b8851fccSafresh1         PERL_UNUSED_ARG(clock_id);
1429b8851fccSafresh1         croak("Time::HiRes::clock_getres(): unimplemented in this platform");
1430b8851fccSafresh1         RETVAL = 0.0;
1431b8851fccSafresh1     OUTPUT:
1432b8851fccSafresh1         RETVAL
1433b8851fccSafresh1 
1434b8851fccSafresh1 #endif /*  #if defined(TIME_HIRES_CLOCK_GETRES) */
1435b8851fccSafresh1 
1436b8851fccSafresh1 #if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME)
1437b8851fccSafresh1 
1438b8851fccSafresh1 NV
1439b8851fccSafresh1 clock_nanosleep(clock_id, nsec, flags = 0)
1440c0dd97bfSafresh1     clockid_t clock_id
1441b8851fccSafresh1     NV  nsec
1442b8851fccSafresh1     int flags
1443b8851fccSafresh1     PREINIT:
1444b8851fccSafresh1         struct timespec sleepfor, unslept;
1445b8851fccSafresh1     CODE:
1446b8851fccSafresh1         if (nsec < 0.0)
1447c0dd97bfSafresh1             croak("Time::HiRes::clock_nanosleep(..., %" NVgf
1448c0dd97bfSafresh1                   "): negative time not invented yet", nsec);
1449b8851fccSafresh1         nanosleep_init(nsec, &sleepfor, &unslept);
1450b8851fccSafresh1         if (clock_nanosleep(clock_id, flags, &sleepfor, &unslept) == 0) {
1451b8851fccSafresh1             RETVAL = nsec;
1452b8851fccSafresh1         } else {
1453b8851fccSafresh1             RETVAL = nsec_without_unslept(&sleepfor, &unslept);
1454b8851fccSafresh1         }
1455b8851fccSafresh1     OUTPUT:
1456b8851fccSafresh1         RETVAL
1457b8851fccSafresh1 
1458b8851fccSafresh1 #else  /* if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) */
1459b8851fccSafresh1 
1460b8851fccSafresh1 NV
1461b8851fccSafresh1 clock_nanosleep(clock_id, nsec, flags = 0)
1462c0dd97bfSafresh1     clockid_t clock_id
1463b8851fccSafresh1     NV  nsec
1464b8851fccSafresh1     int flags
1465b8851fccSafresh1     CODE:
1466b8851fccSafresh1         PERL_UNUSED_ARG(clock_id);
1467b8851fccSafresh1         PERL_UNUSED_ARG(nsec);
1468b8851fccSafresh1         PERL_UNUSED_ARG(flags);
1469b8851fccSafresh1         croak("Time::HiRes::clock_nanosleep(): unimplemented in this platform");
1470b8851fccSafresh1         RETVAL = 0.0;
1471b8851fccSafresh1     OUTPUT:
1472b8851fccSafresh1         RETVAL
1473b8851fccSafresh1 
1474b8851fccSafresh1 #endif /*  #if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) */
1475b8851fccSafresh1 
1476b8851fccSafresh1 #if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC)
1477b8851fccSafresh1 
1478b8851fccSafresh1 NV
1479b8851fccSafresh1 clock()
1480b8851fccSafresh1     PREINIT:
1481b8851fccSafresh1         clock_t clocks;
1482b8851fccSafresh1     CODE:
1483b8851fccSafresh1         clocks = clock();
1484b8851fccSafresh1         RETVAL = clocks == (clock_t) -1 ? (clock_t) -1 : (NV)clocks / (NV)CLOCKS_PER_SEC;
1485b8851fccSafresh1 
1486b8851fccSafresh1     OUTPUT:
1487b8851fccSafresh1         RETVAL
1488b8851fccSafresh1 
1489b8851fccSafresh1 #else  /* if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC) */
1490b8851fccSafresh1 
1491b8851fccSafresh1 NV
1492b8851fccSafresh1 clock()
1493b8851fccSafresh1     CODE:
1494b8851fccSafresh1         croak("Time::HiRes::clock(): unimplemented in this platform");
1495b8851fccSafresh1         RETVAL = 0.0;
1496b8851fccSafresh1     OUTPUT:
1497b8851fccSafresh1         RETVAL
1498b8851fccSafresh1 
1499b8851fccSafresh1 #endif /*  #if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC) */
1500b8851fccSafresh1 
1501b8851fccSafresh1 void
1502b8851fccSafresh1 stat(...)
1503b8851fccSafresh1 PROTOTYPE: ;$
1504b8851fccSafresh1     PREINIT:
1505b8851fccSafresh1         OP fakeop;
1506b8851fccSafresh1         int nret;
1507b8851fccSafresh1     ALIAS:
1508b8851fccSafresh1         Time::HiRes::lstat = 1
1509b8851fccSafresh1     PPCODE:
1510b8851fccSafresh1         XPUSHs(sv_2mortal(newSVsv(items == 1 ? ST(0) : DEFSV)));
1511b8851fccSafresh1         PUTBACK;
1512b8851fccSafresh1         ENTER;
1513b8851fccSafresh1         PL_laststatval = -1;
1514b8851fccSafresh1         SAVEOP();
1515b8851fccSafresh1         Zero(&fakeop, 1, OP);
1516b8851fccSafresh1         fakeop.op_type = ix ? OP_LSTAT : OP_STAT;
1517b8851fccSafresh1         fakeop.op_ppaddr = PL_ppaddr[fakeop.op_type];
1518eac174f2Safresh1         fakeop.op_flags = GIMME_V == G_LIST ? OPf_WANT_LIST :
1519b8851fccSafresh1             GIMME_V == G_SCALAR ? OPf_WANT_SCALAR : OPf_WANT_VOID;
1520b8851fccSafresh1         PL_op = &fakeop;
1521b8851fccSafresh1         (void)fakeop.op_ppaddr(aTHX);
1522b8851fccSafresh1         SPAGAIN;
1523b8851fccSafresh1         LEAVE;
1524b8851fccSafresh1         nret = SP+1 - &ST(0);
1525b8851fccSafresh1         if (nret == 13) {
1526b8851fccSafresh1             UV atime = SvUV(ST( 8));
1527b8851fccSafresh1             UV mtime = SvUV(ST( 9));
1528b8851fccSafresh1             UV ctime = SvUV(ST(10));
1529b8851fccSafresh1             UV atime_nsec;
1530b8851fccSafresh1             UV mtime_nsec;
1531b8851fccSafresh1             UV ctime_nsec;
1532b8851fccSafresh1             hrstatns(&atime_nsec, &mtime_nsec, &ctime_nsec);
1533b8851fccSafresh1             if (atime_nsec)
1534b8851fccSafresh1                 ST( 8) = sv_2mortal(newSVnv(atime + (NV) atime_nsec / NV_1E9));
1535b8851fccSafresh1             if (mtime_nsec)
1536b8851fccSafresh1                 ST( 9) = sv_2mortal(newSVnv(mtime + (NV) mtime_nsec / NV_1E9));
1537b8851fccSafresh1             if (ctime_nsec)
1538b8851fccSafresh1                 ST(10) = sv_2mortal(newSVnv(ctime + (NV) ctime_nsec / NV_1E9));
1539b8851fccSafresh1         }
1540b8851fccSafresh1         XSRETURN(nret);
1541