📄 hires.xs
字号:
/* * * Copyright (c) 1996-2002 Douglas E. Wegscheid. All rights reserved. * * Copyright (c) 2002,2003,2004,2005,2006,2007 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 __cplusplusextern "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#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# define CLOCK_REALTIME CLOCK_REALTIME# define CLOCK_VIRTUAL CLOCK_VIRTUAL# define CLOCK_PROFILE CLOCK_PROFILE# 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_VERSIONtypedef 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 intsleep(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 __VAXstatic long base_adjust[2]={0L,0L};#elsestatic __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 inttimezone_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;}intgettimeofday (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_nanosleep /* could conflict with ncurses for static build */voidhrt_nanosleep(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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -