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,",&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