diff options
Diffstat (limited to 'ext/Time-HiRes')
-rw-r--r-- | ext/Time-HiRes/.gitignore | 2 | ||||
-rw-r--r-- | ext/Time-HiRes/Changes | 886 | ||||
-rw-r--r-- | ext/Time-HiRes/HiRes.pm | 591 | ||||
-rw-r--r-- | ext/Time-HiRes/HiRes.xs | 1257 | ||||
-rw-r--r-- | ext/Time-HiRes/Makefile.PL | 879 | ||||
-rw-r--r-- | ext/Time-HiRes/fallback/const-c.inc | 393 | ||||
-rw-r--r-- | ext/Time-HiRes/fallback/const-xs.inc | 88 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/aix.pl | 18 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/dec_osf.pl | 3 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/dynixptx.pl | 5 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/irix.pl | 6 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/linux.pl | 2 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/sco.pl | 4 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/solaris.pl | 10 | ||||
-rw-r--r-- | ext/Time-HiRes/hints/svr4.pl | 4 | ||||
-rw-r--r-- | ext/Time-HiRes/t/HiRes.t | 783 | ||||
-rw-r--r-- | ext/Time-HiRes/typemap | 313 |
17 files changed, 5244 insertions, 0 deletions
diff --git a/ext/Time-HiRes/.gitignore b/ext/Time-HiRes/.gitignore new file mode 100644 index 0000000000..a89cf3eadf --- /dev/null +++ b/ext/Time-HiRes/.gitignore @@ -0,0 +1,2 @@ +*.inc +/xdefine diff --git a/ext/Time-HiRes/Changes b/ext/Time-HiRes/Changes new file mode 100644 index 0000000000..ffec191c1e --- /dev/null +++ b/ext/Time-HiRes/Changes @@ -0,0 +1,886 @@ +Revision history for the Perl extension Time::HiRes. + +1.9719 [2009-01-04] + - As with QNX, Haiku has the API of interval timers but not + the implementation (bleadperl change #34630), hence skip + the tests, via David Mitchell. + +1.9718 [2008-12-31] + - .xs code cleanup from Albert Dvornik + - in the #39 and #40 do not do us I did, mixing alarm() and + sleep(). Now instead spin until enough time has passed. + +1.9717 [2008-12-30] + - Skip the tests added in 1.9716 (#39, #40) if there's no subsecond + alarm capability, like with the older subsecond alarm tests + +1.9716 [2008-12-26] + - Change documentation to agree with reality: there are + no interval timers in Win32. + - Address [rt.cpan.org #35899] (problem in subsecond sleeps), + add two tests to guard against this problem + - Address [rt.cpan.org #36600] 'Division by zero' failure in test suite + - Address [rt.cpan.org #37340] [PATCH] Address timer process in test + - Address [rt.cpan.org#40311 ] bad implementation of hrt_usleep + with TIME_HIRES_NANOSLEEP + +1.9715 [2008-04-08] + - Silly me: Makefile.PL does need to accept arguments other than mine. + Some testing frameworks obviously do this. + - Add retrying for tests 34..37, which are the most commonly + failing tests. If this helps, consider extending the retry + framework to all the tests. [Inspired by Slaven Rezic, + [rt.cpan.org #34711] Occasional failures of test 35 or 36 (FreeBSD)] + +1.9714 [2008-04-07] + - Under Perl 5.6.* NVgf needs to be "g", reported by Zefram, + it seems that ppport.h 3.13 gets this wrong. + - remove the check in Makefile.PL for 5.7.2, shouldn't be + (a) necessary (b) relevant + - add logic to Makefile.PL to skip configure/write Makefile + step if the "xdefine" file already exists, indicating that + the configure step has already been done, one can still + force (re)configure by "perl Makefile.PL configure", + or of course by "make clean && perl Makefile.PL". + +1.9713 [2008-04-04] + - for alarm() and ualarm() [Perl] prefer setitimer() [C] + instead of ualarm() [C] since ualarm() [C] cannot portably + (and standards-compliantly) be used for more than 999_999 + microseconds (rt.cpan.org #34655) + - it seems that HP-UX has started (at least in 11.31 ia64) + #defining the CLOCK_REALTIME et alia (instead of having + them just as enums) + - document all the diagnostics + +1.9712 [2008-02-09] + - move the sub tick in the test file back to where it used to be + - in the "consider upgrading" message recommend at least Perl 5.8.8 + and make the message to appear only for 5.8.0 since 5.8.1 and + later have the problem fixed + - VOS tweak for Makefile (core perl change #33259) + - since the test #17 seems to fail often, relax its limits a bit + +1.9711 [2007-11-29] + - lost VMS test skippage from Craig Berry + - reformat the test code a little + +1.9710 [2007-11-29] + - I got the sense of the QNX test the wrong way in an attempt + to generalize it for future + +1.9709 [2007-11-28] + - casting fixes from Robin Barker for g++ and 64bitint + - in QNX skip the itimer tests because though the API + is there, the implementation isn't, from Matt Kraai + - raise the dead man timer to 180 seconds for really + slow/busy systems + - elaborate the UTF-8 locale warning from Makefile.PL + +1.9708 [2007-10-05] + - [rt.cpan.org #29747]: Build failure with perl 5.005_05 + Fixed by regenerating the ppport.h using Devel::PPPort 3.13. + +1.9707 [2007-02-27] + - t/HiRes.t failed in Perl 5.6.2, + "action is not of type POSIX::SigAction at t/HiRes.t line 318", + reported and fixed by Anton Berezin, the reason was faulty + use of sigaction() when restoring the old action. + +1.9706 [2007-02-25] + - with bleadperl in VMS the HiRes.t overrun the maximum number + of deferred signals because the libc SIGALRM was not strong + enough to interrupt select(), and select() got restarted every + time, solution is to use POSIX::SigAction if available. + A fix from Craig Berry (not 100% there, but helps). + - allow for more measuring noise for ualarm() tests 35..37 + +1.9705 [2007-02-06] + - nanosleep() and clock_nanosleep() detection and use were + quite broken; in Linux -lrt needed; fixes from Zefram + - [internal] slightly cleaner building of $DEFINE in Makefile.PL, + should avoid double/conflicting -D flags + +1.9704 [2007-01-01] + - allow 10% of slop in test #14 (testing difference between + CORE::time() and Time::HiRes::time()), there seem to be often + transient failures from Perl smoke builds on this test + - small pod tweaks + +1.9703 [2006-12-08] + - use int main(int argc, char **argv) consistently in Makefile.PL, + should help with + [rt.cpan.org #23868] nanosleep not detected under Mac OS 10.3.9 starting with Time::HiRes 1.96 + - if someone still has the locale-broken Perl 5.8.0, + suggest that they upgrade their Perl + +1.9702 [2006-12-06] + - restore the -DATLEASTFIVEOHOHFIVE, Win32 needed it still + +1.9701 [2006-12-04] + - upgrade to ppport.h 3.10_02 + - remove the -DATLEASTFIVEOHOHFIVE + - use the ppport.h PL_ppaddr, PL_statcache, PL_laststatval + - use the ppport.h aTHXR for calling Perl stat() + - switch into four-digit version since 2.0 is coming up + awfully fast but not feeling like a major rewrite + +1.97 [2006-11-30] + - 1.95 broke building in Win32 (since pp_stat is not exported), + figured out how to call an op directly in 5.005 (use Perl_ppaddr + instead of PL_ppaddr) + - backport to Perl 5.004_05 (requires using statcache + and laststatval instead of PL_statcache and PL_laststatval) + (also checked to work in 5.005_04, 5.6.1, and 5.8.8 with threads) + +1.96 [2006-11-30] + - 1.95 broke builds for threaded Perls, rt.cpan.org tickets: + [rt.cpan.org #23694] Time::HiRes fails tests on Solaris and Perl 5.6.1 + [rt.cpan.org #23712] Time-HiRes 1.95 Fails make on AIX 5.2 with Perl 5.8.8 + [rt.cpan.org #23730] Time::HiRes 1.95 fails make on MacOS X 10.3.9/perl 5.8.8 + - use main() prototype consistently in Makefile.PL + +1.95 [2006-11-29] + - integrate core change #29180: Silence VC++ compiler warnings + from Steve Hay + - do not use PL_ppaddr in stat() because that is not available + in Perl 5.005_04 + - regenerate fallback/*.inc for older Perls without + ExtUtils::Constant because of d_hires_stat, resolves + [rt.cpan.org #23694] Time::HiRes fails tests on Solaris and Perl 5.6.1 + - Make Makefile.PL more defensive against false PERL_CORE + +1.94 [2006-10-16] + - file timestamps oddities seen: the atime and mtime + can be out of sync (modify first and read second can leave + atime < mtime) and mtime can be subsecond while atime is not. + So make the test more forgiving. + +1.93 [2006-10-15] + - the ualarm() tests (34-37) assumed that ualarm(N) + could never alarm in less than N seconds, widened + the acceptable relative range to 0.9..1.5. Addresses + [rt.cpan.org #22090] and [rt.cpan.org #22091]. + + - skip the stat() tests in cygwin and win32, because + if run on FAT the timestamp granularity is only 2 seconds. + Any good way to detect (cygwin or win32) whether we are + being run on NTFS or anywhere with better timestamps? + Addresses [rt.cpan.org #22089] and [rt.cpan.org #22098]. + +1.92 [2006-10-13] + - scan for subsecond resolution timestamps in struct stat, + some known possibilities: + + (1) struct timespec st_atimespec; + st_atimespec.tv_nsec; + (2) time_t st_atime; + long st_atimensec; + (3) time_t st_atime; + int st_atime_n; + (4) timestruc_t st_atim; + st_atim.tv_nsec + (5) time_t st_atime; + int st_uatime; + + If something like this is found, one can do + + use Time::HiRes; + my @stat = Time::HiRes::stat(); + + or even override the standard stat(): + + use Time::HiRes qw(stat); + + to get the stat() timestamps + + my ($atime, $mtime, $ctime) = @stat[8, 9, 10]; + + with subsecond resolution (assuming both the operating + system and the filesystem support that kind of thing). + + Contributions for more systems (especially non-UNIX, + e.g. but not limited to: Win32, VMS, OS/2) gladly accepted. + (also more UNIX variants welcome: HP-UX? IRIX?) + + Thanks to H.Merijn Brand, John Peacock, and Craig + Berry for brave beta testing. + +1.91 [2006-09-29] + - ualarm() in SuSE 10.1 was overflowing after ~4.2 seconds, + possibly due to a glibc bug/feature (suspected overflow at + 2**32 microseconds?), workaround by using the setitimer() + implementation of ualarm() if either useconds or + interval > 999_999 (this case seems to vary between systems: + are useconds more than 999_999 for ualarm() defined or not) + Added more ualarm() tests to catch various overflow points, + hopefully no problems in various platforms. + (The problem report by Mark Seger and Jon Paul Sullivan of HP.) + +1.90 [2006-08-22] + - tweak still needed for Const64(), from Jerry Hedden + - get a freshly generated ppport.h + - update Copyright years + +1.89 [2006-08-22] + - Const64() already appends an 'LL' (or i64), so provide LL and i64 + forms for the IV_1E[679] (effects Win32 and Cygwin), reported by + Jerry Hedden. + - the Changes entry for 1.88 talked about [IN]V_1[679], + missing the 'E'. + +1.88 [2006-08-21] + - clean up the g++ warnings in HiRes.xs, all of them + about mixing integer and floating point, introduce + constants IV_1E[679] and NV_1E[679] + +1.87 [2006-02-13] + - [rt.cpan.org #17442] 'make test' frequently fails under + Cygwin Perl v5.8.8, reported and patched by J. R. Hedden + (two race condition bugs in the END block in the case the + main process dies before the timer process, unearthed + by a bug in Cygwin ualarm) + +1.86 [2005-12-17] + - HiRes.t:s/ok 32/ok 33/, from Dominic Dunlop + - tighten up the clock() test marginally by requiring non-negative + - clock_nanosleep() and clock() doc tweaks + +1.85 [2005-12-16] + - the interface to clock_nanosleep() is more natural + when it is like (hires) time() (instead of like nanosleep), + and the .xs implementation of clock_nanosleep() in 1.84 + was broken anyway + - the semantics of clock() are not quite so silly as I thought, + but still somewhat odd, documented as such + - additional enhancements to the clock() documentation + - add test for clock_nanosleep() (I cannot test this + since none of my systems have the function) + - add test for clock() + +1.84 [2005-12-16] + - add clock() which returns the processor time in + (floating point) seconds since an arbitrary era + - add clock_nanosleep() which suspends the current + thread until either absolute time or for relative time + - [rt.cpan.org #16486] printf missing value in HiRes.t + - add constants CLOCKS_PER_SEC, CLOCK_SOFTTIME, TIMER_ABSTIME + - tiny typo fixes + +1.83 [2005-11-19] + - has_symbol() was wrong since e.g. ITIMER_VIRTUAL is exported + via @EXPORT_OK even when it is not available. This is heinous. + @EXPORT_OK should be determined at Makefile.PL time. + - be more lenient is testing clock_gettime(): allow more slop, + and retry up to three times, sleeping a random nap between + the retries + - human months are one-based (noticed by Anton Berezin) + +1.82 [2005-10-06] + - CLOCK_REALTIME is an enum value (of the clockid_t enum) + in HP-UX (and might be so elsewhere, too), debugged by + H. Merijn Brand + - include const-c.inc as late as possible (from Randy Kobes, + [rt.cpan.org #15552] to avoid undefined usleep() on Win32 + +1.81 [2005-11-05] + - try to be more robust and consistent in the detection of + CLOCK_REALTIME and ITIMER_VIRTUAL in HiRes.t: the proper + way is + + sub has_symbol { + my $symbol = shift; + eval 'import Time::HiRes qw($symbol)'; + return 0 unless $@ eq ''; + return exists ${"Time::HiRes::$symbol"}; + } + + and then use + + &FOO_BAR + + in the test. All these moves are needed because + + 1) one cannot directly do eval 'Time::HiRes::FOO_BAR' + because FOO_BAR might have a true value of zero + (or in the general case an empty string or even undef) + + 2) In case FOO_BAR is not available in this platform, + &FOO_BAR avoids the bareword warning + + - wait more (1.5 seconds instead of 0.1) for the CLOCK_REALTIME test + but expect the 'customary' slop of 0.20 instead of 0.25 + - fixed inside a comment HAS_POLL -> TIME_HIRES_NANOSLEEP + - at the end of HiRest.t tell how close we were to termination + +1.80 [2005-11-04] + - Gisle noticed a mistake (using HAS_NANOSLEEP) in 1.79 + +1.79 [2005-11-03] + - try nanosleep for emulating usleep -- may help in some weird + embedded realtime places which have nanosleep but neither usleep + nor select nor poll (doesn't have to be weird embedded realtime + place, though -- in many places usleep is nanosleep anyway) + - try poll for emulating usleep -- this may help some obscure/old + SVR4 places that have neither usleep nor select + - a redundant test guard in HiRes.t + +1.78 [2005-11-03] + - ITIMER_VIRTUAL detection in HiRes.t had problems (that we cannot + in the general case fail already at 'use' phase is suboptimal) + - fixes to the documentation of clock_gettime() and clock_getres() + +1.77 [2005-11-03] + - add support for the POSIX clock_gettime() and clock_getres(), + if available, either as library calls or as syscalls + - be more defensive about missing functionality: break out + early (during 'use') if no e.g. clock_getres() is available, + and protect our back by trapping those cases also in HiRes.xs + - the test added in 1.76 could cause an endless loop e.g. in Solaris, + due to mixing of sleep() and alarm() (bad programmer, no cookie!) + +1.76 [2005-10-22] + - testing for nanosleep had wrong logic which caused nanosleep + to become undefined for e.g. Mac OS X + - added a test for a core dump that was introduced by Perl 5.8.0 + safe signals and was fixed for the time of 5.8.1 (one report of + the core dump was [perl #20920]), the test skipped pre-5.8.1. + - *cough* s/unanosleep/nanosleep/g; *cough* + +1.75 [2005-10-18] + - installation patch from Gisle Aas: in Perls 5.8.x and later + use MakeMaker INSTALLDIRS value of 'perl' instead of 'site'. + +1.74 [2005-09-19] + - [cpan #14608] Solaris 8 perl 5.005_03 File::Spec module does not have method rel2abs + (the workaround is not to use rel2abs, should not be necessary) + - [cpan #14642] U2time wrongly exported on the C API + (patch supplied by the reporter, SALVA@cpan.org) + - add release dates to Changes + +1.73 [2005-08-16] + - Time::HiRes::nanosleep support for Solaris [PATCH] + (POSIX::uname() not available if building with core perl, + from Gisle Aas, via perl5-porters, perl change #25295) + +1.72 [2005-07-01] + - going back to the 1.68 loader setup (using DynaLoader) + since too many weird things starting breaking + - fix a typo in José Auguste-Etienne's name + +1.71 [2005-06-28] + - a thinko in the nanosleep() detection + - move more changes stuff from the README to Changes + - add -w to the Makefile.PL + +1.70 [2005-06-26] + - oops in 1.69 about @ISA (not affecting anything but silly) + - add copyright 2005 to HiRes.pm + - add copyright and license to HiRes.xs + - add copyrights 2003, 2004, 2005 to README + +1.69 [2005-06-25] + - actually run a test for nanosleep + (if there is no $Config{d_nanosleep}) since e.g. in AIX 4.2 + it seems that one can link in nanosleep() but then calling + it fails instantly and sets errno to ENOSYS (Not implemented). + This may be fixable in the AIX case by figuring out the right + (realtime POSIX?) libs and whatnot, but in the general case + running a real test case is better. (Of course, this change + will no doubt run into portability problems because of the + execution step...) Note that because of hysterical raisins + most Perls do NOT have $Config{d_nanosleep} (scanning for + it by Configure would in many platforms require linking in + things like -lrt, which would in many platforms be a bad idea + for Perl itself). + (from José Auguste-Etienne) + - support XSLoader also since it's much faster + (from Alexey Tourbin) + - add SEE ALSO (BSD::Resource and Time::TAI64) + +1.68 [2005-05-14] + - somehow 1.67 had a lot of doubled lines (a major cut-and-paste + error suspected), but miraculously it still worked since the + doubling took place below the __END__ token + - undef Pause() before defining it to avoid redefinition warnings + during compilation in case perl.h had already defined Pause() + (part of perl change #24271) + - minor doc tweaks + +1.67 [2005-05-04] + - (internal) don't ignore the return value of gettimeofday() + - (external) return undef or an empty if the C gettimeofday() fails + (affects Time::HiRes gettimeofday() and the hires time()) + +1.66 [2004-12-19] + - add nanosleep() + - fix the 'hierachy' typo in Makefile.PL [rt.cpan.org #8492] + - should now build in Solaris [rt.cpan.org #7165] (since 1.64) + - should now build in Cygwin [rt.cpan.org #7535] (since 1.64) + - close also [rt.cpan.org #5933] "Time::HiRes::time does not + pick up time adjustments like ntp" since ever reproducing it + (and therefore verifying a possible fix) in the same environment + has become rather unlikely + +1.65 [2004-09-18] + - one should not mix u?alarm and sleep (the tests modified + by 1.65, #12 and #13, hung in Solaris), now we just busy + loop executing an empty block + - in the documentation underline the unspecificity of mixing + sleeps and alarms + - small spelling fixes + +1.64 [2004-09-16] + - regenerate ppport.h with Devel::PPPort 3.03, + now the MY_CXT_CLONE is defined in ppport.h, + we no more need to do that. + + - the test #12 would often hang in sigsuspend() (at least that's + where Mac OS X' ktrace shows it hanging). With the sleep()s + changed to sleep(1)s, the tests still pass but no hang after + a few hundred repeats. + +1.63 [2004-09-01] + - Win32 and any ithread build: ppport.h didn't define + MY_CXT_CLONE, which seems to be a Time-HiRes-ism. + +1.62 [2004-08-31] + - Skip testing if under PERL_CORE and Time::HiRes has not + been Configured (from Marcus Holland-Moritz, core change + #23246) + - Use ppport.h generated by Devel::PPPort 3.01, + allowing cutting away our own portability code. + - Don't use $ENV{PERL_CORE} for < 5.6.0. + - Don't use "for my $i" for <= 5.003. + - Don't use Pause() for <= 5.003. + - Can't use newSVpvf for <= 5.003. + (most of the changes from Marcus) + +1.61 [2004-08-21] + - Win32: reset reading from the performance counters every + five minutes to better track wall clock time (thanks to + PC timers being often quite bad), should help long-running + programs. + +1.60 [2004-08-15] + - Win32: Patch from Steve Hay + [PATCH] Re: [perl #30755] [Win32] Different results from Time::HiRes::gettimeofdayunder the debugger + to [perl #30755] reported by Nigel Sandever + + - Cygwin: Use the Win32 recalibration code also in Cygwin if the + <w32api/windows.h> APIs are available. Cygwin testing by + Yitzchak Scott-Thoennes. + + - Solaris: use -lposix4 to get nanosleep for Solaris 2.6, + after that keep using -lrt, patch from Alan Burlison, + bug reported in [cpan #7165] + +1.59 [2004-04-08] + - Change the Win32 recalibration limit to 0.5 seconds and tweak + the documentation to blather less about the gory details of the + Win32 implementation and more about the complications in general + of meddling with the system clock. + +1.58 [2004-04-08] + - Document the 1.57 change better. + +1.57 [2004-07-04] + - Win32/Cygwin/MinGW: if the performance counter drifts by more + than two seconds from the system clock (due to ntp adjustments, + for example), recalibrate our internal counter: from Jan Dubois, + based on [cpan #5933] by Jerry D. Hedden. + +1.56 [2004-29-02] + - Give a clearer message if the tests timeout (perl change #22253) + - Don't use /tmp or its moral equivalents (perl bug #15036, + perl change #22258) + +1.55 [2004-01-14] + - Windows: mingw32 patch from Mike Pomraning (use Perl's Const64() + instead of VC-specific i64 suffix) + +1.54 [2003-12-31] + - Solaris: like Tru64 (dec_osf) also Solaris need -lrt for nanosleep + +1.53 [2003-12-30] + - Windows: higher resolution time() by using the Windows + performance counter API, from Jan Dubois and Anton Shcherbinin. + The exact new higher resolution depends on the hardware, + but it should be quite a bit better than using the basic + Windows timers. + +1.52 [2003-10-28] + - In AIX (v?) with perl 5.6.1 the HiRes.t can hang after + the subtest 18. No known analysis nor fix, but added + an alarm (that requires fork() and alarm()) to the test. + +1.51 [2003-09-22] + - doc tweaks from mjd (perl change #20456) + - NCR MP-RAS hints file added (svr4.pl) (perl change #21249) + +1.50 [2003-08-02] + - add a message (for non-core builds) to Makefile.PL about + the LC_ALL=C workaround + - &Time::HiRes::d_nanosleep was broken (perl change #20131) + - the nanosleep() probe was broken (perl change #20061) + - use existence instead of definedness for feature probes + (perl change #20043) + - MPE/iX tweak (perl change #20042) + - do not use HAS_NANOSLEEP (perl change #19898) + +1.49 [2003-06-23] + - UVuf for non-IVSIZE platforms (from Keiichiro Nagano) + - OS/2 can always mix subsecond sleeps with signals + (part of perl change #19789) + +1.48 [2003-06-04] + - workaround for buggy gcc 2.95.3 in openbsd/sparc64 + (perl change #19592) + +1.47 [2003-05-03] + - do not use -lrt in Linux (from March Lehmann, perl change #19449) + - unnecessary (nanosleep is in libc anyway) + - harmful (-lrt slows down execution) + - incompatible (with many distributions' pthreads) + +1.46 [2003-04-25] + - do not create files in blib directories under core + (perl change #19160, from rgs) + - detypo s/VTLARM/VTARLM/ (perl change #19328, from mjd) + +1.45 [2003-04-01] + - guarantee that $xdefine in HiRes.t is always defined + (perl change #19109, from IlyaZ) + - a cleaner way to detect PERL_CORE (perl change #19111, + from IlyaZ) + +1.44 [2003-03-30] + - add hints/irix.pl to turn off overly POSIX flags that + cause hide struct timespec to be hidden (and compilation + to fail) (bleadperl change #19085) + - documentation tweaks + +1.43 [2003-03-11] + - add c:/temp to the list of temp directories to probe + so that cygwin (and win*?) builds are happy. This was + needed at least in my cygwin 1.3.20/w2k setup. + +1.42 [2003-01-07] + - modernize the constants code (from Nicholas Clark) + +1.41 [2003-01-03] + - At some point the ability to figure our the correct incdir + for EXTERN.h (either a core perl build, or an installed perl) + had broken (which lead into all test compiles failing with + a core perl build, but thanks to the robustness of Makefile.PL + nothing of this was visible). The brokenness seemed to be + caused by $ENV{PERL_CORE} not being on for core builds? + Now stole a trick from the Encode that sets $ENV{PERL_CORE} + right, and both styles of build should work again. + +1.40 [2003-01-03] + - Nicholas Clark noticed that the my_catdir() emulation function + was broken (which means that we didn't really work for Perls + 5.002 and 5.003) + - inspired by fixing the above made the whole Makefile.PL -w + and strict clean + - tightened up the Makefile.PL output, less whitespace + +1.39 [2003-10-20] + - fix from Craig Berry for better building in VMS with PERL_CORE + +1.38 [2003-10-13] + - no functional changes + - move lib/Time/HiRes.pm as Hires.pm + - libraries scanning was slightly broken (always scanned + for a library even when $Config{libs} already had it) + +1.37 [2003-09-23] + - Ray Zimmerman ran into a race condition in Mac OS X. + A 0.01-second alarm fired before the test expected. + The test first slept indefinitely (blocking for signals) + and only after that tested for the signal having been sent. + Since the signal had already been sent, the test #12 never + completed. The solution: test first, then block. + - default to being silent on all probing attempts, set the + environment variable VERBOSE to a true value to see the + details (the probing command and the possible errors) + +1.36 [2003-09-12] + - do not clear MAN3PODS in Makefile.PL (Radoslaw Zielinski) + - INSTALLDIRS => 'perl' missing which means that Time::HiRes + cannot be upgraded from CPAN to override the 5.8.0 version + (Guido A. Ostkamp) + - Time::HiRes 1.35 could not be dropped as-is to bleadperl + because the include directories did not adjust themselves + if $ENV{PERL_CORE} (Hugo van der Sanden) + - add documentation about the restart of select() under alarm() + +1.35 [2003-08-24] + - small documentation tweaks + + +1.34 [2003-08-22] + - better VMS operation (Craig Berry) + +1.33 [2003-08-20] + - our time machine is accelerating: now works with Perl 5.004_01 + (tried with 5.003_07 and 5.002 but I get segmentation faults + from running the Makefile.PL with those in Tru64 4.0D) + +1.32 [2003-08-20] + - backward compatibility (pre-5.6.0) tweaks: + - no XSLoader in 5.00503, use DynaLoader instead + - no SvPV_nolen, either + - no PerlProc_pause(), either + - now tested with 5.00404 and 5.00503 + - Makefile.PL requires 5.00404 (no more 5.002) + - use nanosleep instead of usleep, if it is available (Wilson Snyder) + (this means that one can mix subsecond sleeps with alarms) + - because of nanosleep we probe for -lrt and -lposix4 + - the existence of getitimer/nanosleep/setitimer/ualarm/usleep + is available by exportable constants Time::HiRes::d_func + (since older Perl do not have them in %Config, and even + 5.8.0 does not probe for nanosleep) + +1.31 [2003-08-19] + - backward compatibility (pre-5.6.1) tweaks: + - define NV if no NVTYPE + - define IVdf if needed (note: the Devel::PPPort + in 5.8.0 does not try hard hard enough since + the IVSIZE might not be defined) + - define NVgf if needed + - grab the typemap from 5.8.0 for the NV stuff + + 1.31 and 1.32 add more backward compatibility (now all the way + back to Perl 5.00404), and using nanosleep() (if available) for + subsecond sleeps. + +1.30 [2003-08-16] + + - release 1.29_02 as 1.30 + + 1.30 adds all the changes made during the Perl 5.6->5.7->5.8 + development cycle. Most notably portability across platforms has been + enhanced, and the interval timers (setitimer, getitimer) have been + added. Note that the version of Time::HiRes that is included in Perl + 5.8.0 calls itself 1.20_00, but it is equivalent to this Time::HiRes + version. Note also that in 1.30 Wegscheid turns over the maintenance + to Jarkko Hietaniemi. + +1.29_02 [2003-08-16] + + - fix a silly unclosed comment typo in HiRes.xs + - document and export REALTIME_REALPROF (Solaris) + +1.29_01 [2003-08-16] + + - only getitimer(ITIMER_REAL) available in Cygwin and Win32 + (need to patch this also in Perl 5.[89]) + - remove CVS revision log from HiRes.xs + +1.29_00 [2003-08-14] + + The following numbered patches refer to the Perl 5.7 changes, + you can browse them at http://public.activestate.com/cgi-bin/perlbrowse + + - 17558: Add #!./perl to the .t + - 17201: linux + usemorebits fix, from Rafael Garcia-Suarez + - 16198: political correctness, from Simon Cozens + - 15857: doc tweaks, from Jarkko Hietaniemi + - 15593: optimization in .xs, from Paul Green + - 14892: pod fixes, from Robin Barker + - 14100: VOS fixes, from Paul Green + - 13422: XS segfault, from Marc Lehmann + - 13378: whether select() gets restarted on signals, depends + - 13354: timing constraints, again, from Andy Dougherty + - 13278: can't do subsecond alarms with ualarm; + break out early if alarms do not seem to be working + - 13266: test relaxation (cygwin gets lower hires + times than lores ones) + - 12846: protect against high load, from Jarkko Hietaniemi + - 12837: HiRes.t VMS tweak, from Craig A. Berry + - 12797: HiRes.t VMS tweak, from Charles Lane + - 12769: HiRes.t VMS tweak, from Craig A. Berry + - 12744: gcc vs MS 64-bit constant syntax, from Nick Ing-Simmons + - 12722: VMS ualarm for VMS without ualarm, from Charles Lane + - 12692: alarm() ain't gonna work if ualarm() ain't, + from Gurusamy Sarathy + - 12680: minor VMS tweak, from Charles Lane + - 12617: don't try to print ints as IVs, from Jarkko Hietaniemi + - 12609: croak on negative time, from Jarkko Hietaniemi + - 12595: Cygwin rounds up for time(), from Jarkko Hietaniemi + - 12594: MacOS Classic timeofday, from Chris Nandor + - 12473: allow for more than one second for sleep() and usleep() + - 12458: test tuning, relax timing constraints, + from Jarkko Hietaniemi + - 12449: make sleep() and usleep() to return the number + of seconds and microseconds actually slept (analogously + with the builtin sleep()), also make usleep() croak if + asked for more than 1_000_000 useconds, from Jarkko Hietaniemi + - 12366: Time::HiRes for VMS pre-7.0, from Charles Lane + - 12199: do not use ftime on Win32, from Gurusamy Sarathy + - 12196: use ftime() on Win32, from Artur Bergman + - 12184: fix Time::HiRes gettimeofday() on Win32, from Gurusamy Sarathy + - 12105: use GetSystemTime() on Win32, from Artur Bergman + - 12060: explain the 1e9 seconds problem, from Jarkko Hietaniemi + - 11901: UNICOS sloppy division, from Jarkko Hietaniemi + - 11797: problem in HiRes.t, from John P. Linderman + - 11414: prototype from Time::HiRes::sleep(), from Abhijit Menon-Sen + - 11409: Time::HiRes qw(sleep) failed, from Abhijit Menon-Sen + - 11270: dynix/ptx 4.5.2 hints fix, from Peter Prymmer + - 11032: VAX VMS s/div/lib\$ediv/ fix, from Peter Prymmer + - 11011: VAX VMS s/qdiv/div/ fix, from Peter Prymmer + - 10953: SCO OpenServer 5.0.5 requires an explicit -lc for usleep(), + from Jonathan Stowe + - 10942: MPE/IX test tweaks, from Mark Bixby + - 10784: unnecessary pod2man calls, from Andy Dougherty + - 10354: ext/ + -Wall, from Doug MacEachern + - 10320: fix the BOOT section to call myU2time correctly + - 10317: correct casting for AIX< from H. Merijn Brand + - 10119: document that the core time() may be rounding, not truncating + - 10118: test fix, from John Peacock + - 9988: long =item, from Robin Barker + - 9714: correct test output + - 9708: test also the scalar aspect of getitimer() + - 9705: Add interval timers (setitimer, getitimer) + - 9692: do not require at least 5.005 using XS + + The following changes were made on top of the changes + made for Time::HiRes during the Perl 5.7 development + cycle that culminated in the release of Perl 5.8.0. + + - add "require 5.005" to the Makefile.PL + - remove the REVISION section (CVS log) from HiRes.pm + - add jhi's copyright alongside Douglas' + - move HiRes.pm to lib/Time/ + - move HiRes.t to t/ + - modify HiRes.t to use $ENV{PERL_CORE} + - modify the original Time::HiRes version 1.20 Makefile.PL + to work both with Perl 5.8.0 and the new code with pre-5.8.0 + Perls (tried with 5.6.1) + - tiny tweaks and updates in README and TODO + - bump the VERSION to 1.29 + +1.20 Wed Feb 24 21:30 1999 + - make our usleep and ualarm substitutes into hrt_usleep + and hrt_ualarm. This helps static links of Perl with other + packages that also have usleep, etc. From + Ilya Zakharevich <ilya@math.ohio-state.edu> + - add C API stuff. From Joshua Pritikin + <joshua.pritikin@db.com> + - VMS Makefile.PL fun. From pvhp@forte.com (Peter Prymmer) + - hopefully correct "-lc" fix for SCO. + - add PPD stuff + + 1.20 adds a platform neutral set of C accessible routines if you are + running 5.005+. All other changes are packaging changes and build + fixes(?) for statically linked Perl, SCO, and VMS. + +1.19 Tue Sep 29 22:30 1998 + - put VMS gettimeofday() in. Patch is from Sebastian Bazley + <seb@stian.demon.co.uk> + - change GIMME_V to GIMME to help people with older versions of + Perl. + - fix Win32 version of gettimeofday(). It didn't affect anything, + but it confuses people reading the code when the return value + is backwards (0 is success). + - fix Makefile.PL (more) so that detection of gettimeofday is + more correct. + + 1.19 has better VMS support. + +1.18 Mon Jul 6 22:40 1998 + - add usleep() for Win32. + - fix Makefile.PL to fix reported HP/UX feature where unresolved + externals still cause an executable to be generated (though no + x bit set). Thanks to David Kozinn for report and explanation. + Problems with the fix are mine :) + + 1.18 has limited Win32 support (no ualarm). Added usleep for Win32. + Probably buggy. I'm sure I'll hear. + +1.17 Wed Jul 1 20:10 1998 + - fix setitimer calls so microseconds is not more than 1000000. + Hp/UX 9 doesn't like that. Provided by Roland B Robert, PhD. + - make Win32. We only get gettimeofday (the select hack doesn't + seem to work on my Win95 system). + - fix test 4 on 01test.t. add test to see if time() and + Time::HiRes::time() are close. + +1.16 Wed Nov 12 21:05 1997 + - add missing EXTEND in new gettimeofday scalar code. + + 1.16+ should be closer to building out of the box on Linux. Thanks + to Gisle Aas for patches, and the ualarm equivalent using setitimer. + + If your underlying operating system doesn't implement ualarm(), then + a fake using setitimer() will be made. If the OS is missing usleep(), + a fake one using select() will be made. If a fake can't be made for + either ualarm() or usleep(), then the corresponding Perl function will + not be available. If the OS is missing gettimeofday(), you will get + unresolved externals, either at link- or run-time. + + This is an improvement; the package used to not even build if + you were missing any of these bits. Roderick Schertler + + <roderick@argon.org> did all the conditional compilation stuff, + look at HiRes.pm and the test suites; it's good educational reading. + +1.15 Mon Nov 10 21:30 1997 + - HiRes.pm: update pod. Provided by Gisle Aas. + - HiRes.xs: if gettimeofday() called in scalar context, do + something more useful than before. Provided by Gisle Aas. + - README: tell of xsubpp '-nolinenumber' woes. thanks to + Edward Henigin <ed@texas.net> for pointing out the problem. + +1.14 Wed Nov 5 9:40 1997 + - Makefile.PL: look for setitimer + - HiRes.xs: if missing ualarm, but we have setitimer, make up + our own setitimer. These were provided by Gisle Aas. + +1.13 Tue Nov 4 23:30 1997 + - Makefile.PL: fix autodetect mechanism to do try linking in addition + to just compiling; should fix Linux build problem. Fix was provided + by Gisle Aas. + +1.12 Sun Oct 12 12:00:00 1997 + - Makefile.PL: set XSOPT to '-nolinenumbers' to work around xsubpp bug; + you may need to comment this back out if you have an older xsubpp. + - HiRes.xs: set PROTOTYPES: DISABLE + +1.11 Fri Sep 05 16:00:00 1997 + - Makefile.PL: + Had some line commented out that shouldn't have been (testing + remnants) + - README: + Previous version was corrupted. + +1.10 Thu May 22 20:20:00 1997 + - HiRes.xs, HiRes.pm, t/*: + - only compile what we have OS support for (or can + fake with select()) + - only test what we compiled + - gross improvement to the test suite + - fix EXPORT_FAIL. + This work was all done by Roderick Schertler + <roderick@argon.org>. If you run Linux or + one of the other ualarm-less platforms, and you like this + module, let Roderick know; without him, it still wouldn't + be working on those boxes... + - Makefile.PL: figure out what routines the OS has and + only build what we need. These bits were written by Jarkko + Hietaniemi <jhi@iki.fi>. Again, gratitude is due... + +1.02 Mon Dec 30 08:00:00 1996 + - HiRes.pm: update documentation to say what to do when missing + ualarm() and friends. + - README: update to warn that ualarm() and friends need to exist + +1.01 Fri Oct 17 08:00:00 1996 + - Makefile.PL: make XSPROTOARGS => '-noprototyopes' + - HiRes.pm: put blank line between __END__ and =head1 so that + pod2man works. + +1.00 Tue Sep 03 13:00:00 1996 + - original version; created by h2xs 1.16 diff --git a/ext/Time-HiRes/HiRes.pm b/ext/Time-HiRes/HiRes.pm new file mode 100644 index 0000000000..da4d45a96e --- /dev/null +++ b/ext/Time-HiRes/HiRes.pm @@ -0,0 +1,591 @@ +package Time::HiRes; + +use strict; +use vars qw($VERSION $XS_VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD); + +require Exporter; +require DynaLoader; + +@ISA = qw(Exporter DynaLoader); + +@EXPORT = qw( ); +@EXPORT_OK = qw (usleep sleep ualarm alarm gettimeofday time tv_interval + getitimer setitimer nanosleep clock_gettime clock_getres + clock clock_nanosleep + CLOCK_HIGHRES CLOCK_MONOTONIC CLOCK_PROCESS_CPUTIME_ID + CLOCK_REALTIME CLOCK_SOFTTIME CLOCK_THREAD_CPUTIME_ID + CLOCK_TIMEOFDAY CLOCKS_PER_SEC + ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF + TIMER_ABSTIME + d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer + d_nanosleep d_clock_gettime d_clock_getres + d_clock d_clock_nanosleep + stat + ); + +$VERSION = '1.9719'; +$XS_VERSION = $VERSION; +$VERSION = eval $VERSION; + +sub AUTOLOAD { + my $constname; + ($constname = $AUTOLOAD) =~ s/.*:://; + # print "AUTOLOAD: constname = $constname ($AUTOLOAD)\n"; + die "&Time::HiRes::constant not defined" if $constname eq 'constant'; + my ($error, $val) = constant($constname); + # print "AUTOLOAD: error = $error, val = $val\n"; + if ($error) { + my (undef,$file,$line) = caller; + die "$error at $file line $line.\n"; + } + { + no strict 'refs'; + *$AUTOLOAD = sub { $val }; + } + goto &$AUTOLOAD; +} + +sub import { + my $this = shift; + for my $i (@_) { + if (($i eq 'clock_getres' && !&d_clock_getres) || + ($i eq 'clock_gettime' && !&d_clock_gettime) || + ($i eq 'clock_nanosleep' && !&d_clock_nanosleep) || + ($i eq 'clock' && !&d_clock) || + ($i eq 'nanosleep' && !&d_nanosleep) || + ($i eq 'usleep' && !&d_usleep) || + ($i eq 'ualarm' && !&d_ualarm)) { + require Carp; + Carp::croak("Time::HiRes::$i(): unimplemented in this platform"); + } + } + Time::HiRes->export_to_level(1, $this, @_); +} + +bootstrap Time::HiRes; + +# Preloaded methods go here. + +sub tv_interval { + # probably could have been done in C + my ($a, $b) = @_; + $b = [gettimeofday()] unless defined($b); + (${$b}[0] - ${$a}[0]) + ((${$b}[1] - ${$a}[1]) / 1_000_000); +} + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ + +=head1 NAME + +Time::HiRes - High resolution alarm, sleep, gettimeofday, interval timers + +=head1 SYNOPSIS + + use Time::HiRes qw( usleep ualarm gettimeofday tv_interval nanosleep + clock_gettime clock_getres clock_nanosleep clock + stat ); + + usleep ($microseconds); + nanosleep ($nanoseconds); + + ualarm ($microseconds); + ualarm ($microseconds, $interval_microseconds); + + $t0 = [gettimeofday]; + ($seconds, $microseconds) = gettimeofday; + + $elapsed = tv_interval ( $t0, [$seconds, $microseconds]); + $elapsed = tv_interval ( $t0, [gettimeofday]); + $elapsed = tv_interval ( $t0 ); + + use Time::HiRes qw ( time alarm sleep ); + + $now_fractions = time; + sleep ($floating_seconds); + alarm ($floating_seconds); + alarm ($floating_seconds, $floating_interval); + + use Time::HiRes qw( setitimer getitimer ); + + setitimer ($which, $floating_seconds, $floating_interval ); + getitimer ($which); + + use Time::HiRes qw( clock_gettime clock_getres clock_nanosleep + ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF ); + + $realtime = clock_gettime(CLOCK_REALTIME); + $resolution = clock_getres(CLOCK_REALTIME); + + clock_nanosleep(CLOCK_REALTIME, 1.5e9); + clock_nanosleep(CLOCK_REALTIME, time()*1e9 + 10e9, TIMER_ABSTIME); + + my $ticktock = clock(); + + use Time::HiRes qw( stat ); + + my @stat = stat("file"); + my @stat = stat(FH); + +=head1 DESCRIPTION + +The C<Time::HiRes> module implements a Perl interface to the +C<usleep>, C<nanosleep>, C<ualarm>, C<gettimeofday>, and +C<setitimer>/C<getitimer> system calls, in other words, high +resolution time and timers. See the L</EXAMPLES> section below and the +test scripts for usage; see your system documentation for the +description of the underlying C<nanosleep> or C<usleep>, C<ualarm>, +C<gettimeofday>, and C<setitimer>/C<getitimer> calls. + +If your system lacks C<gettimeofday()> or an emulation of it you don't +get C<gettimeofday()> or the one-argument form of C<tv_interval()>. +If your system lacks all of C<nanosleep()>, C<usleep()>, +C<select()>, and C<poll>, you don't get C<Time::HiRes::usleep()>, +C<Time::HiRes::nanosleep()>, or C<Time::HiRes::sleep()>. +If your system lacks both C<ualarm()> and C<setitimer()> you don't get +C<Time::HiRes::ualarm()> or C<Time::HiRes::alarm()>. + +If you try to import an unimplemented function in the C<use> statement +it will fail at compile time. + +If your subsecond sleeping is implemented with C<nanosleep()> instead +of C<usleep()>, you can mix subsecond sleeping with signals since +C<nanosleep()> does not use signals. This, however, is not portable, +and you should first check for the truth value of +C<&Time::HiRes::d_nanosleep> to see whether you have nanosleep, and +then carefully read your C<nanosleep()> C API documentation for any +peculiarities. + +If you are using C<nanosleep> for something else than mixing sleeping +with signals, give some thought to whether Perl is the tool you should +be using for work requiring nanosecond accuracies. + +Remember that unless you are working on a I<hard realtime> system, +any clocks and timers will be imprecise, especially so if you are working +in a pre-emptive multiuser system. Understand the difference between +I<wallclock time> and process time (in UNIX-like systems the sum of +I<user> and I<system> times). Any attempt to sleep for X seconds will +most probably end up sleeping B<more> than that, but don't be surpised +if you end up sleeping slightly B<less>. + +The following functions can be imported from this module. +No functions are exported by default. + +=over 4 + +=item gettimeofday () + +In array context returns a two-element array with the seconds and +microseconds since the epoch. In scalar context returns floating +seconds like C<Time::HiRes::time()> (see below). + +=item usleep ( $useconds ) + +Sleeps for the number of microseconds (millionths of a second) +specified. Returns the number of microseconds actually slept. +Can sleep for more than one second, unlike the C<usleep> system call. +Can also sleep for zero seconds, which often works like a I<thread yield>. +See also C<Time::HiRes::usleep()>, C<Time::HiRes::sleep()>, and +C<Time::HiRes::clock_nanosleep()>. + +Do not expect usleep() to be exact down to one microsecond. + +=item nanosleep ( $nanoseconds ) + +Sleeps for the number of nanoseconds (1e9ths of a second) specified. +Returns the number of nanoseconds actually slept (accurate only to +microseconds, the nearest thousand of them). Can sleep for more than +one second. Can also sleep for zero seconds, which often works like +a I<thread yield>. See also C<Time::HiRes::sleep()>, +C<Time::HiRes::usleep()>, and C<Time::HiRes::clock_nanosleep()>. + +Do not expect nanosleep() to be exact down to one nanosecond. +Getting even accuracy of one thousand nanoseconds is good. + +=item ualarm ( $useconds [, $interval_useconds ] ) + +Issues a C<ualarm> call; the C<$interval_useconds> is optional and +will be zero if unspecified, resulting in C<alarm>-like behaviour. + +Returns the remaining time in the alarm in microseconds, or C<undef> +if an error occurred. + +ualarm(0) will cancel an outstanding ualarm(). + +Note that the interaction between alarms and sleeps is unspecified. + +=item tv_interval + +tv_interval ( $ref_to_gettimeofday [, $ref_to_later_gettimeofday] ) + +Returns the floating seconds between the two times, which should have +been returned by C<gettimeofday()>. If the second argument is omitted, +then the current time is used. + +=item time () + +Returns a floating seconds since the epoch. This function can be +imported, resulting in a nice drop-in replacement for the C<time> +provided with core Perl; see the L</EXAMPLES> below. + +B<NOTE 1>: This higher resolution timer can return values either less +or more than the core C<time()>, depending on whether your platform +rounds the higher resolution timer values up, down, or to the nearest second +to get the core C<time()>, but naturally the difference should be never +more than half a second. See also L</clock_getres>, if available +in your system. + +B<NOTE 2>: Since Sunday, September 9th, 2001 at 01:46:40 AM GMT, when +the C<time()> seconds since epoch rolled over to 1_000_000_000, the +default floating point format of Perl and the seconds since epoch have +conspired to produce an apparent bug: if you print the value of +C<Time::HiRes::time()> you seem to be getting only five decimals, not +six as promised (microseconds). Not to worry, the microseconds are +there (assuming your platform supports such granularity in the first +place). What is going on is that the default floating point format of +Perl only outputs 15 digits. In this case that means ten digits +before the decimal separator and five after. To see the microseconds +you can use either C<printf>/C<sprintf> with C<"%.6f">, or the +C<gettimeofday()> function in list context, which will give you the +seconds and microseconds as two separate values. + +=item sleep ( $floating_seconds ) + +Sleeps for the specified amount of seconds. Returns the number of +seconds actually slept (a floating point value). This function can +be imported, resulting in a nice drop-in replacement for the C<sleep> +provided with perl, see the L</EXAMPLES> below. + +Note that the interaction between alarms and sleeps is unspecified. + +=item alarm ( $floating_seconds [, $interval_floating_seconds ] ) + +The C<SIGALRM> signal is sent after the specified number of seconds. +Implemented using C<setitimer()> if available, C<ualarm()> if not. +The C<$interval_floating_seconds> argument is optional and will be +zero if unspecified, resulting in C<alarm()>-like behaviour. This +function can be imported, resulting in a nice drop-in replacement for +the C<alarm> provided with perl, see the L</EXAMPLES> below. + +Returns the remaining time in the alarm in seconds, or C<undef> +if an error occurred. + +B<NOTE 1>: With some combinations of operating systems and Perl +releases C<SIGALRM> restarts C<select()>, instead of interrupting it. +This means that an C<alarm()> followed by a C<select()> may together +take the sum of the times specified for the the C<alarm()> and the +C<select()>, not just the time of the C<alarm()>. + +Note that the interaction between alarms and sleeps is unspecified. + +=item setitimer ( $which, $floating_seconds [, $interval_floating_seconds ] ) + +Start up an interval timer: after a certain time, a signal ($which) arrives, +and more signals may keep arriving at certain intervals. To disable +an "itimer", use C<$floating_seconds> of zero. If the +C<$interval_floating_seconds> is set to zero (or unspecified), the +timer is disabled B<after> the next delivered signal. + +Use of interval timers may interfere with C<alarm()>, C<sleep()>, +and C<usleep()>. In standard-speak the "interaction is unspecified", +which means that I<anything> may happen: it may work, it may not. + +In scalar context, the remaining time in the timer is returned. + +In list context, both the remaining time and the interval are returned. + +There are usually three or four interval timers (signals) available: the +C<$which> can be C<ITIMER_REAL>, C<ITIMER_VIRTUAL>, C<ITIMER_PROF>, or +C<ITIMER_REALPROF>. Note that which ones are available depends: true +UNIX platforms usually have the first three, but only Solaris seems to +have C<ITIMER_REALPROF> (which is used to profile multithreaded programs). +Win32 unfortunately does not haveinterval timers. + +C<ITIMER_REAL> results in C<alarm()>-like behaviour. Time is counted in +I<real time>; that is, wallclock time. C<SIGALRM> is delivered when +the timer expires. + +C<ITIMER_VIRTUAL> counts time in (process) I<virtual time>; that is, +only when the process is running. In multiprocessor/user/CPU systems +this may be more or less than real or wallclock time. (This time is +also known as the I<user time>.) C<SIGVTALRM> is delivered when the +timer expires. + +C<ITIMER_PROF> counts time when either the process virtual time or when +the operating system is running on behalf of the process (such as I/O). +(This time is also known as the I<system time>.) (The sum of user +time and system time is known as the I<CPU time>.) C<SIGPROF> is +delivered when the timer expires. C<SIGPROF> can interrupt system calls. + +The semantics of interval timers for multithreaded programs are +system-specific, and some systems may support additional interval +timers. For example, it is unspecified which thread gets the signals. +See your C<setitimer()> documentation. + +=item getitimer ( $which ) + +Return the remaining time in the interval timer specified by C<$which>. + +In scalar context, the remaining time is returned. + +In list context, both the remaining time and the interval are returned. +The interval is always what you put in using C<setitimer()>. + +=item clock_gettime ( $which ) + +Return as seconds the current value of the POSIX high resolution timer +specified by C<$which>. All implementations that support POSIX high +resolution timers are supposed to support at least the C<$which> value +of C<CLOCK_REALTIME>, which is supposed to return results close to the +results of C<gettimeofday>, or the number of seconds since 00:00:00:00 +January 1, 1970 Greenwich Mean Time (GMT). Do not assume that +CLOCK_REALTIME is zero, it might be one, or something else. +Another potentially useful (but not available everywhere) value is +C<CLOCK_MONOTONIC>, which guarantees a monotonically increasing time +value (unlike time() or gettimeofday(), which can be adjusted). +See your system documentation for other possibly supported values. + +=item clock_getres ( $which ) + +Return as seconds the resolution of the POSIX high resolution timer +specified by C<$which>. All implementations that support POSIX high +resolution timers are supposed to support at least the C<$which> value +of C<CLOCK_REALTIME>, see L</clock_gettime>. + +=item clock_nanosleep ( $which, $nanoseconds, $flags = 0) + +Sleeps for the number of nanoseconds (1e9ths of a second) specified. +Returns the number of nanoseconds actually slept. The $which is the +"clock id", as with clock_gettime() and clock_getres(). The flags +default to zero but C<TIMER_ABSTIME> can specified (must be exported +explicitly) which means that C<$nanoseconds> is not a time interval +(as is the default) but instead an absolute time. Can sleep for more +than one second. Can also sleep for zero seconds, which often works +like a I<thread yield>. See also C<Time::HiRes::sleep()>, +C<Time::HiRes::usleep()>, and C<Time::HiRes::nanosleep()>. + +Do not expect clock_nanosleep() to be exact down to one nanosecond. +Getting even accuracy of one thousand nanoseconds is good. + +=item clock() + +Return as seconds the I<process time> (user + system time) spent by +the process since the first call to clock() (the definition is B<not> +"since the start of the process", though if you are lucky these times +may be quite close to each other, depending on the system). What this +means is that you probably need to store the result of your first call +to clock(), and subtract that value from the following results of clock(). + +The time returned also includes the process times of the terminated +child processes for which wait() has been executed. This value is +somewhat like the second value returned by the times() of core Perl, +but not necessarily identical. Note that due to backward +compatibility limitations the returned value may wrap around at about +2147 seconds or at about 36 minutes. + +=item stat + +=item stat FH + +=item stat EXPR + +As L<perlfunc/stat> but with the access/modify/change file timestamps +in subsecond resolution, if the operating system and the filesystem +both support such timestamps. To override the standard stat(): + + use Time::HiRes qw(stat); + +Test for the value of &Time::HiRes::d_hires_stat to find out whether +the operating system supports subsecond file timestamps: a value +larger than zero means yes. There are unfortunately no easy +ways to find out whether the filesystem supports such timestamps. +UNIX filesystems often do; NTFS does; FAT doesn't (FAT timestamp +granularity is B<two> seconds). + +A zero return value of &Time::HiRes::d_hires_stat means that +Time::HiRes::stat is a no-op passthrough for CORE::stat(), +and therefore the timestamps will stay integers. The same +thing will happen if the filesystem does not do subsecond timestamps, +even if the &Time::HiRes::d_hires_stat is non-zero. + +In any case do not expect nanosecond resolution, or even a microsecond +resolution. Also note that the modify/access timestamps might have +different resolutions, and that they need not be synchronized, e.g. +if the operations are + + write + stat # t1 + read + stat # t2 + +the access time stamp from t2 need not be greater-than the modify +time stamp from t1: it may be equal or I<less>. + +=back + +=head1 EXAMPLES + + use Time::HiRes qw(usleep ualarm gettimeofday tv_interval); + + $microseconds = 750_000; + usleep($microseconds); + + # signal alarm in 2.5s & every .1s thereafter + ualarm(2_500_000, 100_000); + # cancel that ualarm + ualarm(0); + + # get seconds and microseconds since the epoch + ($s, $usec) = gettimeofday(); + + # measure elapsed time + # (could also do by subtracting 2 gettimeofday return values) + $t0 = [gettimeofday]; + # do bunch of stuff here + $t1 = [gettimeofday]; + # do more stuff here + $t0_t1 = tv_interval $t0, $t1; + + $elapsed = tv_interval ($t0, [gettimeofday]); + $elapsed = tv_interval ($t0); # equivalent code + + # + # replacements for time, alarm and sleep that know about + # floating seconds + # + use Time::HiRes; + $now_fractions = Time::HiRes::time; + Time::HiRes::sleep (2.5); + Time::HiRes::alarm (10.6666666); + + use Time::HiRes qw ( time alarm sleep ); + $now_fractions = time; + sleep (2.5); + alarm (10.6666666); + + # Arm an interval timer to go off first at 10 seconds and + # after that every 2.5 seconds, in process virtual time + + use Time::HiRes qw ( setitimer ITIMER_VIRTUAL time ); + + $SIG{VTALRM} = sub { print time, "\n" }; + setitimer(ITIMER_VIRTUAL, 10, 2.5); + + use Time::HiRes qw( clock_gettime clock_getres CLOCK_REALTIME ); + # Read the POSIX high resolution timer. + my $high = clock_getres(CLOCK_REALTIME); + # But how accurate we can be, really? + my $reso = clock_getres(CLOCK_REALTIME); + + use Time::HiRes qw( clock_nanosleep TIMER_ABSTIME ); + clock_nanosleep(CLOCK_REALTIME, 1e6); + clock_nanosleep(CLOCK_REALTIME, 2e9, TIMER_ABSTIME); + + use Time::HiRes qw( clock ); + my $clock0 = clock(); + ... # Do something. + my $clock1 = clock(); + my $clockd = $clock1 - $clock0; + + use Time::HiRes qw( stat ); + my ($atime, $mtime, $ctime) = (stat("istics"))[8, 9, 10]; + +=head1 C API + +In addition to the perl API described above, a C API is available for +extension writers. The following C functions are available in the +modglobal hash: + + name C prototype + --------------- ---------------------- + Time::NVtime double (*)() + Time::U2time void (*)(pTHX_ UV ret[2]) + +Both functions return equivalent information (like C<gettimeofday>) +but with different representations. The names C<NVtime> and C<U2time> +were selected mainly because they are operating system independent. +(C<gettimeofday> is Unix-centric, though some platforms like Win32 and +VMS have emulations for it.) + +Here is an example of using C<NVtime> from C: + + double (*myNVtime)(); /* Returns -1 on failure. */ + SV **svp = hv_fetch(PL_modglobal, "Time::NVtime", 12, 0); + if (!svp) croak("Time::HiRes is required"); + if (!SvIOK(*svp)) croak("Time::NVtime isn't a function pointer"); + myNVtime = INT2PTR(double(*)(), SvIV(*svp)); + printf("The current time is: %f\n", (*myNVtime)()); + +=head1 DIAGNOSTICS + +=head2 useconds or interval more than ... + +In ualarm() you tried to use number of microseconds or interval (also +in microseconds) more than 1_000_000 and setitimer() is not available +in your system to emulate that case. + +=head2 negative time not invented yet + +You tried to use a negative time argument. + +=head2 internal error: useconds < 0 (unsigned ... signed ...) + +Something went horribly wrong-- the number of microseconds that cannot +become negative just became negative. Maybe your compiler is broken? + +=head2 useconds or uinterval equal to or more than 1000000 + +In some platforms it is not possible to get an alarm with subsecond +resolution and later than one second. + +=head2 unimplemented in this platform + +Some calls simply aren't available, real or emulated, on every platform. + +=head1 CAVEATS + +Notice that the core C<time()> maybe rounding rather than truncating. +What this means is that the core C<time()> may be reporting the time +as one second later than C<gettimeofday()> and C<Time::HiRes::time()>. + +Adjusting the system clock (either manually or by services like ntp) +may cause problems, especially for long running programs that assume +a monotonously increasing time (note that all platforms do not adjust +time as gracefully as UNIX ntp does). For example in Win32 (and derived +platforms like Cygwin and MinGW) the Time::HiRes::time() may temporarily +drift off from the system clock (and the original time()) by up to 0.5 +seconds. Time::HiRes will notice this eventually and recalibrate. +Note that since Time::HiRes 1.77 the clock_gettime(CLOCK_MONOTONIC) +might help in this (in case your system supports CLOCK_MONOTONIC). + +Some systems have APIs but not implementations: for example QNX and Haiku +have the interval timer APIs but not the functionality. + +=head1 SEE ALSO + +Perl modules L<BSD::Resource>, L<Time::TAI64>. + +Your system documentation for C<clock>, C<clock_gettime>, +C<clock_getres>, C<clock_nanosleep>, C<clock_settime>, C<getitimer>, +C<gettimeofday>, C<setitimer>, C<sleep>, C<stat>, C<ualarm>. + +=head1 AUTHORS + +D. Wegscheid <wegscd@whirlpool.com> +R. Schertler <roderick@argon.org> +J. Hietaniemi <jhi@iki.fi> +G. Aas <gisle@aas.no> + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 1996-2002 Douglas E. Wegscheid. All rights reserved. + +Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Jarkko Hietaniemi. +All rights reserved. + +This program is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut diff --git a/ext/Time-HiRes/HiRes.xs b/ext/Time-HiRes/HiRes.xs new file mode 100644 index 0000000000..69eee69333 --- /dev/null +++ b/ext/Time-HiRes/HiRes.xs @@ -0,0 +1,1257 @@ +/* + * + * Copyright (c) 1996-2002 Douglas E. Wegscheid. All rights reserved. + * + * Copyright (c) 2002,2003,2004,2005,2006,2007,2008 Jarkko Hietaniemi. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the same terms as Perl itself. + */ + +#ifdef __cplusplus +extern "C" { +#endif +#define PERL_NO_GET_CONTEXT +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ppport.h" +#if defined(__CYGWIN__) && defined(HAS_W32API_WINDOWS_H) +# include <w32api/windows.h> +# define CYGWIN_WITH_W32API +#endif +#ifdef WIN32 +# include <time.h> +#else +# include <sys/time.h> +#endif +#ifdef HAS_SELECT +# ifdef I_SYS_SELECT +# include <sys/select.h> +# endif +#endif +#if defined(TIME_HIRES_CLOCK_GETTIME_SYSCALL) || defined(TIME_HIRES_CLOCK_GETRES_SYSCALL) +#include <syscall.h> +#endif +#ifdef __cplusplus +} +#endif + +/* At least ppport.h 3.13 gets this wrong: one really cannot + * have NVgf as anything else than "g" under Perl 5.6.x. */ +#if PERL_REVISION == 5 && PERL_VERSION == 6 +# undef NVgf +# define NVgf "g" +#endif + +#define IV_1E6 1000000 +#define IV_1E7 10000000 +#define IV_1E9 1000000000 + +#define NV_1E6 1000000.0 +#define NV_1E7 10000000.0 +#define NV_1E9 1000000000.0 + +#ifndef PerlProc_pause +# define PerlProc_pause() Pause() +#endif + +#ifdef HAS_PAUSE +# define Pause pause +#else +# undef Pause /* In case perl.h did it already. */ +# define Pause() sleep(~0) /* Zzz for a long time. */ +#endif + +/* Though the cpp define ITIMER_VIRTUAL is available the functionality + * is not supported in Cygwin as of August 2004, ditto for Win32. + * Neither are ITIMER_PROF or ITIMER_REALPROF implemented. --jhi + */ +#if defined(__CYGWIN__) || defined(WIN32) +# undef ITIMER_VIRTUAL +# undef ITIMER_PROF +# undef ITIMER_REALPROF +#endif + +#if defined(TIME_HIRES_CLOCK_GETTIME) && defined(_STRUCT_ITIMERSPEC) + +/* HP-UX has CLOCK_XXX values but as enums, not as defines. + * The only way to detect these would be to test compile for each. */ +# ifdef __hpux +/* However, it seems that at least in HP-UX 11.31 ia64 there *are* + * defines for these, so let's try detecting them. */ +# ifndef CLOCK_REALTIME +# define CLOCK_REALTIME CLOCK_REALTIME +# define CLOCK_VIRTUAL CLOCK_VIRTUAL +# define CLOCK_PROFILE CLOCK_PROFILE +# endif +# endif /* # ifdef __hpux */ + +#endif /* #if defined(TIME_HIRES_CLOCK_GETTIME) && defined(_STRUCT_ITIMERSPEC) */ + +#if defined(WIN32) || defined(CYGWIN_WITH_W32API) + +#ifndef HAS_GETTIMEOFDAY +# define HAS_GETTIMEOFDAY +#endif + +/* shows up in winsock.h? +struct timeval { + long tv_sec; + long tv_usec; +} +*/ + +typedef union { + unsigned __int64 ft_i64; + FILETIME ft_val; +} FT_t; + +#define MY_CXT_KEY "Time::HiRes_" XS_VERSION + +typedef struct { + unsigned long run_count; + unsigned __int64 base_ticks; + unsigned __int64 tick_frequency; + FT_t base_systime_as_filetime; + unsigned __int64 reset_time; +} my_cxt_t; + +START_MY_CXT + +/* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */ +#ifdef __GNUC__ +# define Const64(x) x##LL +#else +# define Const64(x) x##i64 +#endif +#define EPOCH_BIAS Const64(116444736000000000) + +#ifdef Const64 +# ifdef __GNUC__ +# define IV_1E6LL 1000000LL /* Needed because of Const64() ##-appends LL (or i64). */ +# define IV_1E7LL 10000000LL +# define IV_1E9LL 1000000000LL +# else +# define IV_1E6i64 1000000i64 +# define IV_1E7i64 10000000i64 +# define IV_1E9i64 1000000000i64 +# endif +#endif + +/* NOTE: This does not compute the timezone info (doing so can be expensive, + * and appears to be unsupported even by glibc) */ + +/* dMY_CXT needs a Perl context and we don't want to call PERL_GET_CONTEXT + for performance reasons */ + +#undef gettimeofday +#define gettimeofday(tp, not_used) _gettimeofday(aTHX_ tp, not_used) + +/* If the performance counter delta drifts more than 0.5 seconds from the + * system time then we recalibrate to the system time. This means we may + * move *backwards* in time! */ +#define MAX_PERF_COUNTER_SKEW Const64(5000000) /* 0.5 seconds */ + +/* Reset reading from the performance counter every five minutes. + * Many PC clocks just seem to be so bad. */ +#define MAX_PERF_COUNTER_TICKS Const64(300000000) /* 300 seconds */ + +static int +_gettimeofday(pTHX_ struct timeval *tp, void *not_used) +{ + dMY_CXT; + + unsigned __int64 ticks; + FT_t ft; + + if (MY_CXT.run_count++ == 0 || + MY_CXT.base_systime_as_filetime.ft_i64 > MY_CXT.reset_time) { + QueryPerformanceFrequency((LARGE_INTEGER*)&MY_CXT.tick_frequency); + QueryPerformanceCounter((LARGE_INTEGER*)&MY_CXT.base_ticks); + GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val); + ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64; + MY_CXT.reset_time = ft.ft_i64 + MAX_PERF_COUNTER_TICKS; + } + else { + __int64 diff; + QueryPerformanceCounter((LARGE_INTEGER*)&ticks); + ticks -= MY_CXT.base_ticks; + ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64 + + Const64(IV_1E7) * (ticks / MY_CXT.tick_frequency) + +(Const64(IV_1E7) * (ticks % MY_CXT.tick_frequency)) / MY_CXT.tick_frequency; + diff = ft.ft_i64 - MY_CXT.base_systime_as_filetime.ft_i64; + if (diff < -MAX_PERF_COUNTER_SKEW || diff > MAX_PERF_COUNTER_SKEW) { + MY_CXT.base_ticks += ticks; + GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val); + ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64; + } + } + + /* seconds since epoch */ + tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(IV_1E7)); + + /* microseconds remaining */ + tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(IV_1E6)); + + return 0; +} +#endif + +#if defined(WIN32) && !defined(ATLEASTFIVEOHOHFIVE) +static unsigned int +sleep(unsigned int t) +{ + Sleep(t*1000); + return 0; +} +#endif + +#if !defined(HAS_GETTIMEOFDAY) && defined(VMS) +#define HAS_GETTIMEOFDAY + +#include <lnmdef.h> +#include <time.h> /* gettimeofday */ +#include <stdlib.h> /* qdiv */ +#include <starlet.h> /* sys$gettim */ +#include <descrip.h> +#ifdef __VAX +#include <lib$routines.h> /* lib$ediv() */ +#endif + +/* + VMS binary time is expressed in 100 nano-seconds since + system base time which is 17-NOV-1858 00:00:00.00 +*/ + +#define DIV_100NS_TO_SECS 10000000L +#define DIV_100NS_TO_USECS 10L + +/* + gettimeofday is supposed to return times since the epoch + so need to determine this in terms of VMS base time +*/ +static $DESCRIPTOR(dscepoch,"01-JAN-1970 00:00:00.00"); + +#ifdef __VAX +static long base_adjust[2]={0L,0L}; +#else +static __int64 base_adjust=0; +#endif + +/* + + If we don't have gettimeofday, then likely we are on a VMS machine that + operates on local time rather than UTC...so we have to zone-adjust. + This code gleefully swiped from VMS.C + +*/ +/* method used to handle UTC conversions: + * 1 == CRTL gmtime(); 2 == SYS$TIMEZONE_DIFFERENTIAL; 3 == no correction + */ +static int gmtime_emulation_type; +/* number of secs to add to UTC POSIX-style time to get local time */ +static long int utc_offset_secs; +static struct dsc$descriptor_s fildevdsc = + { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" }; +static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL }; + +static time_t toutc_dst(time_t loc) { + struct tm *rsltmp; + + if ((rsltmp = localtime(&loc)) == NULL) return -1; + loc -= utc_offset_secs; + if (rsltmp->tm_isdst) loc -= 3600; + return loc; +} + +static time_t toloc_dst(time_t utc) { + struct tm *rsltmp; + + utc += utc_offset_secs; + if ((rsltmp = localtime(&utc)) == NULL) return -1; + if (rsltmp->tm_isdst) utc += 3600; + return utc; +} + +#define _toutc(secs) ((secs) == (time_t) -1 ? (time_t) -1 : \ + ((gmtime_emulation_type || timezone_setup()), \ + (gmtime_emulation_type == 1 ? toutc_dst(secs) : \ + ((secs) - utc_offset_secs)))) + +#define _toloc(secs) ((secs) == (time_t) -1 ? (time_t) -1 : \ + ((gmtime_emulation_type || timezone_setup()), \ + (gmtime_emulation_type == 1 ? toloc_dst(secs) : \ + ((secs) + utc_offset_secs)))) + +static int +timezone_setup(void) +{ + struct tm *tm_p; + + if (gmtime_emulation_type == 0) { + int dstnow; + time_t base = 15 * 86400; /* 15jan71; to avoid month/year ends between */ + /* results of calls to gmtime() and localtime() */ + /* for same &base */ + + gmtime_emulation_type++; + if ((tm_p = gmtime(&base)) == NULL) { /* CRTL gmtime() is a fake */ + char off[LNM$C_NAMLENGTH+1];; + + gmtime_emulation_type++; + if (!Perl_vmstrnenv("SYS$TIMEZONE_DIFFERENTIAL",off,0,fildev,0)) { + gmtime_emulation_type++; + utc_offset_secs = 0; + Perl_warn(aTHX_ "no UTC offset information; assuming local time is UTC"); + } + else { utc_offset_secs = atol(off); } + } + else { /* We've got a working gmtime() */ + struct tm gmt, local; + + gmt = *tm_p; + tm_p = localtime(&base); + local = *tm_p; + utc_offset_secs = (local.tm_mday - gmt.tm_mday) * 86400; + utc_offset_secs += (local.tm_hour - gmt.tm_hour) * 3600; + utc_offset_secs += (local.tm_min - gmt.tm_min) * 60; + utc_offset_secs += (local.tm_sec - gmt.tm_sec); + } + } + return 1; +} + + +int +gettimeofday (struct timeval *tp, void *tpz) +{ + long ret; +#ifdef __VAX + long quad[2]; + long quad1[2]; + long div_100ns_to_secs; + long div_100ns_to_usecs; + long quo,rem; + long quo1,rem1; +#else + __int64 quad; + __qdiv_t ans1,ans2; +#endif +/* + In case of error, tv_usec = 0 and tv_sec = VMS condition code. + The return from function is also set to -1. + This is not exactly as per the manual page. +*/ + + tp->tv_usec = 0; + +#ifdef __VAX + if (base_adjust[0]==0 && base_adjust[1]==0) { +#else + if (base_adjust==0) { /* Need to determine epoch adjustment */ +#endif + ret=sys$bintim(&dscepoch,&base_adjust); + if (1 != (ret &&1)) { + tp->tv_sec = ret; + return -1; + } + } + + ret=sys$gettim(&quad); /* Get VMS system time */ + if ((1 && ret) == 1) { +#ifdef __VAX + quad[0] -= base_adjust[0]; /* convert to epoch offset */ + quad[1] -= base_adjust[1]; /* convert 2nd half of quadword */ + div_100ns_to_secs = DIV_100NS_TO_SECS; + div_100ns_to_usecs = DIV_100NS_TO_USECS; + lib$ediv(&div_100ns_to_secs,&quad,&quo,&rem); + quad1[0] = rem; + quad1[1] = 0L; + lib$ediv(&div_100ns_to_usecs,&quad1,&quo1,&rem1); + tp->tv_sec = quo; /* Whole seconds */ + tp->tv_usec = quo1; /* Micro-seconds */ +#else + quad -= base_adjust; /* convert to epoch offset */ + ans1=qdiv(quad,DIV_100NS_TO_SECS); + ans2=qdiv(ans1.rem,DIV_100NS_TO_USECS); + tp->tv_sec = ans1.quot; /* Whole seconds */ + tp->tv_usec = ans2.quot; /* Micro-seconds */ +#endif + } else { + tp->tv_sec = ret; + return -1; + } +# ifdef VMSISH_TIME +# ifdef RTL_USES_UTC + if (VMSISH_TIME) tp->tv_sec = _toloc(tp->tv_sec); +# else + if (!VMSISH_TIME) tp->tv_sec = _toutc(tp->tv_sec); +# endif +# endif + return 0; +} +#endif + + + /* Do not use H A S _ N A N O S L E E P + * so that Perl Configure doesn't scan for it (and pull in -lrt and + * the like which are not usually good ideas for the default Perl). + * (We are part of the core perl now.) + * The TIME_HIRES_NANOSLEEP is set by Makefile.PL. */ +#if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP) +#define HAS_USLEEP +#define usleep hrt_usleep /* could conflict with ncurses for static build */ + +void +hrt_usleep(unsigned long usec) /* This is used to emulate usleep. */ +{ + struct timespec res; + res.tv_sec = usec / IV_1E6; + res.tv_nsec = ( usec - res.tv_sec * IV_1E6 ) * 1000; + nanosleep(&res, NULL); +} + +#endif /* #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP) */ + +#if !defined(HAS_USLEEP) && defined(HAS_SELECT) +#ifndef SELECT_IS_BROKEN +#define HAS_USLEEP +#define usleep hrt_usleep /* could conflict with ncurses for static build */ + +void +hrt_usleep(unsigned long usec) +{ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = usec; + select(0, (Select_fd_set_t)NULL, (Select_fd_set_t)NULL, + (Select_fd_set_t)NULL, &tv); +} +#endif +#endif /* #if !defined(HAS_USLEEP) && defined(HAS_SELECT) */ + +#if !defined(HAS_USLEEP) && defined(WIN32) +#define HAS_USLEEP +#define usleep hrt_usleep /* could conflict with ncurses for static build */ + +void +hrt_usleep(unsigned long usec) +{ + long msec; + msec = usec / 1000; + Sleep (msec); +} +#endif /* #if !defined(HAS_USLEEP) && defined(WIN32) */ + +#if !defined(HAS_USLEEP) && defined(HAS_POLL) +#define HAS_USLEEP +#define usleep hrt_usleep /* could conflict with ncurses for static build */ + +void +hrt_usleep(unsigned long usec) +{ + int msec = usec / 1000; + poll(0, 0, msec); +} + +#endif /* #if !defined(HAS_USLEEP) && defined(HAS_POLL) */ + +#if defined(HAS_SETITIMER) && defined(ITIMER_REAL) + +static int +hrt_ualarm_itimero(struct itimerval* itv, int usec, int uinterval) +{ + itv->it_value.tv_sec = usec / IV_1E6; + itv->it_value.tv_usec = usec % IV_1E6; + itv->it_interval.tv_sec = uinterval / IV_1E6; + itv->it_interval.tv_usec = uinterval % IV_1E6; + return setitimer(ITIMER_REAL, itv, 0); +} + +int +hrt_ualarm_itimer(int usec, int uinterval) +{ + struct itimerval itv; + return hrt_ualarm_itimero(&itv, usec, uinterval); +} + +#ifdef HAS_UALARM +int +hrt_ualarm(int usec, int interval) /* for binary compat before 1.91 */ +{ + return hrt_ualarm_itimer(usec, interval); +} +#endif /* #ifdef HAS_UALARM */ +#endif /* #if !defined(HAS_UALARM) && defined(HAS_SETITIMER) */ + +#if !defined(HAS_UALARM) && defined(HAS_SETITIMER) +#define HAS_UALARM +#define ualarm hrt_ualarm_itimer /* could conflict with ncurses for static build */ +#endif + +#if !defined(HAS_UALARM) && defined(VMS) +#define HAS_UALARM +#define ualarm vms_ualarm + +#include <lib$routines.h> +#include <ssdef.h> +#include <starlet.h> +#include <descrip.h> +#include <signal.h> +#include <jpidef.h> +#include <psldef.h> + +#define VMSERR(s) (!((s)&1)) + +static void +us_to_VMS(useconds_t mseconds, unsigned long v[]) +{ + int iss; + unsigned long qq[2]; + + qq[0] = mseconds; + qq[1] = 0; + v[0] = v[1] = 0; + + iss = lib$addx(qq,qq,qq); + if (VMSERR(iss)) lib$signal(iss); + iss = lib$subx(v,qq,v); + if (VMSERR(iss)) lib$signal(iss); + iss = lib$addx(qq,qq,qq); + if (VMSERR(iss)) lib$signal(iss); + iss = lib$subx(v,qq,v); + if (VMSERR(iss)) lib$signal(iss); + iss = lib$subx(v,qq,v); + if (VMSERR(iss)) lib$signal(iss); +} + +static int +VMS_to_us(unsigned long v[]) +{ + int iss; + unsigned long div=10,quot, rem; + + iss = lib$ediv(&div,v,",&rem); + if (VMSERR(iss)) lib$signal(iss); + + return quot; +} + +typedef unsigned short word; +typedef struct _ualarm { + int function; + int repeat; + unsigned long delay[2]; + unsigned long interval[2]; + unsigned long remain[2]; +} Alarm; + + +static int alarm_ef; +static Alarm *a0, alarm_base; +#define UAL_NULL 0 +#define UAL_SET 1 +#define UAL_CLEAR 2 +#define UAL_ACTIVE 4 +static void ualarm_AST(Alarm *a); + +static int +vms_ualarm(int mseconds, int interval) +{ + Alarm *a, abase; + struct item_list3 { + word length; + word code; + void *bufaddr; + void *retlenaddr; + } ; + static struct item_list3 itmlst[2]; + static int first = 1; + unsigned long asten; + int iss, enabled; + + if (first) { + first = 0; + itmlst[0].code = JPI$_ASTEN; + itmlst[0].length = sizeof(asten); + itmlst[0].retlenaddr = NULL; + itmlst[1].code = 0; + itmlst[1].length = 0; + itmlst[1].bufaddr = NULL; + itmlst[1].retlenaddr = NULL; + + iss = lib$get_ef(&alarm_ef); + if (VMSERR(iss)) lib$signal(iss); + + a0 = &alarm_base; + a0->function = UAL_NULL; + } + itmlst[0].bufaddr = &asten; + + iss = sys$getjpiw(0,0,0,itmlst,0,0,0); + if (VMSERR(iss)) lib$signal(iss); + if (!(asten&0x08)) return -1; + + a = &abase; + if (mseconds) { + a->function = UAL_SET; + } else { + a->function = UAL_CLEAR; + } + + us_to_VMS(mseconds, a->delay); + if (interval) { + us_to_VMS(interval, a->interval); + a->repeat = 1; + } else + a->repeat = 0; + + iss = sys$clref(alarm_ef); + if (VMSERR(iss)) lib$signal(iss); + + iss = sys$dclast(ualarm_AST,a,0); + if (VMSERR(iss)) lib$signal(iss); + + iss = sys$waitfr(alarm_ef); + if (VMSERR(iss)) lib$signal(iss); + + if (a->function == UAL_ACTIVE) + return VMS_to_us(a->remain); + else + return 0; +} + + + +static void +ualarm_AST(Alarm *a) +{ + int iss; + unsigned long now[2]; + + iss = sys$gettim(now); + if (VMSERR(iss)) lib$signal(iss); + + if (a->function == UAL_SET || a->function == UAL_CLEAR) { + if (a0->function == UAL_ACTIVE) { + iss = sys$cantim(a0,PSL$C_USER); + if (VMSERR(iss)) lib$signal(iss); + + iss = lib$subx(a0->remain, now, a->remain); + if (VMSERR(iss)) lib$signal(iss); + + if (a->remain[1] & 0x80000000) + a->remain[0] = a->remain[1] = 0; + } + + if (a->function == UAL_SET) { + a->function = a0->function; + a0->function = UAL_ACTIVE; + a0->repeat = a->repeat; + if (a0->repeat) { + a0->interval[0] = a->interval[0]; + a0->interval[1] = a->interval[1]; + } + a0->delay[0] = a->delay[0]; + a0->delay[1] = a->delay[1]; + + iss = lib$subx(now, a0->delay, a0->remain); + if (VMSERR(iss)) lib$signal(iss); + + iss = sys$setimr(0,a0->delay,ualarm_AST,a0); + if (VMSERR(iss)) lib$signal(iss); + } else { + a->function = a0->function; + a0->function = UAL_NULL; + } + iss = sys$setef(alarm_ef); + if (VMSERR(iss)) lib$signal(iss); + } else if (a->function == UAL_ACTIVE) { + if (a->repeat) { + iss = lib$subx(now, a->interval, a->remain); + if (VMSERR(iss)) lib$signal(iss); + + iss = sys$setimr(0,a->interval,ualarm_AST,a); + if (VMSERR(iss)) lib$signal(iss); + } else { + a->function = UAL_NULL; + } + iss = sys$wake(0,0); + if (VMSERR(iss)) lib$signal(iss); + lib$signal(SS$_ASTFLT); + } else { + lib$signal(SS$_BADPARAM); + } +} + +#endif /* #if !defined(HAS_UALARM) && defined(VMS) */ + +#ifdef HAS_GETTIMEOFDAY + +static int +myU2time(pTHX_ UV *ret) +{ + struct timeval Tp; + int status; + status = gettimeofday (&Tp, NULL); + ret[0] = Tp.tv_sec; + ret[1] = Tp.tv_usec; + return status; +} + +static NV +myNVtime() +{ +#ifdef WIN32 + dTHX; +#endif + struct timeval Tp; + int status; + status = gettimeofday (&Tp, NULL); + return status == 0 ? Tp.tv_sec + (Tp.tv_usec / NV_1E6) : -1.0; +} + +#endif /* #ifdef HAS_GETTIMEOFDAY */ + +static void +hrstatns(UV atime, UV mtime, UV ctime, UV *atime_nsec, UV *mtime_nsec, UV *ctime_nsec) +{ + dTHXR; + *atime_nsec = 0; + *mtime_nsec = 0; + *ctime_nsec = 0; +#ifdef TIME_HIRES_STAT +#if TIME_HIRES_STAT == 1 + *atime_nsec = PL_statcache.st_atimespec.tv_nsec; + *mtime_nsec = PL_statcache.st_mtimespec.tv_nsec; + *ctime_nsec = PL_statcache.st_ctimespec.tv_nsec; +#endif +#if TIME_HIRES_STAT == 2 + *atime_nsec = PL_statcache.st_atimensec; + *mtime_nsec = PL_statcache.st_mtimensec; + *ctime_nsec = PL_statcache.st_ctimensec; +#endif +#if TIME_HIRES_STAT == 3 + *atime_nsec = PL_statcache.st_atime_n; + *mtime_nsec = PL_statcache.st_mtime_n; + *ctime_nsec = PL_statcache.st_ctime_n; +#endif +#if TIME_HIRES_STAT == 4 + *atime_nsec = PL_statcache.st_atim.tv_nsec; + *mtime_nsec = PL_statcache.st_mtim.tv_nsec; + *ctime_nsec = PL_statcache.st_ctim.tv_nsec; +#endif +#if TIME_HIRES_STAT == 5 + *atime_nsec = PL_statcache.st_uatime * 1000; + *mtime_nsec = PL_statcache.st_umtime * 1000; + *ctime_nsec = PL_statcache.st_uctime * 1000; +#endif +#endif +} + +#include "const-c.inc" + +MODULE = Time::HiRes PACKAGE = Time::HiRes + +PROTOTYPES: ENABLE + +BOOT: +{ +#ifdef MY_CXT_KEY + MY_CXT_INIT; +#endif +#ifdef ATLEASTFIVEOHOHFIVE +# ifdef HAS_GETTIMEOFDAY + { + hv_store(PL_modglobal, "Time::NVtime", 12, newSViv(PTR2IV(myNVtime)), 0); + hv_store(PL_modglobal, "Time::U2time", 12, newSViv(PTR2IV(myU2time)), 0); + } +# endif +#endif +} + +#if defined(USE_ITHREADS) && defined(MY_CXT_KEY) + +void +CLONE(...) + CODE: + MY_CXT_CLONE; + +#endif + +INCLUDE: const-xs.inc + +#if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) + +NV +usleep(useconds) + NV useconds + PREINIT: + struct timeval Ta, Tb; + CODE: + gettimeofday(&Ta, NULL); + if (items > 0) { + if (useconds > 1E6) { + IV seconds = (IV) (useconds / 1E6); + /* If usleep() has been implemented using setitimer() + * then this contortion is unnecessary-- but usleep() + * may be implemented in some other way, so let's contort. */ + if (seconds) { + sleep(seconds); + useconds -= 1E6 * seconds; + } + } else if (useconds < 0.0) + croak("Time::HiRes::usleep(%"NVgf"): negative time not invented yet", useconds); + usleep((U32)useconds); + } else + PerlProc_pause(); + gettimeofday(&Tb, NULL); +#if 0 + printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec); +#endif + RETVAL = 1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec); + + OUTPUT: + RETVAL + +#if defined(TIME_HIRES_NANOSLEEP) + +NV +nanosleep(nsec) + NV nsec + PREINIT: + struct timespec sleepfor, unslept; + CODE: + if (nsec < 0.0) + croak("Time::HiRes::nanosleep(%"NVgf"): negative time not invented yet", nsec); + sleepfor.tv_sec = (Time_t)(nsec / 1e9); + sleepfor.tv_nsec = (long)(nsec - ((NV)sleepfor.tv_sec) * 1e9); + if (!nanosleep(&sleepfor, &unslept)) { + RETVAL = nsec; + } else { + sleepfor.tv_sec -= unslept.tv_sec; + sleepfor.tv_nsec -= unslept.tv_nsec; + if (sleepfor.tv_nsec < 0) { + sleepfor.tv_sec--; + sleepfor.tv_nsec += 1000000000; + } + RETVAL = ((NV)sleepfor.tv_sec) * 1e9 + ((NV)sleepfor.tv_nsec); + } + OUTPUT: + RETVAL + +#else /* #if defined(TIME_HIRES_NANOSLEEP) */ + +NV +nanosleep(nsec) + NV nsec + CODE: + croak("Time::HiRes::nanosleep(): unimplemented in this platform"); + RETVAL = 0.0; + +#endif /* #if defined(TIME_HIRES_NANOSLEEP) */ + +NV +sleep(...) + PREINIT: + struct timeval Ta, Tb; + CODE: + gettimeofday(&Ta, NULL); + if (items > 0) { + NV seconds = SvNV(ST(0)); + if (seconds >= 0.0) { + UV useconds = (UV)(1E6 * (seconds - (UV)seconds)); + if (seconds >= 1.0) + sleep((U32)seconds); + if ((IV)useconds < 0) { +#if defined(__sparc64__) && defined(__GNUC__) + /* Sparc64 gcc 2.95.3 (e.g. on NetBSD) has a bug + * where (0.5 - (UV)(0.5)) will under certain + * circumstances (if the double is cast to UV more + * than once?) evaluate to -0.5, instead of 0.5. */ + useconds = -(IV)useconds; +#endif /* #if defined(__sparc64__) && defined(__GNUC__) */ + if ((IV)useconds < 0) + croak("Time::HiRes::sleep(%"NVgf"): internal error: useconds < 0 (unsigned %"UVuf" signed %"IVdf")", seconds, useconds, (IV)useconds); + } + usleep(useconds); + } else + croak("Time::HiRes::sleep(%"NVgf"): negative time not invented yet", seconds); + } else + PerlProc_pause(); + gettimeofday(&Tb, NULL); +#if 0 + printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec); +#endif + RETVAL = (NV)(Tb.tv_sec-Ta.tv_sec)+0.000001*(NV)(Tb.tv_usec-Ta.tv_usec); + + OUTPUT: + RETVAL + +#else /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */ + +NV +usleep(useconds) + NV useconds + CODE: + croak("Time::HiRes::usleep(): unimplemented in this platform"); + RETVAL = 0.0; + +#endif /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */ + +#ifdef HAS_UALARM + +IV +ualarm(useconds,uinterval=0) + int useconds + int uinterval + CODE: + if (useconds < 0 || uinterval < 0) + croak("Time::HiRes::ualarm(%d, %d): negative time not invented yet", useconds, uinterval); +#if defined(HAS_SETITIMER) && defined(ITIMER_REAL) + { + struct itimerval itv; + if (hrt_ualarm_itimero(&itv, useconds, uinterval)) { + RETVAL = itv.it_value.tv_sec + IV_1E6 * itv.it_value.tv_usec; + } else { + RETVAL = 0; + } + } +#else + if (useconds >= IV_1E6 || uinterval >= IV_1E6) + croak("Time::HiRes::ualarm(%d, %d): useconds or uinterval equal to or more than %"IVdf, useconds, uinterval, IV_1E6); + RETVAL = ualarm(useconds, uinterval); +#endif + + OUTPUT: + RETVAL + +NV +alarm(seconds,interval=0) + NV seconds + NV interval + CODE: + if (seconds < 0.0 || interval < 0.0) + croak("Time::HiRes::alarm(%"NVgf", %"NVgf"): negative time not invented yet", seconds, interval); + { + IV useconds = IV_1E6 * seconds; + IV uinterval = IV_1E6 * interval; +#if defined(HAS_SETITIMER) && defined(ITIMER_REAL) + { + struct itimerval itv; + if (hrt_ualarm_itimero(&itv, useconds, uinterval)) { + RETVAL = (NV)itv.it_value.tv_sec + (NV)itv.it_value.tv_usec / NV_1E6; + } else { + RETVAL = 0; + } + } +#else + if (useconds >= IV_1E6 || uinterval >= IV_1E6) + croak("Time::HiRes::alarm(%d, %d): seconds or interval equal to or more than 1.0 ", useconds, uinterval, IV_1E6); + RETVAL = (NV)ualarm( useconds, uinterval ) / NV_1E6; +#endif + } + + OUTPUT: + RETVAL + +#else + +int +ualarm(useconds,interval=0) + int useconds + int interval + CODE: + croak("Time::HiRes::ualarm(): unimplemented in this platform"); + RETVAL = -1; + +NV +alarm(seconds,interval=0) + NV seconds + NV interval + CODE: + croak("Time::HiRes::alarm(): unimplemented in this platform"); + RETVAL = 0.0; + +#endif /* #ifdef HAS_UALARM */ + +#ifdef HAS_GETTIMEOFDAY +# ifdef MACOS_TRADITIONAL /* fix epoch TZ and use unsigned time_t */ +void +gettimeofday() + PREINIT: + struct timeval Tp; + struct timezone Tz; + PPCODE: + int status; + status = gettimeofday (&Tp, &Tz); + + if (status == 0) { + Tp.tv_sec += Tz.tz_minuteswest * 60; /* adjust for TZ */ + if (GIMME == G_ARRAY) { + EXTEND(sp, 2); + /* Mac OS (Classic) has unsigned time_t */ + PUSHs(sv_2mortal(newSVuv(Tp.tv_sec))); + PUSHs(sv_2mortal(newSViv(Tp.tv_usec))); + } else { + EXTEND(sp, 1); + PUSHs(sv_2mortal(newSVnv(Tp.tv_sec + (Tp.tv_usec / NV_1E6)))); + } + } + +NV +time() + PREINIT: + struct timeval Tp; + struct timezone Tz; + CODE: + int status; + status = gettimeofday (&Tp, &Tz); + if (status == 0) { + Tp.tv_sec += Tz.tz_minuteswest * 60; /* adjust for TZ */ + RETVAL = Tp.tv_sec + (Tp.tv_usec / NV_1E6); + } else { + RETVAL = -1.0; + } + OUTPUT: + RETVAL + +# else /* MACOS_TRADITIONAL */ +void +gettimeofday() + PREINIT: + struct timeval Tp; + PPCODE: + int status; + status = gettimeofday (&Tp, NULL); + if (status == 0) { + if (GIMME == G_ARRAY) { + EXTEND(sp, 2); + PUSHs(sv_2mortal(newSViv(Tp.tv_sec))); + PUSHs(sv_2mortal(newSViv(Tp.tv_usec))); + } else { + EXTEND(sp, 1); + PUSHs(sv_2mortal(newSVnv(Tp.tv_sec + (Tp.tv_usec / NV_1E6)))); + } + } + +NV +time() + PREINIT: + struct timeval Tp; + CODE: + int status; + status = gettimeofday (&Tp, NULL); + if (status == 0) { + RETVAL = Tp.tv_sec + (Tp.tv_usec / NV_1E6); + } else { + RETVAL = -1.0; + } + OUTPUT: + RETVAL + +# endif /* MACOS_TRADITIONAL */ +#endif /* #ifdef HAS_GETTIMEOFDAY */ + +#if defined(HAS_GETITIMER) && defined(HAS_SETITIMER) + +#define TV2NV(tv) ((NV)((tv).tv_sec) + 0.000001 * (NV)((tv).tv_usec)) + +void +setitimer(which, seconds, interval = 0) + int which + NV seconds + NV interval + PREINIT: + struct itimerval newit; + struct itimerval oldit; + PPCODE: + if (seconds < 0.0 || interval < 0.0) + croak("Time::HiRes::setitimer(%"IVdf", %"NVgf", %"NVgf"): negative time not invented yet", (IV)which, seconds, interval); + newit.it_value.tv_sec = (IV)seconds; + newit.it_value.tv_usec = + (IV)((seconds - (NV)newit.it_value.tv_sec) * NV_1E6); + newit.it_interval.tv_sec = (IV)interval; + newit.it_interval.tv_usec = + (IV)((interval - (NV)newit.it_interval.tv_sec) * NV_1E6); + if (setitimer(which, &newit, &oldit) == 0) { + EXTEND(sp, 1); + PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_value)))); + if (GIMME == G_ARRAY) { + EXTEND(sp, 1); + PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_interval)))); + } + } + +void +getitimer(which) + int which + PREINIT: + struct itimerval nowit; + PPCODE: + if (getitimer(which, &nowit) == 0) { + EXTEND(sp, 1); + PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_value)))); + if (GIMME == G_ARRAY) { + EXTEND(sp, 1); + PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_interval)))); + } + } + +#endif /* #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER) */ + +#if defined(TIME_HIRES_CLOCK_GETTIME) + +NV +clock_gettime(clock_id = CLOCK_REALTIME) + int clock_id + PREINIT: + struct timespec ts; + int status = -1; + CODE: +#ifdef TIME_HIRES_CLOCK_GETTIME_SYSCALL + status = syscall(SYS_clock_gettime, clock_id, &ts); +#else + status = clock_gettime(clock_id, &ts); +#endif + RETVAL = status == 0 ? ts.tv_sec + (NV) ts.tv_nsec / (NV) 1e9 : -1; + + OUTPUT: + RETVAL + +#else /* if defined(TIME_HIRES_CLOCK_GETTIME) */ + +NV +clock_gettime(clock_id = 0) + int clock_id + CODE: + croak("Time::HiRes::clock_gettime(): unimplemented in this platform"); + RETVAL = 0.0; + +#endif /* #if defined(TIME_HIRES_CLOCK_GETTIME) */ + +#if defined(TIME_HIRES_CLOCK_GETRES) + +NV +clock_getres(clock_id = CLOCK_REALTIME) + int clock_id + PREINIT: + int status = -1; + struct timespec ts; + CODE: +#ifdef TIME_HIRES_CLOCK_GETRES_SYSCALL + status = syscall(SYS_clock_getres, clock_id, &ts); +#else + status = clock_getres(clock_id, &ts); +#endif + RETVAL = status == 0 ? ts.tv_sec + (NV) ts.tv_nsec / (NV) 1e9 : -1; + + OUTPUT: + RETVAL + +#else /* if defined(TIME_HIRES_CLOCK_GETRES) */ + +NV +clock_getres(clock_id = 0) + int clock_id + CODE: + croak("Time::HiRes::clock_getres(): unimplemented in this platform"); + RETVAL = 0.0; + +#endif /* #if defined(TIME_HIRES_CLOCK_GETRES) */ + +#if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) + +NV +clock_nanosleep(clock_id, nsec, flags = 0) + int clock_id + NV nsec + int flags + PREINIT: + struct timespec sleepfor, unslept; + CODE: + if (nsec < 0.0) + croak("Time::HiRes::clock_nanosleep(..., %"NVgf"): negative time not invented yet", nsec); + sleepfor.tv_sec = (Time_t)(nsec / 1e9); + sleepfor.tv_nsec = (long)(nsec - ((NV)sleepfor.tv_sec) * 1e9); + if (!clock_nanosleep(clock_id, flags, &sleepfor, &unslept)) { + RETVAL = nsec; + } else { + sleepfor.tv_sec -= unslept.tv_sec; + sleepfor.tv_nsec -= unslept.tv_nsec; + if (sleepfor.tv_nsec < 0) { + sleepfor.tv_sec--; + sleepfor.tv_nsec += 1000000000; + } + RETVAL = ((NV)sleepfor.tv_sec) * 1e9 + ((NV)sleepfor.tv_nsec); + } + OUTPUT: + RETVAL + +#else /* if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) */ + +NV +clock_nanosleep() + CODE: + croak("Time::HiRes::clock_nanosleep(): unimplemented in this platform"); + RETVAL = 0.0; + +#endif /* #if defined(TIME_HIRES_CLOCK_NANOSLEEP) && defined(TIMER_ABSTIME) */ + +#if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC) + +NV +clock() + PREINIT: + clock_t clocks; + CODE: + clocks = clock(); + RETVAL = clocks == -1 ? -1 : (NV)clocks / (NV)CLOCKS_PER_SEC; + + OUTPUT: + RETVAL + +#else /* if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC) */ + +NV +clock() + CODE: + croak("Time::HiRes::clock(): unimplemented in this platform"); + RETVAL = 0.0; + +#endif /* #if defined(TIME_HIRES_CLOCK) && defined(CLOCKS_PER_SEC) */ + +void +stat(...) +PROTOTYPE: ;$ + PPCODE: + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVsv(items == 1 ? ST(0) : DEFSV))); + PUTBACK; + ENTER; + PL_laststatval = -1; + (void)*(PL_ppaddr[OP_STAT])(aTHXR); + SPAGAIN; + LEAVE; + if (PL_laststatval == 0) { + /* We assume that pp_stat() left us with 13 valid stack items, + * and that the timestamps are at offsets 8, 9, and 10. */ + UV atime = SvUV(ST( 8)); + UV mtime = SvUV(ST( 9)); + UV ctime = SvUV(ST(10)); + UV atime_nsec; + UV mtime_nsec; + UV ctime_nsec; + hrstatns(atime, mtime, ctime, + &atime_nsec, &mtime_nsec, &ctime_nsec); + if (atime_nsec) + ST( 8) = sv_2mortal(newSVnv(atime + 1e-9 * (NV) atime_nsec)); + if (mtime_nsec) + ST( 9) = sv_2mortal(newSVnv(mtime + 1e-9 * (NV) mtime_nsec)); + if (ctime_nsec) + ST(10) = sv_2mortal(newSVnv(ctime + 1e-9 * (NV) ctime_nsec)); + XSRETURN(13); + } + XSRETURN(0); diff --git a/ext/Time-HiRes/Makefile.PL b/ext/Time-HiRes/Makefile.PL new file mode 100644 index 0000000000..c44199835f --- /dev/null +++ b/ext/Time-HiRes/Makefile.PL @@ -0,0 +1,879 @@ +#!/usr/bin/perl +# +# In general we trust %Config, but for nanosleep() this trust +# may be misplaced (it may be linkable but not really functional). +# Use $ENV{FORCE_NANOSLEEP_SCAN} to force rescanning whether there +# really is hope. + +require 5.002; + +use Config; +use ExtUtils::MakeMaker; +use strict; + +my $VERBOSE = $ENV{VERBOSE}; +my $DEFINE; +my $LIBS = []; +my $XSOPT = ''; +my $SYSCALL_H; + +use vars qw($self); # Used in 'sourcing' the hints. + +# TBD: Can we just use $Config(exe_ext) here instead of this complex +# expression? +my $ld_exeext = ($^O eq 'cygwin' || + $^O eq 'os2' && $Config{ldflags} =~ /-Zexe\b/) ? '.exe' : + (($^O eq 'vos') ? $Config{exe_ext} : ''); + +unless($ENV{PERL_CORE}) { + $ENV{PERL_CORE} = 1 if grep { $_ eq 'PERL_CORE=1' } @ARGV; +} + +# Perls 5.002 and 5.003 did not have File::Spec, fake what we need. + +sub my_dirsep { + $^O eq 'VMS' ? '.' : + $^O =~ /mswin32|netware|djgpp/i ? '\\' : + $^O eq 'MacOS' ? ':' + : '/'; +} + +sub my_catdir { + shift; + my $catdir = join(my_dirsep, @_); + $^O eq 'VMS' ? "[$catdir]" : $catdir; +} + +sub my_catfile { + shift; + return join(my_dirsep, @_) unless $^O eq 'VMS'; + my $file = pop; + return my_catdir (undef, @_) . $file; +} + +sub my_updir { + shift; + $^O eq 'VMS' ? "-" : ".."; +} + +BEGIN { + eval { require File::Spec }; + if ($@) { + *File::Spec::catdir = \&my_catdir; + *File::Spec::updir = \&my_updir; + *File::Spec::catfile = \&my_catfile; + } +} + +# Avoid 'used only once' warnings. +my $nop1 = *File::Spec::catdir; +my $nop2 = *File::Spec::updir; +my $nop3 = *File::Spec::catfile; + +# if you have 5.004_03 (and some slightly older versions?), xsubpp +# tries to generate line numbers in the C code generated from the .xs. +# unfortunately, it is a little buggy around #ifdef'd code. +# my choice is leave it in and have people with old perls complain +# about the "Usage" bug, or leave it out and be unable to compile myself +# without changing it, and then I'd always forget to change it before a +# release. Sorry, Edward :) + +sub try_compile_and_link { + my ($c, %args) = @_; + + my ($ok) = 0; + my ($tmp) = "tmp$$"; + local(*TMPC); + + my $obj_ext = $Config{obj_ext} || ".o"; + unlink("$tmp.c", "$tmp$obj_ext"); + + if (open(TMPC, ">$tmp.c")) { + print TMPC $c; + close(TMPC); + + my $cccmd = $args{cccmd}; + + my $errornull; + + my $COREincdir; + + if ($ENV{PERL_CORE}) { + my $updir = File::Spec->updir; + $COREincdir = File::Spec->catdir(($updir) x 2); + } else { + $COREincdir = File::Spec->catdir($Config{'archlibexp'}, 'CORE'); + } + + if ($ENV{PERL_CORE}) { + unless (-f File::Spec->catfile($COREincdir, "EXTERN.h")) { + die <<__EOD__; +Your environment variable PERL_CORE is '$ENV{PERL_CORE}' but there +is no EXTERN.h in $COREincdir. +Cannot continue, aborting. +__EOD__ + } + } + + my $ccflags = $Config{'ccflags'} . ' ' . "-I$COREincdir"; + + if ($^O eq 'VMS') { + if ($ENV{PERL_CORE}) { + # Fragile if the extensions change hierarchy within + # the Perl core but this should do for now. + $cccmd = "$Config{'cc'} /include=([---]) $tmp.c"; + } else { + my $perl_core = $Config{'installarchlib'}; + $perl_core =~ s/\]$/.CORE]/; + $cccmd = "$Config{'cc'} /include=(perl_root:[000000],$perl_core) $tmp.c"; + } + } + + if ($args{silent} || !$VERBOSE) { + $errornull = "2>/dev/null" unless defined $errornull; + } else { + $errornull = ''; + } + + $cccmd = "$Config{'cc'} -o $tmp $ccflags $tmp.c @$LIBS $errornull" + unless defined $cccmd; + + if ($^O eq 'VMS') { + open( CMDFILE, ">$tmp.com" ); + print CMDFILE "\$ SET MESSAGE/NOFACILITY/NOSEVERITY/NOIDENT/NOTEXT\n"; + print CMDFILE "\$ $cccmd\n"; + print CMDFILE "\$ IF \$SEVERITY .NE. 1 THEN EXIT 44\n"; # escalate + close CMDFILE; + system("\@ $tmp.com"); + $ok = $?==0; + for ("$tmp.c", "$tmp$obj_ext", "$tmp.com", "$tmp$Config{exe_ext}") { + 1 while unlink $_; + } + } + else + { + my $tmp_exe = "$tmp$ld_exeext"; + printf "cccmd = $cccmd\n" if $VERBOSE; + my $res = system($cccmd); + $ok = defined($res) && $res == 0 && -s $tmp_exe && -x _; + + if ( $ok && exists $args{run} && $args{run}) { + my $tmp_exe = + File::Spec->catfile(File::Spec->curdir, $tmp_exe); + printf "Running $tmp_exe..." if $VERBOSE; + if (system($tmp_exe) == 0) { + $ok = 1; + } else { + $ok = 0; + my $errno = $? >> 8; + local $! = $errno; + printf <<EOF; + +*** The test run of '$tmp_exe' failed: status $? +*** (the status means: errno = $errno or '$!') +*** DO NOT PANIC: this just means that *some* functionality will be missing. +EOF + } + } + unlink("$tmp.c", $tmp_exe); + } + } + + return $ok; +} + +my $TIME_HEADERS = <<EOH; +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#ifdef I_SYS_TYPES +# include <sys/types.h> +#endif +#ifdef I_SYS_TIME +# include <sys/time.h> +#endif +#ifdef I_SYS_SELECT +# include <sys/select.h> /* struct timeval might be hidden in here */ +#endif +EOH + +sub has_gettimeofday { + # confusing but true (if condition true ==> -DHAS_GETTIMEOFDAY already) + return 0 if $Config{d_gettimeod}; + return 1 if try_compile_and_link(<<EOM); +$TIME_HEADERS +static int foo() +{ + struct timeval tv; + gettimeofday(&tv, 0); +} +int main(int argc, char** argv) +{ + foo(); +} +EOM + return 0; +} + +sub has_x { + my ($x, %args) = @_; + + return 1 if + try_compile_and_link(<<EOM, %args); +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifdef I_UNISTD +# include <unistd.h> +#endif + +#ifdef I_SYS_TYPES +# include <sys/types.h> +#endif + +#ifdef I_SYS_TIME +# include <sys/time.h> +#endif + +int main(int argc, char** argv) +{ + $x; +} +EOM + return 0; +} + +sub has_nanosleep { + print "testing... "; + return 1 if + try_compile_and_link(<<EOM, run => 1); +#include <time.h> +#include <sys/time.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +/* int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); */ + +int main(int argc, char** argv) { + struct timespec ts1, ts2; + int ret; + ts1.tv_sec = 0; + ts1.tv_nsec = 750000000; + ts2.tv_sec = 0; + ts2.tv_nsec = 0; + errno = 0; + ret = nanosleep(&ts1, &ts2); /* E.g. in AIX nanosleep() fails and sets errno to ENOSYS. */ + ret == 0 ? exit(0) : exit(errno ? errno : -1); +} +EOM +} + +sub has_include { + my ($inc) = @_; + return 1 if + try_compile_and_link(<<EOM); +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include <$inc> +int main(int argc, char** argv) +{ + return 0; +} +EOM + return 0; +} + +sub has_clock_xxx_syscall { + my $x = shift; + return 0 unless defined $SYSCALL_H; + return 1 if + try_compile_and_link(<<EOM, run => 1); +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <$SYSCALL_H> +int main(int argc, char** argv) +{ + struct timespec ts; + /* Many Linuxes get ENOSYS even though the syscall exists. */ + /* All implementations are supposed to support CLOCK_REALTIME. */ + int ret = syscall(SYS_clock_$x, CLOCK_REALTIME, &ts); + ret == 0 ? exit(0) : exit(errno ? errno : -1); +} +EOM +} + +sub has_clock_xxx { + my $xxx = shift; + return 1 if + try_compile_and_link(<<EOM, run => 1); +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +int main(int argc, char** argv) +{ + struct timespec ts; + int ret = clock_$xxx(CLOCK_REALTIME, &ts); /* Many Linuxes get ENOSYS. */ + /* All implementations are supposed to support CLOCK_REALTIME. */ + ret == 0 ? exit(0) : exit(errno ? errno : -1); +} +EOM +} + +sub has_clock { + return 1 if + try_compile_and_link(<<EOM, run => 1); +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +int main(int argc, char** argv) +{ + clock_t tictoc; + clock_t ret = clock(); + ret == (clock_t)-1 ? exit(errno ? errno : -1) : exit(0); +} +EOM +} + +sub has_clock_nanosleep { + return 1 if + try_compile_and_link(<<EOM, run => 1); +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include <time.h> +int main(int argc, char** argv) +{ + int ret; + struct timespec ts1; + struct timespec ts2; + ts1.tv_sec = 0; + ts1.tv_nsec = 750000000;; + ret = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts1, &ts2); + ret == 0 ? exit(0) : exit(errno ? errno : -1); +} +EOM +} + +sub DEFINE { + my ($def, $val) = @_; + my $define = defined $val ? "$def=$val" : $def ; + unless ($DEFINE =~ /(?:^| )-D\Q$define\E(?: |$)/) { + $DEFINE .= " -D$define"; + } +} + +sub init { + my $hints = File::Spec->catfile("hints", "$^O.pl"); + if (-f $hints) { + print "Using hints $hints...\n"; + local $self; + do $hints; + if (exists $self->{LIBS}) { + $LIBS = $self->{LIBS}; + print "Extra libraries: @$LIBS...\n"; + } + } + + $DEFINE = ''; + + if ($Config{d_syscall}) { + print "Have syscall()... looking for syscall.h... "; + if (has_include('syscall.h')) { + $SYSCALL_H = 'syscall.h'; + } elsif (has_include('sys/syscall.h')) { + $SYSCALL_H = 'sys/syscall.h'; + } + } else { + print "No syscall()...\n"; + } + + if ($Config{d_syscall}) { + if (defined $SYSCALL_H) { + print "found <$SYSCALL_H>.\n"; + } else { + print "NOT found.\n"; + } + } + + print "Looking for gettimeofday()... "; + my $has_gettimeofday; + if (exists $Config{d_gettimeod}) { + $has_gettimeofday++ if $Config{d_gettimeod}; + } elsif (has_gettimeofday()) { + $DEFINE .= ' -DHAS_GETTIMEOFDAY'; + $has_gettimeofday++; + } + + if ($has_gettimeofday) { + print "found.\n"; + } else { + die <<EOD +Your operating system does not seem to have the gettimeofday() function. +(or, at least, I cannot find it) + +There is no way Time::HiRes is going to work. + +I am awfully sorry but I cannot go further. + +Aborting configuration. + +EOD + } + + print "Looking for setitimer()... "; + my $has_setitimer; + if (exists $Config{d_setitimer}) { + $has_setitimer++ if $Config{d_setitimer}; + } elsif (has_x("setitimer(ITIMER_REAL, 0, 0)")) { + $has_setitimer++; + $DEFINE .= ' -DHAS_SETITIMER'; + } + + if ($has_setitimer) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + print "Looking for getitimer()... "; + my $has_getitimer; + if (exists $Config{'d_getitimer'}) { + $has_getitimer++ if $Config{'d_getitimer'}; + } elsif (has_x("getitimer(ITIMER_REAL, 0)")) { + $has_getitimer++; + $DEFINE .= ' -DHAS_GETITIMER'; + } + + if ($has_getitimer) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + if ($has_setitimer && $has_getitimer) { + print "You have interval timers (both setitimer and getitimer).\n"; + } else { + print "You do not have interval timers.\n"; + } + + print "Looking for ualarm()... "; + my $has_ualarm; + if (exists $Config{d_ualarm}) { + $has_ualarm++ if $Config{d_ualarm}; + } elsif (has_x ("ualarm (0, 0)")) { + $has_ualarm++; + $DEFINE .= ' -DHAS_UALARM'; + } + + if ($has_ualarm) { + print "found.\n"; + } else { + print "NOT found.\n"; + if ($has_setitimer) { + print "But you have setitimer().\n"; + print "We can make a Time::HiRes::ualarm().\n"; + } + } + + print "Looking for usleep()... "; + my $has_usleep; + if (exists $Config{d_usleep}) { + $has_usleep++ if $Config{d_usleep}; + } elsif (has_x ("usleep (0)")) { + $has_usleep++; + $DEFINE .= ' -DHAS_USLEEP'; + } + + if ($has_usleep) { + print "found.\n"; + } else { + print "NOT found.\n"; + print "Let's see if you have select()... "; + if ($Config{'d_select'}) { + print "found.\n"; + print "We can make a Time::HiRes::usleep().\n"; + } else { + print "NOT found.\n"; + print "You won't have a Time::HiRes::usleep().\n"; + } + } + + print "Looking for nanosleep()... "; + my $has_nanosleep; + if ($ENV{FORCE_NANOSLEEP_SCAN}) { + print "forced scan... "; + if (has_nanosleep()) { + $has_nanosleep++; + $DEFINE .= ' -DTIME_HIRES_NANOSLEEP'; + } + } + elsif (exists $Config{d_nanosleep}) { + print "believing \$Config{d_nanosleep}... "; + if ($Config{d_nanosleep}) { + $has_nanosleep++; + $DEFINE .= ' -DTIME_HIRES_NANOSLEEP'; + } + } elsif ($^O =~ /^(mpeix)$/) { + # MPE/iX falsely finds nanosleep from its libc equivalent. + print "skipping because in $^O... "; + } else { + if (has_nanosleep()) { + $has_nanosleep++; + $DEFINE .= ' -DTIME_HIRES_NANOSLEEP'; + } + } + + if ($has_nanosleep) { + print "found.\n"; + print "You can mix subsecond sleeps with signals, if you want to.\n"; + print "(It's still not portable, though.)\n"; + } else { + print "NOT found.\n"; + my $nt = ($^O eq 'os2' ? '' : 'not'); + print "You can$nt mix subsecond sleeps with signals.\n"; + print "(It would not be portable anyway.)\n"; + } + + print "Looking for clock_gettime()... "; + my $has_clock_gettime; + if (exists $Config{d_clock_gettime}) { + $has_clock_gettime++ if $Config{d_clock_gettime}; # Unlikely... + } elsif (has_clock_xxx('gettime')) { + $has_clock_gettime++; + $DEFINE .= ' -DTIME_HIRES_CLOCK_GETTIME'; + } elsif (defined $SYSCALL_H && has_clock_xxx_syscall('gettime')) { + $has_clock_gettime++; + $DEFINE .= ' -DTIME_HIRES_CLOCK_GETTIME -DTIME_HIRES_CLOCK_GETTIME_SYSCALL'; + } + + if ($has_clock_gettime) { + if ($DEFINE =~ /-DTIME_HIRES_CLOCK_GETTIME_SYSCALL/) { + print "found (via syscall).\n"; + } else { + print "found.\n"; + } + } else { + print "NOT found.\n"; + } + + print "Looking for clock_getres()... "; + my $has_clock_getres; + if (exists $Config{d_clock_getres}) { + $has_clock_getres++ if $Config{d_clock_getres}; # Unlikely... + } elsif (has_clock_xxx('getres')) { + $has_clock_getres++; + $DEFINE .= ' -DTIME_HIRES_CLOCK_GETRES'; + } elsif (defined $SYSCALL_H && has_clock_xxx_syscall('getres')) { + $has_clock_getres++; + $DEFINE .= ' -DTIME_HIRES_CLOCK_GETRES -DTIME_HIRES_CLOCK_GETRES_SYSCALL'; + } + + if ($has_clock_getres) { + if ($DEFINE =~ /-DTIME_HIRES_CLOCK_GETRES_SYSCALL/) { + print "found (via syscall).\n"; + } else { + print "found.\n"; + } + } else { + print "NOT found.\n"; + } + + print "Looking for clock_nanosleep()... "; + my $has_clock_nanosleep; + if (exists $Config{d_clock_nanosleep}) { + $has_clock_nanosleep++ if $Config{d_clock_nanosleep}; # Unlikely... + } elsif (has_clock_nanosleep()) { + $has_clock_nanosleep++; + $DEFINE .= ' -DTIME_HIRES_CLOCK_NANOSLEEP'; + } + + if ($has_clock_nanosleep) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + print "Looking for clock()... "; + my $has_clock; + if (exists $Config{d_clock}) { + $has_clock++ if $Config{d_clock}; # Unlikely... + } elsif (has_clock()) { + $has_clock++; + $DEFINE .= ' -DTIME_HIRES_CLOCK'; + } + + if ($has_clock) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + print "Looking for stat() subsecond timestamps...\n"; + + print "Trying struct stat st_atimespec.tv_nsec..."; + my $has_stat_st_xtimespec; + if (try_compile_and_link(<<EOM)) { +$TIME_HEADERS +#include <sys/stat.h> +int main(int argc, char** argv) { + struct stat st; + st.st_atimespec.tv_nsec = 0; +} +EOM + $has_stat_st_xtimespec++; + DEFINE('TIME_HIRES_STAT', 1); + } + + if ($has_stat_st_xtimespec) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + print "Trying struct stat st_atimensec..."; + my $has_stat_st_xtimensec; + if (try_compile_and_link(<<EOM)) { +$TIME_HEADERS +#include <sys/stat.h> +int main(int argc, char** argv) { + struct stat st; + st.st_atimensec = 0; +} +EOM + $has_stat_st_xtimensec++; + DEFINE('TIME_HIRES_STAT', 2); + } + + if ($has_stat_st_xtimensec) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + print "Trying struct stat st_atime_n..."; + my $has_stat_st_xtime_n; + if (try_compile_and_link(<<EOM)) { +$TIME_HEADERS +#include <sys/stat.h> +int main(int argc, char** argv) { + struct stat st; + st.st_atime_n = 0; +} +EOM + $has_stat_st_xtime_n++; + DEFINE('TIME_HIRES_STAT', 3); + } + + if ($has_stat_st_xtime_n) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + print "Trying struct stat st_atim.tv_nsec..."; + my $has_stat_st_xtim; + if (try_compile_and_link(<<EOM)) { +$TIME_HEADERS +#include <sys/stat.h> +int main(int argc, char** argv) { + struct stat st; + st.st_atim.tv_nsec = 0; +} +EOM + $has_stat_st_xtim++; + DEFINE('TIME_HIRES_STAT', 4); + } + + if ($has_stat_st_xtim) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + print "Trying struct stat st_uatime..."; + my $has_stat_st_uxtime; + if (try_compile_and_link(<<EOM)) { +$TIME_HEADERS +#include <sys/stat.h> +int main(int argc, char** argv) { + struct stat st; + st.st_uatime = 0; +} +EOM + $has_stat_st_uxtime++; + DEFINE('TIME_HIRES_STAT', 5); + } + + if ($has_stat_st_uxtime) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + + if ($DEFINE =~ /-DTIME_HIRES_STAT=\d+/) { + print "You seem to have stat() subsecond timestamps.\n"; + print "(Your struct stat has them, but the filesystems must help.)\n"; + } else { + print "You do not seem to have stat subsecond timestamps.\n"; + } + + my $has_w32api_windows_h; + + if ($^O eq 'cygwin') { + print "Looking for <w32api/windows.h>... "; + if (has_include('w32api/windows.h')) { + $has_w32api_windows_h++; + DEFINE('HAS_W32API_WINDOWS_H'); + } + if ($has_w32api_windows_h) { + print "found.\n"; + } else { + print "NOT found.\n"; + } + } + + if ($DEFINE) { + $DEFINE =~ s/^\s+//; + if (open(XDEFINE, ">xdefine")) { + print XDEFINE $DEFINE, "\n"; + close(XDEFINE); + } + } +} + +sub doMakefile { + my @makefileopts = (); + + if ($] >= 5.005) { + push (@makefileopts, + 'AUTHOR' => 'Jarkko Hietaniemi <jhi@iki.fi>', + 'ABSTRACT_FROM' => 'HiRes.pm', + ); + DEFINE('ATLEASTFIVEOHOHFIVE'); + } + + push (@makefileopts, + 'NAME' => 'Time::HiRes', + 'VERSION_FROM' => 'HiRes.pm', # finds $VERSION + 'LIBS' => $LIBS, # e.g., '-lm' + 'DEFINE' => $DEFINE, # e.g., '-DHAS_SOMETHING' + 'XSOPT' => $XSOPT, + # Do not even think about 'INC' => '-I/usr/ucbinclude', + # Solaris will avenge. + 'INC' => '', # e.g., '-I/usr/include/other' + 'INSTALLDIRS' => ($] >= 5.008 ? 'perl' : 'site'), + 'dist' => { + 'CI' => 'ci -l', + 'COMPRESS' => 'gzip -9f', + 'SUFFIX' => 'gz', + }, + clean => { FILES => "xdefine" }, + realclean => { FILES=> 'const-c.inc const-xs.inc' }, + ); + + if ($ENV{PERL_CORE}) { + push @makefileopts, MAN3PODS => {}; + } + + WriteMakefile(@makefileopts); +} + +sub doConstants { + if (eval {require ExtUtils::Constant; 1}) { + my @names = qw(CLOCK_HIGHRES CLOCK_MONOTONIC + CLOCK_PROCESS_CPUTIME_ID + CLOCK_REALTIME + CLOCK_SOFTTIME + CLOCK_THREAD_CPUTIME_ID + CLOCK_TIMEOFDAY + CLOCKS_PER_SEC + ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF + ITIMER_REALPROF + TIMER_ABSTIME); + foreach (qw (d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer + d_nanosleep d_clock_gettime d_clock_getres + d_clock d_clock_nanosleep d_hires_stat)) { + my $macro = $_; + if ($macro =~ /^(d_nanosleep|d_clock_gettime|d_clock_getres|d_clock|d_clock_nanosleep)$/) { + $macro =~ s/^d_(.+)/TIME_HIRES_\U$1/; + } elsif ($macro =~ /^(d_hires_stat)$/) { + my $d_hires_stat = 0; + $d_hires_stat = $1 if ($DEFINE =~ /-DTIME_HIRES_STAT=(\d+)/); + push @names, {name => $_, macro => "TIME_HIRES_STAT", value => $d_hires_stat, + default => ["IV", "0"]}; + next; + } else { + $macro =~ s/^d_(.+)/HAS_\U$1/; + } + push @names, {name => $_, macro => $macro, value => 1, + default => ["IV", "0"]}; + } + ExtUtils::Constant::WriteConstants( + NAME => 'Time::HiRes', + NAMES => \@names, + ); + } else { + my $file; + foreach $file ('const-c.inc', 'const-xs.inc') { + my $fallback = File::Spec->catfile('fallback', $file); + local $/; + open IN, "<$fallback" or die "Can't open $fallback: $!"; + open OUT, ">$file" or die "Can't open $file: $!"; + print OUT <IN> or die $!; + close OUT or die "Can't close $file: $!"; + close IN or die "Can't close $fallback: $!"; + } + } +} + +sub main { + if (-f "Makefile" and -f "xdefine" && !(@ARGV && $ARGV[0] eq '--configure')) { + print qq[$0: The "xdefine" exists, skipping the configure step.\n]; + print qq[("$^X $0 --configure" to force the configure step)\n]; + } else { + print "Configuring Time::HiRes...\n"; + 1 while unlink("define"); + if ($^O =~ /Win32/i) { + DEFINE('SELECT_IS_BROKEN'); + $LIBS = []; + print "System is $^O, skipping full configure...\n"; + open(XDEFINE, ">xdefine") or die "$0: Cannot create xdefine: $!\n"; + close(XDEFINE); + } else { + init(); + } + doMakefile; + doConstants; + } + my $make = $Config{'make'} || "make"; + unless (exists $ENV{PERL_CORE} && $ENV{PERL_CORE}) { + print <<EOM; +Now you may issue '$make'. Do not forget also '$make test'. +EOM + if ($] == 5.008 && + ((exists $ENV{LC_ALL} && $ENV{LC_ALL} =~ /utf-?8/i) || + (exists $ENV{LC_CTYPE} && $ENV{LC_CTYPE} =~ /utf-?8/i) || + (exists $ENV{LANG} && $ENV{LANG} =~ /utf-?8/i))) { + print <<EOM; + +NOTE: if you get an error like this (the Makefile line number may vary): +Makefile:91: *** missing separator +then set the environment variable LC_ALL to "C" and retry +from scratch (re-run perl "Makefile.PL"). +(And consider upgrading your Perl to, say, at least Perl 5.8.8.) +(You got this message because you seem to have + an UTF-8 locale active in your shell environment, this used + to cause broken Makefiles to be created from Makefile.PLs) +EOM + } + } +} + +&main; + +# EOF diff --git a/ext/Time-HiRes/fallback/const-c.inc b/ext/Time-HiRes/fallback/const-c.inc new file mode 100644 index 0000000000..a8626172af --- /dev/null +++ b/ext/Time-HiRes/fallback/const-c.inc @@ -0,0 +1,393 @@ +#define PERL_constant_NOTFOUND 1 +#define PERL_constant_NOTDEF 2 +#define PERL_constant_ISIV 3 +#define PERL_constant_ISNO 4 +#define PERL_constant_ISNV 5 +#define PERL_constant_ISPV 6 +#define PERL_constant_ISPVN 7 +#define PERL_constant_ISSV 8 +#define PERL_constant_ISUNDEF 9 +#define PERL_constant_ISUV 10 +#define PERL_constant_ISYES 11 + +#ifndef NVTYPE +typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */ +#endif +#ifndef aTHX_ +#define aTHX_ /* 5.6 or later define this for threading support. */ +#endif +#ifndef pTHX_ +#define pTHX_ /* 5.6 or later define this for threading support. */ +#endif +static int +constant_11 (pTHX_ const char *name, IV *iv_return) { + /* When generated this function returned values for the list of names given + here. However, subsequent manual editing may have added or removed some. + ITIMER_PROF ITIMER_REAL d_getitimer d_nanosleep d_setitimer */ + /* Offset 7 gives the best switch position. */ + switch (name[7]) { + case 'P': + if (memEQ(name, "ITIMER_PROF", 11)) { + /* ^ */ +#ifdef ITIMER_PROF + *iv_return = ITIMER_PROF; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'R': + if (memEQ(name, "ITIMER_REAL", 11)) { + /* ^ */ +#ifdef ITIMER_REAL + *iv_return = ITIMER_REAL; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'i': + if (memEQ(name, "d_getitimer", 11)) { + /* ^ */ +#ifdef HAS_GETITIMER + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + if (memEQ(name, "d_setitimer", 11)) { + /* ^ */ +#ifdef HAS_SETITIMER + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + case 'l': + if (memEQ(name, "d_nanosleep", 11)) { + /* ^ */ +#ifdef TIME_HIRES_NANOSLEEP + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + } + return PERL_constant_NOTFOUND; +} + +static int +constant_14 (pTHX_ const char *name, IV *iv_return) { + /* When generated this function returned values for the list of names given + here. However, subsequent manual editing may have added or removed some. + CLOCKS_PER_SEC CLOCK_REALTIME CLOCK_SOFTTIME ITIMER_VIRTUAL d_clock_getres + d_gettimeofday */ + /* Offset 8 gives the best switch position. */ + switch (name[8]) { + case 'A': + if (memEQ(name, "CLOCK_REALTIME", 14)) { + /* ^ */ +#ifdef CLOCK_REALTIME + *iv_return = CLOCK_REALTIME; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'E': + if (memEQ(name, "CLOCKS_PER_SEC", 14)) { + /* ^ */ +#ifdef CLOCKS_PER_SEC + *iv_return = CLOCKS_PER_SEC; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'F': + if (memEQ(name, "CLOCK_SOFTTIME", 14)) { + /* ^ */ +#ifdef CLOCK_SOFTTIME + *iv_return = CLOCK_SOFTTIME; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'I': + if (memEQ(name, "ITIMER_VIRTUAL", 14)) { + /* ^ */ +#ifdef ITIMER_VIRTUAL + *iv_return = ITIMER_VIRTUAL; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'e': + if (memEQ(name, "d_gettimeofday", 14)) { + /* ^ */ +#ifdef HAS_GETTIMEOFDAY + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + case 'g': + if (memEQ(name, "d_clock_getres", 14)) { + /* ^ */ +#ifdef TIME_HIRES_CLOCK_GETRES + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + } + return PERL_constant_NOTFOUND; +} + +static int +constant_15 (pTHX_ const char *name, IV *iv_return) { + /* When generated this function returned values for the list of names given + here. However, subsequent manual editing may have added or removed some. + CLOCK_MONOTONIC CLOCK_TIMEOFDAY ITIMER_REALPROF d_clock_gettime */ + /* Offset 7 gives the best switch position. */ + switch (name[7]) { + case 'I': + if (memEQ(name, "CLOCK_TIMEOFDAY", 15)) { + /* ^ */ +#ifdef CLOCK_TIMEOFDAY + *iv_return = CLOCK_TIMEOFDAY; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'O': + if (memEQ(name, "CLOCK_MONOTONIC", 15)) { + /* ^ */ +#ifdef CLOCK_MONOTONIC + *iv_return = CLOCK_MONOTONIC; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'R': + if (memEQ(name, "ITIMER_REALPROF", 15)) { + /* ^ */ +#ifdef ITIMER_REALPROF + *iv_return = ITIMER_REALPROF; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case '_': + if (memEQ(name, "d_clock_gettime", 15)) { + /* ^ */ +#ifdef TIME_HIRES_CLOCK_GETTIME + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + } + return PERL_constant_NOTFOUND; +} + +static int +constant (pTHX_ const char *name, STRLEN len, IV *iv_return) { + /* Initially switch on the length of the name. */ + /* When generated this function returned values for the list of names given + in this section of perl code. Rather than manually editing these functions + to add or remove constants, which would result in this comment and section + of code becoming inaccurate, we recommend that you edit this section of + code, and use it to regenerate a new set of constant functions which you + then use to replace the originals. + + Regenerate these constant functions by feeding this entire source file to + perl -x + +#!perl -w +use ExtUtils::Constant qw (constant_types C_constant XS_constant); + +my $types = {map {($_, 1)} qw(IV)}; +my @names = (qw(CLOCKS_PER_SEC CLOCK_HIGHRES CLOCK_MONOTONIC + CLOCK_PROCESS_CPUTIME_ID CLOCK_REALTIME CLOCK_SOFTTIME + CLOCK_THREAD_CPUTIME_ID CLOCK_TIMEOFDAY ITIMER_PROF ITIMER_REAL + ITIMER_REALPROF ITIMER_VIRTUAL TIMER_ABSTIME), + {name=>"d_clock", type=>"IV", macro=>"TIME_HIRES_CLOCK", value=>"1", default=>["IV", "0"]}, + {name=>"d_clock_getres", type=>"IV", macro=>"TIME_HIRES_CLOCK_GETRES", value=>"1", default=>["IV", "0"]}, + {name=>"d_clock_gettime", type=>"IV", macro=>"TIME_HIRES_CLOCK_GETTIME", value=>"1", default=>["IV", "0"]}, + {name=>"d_clock_nanosleep", type=>"IV", macro=>"TIME_HIRES_CLOCK_NANOSLEEP", value=>"1", default=>["IV", "0"]}, + {name=>"d_getitimer", type=>"IV", macro=>"HAS_GETITIMER", value=>"1", default=>["IV", "0"]}, + {name=>"d_gettimeofday", type=>"IV", macro=>"HAS_GETTIMEOFDAY", value=>"1", default=>["IV", "0"]}, + {name=>"d_hires_stat", type=>"IV", macro=>"TIME_HIRES_STAT", value=>"1", default=>["IV", "0"]}, + {name=>"d_nanosleep", type=>"IV", macro=>"TIME_HIRES_NANOSLEEP", value=>"1", default=>["IV", "0"]}, + {name=>"d_setitimer", type=>"IV", macro=>"HAS_SETITIMER", value=>"1", default=>["IV", "0"]}, + {name=>"d_ualarm", type=>"IV", macro=>"HAS_UALARM", value=>"1", default=>["IV", "0"]}, + {name=>"d_usleep", type=>"IV", macro=>"HAS_USLEEP", value=>"1", default=>["IV", "0"]}); + +print constant_types(); # macro defs +foreach (C_constant ("Time::HiRes", 'constant', 'IV', $types, undef, 3, @names) ) { + print $_, "\n"; # C constant subs +} +print "#### XS Section:\n"; +print XS_constant ("Time::HiRes", $types); +__END__ + */ + + switch (len) { + case 7: + if (memEQ(name, "d_clock", 7)) { +#ifdef TIME_HIRES_CLOCK + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + case 8: + /* Names all of length 8. */ + /* d_ualarm d_usleep */ + /* Offset 7 gives the best switch position. */ + switch (name[7]) { + case 'm': + if (memEQ(name, "d_ualar", 7)) { + /* m */ +#ifdef HAS_UALARM + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + case 'p': + if (memEQ(name, "d_uslee", 7)) { + /* p */ +#ifdef HAS_USLEEP + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + } + break; + case 11: + return constant_11 (aTHX_ name, iv_return); + break; + case 12: + if (memEQ(name, "d_hires_stat", 12)) { +#ifdef TIME_HIRES_STAT + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + case 13: + /* Names all of length 13. */ + /* CLOCK_HIGHRES TIMER_ABSTIME */ + /* Offset 2 gives the best switch position. */ + switch (name[2]) { + case 'M': + if (memEQ(name, "TIMER_ABSTIME", 13)) { + /* ^ */ +#ifdef TIMER_ABSTIME + *iv_return = TIMER_ABSTIME; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 'O': + if (memEQ(name, "CLOCK_HIGHRES", 13)) { + /* ^ */ +#ifdef CLOCK_HIGHRES + *iv_return = CLOCK_HIGHRES; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + } + break; + case 14: + return constant_14 (aTHX_ name, iv_return); + break; + case 15: + return constant_15 (aTHX_ name, iv_return); + break; + case 17: + if (memEQ(name, "d_clock_nanosleep", 17)) { +#ifdef TIME_HIRES_CLOCK_NANOSLEEP + *iv_return = 1; + return PERL_constant_ISIV; +#else + *iv_return = 0; + return PERL_constant_ISIV; +#endif + } + break; + case 23: + if (memEQ(name, "CLOCK_THREAD_CPUTIME_ID", 23)) { +#ifdef CLOCK_THREAD_CPUTIME_ID + *iv_return = CLOCK_THREAD_CPUTIME_ID; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + case 24: + if (memEQ(name, "CLOCK_PROCESS_CPUTIME_ID", 24)) { +#ifdef CLOCK_PROCESS_CPUTIME_ID + *iv_return = CLOCK_PROCESS_CPUTIME_ID; + return PERL_constant_ISIV; +#else + return PERL_constant_NOTDEF; +#endif + } + break; + } + return PERL_constant_NOTFOUND; +} + diff --git a/ext/Time-HiRes/fallback/const-xs.inc b/ext/Time-HiRes/fallback/const-xs.inc new file mode 100644 index 0000000000..c84dd051dd --- /dev/null +++ b/ext/Time-HiRes/fallback/const-xs.inc @@ -0,0 +1,88 @@ +void +constant(sv) + PREINIT: +#ifdef dXSTARG + dXSTARG; /* Faster if we have it. */ +#else + dTARGET; +#endif + STRLEN len; + int type; + IV iv; + /* NV nv; Uncomment this if you need to return NVs */ + /* const char *pv; Uncomment this if you need to return PVs */ + INPUT: + SV * sv; + const char * s = SvPV(sv, len); + PPCODE: + /* Change this to constant(aTHX_ s, len, &iv, &nv); + if you need to return both NVs and IVs */ + type = constant(aTHX_ s, len, &iv); + /* Return 1 or 2 items. First is error message, or undef if no error. + Second, if present, is found value */ + switch (type) { + case PERL_constant_NOTFOUND: + sv = sv_2mortal(newSVpvf("%s is not a valid Time::HiRes macro", s)); + PUSHs(sv); + break; + case PERL_constant_NOTDEF: + sv = sv_2mortal(newSVpvf( + "Your vendor has not defined Time::HiRes macro %s, used", s)); + PUSHs(sv); + break; + case PERL_constant_ISIV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHi(iv); + break; + /* Uncomment this if you need to return NOs + case PERL_constant_ISNO: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(&PL_sv_no); + break; */ + /* Uncomment this if you need to return NVs + case PERL_constant_ISNV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHn(nv); + break; */ + /* Uncomment this if you need to return PVs + case PERL_constant_ISPV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHp(pv, strlen(pv)); + break; */ + /* Uncomment this if you need to return PVNs + case PERL_constant_ISPVN: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHp(pv, iv); + break; */ + /* Uncomment this if you need to return SVs + case PERL_constant_ISSV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(sv); + break; */ + /* Uncomment this if you need to return UNDEFs + case PERL_constant_ISUNDEF: + break; */ + /* Uncomment this if you need to return UVs + case PERL_constant_ISUV: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHu((UV)iv); + break; */ + /* Uncomment this if you need to return YESs + case PERL_constant_ISYES: + EXTEND(SP, 1); + PUSHs(&PL_sv_undef); + PUSHs(&PL_sv_yes); + break; */ + default: + sv = sv_2mortal(newSVpvf( + "Unexpected return type %d while processing Time::HiRes macro %s, used", + type, s)); + PUSHs(sv); + } diff --git a/ext/Time-HiRes/hints/aix.pl b/ext/Time-HiRes/hints/aix.pl new file mode 100644 index 0000000000..bbb7fa8342 --- /dev/null +++ b/ext/Time-HiRes/hints/aix.pl @@ -0,0 +1,18 @@ +# Many AIX installations seem not to have the right PATH +# for the C compiler. Steal the logic from Perl's hints/aix.sh. +use Config; +unless ($Config{gccversion}) { + my $cc = $Config{cc}; + if (! -x $cc && -x "/usr/vac/bin/$cc") { + unless (":$ENV{PATH}:" =~ m{:/usr/vac/bin:}) { + die <<__EOE__; +*** +*** You either implicitly or explicitly specified an IBM C compiler, +*** but you do not seem to have one in /usr/bin, but you seem to have +*** the VAC installed in /usr/vac, but you do not have the /usr/vac/bin +*** in your PATH. I suggest adding that and retrying Makefile.PL. +*** +__EOE__ + } + } +} diff --git a/ext/Time-HiRes/hints/dec_osf.pl b/ext/Time-HiRes/hints/dec_osf.pl new file mode 100644 index 0000000000..b19d149e70 --- /dev/null +++ b/ext/Time-HiRes/hints/dec_osf.pl @@ -0,0 +1,3 @@ +# needs to explicitly link against librt to pull in nanosleep +$self->{LIBS} = ['-lrt']; + diff --git a/ext/Time-HiRes/hints/dynixptx.pl b/ext/Time-HiRes/hints/dynixptx.pl new file mode 100644 index 0000000000..0a1e5db38f --- /dev/null +++ b/ext/Time-HiRes/hints/dynixptx.pl @@ -0,0 +1,5 @@ +# uname -v +# V4.5.2 +# needs to explicitly link against libc to pull in usleep +$self->{LIBS} = ['-lc']; + diff --git a/ext/Time-HiRes/hints/irix.pl b/ext/Time-HiRes/hints/irix.pl new file mode 100644 index 0000000000..83d98bcab6 --- /dev/null +++ b/ext/Time-HiRes/hints/irix.pl @@ -0,0 +1,6 @@ +use Config; +if ($Config{osvers} == 5) { + $self->{CCFLAGS} = $Config{ccflags}; + $self->{CCFLAGS} =~ s/-ansiposix //; + $self->{CCFLAGS} =~ s/-D_POSIX_SOURCE /-D_POSIX_4SOURCE /; +} diff --git a/ext/Time-HiRes/hints/linux.pl b/ext/Time-HiRes/hints/linux.pl new file mode 100644 index 0000000000..84ce5221b1 --- /dev/null +++ b/ext/Time-HiRes/hints/linux.pl @@ -0,0 +1,2 @@ +# needs to explicitly link against librt to pull in clock_nanosleep +$self->{LIBS} = ['-lrt']; diff --git a/ext/Time-HiRes/hints/sco.pl b/ext/Time-HiRes/hints/sco.pl new file mode 100644 index 0000000000..22f2764347 --- /dev/null +++ b/ext/Time-HiRes/hints/sco.pl @@ -0,0 +1,4 @@ +# osr5 needs to explicitly link against libc to pull in usleep +# what's the reason for -lm? +$self->{LIBS} = ['-lm', '-lc']; + diff --git a/ext/Time-HiRes/hints/solaris.pl b/ext/Time-HiRes/hints/solaris.pl new file mode 100644 index 0000000000..6cc80e7bc5 --- /dev/null +++ b/ext/Time-HiRes/hints/solaris.pl @@ -0,0 +1,10 @@ +# 2.6 has nanosleep in -lposix4, after that it's in -lrt +my $r = `/usr/bin/uname -r`; +chomp($r); +if (substr($r, 2) <= 6) { + $self->{LIBS} = ['-lposix4']; +} else { + $self->{LIBS} = ['-lrt']; +} + + diff --git a/ext/Time-HiRes/hints/svr4.pl b/ext/Time-HiRes/hints/svr4.pl new file mode 100644 index 0000000000..75128724f2 --- /dev/null +++ b/ext/Time-HiRes/hints/svr4.pl @@ -0,0 +1,4 @@ +# NCR MP-RAS needs to explicitly link against libc to pull in usleep +# what's the reason for -lm? +$self->{LIBS} = ['-lm', '-lc']; + diff --git a/ext/Time-HiRes/t/HiRes.t b/ext/Time-HiRes/t/HiRes.t new file mode 100644 index 0000000000..373c328d0a --- /dev/null +++ b/ext/Time-HiRes/t/HiRes.t @@ -0,0 +1,783 @@ +#!./perl -w + +BEGIN { + if ($ENV{PERL_CORE}) { + chdir 't' if -d 't'; + @INC = '../lib'; + require Config; import Config; + if (" $Config{'extensions'} " !~ m[ Time/HiRes ]) { + print "1..0 # Skip -- Perl configured without Time::HiRes module\n"; + exit 0; + } + } +} + +BEGIN { $| = 1; print "1..40\n"; } + +END { print "not ok 1\n" unless $loaded } + +use Time::HiRes 1.9704; # Remember to bump this once in a while. +use Time::HiRes qw(tv_interval); + +$loaded = 1; + +print "ok 1\n"; + +use strict; + +my $have_gettimeofday = &Time::HiRes::d_gettimeofday; +my $have_usleep = &Time::HiRes::d_usleep; +my $have_nanosleep = &Time::HiRes::d_nanosleep; +my $have_ualarm = &Time::HiRes::d_ualarm; +my $have_clock_gettime = &Time::HiRes::d_clock_gettime; +my $have_clock_getres = &Time::HiRes::d_clock_getres; +my $have_clock_nanosleep = &Time::HiRes::d_clock_nanosleep; +my $have_clock = &Time::HiRes::d_clock; +my $have_hires_stat = &Time::HiRes::d_hires_stat; + +sub has_symbol { + my $symbol = shift; + eval "use Time::HiRes qw($symbol)"; + return 0 unless $@ eq ''; + eval "my \$a = $symbol"; + return $@ eq ''; +} + +printf "# have_gettimeofday = %d\n", $have_gettimeofday; +printf "# have_usleep = %d\n", $have_usleep; +printf "# have_nanosleep = %d\n", $have_nanosleep; +printf "# have_ualarm = %d\n", $have_ualarm; +printf "# have_clock_gettime = %d\n", $have_clock_gettime; +printf "# have_clock_getres = %d\n", $have_clock_getres; +printf "# have_clock_nanosleep = %d\n", $have_clock_nanosleep; +printf "# have_clock = %d\n", $have_clock; +printf "# have_hires_stat = %d\n", $have_hires_stat; + +import Time::HiRes 'gettimeofday' if $have_gettimeofday; +import Time::HiRes 'usleep' if $have_usleep; +import Time::HiRes 'nanosleep' if $have_nanosleep; +import Time::HiRes 'ualarm' if $have_ualarm; +import Time::HiRes 'clock_gettime' if $have_clock_gettime; +import Time::HiRes 'clock_getres' if $have_clock_getres; +import Time::HiRes 'clock_nanosleep' if $have_clock_nanosleep; +import Time::HiRes 'clock' if $have_clock; + +use Config; + +use Time::HiRes qw(gettimeofday); + +my $have_alarm = $Config{d_alarm}; +my $have_fork = $Config{d_fork}; +my $waitfor = 360; # 30-45 seconds is normal (load affects this). +my $timer_pid; +my $TheEnd; + +if ($have_fork) { + print "# I am the main process $$, starting the timer process...\n"; + $timer_pid = fork(); + if (defined $timer_pid) { + if ($timer_pid == 0) { # We are the kid, set up the timer. + my $ppid = getppid(); + print "# I am the timer process $$, sleeping for $waitfor seconds...\n"; + sleep($waitfor - 2); # Workaround for perlbug #49073 + sleep(2); # Wait for parent to exit + if (kill(0, $ppid)) { # Check if parent still exists + warn "\n$0: overall time allowed for tests (${waitfor}s) exceeded!\n"; + print "# Terminating main process $ppid...\n"; + kill('KILL', $ppid); + print "# This is the timer process $$, over and out.\n"; + } + exit(0); + } else { + print "# The timer process $timer_pid launched, continuing testing...\n"; + $TheEnd = time() + $waitfor; + } + } else { + warn "$0: fork failed: $!\n"; + } +} else { + print "# No timer process (need fork)\n"; +} + +my $xdefine = ''; + +if (open(XDEFINE, "xdefine")) { + chomp($xdefine = <XDEFINE>); + close(XDEFINE); +} + +# Ideally, we'd like to test that the timers are rather precise. +# However, if the system is busy, there are no guarantees on how +# quickly we will return. This limit used to be 10%, but that +# was occasionally triggered falsely. +# So let's try 25%. +# Another possibility might be to print "ok" if the test completes fine +# with (say) 10% slosh, "skip - system may have been busy?" if the test +# completes fine with (say) 30% slosh, and fail otherwise. If you do that, +# consider changing over to test.pl at the same time. +# --A.D., Nov 27, 2001 +my $limit = 0.25; # 25% is acceptable slosh for testing timers + +sub skip { + map { print "ok $_ # skipped\n" } @_; +} + +sub ok { + my ($n, $result, @info) = @_; + if ($result) { + print "ok $n\n"; + } + else { + print "not ok $n\n"; + print "# @info\n" if @info; + } +} + +unless ($have_gettimeofday) { + skip 2..6; +} +else { + my @one = gettimeofday(); + ok 2, @one == 2, 'gettimeofday returned ', 0+@one, ' args'; + ok 3, $one[0] > 850_000_000, "@one too small"; + + sleep 1; + + my @two = gettimeofday(); + ok 4, ($two[0] > $one[0] || ($two[0] == $one[0] && $two[1] > $one[1])), + "@two is not greater than @one"; + + my $f = Time::HiRes::time(); + ok 5, $f > 850_000_000, "$f too small"; + ok 6, $f - $two[0] < 2, "$f - $two[0] >= 2"; +} + +unless ($have_usleep) { + skip 7..8; +} +else { + use Time::HiRes qw(usleep); + my $one = time; + usleep(10_000); + my $two = time; + usleep(10_000); + my $three = time; + ok 7, $one == $two || $two == $three, "slept too long, $one $two $three"; + + unless ($have_gettimeofday) { + skip 8; + } + else { + my $f = Time::HiRes::time(); + usleep(500_000); + my $f2 = Time::HiRes::time(); + my $d = $f2 - $f; + ok 8, $d > 0.4 && $d < 0.9, "slept $d secs $f to $f2"; + } +} + +# Two-arg tv_interval() is always available. +{ + my $f = tv_interval [5, 100_000], [10, 500_000]; + ok 9, abs($f - 5.4) < 0.001, $f; +} + +unless ($have_gettimeofday) { + skip 10; +} +else { + my $r = [gettimeofday()]; + my $f = tv_interval $r; + ok 10, $f < 2, $f; +} + +unless ($have_usleep && $have_gettimeofday) { + skip 11; +} +else { + my $r = [ gettimeofday() ]; + Time::HiRes::sleep( 0.5 ); + my $f = tv_interval $r; + ok 11, $f > 0.4 && $f < 0.9, "slept $f instead of 0.5 secs."; +} + +unless ($have_ualarm && $have_alarm) { + skip 12..13; +} +else { + my $tick = 0; + local $SIG{ ALRM } = sub { $tick++ }; + + my $one = time; $tick = 0; ualarm(10_000); while ($tick == 0) { } + my $two = time; $tick = 0; ualarm(10_000); while ($tick == 0) { } + my $three = time; + ok 12, $one == $two || $two == $three, "slept too long, $one $two $three"; + print "# tick = $tick, one = $one, two = $two, three = $three\n"; + + $tick = 0; ualarm(10_000, 10_000); while ($tick < 3) { } + ok 13, 1; + ualarm(0); + print "# tick = $tick, one = $one, two = $two, three = $three\n"; +} + +# Did we even get close? + +unless ($have_gettimeofday) { + skip 14; +} else { + my ($s, $n, $i) = (0); + for $i (1 .. 100) { + $s += Time::HiRes::time() - time(); + $n++; + } + # $s should be, at worst, equal to $n + # (time() may be rounding down, up, or closest), + # but allow 10% of slop. + ok 14, abs($s) / $n <= 1.10, "Time::HiRes::time() not close to time()"; + print "# s = $s, n = $n, s/n = ", abs($s)/$n, "\n"; +} + +my $has_ualarm = $Config{d_ualarm}; + +$has_ualarm ||= $xdefine =~ /-DHAS_UALARM/; + +my $can_subsecond_alarm = + defined &Time::HiRes::gettimeofday && + defined &Time::HiRes::ualarm && + defined &Time::HiRes::usleep && + $has_ualarm; + +unless ($can_subsecond_alarm) { + for (15..17) { + print "ok $_ # Skip: no gettimeofday or no ualarm or no usleep\n"; + } +} else { + use Time::HiRes qw(time alarm sleep); + eval { require POSIX }; + my $use_sigaction = + !$@ && defined &POSIX::sigaction && &POSIX::SIGALRM > 0; + + my ($f, $r, $i, $not, $ok); + + $f = time; + print "# time...$f\n"; + print "ok 15\n"; + + $r = [Time::HiRes::gettimeofday()]; + sleep (0.5); + print "# sleep...", Time::HiRes::tv_interval($r), "\nok 16\n"; + + $r = [Time::HiRes::gettimeofday()]; + $i = 5; + my $oldaction; + if ($use_sigaction) { + $oldaction = new POSIX::SigAction; + printf "# sigaction tick, ALRM = %d\n", &POSIX::SIGALRM; + + # Perl's deferred signals may be too wimpy to break through + # a restartable select(), so use POSIX::sigaction if available. + + POSIX::sigaction(&POSIX::SIGALRM, + POSIX::SigAction->new("tick"), + $oldaction) + or die "Error setting SIGALRM handler with sigaction: $!\n"; + } else { + print "# SIG tick\n"; + $SIG{ALRM} = "tick"; + } + + # On VMS timers can not interrupt select. + if ($^O eq 'VMS') { + $ok = "Skip: VMS select() does not get interrupted."; + } else { + while ($i > 0) { + alarm(0.3); + select (undef, undef, undef, 3); + my $ival = Time::HiRes::tv_interval ($r); + print "# Select returned! $i $ival\n"; + print "# ", abs($ival/3 - 1), "\n"; + # Whether select() gets restarted after signals is + # implementation dependent. If it is restarted, we + # will get about 3.3 seconds: 3 from the select, 0.3 + # from the alarm. If this happens, let's just skip + # this particular test. --jhi + if (abs($ival/3.3 - 1) < $limit) { + $ok = "Skip: your select() may get restarted by your SIGALRM (or just retry test)"; + undef $not; + last; + } + my $exp = 0.3 * (5 - $i); + if ($exp == 0) { + $not = "while: divisor became zero"; + last; + } + # This test is more sensitive, so impose a softer limit. + if (abs($ival/$exp - 1) > 4*$limit) { + my $ratio = abs($ival/$exp); + $not = "while: $exp sleep took $ival ratio $ratio"; + last; + } + $ok = $i; + } + } + + sub tick { + $i--; + my $ival = Time::HiRes::tv_interval ($r); + print "# Tick! $i $ival\n"; + my $exp = 0.3 * (5 - $i); + if ($exp == 0) { + $not = "tick: divisor became zero"; + last; + } + # This test is more sensitive, so impose a softer limit. + if (abs($ival/$exp - 1) > 4*$limit) { + my $ratio = abs($ival/$exp); + $not = "tick: $exp sleep took $ival ratio $ratio"; + $i = 0; + } + } + + if ($use_sigaction) { + POSIX::sigaction(&POSIX::SIGALRM, $oldaction); + } else { + alarm(0); # can't cancel usig %SIG + } + + print $not ? "not ok 17 # $not\n" : "ok 17 # $ok\n"; +} + +unless (defined &Time::HiRes::setitimer + && defined &Time::HiRes::getitimer + && has_symbol('ITIMER_VIRTUAL') + && $Config{sig_name} =~ m/\bVTALRM\b/ + && $^O ne 'nto' # nto: QNX 6 has the API but no implementation + && $^O ne 'haiku' # haiku: has the API but no implementation + ) { + for (18..19) { + print "ok $_ # Skip: no virtual interval timers\n"; + } +} else { + use Time::HiRes qw(setitimer getitimer ITIMER_VIRTUAL); + + my $i = 3; + my $r = [Time::HiRes::gettimeofday()]; + + $SIG{VTALRM} = sub { + $i ? $i-- : setitimer(&ITIMER_VIRTUAL, 0); + print "# Tick! $i ", Time::HiRes::tv_interval($r), "\n"; + }; + + print "# setitimer: ", join(" ", setitimer(ITIMER_VIRTUAL, 0.5, 0.4)), "\n"; + + # Assume interval timer granularity of $limit * 0.5 seconds. Too bold? + my $virt = getitimer(&ITIMER_VIRTUAL); + print "not " unless defined $virt && abs($virt / 0.5) - 1 < $limit; + print "ok 18\n"; + + print "# getitimer: ", join(" ", getitimer(ITIMER_VIRTUAL)), "\n"; + + while (getitimer(&ITIMER_VIRTUAL)) { + my $j; + for (1..1000) { $j++ } # Can't be unbreakable, must test getitimer(). + } + + print "# getitimer: ", join(" ", getitimer(ITIMER_VIRTUAL)), "\n"; + + $virt = getitimer(&ITIMER_VIRTUAL); + print "not " unless defined $virt && $virt == 0; + print "ok 19\n"; + + $SIG{VTALRM} = 'DEFAULT'; +} + +if ($have_gettimeofday && + $have_usleep) { + use Time::HiRes qw(usleep); + + my ($t0, $td); + + my $sleep = 1.5; # seconds + my $msg; + + $t0 = gettimeofday(); + $a = abs(sleep($sleep) / $sleep - 1.0); + $td = gettimeofday() - $t0; + my $ratio = 1.0 + $a; + + $msg = "$td went by while sleeping $sleep, ratio $ratio.\n"; + + if ($td < $sleep * (1 + $limit)) { + print $a < $limit ? "ok 20 # $msg" : "not ok 20 # $msg"; + } else { + print "ok 20 # Skip: $msg"; + } + + $t0 = gettimeofday(); + $a = abs(usleep($sleep * 1E6) / ($sleep * 1E6) - 1.0); + $td = gettimeofday() - $t0; + $ratio = 1.0 + $a; + + $msg = "$td went by while sleeping $sleep, ratio $ratio.\n"; + + if ($td < $sleep * (1 + $limit)) { + print $a < $limit ? "ok 21 # $msg" : "not ok 21 # $msg"; + } else { + print "ok 21 # Skip: $msg"; + } + +} else { + for (20..21) { + print "ok $_ # Skip: no gettimeofday\n"; + } +} + +unless ($have_nanosleep) { + skip 22..23; +} +else { + my $one = CORE::time; + nanosleep(10_000_000); + my $two = CORE::time; + nanosleep(10_000_000); + my $three = CORE::time; + ok 22, $one == $two || $two == $three, "slept too long, $one $two $three"; + + unless ($have_gettimeofday) { + skip 23; + } + else { + my $f = Time::HiRes::time(); + nanosleep(500_000_000); + my $f2 = Time::HiRes::time(); + my $d = $f2 - $f; + ok 23, $d > 0.4 && $d < 0.9, "slept $d secs $f to $f2"; + } +} + +eval { sleep(-1) }; +print $@ =~ /::sleep\(-1\): negative time not invented yet/ ? + "ok 24\n" : "not ok 24\n"; + +eval { usleep(-2) }; +print $@ =~ /::usleep\(-2\): negative time not invented yet/ ? + "ok 25\n" : "not ok 25\n"; + +if ($have_ualarm) { + eval { alarm(-3) }; + print $@ =~ /::alarm\(-3, 0\): negative time not invented yet/ ? + "ok 26\n" : "not ok 26\n"; + + eval { ualarm(-4) }; + print $@ =~ /::ualarm\(-4, 0\): negative time not invented yet/ ? + "ok 27\n" : "not ok 27\n"; +} else { + skip 26; + skip 27; +} + +if ($have_nanosleep) { + eval { nanosleep(-5) }; + print $@ =~ /::nanosleep\(-5\): negative time not invented yet/ ? + "ok 28\n" : "not ok 28\n"; +} else { + skip 28; +} + +# Find the loop size N (a for() loop 0..N-1) +# that will take more than T seconds. + +if ($have_ualarm && $] >= 5.008001) { + # http://groups.google.com/group/perl.perl5.porters/browse_thread/thread/adaffaaf939b042e/20dafc298df737f0%2320dafc298df737f0?sa=X&oi=groupsr&start=0&num=3 + # Perl changes [18765] and [18770], perl bug [perl #20920] + + print "# Finding delay loop...\n"; + + my $T = 0.01; + use Time::HiRes qw(time); + my $DelayN = 1024; + my $i; + N: { + do { + my $t0 = time(); + for ($i = 0; $i < $DelayN; $i++) { } + my $t1 = time(); + my $dt = $t1 - $t0; + print "# N = $DelayN, t1 = $t1, t0 = $t0, dt = $dt\n"; + last N if $dt > $T; + $DelayN *= 2; + } while (1); + } + + # The time-burner which takes at least T (default 1) seconds. + my $Delay = sub { + my $c = @_ ? shift : 1; + my $n = $c * $DelayN; + my $i; + for ($i = 0; $i < $n; $i++) { } + }; + + # Next setup a periodic timer (the two-argument alarm() of + # Time::HiRes, behind the curtains the libc getitimer() or + # ualarm()) which has a signal handler that takes so much time (on + # the first initial invocation) that the first periodic invocation + # (second invocation) will happen before the first invocation has + # finished. In Perl 5.8.0 the "safe signals" concept was + # implemented, with unfortunately at least one bug that caused a + # core dump on reentering the handler. This bug was fixed by the + # time of Perl 5.8.1. + + # Do not try mixing sleep() and alarm() for testing this. + + my $a = 0; # Number of alarms we receive. + my $A = 2; # Number of alarms we will handle before disarming. + # (We may well get $A + 1 alarms.) + + $SIG{ALRM} = sub { + $a++; + print "# Alarm $a - ", time(), "\n"; + alarm(0) if $a >= $A; # Disarm the alarm. + $Delay->(2); # Try burning CPU at least for 2T seconds. + }; + + use Time::HiRes qw(alarm); + alarm($T, $T); # Arm the alarm. + + $Delay->(10); # Try burning CPU at least for 10T seconds. + + print "ok 29\n"; # Not core dumping by now is considered to be the success. +} else { + skip 29; +} + +if ($have_clock_gettime && + # All implementations of clock_gettime() + # are SUPPOSED TO support CLOCK_REALTIME. + has_symbol('CLOCK_REALTIME')) { + my $ok = 0; + TRY: { + for my $try (1..3) { + print "# CLOCK_REALTIME: try = $try\n"; + my $t0 = clock_gettime(&CLOCK_REALTIME); + use Time::HiRes qw(sleep); + my $T = 1.5; + sleep($T); + my $t1 = clock_gettime(&CLOCK_REALTIME); + if ($t0 > 0 && $t1 > $t0) { + print "# t1 = $t1, t0 = $t0\n"; + my $dt = $t1 - $t0; + my $rt = abs(1 - $dt / $T); + print "# dt = $dt, rt = $rt\n"; + if ($rt <= 2 * $limit) { + $ok = 1; + last TRY; + } + } else { + print "# Error: t0 = $t0, t1 = $t1\n"; + } + my $r = rand() + rand(); + printf "# Sleeping for %.6f seconds...\n", $r; + sleep($r); + } + } + if ($ok) { + print "ok 30\n"; + } else { + print "not ok 30\n"; + } +} else { + print "# No clock_gettime\n"; + skip 30; +} + +if ($have_clock_getres) { + my $tr = clock_getres(); + if ($tr > 0) { + print "ok 31 # tr = $tr\n"; + } else { + print "not ok 31 # tr = $tr\n"; + } +} else { + print "# No clock_getres\n"; + skip 31; +} + +if ($have_clock_nanosleep && + has_symbol('CLOCK_REALTIME')) { + my $s = 1.5e9; + my $t = clock_nanosleep(&CLOCK_REALTIME, $s); + my $r = abs(1 - $t / $s); + if ($r < 2 * $limit) { + print "ok 32\n"; + } else { + print "not ok 32 # $t = $t, r = $r\n"; + } +} else { + print "# No clock_nanosleep\n"; + skip 32; +} + +if ($have_clock) { + my @clock = clock(); + print "# clock = @clock\n"; + for my $i (1..3) { + for (my $j = 0; $j < 1e6; $j++) { } + push @clock, clock(); + print "# clock = @clock\n"; + } + if ($clock[0] >= 0 && + $clock[1] > $clock[0] && + $clock[2] > $clock[1] && + $clock[3] > $clock[2]) { + print "ok 33\n"; + } else { + print "not ok 33\n"; + } +} else { + skip 33; +} + +sub bellish { # Cheap emulation of a bell curve. + my ($min, $max) = @_; + my $rand = ($max - $min) / 5; + my $sum = 0; + for my $i (0..4) { + $sum += rand($rand); + } + return $min + $sum; +} + +if ($have_ualarm) { + # 1_100_000 sligthly over 1_000_000, + # 2_200_000 slightly over 2**31/1000, + # 4_300_000 slightly over 2**32/1000. + for my $t ([34, 100_000], + [35, 1_100_000], + [36, 2_200_000], + [37, 4_300_000]) { + my ($i, $n) = @$t; + my $ok; + for my $retry (1..10) { + my $alarmed = 0; + local $SIG{ ALRM } = sub { $alarmed++ }; + my $t0 = Time::HiRes::time(); + print "# t0 = $t0\n"; + print "# ualarm($n)\n"; + ualarm($n); 1 while $alarmed == 0; + my $t1 = Time::HiRes::time(); + print "# t1 = $t1\n"; + my $dt = $t1 - $t0; + print "# dt = $dt\n"; + my $r = $dt / ($n/1e6); + print "# r = $r\n"; + $ok = + ($n < 1_000_000 || # Too much noise. + ($r >= 0.8 && $r <= 1.6)); + last if $ok; + my $nap = bellish(3, 15); + printf "# Retrying in %.1f seconds...\n", $nap; + Time::HiRes::sleep($nap); + } + ok $i, $ok, "ualarm($n) close enough"; + } +} else { + print "# No ualarm\n"; + skip 34..37; +} + +if ($^O =~ /^(cygwin|MSWin)/) { + print "# $^O: timestamps may not be good enough\n"; + skip 38; +} elsif (&Time::HiRes::d_hires_stat) { + my @stat; + my @atime; + my @mtime; + for (1..5) { + Time::HiRes::sleep(rand(0.1) + 0.1); + open(X, ">$$"); + print X $$; + close(X); + @stat = Time::HiRes::stat($$); + push @mtime, $stat[9]; + Time::HiRes::sleep(rand(0.1) + 0.1); + open(X, "<$$"); + <X>; + close(X); + @stat = Time::HiRes::stat($$); + push @atime, $stat[8]; + } + 1 while unlink $$; + print "# mtime = @mtime\n"; + print "# atime = @atime\n"; + my $ai = 0; + my $mi = 0; + my $ss = 0; + for (my $i = 1; $i < @atime; $i++) { + if ($atime[$i] >= $atime[$i-1]) { + $ai++; + } + if ($atime[$i] > int($atime[$i])) { + $ss++; + } + } + for (my $i = 1; $i < @mtime; $i++) { + if ($mtime[$i] >= $mtime[$i-1]) { + $mi++; + } + if ($mtime[$i] > int($mtime[$i])) { + $ss++; + } + } + print "# ai = $ai, mi = $mi, ss = $ss\n"; + # Need at least 75% of monotonical increase and + # 20% of subsecond results. Yes, this is guessing. + if ($ss == 0) { + print "# No subsecond timestamps detected\n"; + skip 38; + } elsif ($mi/(@mtime-1) >= 0.75 && $ai/(@atime-1) >= 0.75 && + $ss/(@mtime+@atime) >= 0.2) { + print "ok 38\n"; + } else { + print "not ok 38\n"; + } +} else { + print "# No effectual d_hires_stat\n"; + skip 38; +} + +unless ($can_subsecond_alarm) { + skip 39..40; +} else { + { + my $alrm; + $SIG{ALRM} = sub { $alrm++ }; + Time::HiRes::alarm(0.1); + my $t0 = time(); + 1 while time() - $t0 <= 1; + print $alrm ? "ok 39\n" : "not ok 39\n"; + } + { + my $alrm; + $SIG{ALRM} = sub { $alrm++ }; + Time::HiRes::alarm(1.1); + my $t0 = time(); + 1 while time() - $t0 <= 2; + print $alrm ? "ok 40\n" : "not ok 40\n"; + } +} + +END { + if ($timer_pid) { # Only in the main process. + my $left = $TheEnd - time(); + printf "# I am the main process $$, terminating the timer process $timer_pid\n# before it terminates me in %d seconds (testing took %d seconds).\n", $left, $waitfor - $left; + if (kill(0, $timer_pid)) { + local $? = 0; + my $kill = kill('KILL', $timer_pid); # We are done, the timer can go. + wait(); + printf "# kill KILL $timer_pid = %d\n", $kill; + } + unlink("ktrace.out"); # Used in BSD system call tracing. + print "# All done.\n"; + } +} + diff --git a/ext/Time-HiRes/typemap b/ext/Time-HiRes/typemap new file mode 100644 index 0000000000..1124eb6483 --- /dev/null +++ b/ext/Time-HiRes/typemap @@ -0,0 +1,313 @@ +# basic C types +int T_IV +unsigned T_UV +unsigned int T_UV +long T_IV +unsigned long T_UV +short T_IV +unsigned short T_UV +char T_CHAR +unsigned char T_U_CHAR +char * T_PV +unsigned char * T_PV +const char * T_PV +caddr_t T_PV +wchar_t * T_PV +wchar_t T_IV +bool_t T_IV +size_t T_UV +ssize_t T_IV +time_t T_NV +unsigned long * T_OPAQUEPTR +char ** T_PACKEDARRAY +void * T_PTR +Time_t * T_PV +SV * T_SV +SVREF T_SVREF +AV * T_AVREF +HV * T_HVREF +CV * T_CVREF + +IV T_IV +UV T_UV +NV T_NV +I32 T_IV +I16 T_IV +I8 T_IV +STRLEN T_UV +U32 T_U_LONG +U16 T_U_SHORT +U8 T_UV +Result T_U_CHAR +Boolean T_BOOL +float T_FLOAT +double T_DOUBLE +SysRet T_SYSRET +SysRetLong T_SYSRET +FILE * T_STDIO +PerlIO * T_INOUT +FileHandle T_PTROBJ +InputStream T_IN +InOutStream T_INOUT +OutputStream T_OUT +bool T_BOOL + +############################################################################# +INPUT +T_SV + $var = $arg +T_SVREF + if (SvROK($arg)) + $var = (SV*)SvRV($arg); + else + Perl_croak(aTHX_ \"$var is not a reference\") +T_AVREF + if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) + $var = (AV*)SvRV($arg); + else + Perl_croak(aTHX_ \"$var is not an array reference\") +T_HVREF + if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVHV) + $var = (HV*)SvRV($arg); + else + Perl_croak(aTHX_ \"$var is not a hash reference\") +T_CVREF + if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVCV) + $var = (CV*)SvRV($arg); + else + Perl_croak(aTHX_ \"$var is not a code reference\") +T_SYSRET + $var NOT IMPLEMENTED +T_UV + $var = ($type)SvUV($arg) +T_IV + $var = ($type)SvIV($arg) +T_INT + $var = (int)SvIV($arg) +T_ENUM + $var = ($type)SvIV($arg) +T_BOOL + $var = (bool)SvTRUE($arg) +T_U_INT + $var = (unsigned int)SvUV($arg) +T_SHORT + $var = (short)SvIV($arg) +T_U_SHORT + $var = (unsigned short)SvUV($arg) +T_LONG + $var = (long)SvIV($arg) +T_U_LONG + $var = (unsigned long)SvUV($arg) +T_CHAR + $var = (char)*SvPV_nolen($arg) +T_U_CHAR + $var = (unsigned char)SvUV($arg) +T_FLOAT + $var = (float)SvNV($arg) +T_NV + $var = ($type)SvNV($arg) +T_DOUBLE + $var = (double)SvNV($arg) +T_PV + $var = ($type)SvPV_nolen($arg) +T_PTR + $var = INT2PTR($type,SvIV($arg)) +T_PTRREF + if (SvROK($arg)) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"$var is not a reference\") +T_REF_IV_REF + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = *INT2PTR($type *, tmp); + } + else + Perl_croak(aTHX_ \"$var is not of type ${ntype}\") +T_REF_IV_PTR + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = INT2PTR($type, tmp); + } + else + Perl_croak(aTHX_ \"$var is not of type ${ntype}\") +T_PTROBJ + if (sv_derived_from($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"$var is not of type ${ntype}\") +T_PTRDESC + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + ${type}_desc = (\U${type}_DESC\E*) tmp; + $var = ${type}_desc->ptr; + } + else + Perl_croak(aTHX_ \"$var is not of type ${ntype}\") +T_REFREF + if (SvROK($arg)) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = *INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"$var is not a reference\") +T_REFOBJ + if (sv_isa($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = *INT2PTR($type,tmp); + } + else + Perl_croak(aTHX_ \"$var is not of type ${ntype}\") +T_OPAQUE + $var = *($type *)SvPV_nolen($arg) +T_OPAQUEPTR + $var = ($type)SvPV_nolen($arg) +T_PACKED + $var = XS_unpack_$ntype($arg) +T_PACKEDARRAY + $var = XS_unpack_$ntype($arg) +T_CALLBACK + $var = make_perl_cb_$type($arg) +T_ARRAY + U32 ix_$var = $argoff; + $var = $ntype(items -= $argoff); + while (items--) { + DO_ARRAY_ELEM; + ix_$var++; + } + /* this is the number of elements in the array */ + ix_$var -= $argoff +T_STDIO + $var = PerlIO_findFILE(IoIFP(sv_2io($arg))) +T_IN + $var = IoIFP(sv_2io($arg)) +T_INOUT + $var = IoIFP(sv_2io($arg)) +T_OUT + $var = IoOFP(sv_2io($arg)) +############################################################################# +OUTPUT +T_SV + $arg = $var; +T_SVREF + $arg = newRV((SV*)$var); +T_AVREF + $arg = newRV((SV*)$var); +T_HVREF + $arg = newRV((SV*)$var); +T_CVREF + $arg = newRV((SV*)$var); +T_IV + sv_setiv($arg, (IV)$var); +T_UV + sv_setuv($arg, (UV)$var); +T_INT + sv_setiv($arg, (IV)$var); +T_SYSRET + if ($var != -1) { + if ($var == 0) + sv_setpvn($arg, "0 but true", 10); + else + sv_setiv($arg, (IV)$var); + } +T_ENUM + sv_setiv($arg, (IV)$var); +T_BOOL + $arg = boolSV($var); +T_U_INT + sv_setuv($arg, (UV)$var); +T_SHORT + sv_setiv($arg, (IV)$var); +T_U_SHORT + sv_setuv($arg, (UV)$var); +T_LONG + sv_setiv($arg, (IV)$var); +T_U_LONG + sv_setuv($arg, (UV)$var); +T_CHAR + sv_setpvn($arg, (char *)&$var, 1); +T_U_CHAR + sv_setuv($arg, (UV)$var); +T_FLOAT + sv_setnv($arg, (double)$var); +T_NV + sv_setnv($arg, (NV)$var); +T_DOUBLE + sv_setnv($arg, (double)$var); +T_PV + sv_setpv((SV*)$arg, $var); +T_PTR + sv_setiv($arg, PTR2IV($var)); +T_PTRREF + sv_setref_pv($arg, Nullch, (void*)$var); +T_REF_IV_REF + sv_setref_pv($arg, \"${ntype}\", (void*)new $ntype($var)); +T_REF_IV_PTR + sv_setref_pv($arg, \"${ntype}\", (void*)$var); +T_PTROBJ + sv_setref_pv($arg, \"${ntype}\", (void*)$var); +T_PTRDESC + sv_setref_pv($arg, \"${ntype}\", (void*)new\U${type}_DESC\E($var)); +T_REFREF + NOT_IMPLEMENTED +T_REFOBJ + NOT IMPLEMENTED +T_OPAQUE + sv_setpvn($arg, (char *)&$var, sizeof($var)); +T_OPAQUEPTR + sv_setpvn($arg, (char *)$var, sizeof(*$var)); +T_PACKED + XS_pack_$ntype($arg, $var); +T_PACKEDARRAY + XS_pack_$ntype($arg, $var, count_$ntype); +T_DATAUNIT + sv_setpvn($arg, $var.chp(), $var.size()); +T_CALLBACK + sv_setpvn($arg, $var.context.value().chp(), + $var.context.value().size()); +T_ARRAY + { + U32 ix_$var; + EXTEND(SP,size_$var); + for (ix_$var = 0; ix_$var < size_$var; ix_$var++) { + ST(ix_$var) = sv_newmortal(); + DO_ARRAY_ELEM + } + } +T_STDIO + { + GV *gv = newGVgen("$Package"); + PerlIO *fp = PerlIO_importFILE($var,0); + if ( fp && do_open(gv, "+<&", 3, FALSE, 0, 0, fp) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } +T_IN + { + GV *gv = newGVgen("$Package"); + if ( do_open(gv, "<&", 2, FALSE, 0, 0, $var) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } +T_INOUT + { + GV *gv = newGVgen("$Package"); + if ( do_open(gv, "+<&", 3, FALSE, 0, 0, $var) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } +T_OUT + { + GV *gv = newGVgen("$Package"); + if ( do_open(gv, "+>&", 3, FALSE, 0, 0, $var) ) + sv_setsv($arg, sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))); + else + $arg = &PL_sv_undef; + } |