#ifdef __cplusplus
extern "C" {
#endif
+#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#else
#include <sys/time.h>
#endif
+#ifdef HAS_SELECT
+# ifdef I_SYS_SELECT
+# include <sys/select.h>
+# endif
+#endif
#ifdef __cplusplus
}
#endif
-static IV
-constant(char *name, int arg)
-{
- errno = 0;
- switch (*name) {
- case 'I':
- if (strEQ(name, "ITIMER_REAL"))
-#ifdef ITIMER_REAL
- return ITIMER_REAL;
-#else
- goto not_there;
+#ifndef NOOP
+# define NOOP (void)0
#endif
- if (strEQ(name, "ITIMER_REALPROF"))
-#ifdef ITIMER_REALPROF
- return ITIMER_REALPROF;
-#else
- goto not_there;
+#ifndef dNOOP
+# define dNOOP extern int Perl___notused
+#endif
+
+#ifndef aTHX_
+# define aTHX_
+# define pTHX_
+# define dTHX dNOOP
#endif
- if (strEQ(name, "ITIMER_VIRTUAL"))
-#ifdef ITIMER_VIRTUAL
- return ITIMER_VIRTUAL;
+
+#ifdef START_MY_CXT
+# ifndef MY_CXT_CLONE
+# define MY_CXT_CLONE \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+ Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+# endif
#else
- goto not_there;
+# define START_MY_CXT static my_cxt_t my_cxt;
+# define dMY_CXT dNOOP
+# define MY_CXT_INIT NOOP
+# define MY_CXT_CLONE NOOP
+# define MY_CXT my_cxt
#endif
- if (strEQ(name, "ITIMER_PROF"))
-#ifdef ITIMER_PROF
- return ITIMER_PROF;
+
+#ifndef NVTYPE
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
+# define NVTYPE long double
+# else
+# define NVTYPE double
+# endif
+typedef NVTYPE NV;
+#endif
+
+#ifndef IVdf
+# ifdef IVSIZE
+# if IVSIZE == LONGSIZE
+# define IVdf "ld"
+# define UVuf "lu"
+# else
+# if IVSIZE == INTSIZE
+# define IVdf "d"
+# define UVuf "u"
+# endif
+# endif
+# else
+# define IVdf "ld"
+# define UVuf "lu"
+# endif
+#endif
+
+#ifndef NVef
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
+ defined(PERL_PRIgldbl) /* Not very likely, but let's try anyway. */
+# define NVgf PERL_PRIgldbl
+# else
+# define NVgf "g"
+# endif
+#endif
+
+#ifndef INT2PTR
+
+#if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+# define PTRV UV
+# define INT2PTR(any,d) (any)(d)
#else
- goto not_there;
+# if PTRSIZE == LONGSIZE
+# define PTRV unsigned long
+# else
+# define PTRV unsigned
+# endif
+# define INT2PTR(any,d) (any)(PTRV)(d)
#endif
- break;
- }
- errno = EINVAL;
- return 0;
+#define PTR2IV(p) INT2PTR(IV,p)
-not_there:
- errno = ENOENT;
- return 0;
+#endif /* !INT2PTR */
+
+#ifndef SvPV_nolen
+static char *
+sv_2pv_nolen(pTHX_ register SV *sv)
+{
+ STRLEN n_a;
+ return sv_2pv(sv, &n_a);
}
+# define SvPV_nolen(sv) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? SvPVX(sv) : sv_2pv_nolen(sv))
+#endif
-#if !defined(HAS_GETTIMEOFDAY) && defined(WIN32)
-#define HAS_GETTIMEOFDAY
+#ifndef PerlProc_pause
+# define PerlProc_pause() Pause()
+#endif
+
+/* Though the cpp define ITIMER_VIRTUAL is available the functionality
+ * is not supported in Cygwin as of August 2002, 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
+
+/* 5.004 doesn't define PL_sv_undef */
+#ifndef ATLEASTFIVEOHOHFIVE
+#ifndef PL_sv_undef
+#define PL_sv_undef sv_undef
+#endif
+#endif
+
+#include "const-c.inc"
+
+#ifdef WIN32
+
+#ifndef HAS_GETTIMEOFDAY
+# define HAS_GETTIMEOFDAY
+#endif
/* shows up in winsock.h?
struct timeval {
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;
+} my_cxt_t;
+
+START_MY_CXT
+
/* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
-#define EPOCH_BIAS 116444736000000000i64
+#ifdef __GNUC__
+#define Const64(x) x##LL
+#else
+#define Const64(x) x##i64
+#endif
+#define EPOCH_BIAS Const64(116444736000000000)
/* NOTE: This does not compute the timezone info (doing so can be expensive,
* and appears to be unsupported even by glibc) */
-int
-gettimeofday (struct timeval *tp, void *not_used)
+
+/* 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)
+
+static int
+_gettimeofday(pTHX_ struct timeval *tp, void *not_used)
{
+ dMY_CXT;
+
+ unsigned __int64 ticks;
FT_t ft;
- /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
- GetSystemTimeAsFileTime(&ft.ft_val);
+ if (MY_CXT.run_count++) {
+ QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
+ ticks -= MY_CXT.base_ticks;
+ ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64
+ + 10000000i64 * (ticks / MY_CXT.tick_frequency)
+ +(10000000i64 * (ticks % MY_CXT.tick_frequency)) / MY_CXT.tick_frequency;
+ }
+ else {
+ 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;
+ }
/* seconds since epoch */
- tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / 10000000i64);
+ tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
/* microseconds remaining */
- tp->tv_usec = (long)((ft.ft_i64 / 10i64) % 1000000i64);
+ tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
+
+ return 0;
+}
+#endif
+#if defined(WIN32) && !defined(ATLEASTFIVEOHOHFIVE)
+static unsigned int
+sleep(unsigned int t)
+{
+ Sleep(t*1000);
return 0;
}
#endif
}
#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.
+ * 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 */
+
+void
+hrt_nanosleep(unsigned long usec)
+{
+ struct timespec res;
+ res.tv_sec = usec/1000/1000;
+ res.tv_nsec = ( usec - res.tv_sec*1000*1000 ) * 1000;
+ nanosleep(&res, NULL);
+}
+#endif
+
+
#if !defined(HAS_USLEEP) && defined(HAS_SELECT)
#ifndef SELECT_IS_BROKEN
#define HAS_USLEEP
}
#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 /* !HAS_UALARM && VMS */
+
#ifdef HAS_GETTIMEOFDAY
static int
-myU2time(UV *ret)
+myU2time(pTHX_ UV *ret)
{
struct timeval Tp;
int status;
static NV
myNVtime()
{
+#ifdef WIN32
+ dTHX;
+#endif
struct timeval Tp;
int status;
status = gettimeofday (&Tp, NULL);
PROTOTYPES: ENABLE
BOOT:
-#ifdef HAS_GETTIMEOFDAY
{
- UV auv[2];
- hv_store(PL_modglobal, "Time::NVtime", 12, newSViv((IV) myNVtime()), 0);
- if (myU2time(auv) == 0)
- hv_store(PL_modglobal, "Time::U2time", 12, newSViv((IV) auv[0]), 0);
+#ifdef MY_CXT_KEY
+ MY_CXT_INIT;
+#endif
+#ifdef ATLEASTFIVEOHOHFIVE
+#ifdef HAS_GETTIMEOFDAY
+ {
+ UV auv[2];
+ hv_store(PL_modglobal, "Time::NVtime", 12, newSViv(PTR2IV(myNVtime)), 0);
+ if (myU2time(aTHX_ auv) == 0)
+ hv_store(PL_modglobal, "Time::U2time", 12, newSViv((IV) auv[0]), 0);
+ }
+#endif
+#endif
}
+
+#if defined(USE_ITHREADS) && defined(MY_CXT_KEY)
+
+void
+CLONE(...)
+ CODE:
+ MY_CXT_CLONE;
+
#endif
-IV
-constant(name, arg)
- char * name
- int arg
+INCLUDE: const-xs.inc
#if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY)
}
} else if (useconds < 0.0)
croak("Time::HiRes::usleep(%"NVgf"): negative time not invented yet", useconds);
- usleep((UV)useconds);
+ usleep((U32)useconds);
} else
PerlProc_pause();
gettimeofday(&Tb, NULL);
if (items > 0) {
NV seconds = SvNV(ST(0));
if (seconds >= 0.0) {
- UV useconds = 1E6 * (seconds - (UV)seconds);
- sleep((UV)seconds);
+ 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 ((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);
struct itimerval oldit;
PPCODE:
if (seconds < 0.0 || interval < 0.0)
- croak("Time::HiRes::setitimer(%"IVdf", %"NVgf", %"NVgf"): negative time not invented yet", which, seconds, interval);
+ croak("Time::HiRes::setitimer(%"IVdf", %"NVgf", %"NVgf"): negative time not invented yet", (IV)which, seconds, interval);
newit.it_value.tv_sec = seconds;
newit.it_value.tv_usec =
(seconds - (NV)newit.it_value.tv_sec) * 1000000.0;
#endif
-# $Id: HiRes.xs,v 1.11 1999/03/16 02:27:38 wegscd Exp wegscd $
-
-# $Log: HiRes.xs,v $
-# Revision 1.11 1999/03/16 02:27:38 wegscd
-# Add U2time, NVtime. Fix symbols for static link.
-#
-# Revision 1.10 1998/09/30 02:36:25 wegscd
-# Add VMS changes.
-#
-# Revision 1.9 1998/07/07 02:42:06 wegscd
-# Win32 usleep()
-#
-# Revision 1.8 1998/07/02 01:47:26 wegscd
-# Add Win32 code for gettimeofday.
-#
-# Revision 1.7 1997/11/13 02:08:12 wegscd
-# Add missing EXTEND in gettimeofday() scalar code.
-#
-# Revision 1.6 1997/11/11 02:32:35 wegscd
-# Do something useful when calling gettimeofday() in a scalar context.
-# The patch is courtesy of Gisle Aas.
-#
-# Revision 1.5 1997/11/06 03:10:47 wegscd
-# Fake ualarm() if we have setitimer.
-#
-# Revision 1.4 1997/11/05 05:41:23 wegscd
-# Turn prototypes ON (suggested by Gisle Aas)
-#
-# Revision 1.3 1997/10/13 20:56:15 wegscd
-# Add PROTOTYPES: DISABLE
-#
-# Revision 1.2 1997/05/23 01:01:38 wegscd
-# Conditional compilation, depending on what the OS gives us.
-#
-# Revision 1.1 1996/09/03 18:26:35 wegscd
-# Initial revision
-#
-#