This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
GCC vs MS 64-bit constant syntax
[perl5.git] / ext / Time / HiRes / HiRes.xs
1 #ifdef __cplusplus
2 extern "C" {
3 #endif
4 #include "EXTERN.h"
5 #include "perl.h"
6 #include "XSUB.h"
7 #ifdef WIN32
8 #include <time.h>
9 #else
10 #include <sys/time.h>
11 #endif
12 #ifdef __cplusplus
13 }
14 #endif
15
16 static IV
17 constant(char *name, int arg)
18 {
19     errno = 0;
20     switch (*name) {
21     case 'I':
22       if (strEQ(name, "ITIMER_REAL"))
23 #ifdef ITIMER_REAL
24         return ITIMER_REAL;
25 #else
26         goto not_there;
27 #endif
28       if (strEQ(name, "ITIMER_REALPROF"))
29 #ifdef ITIMER_REALPROF
30         return ITIMER_REALPROF;
31 #else
32         goto not_there;
33 #endif
34       if (strEQ(name, "ITIMER_VIRTUAL"))
35 #ifdef ITIMER_VIRTUAL
36         return ITIMER_VIRTUAL;
37 #else
38         goto not_there;
39 #endif
40       if (strEQ(name, "ITIMER_PROF"))
41 #ifdef ITIMER_PROF
42         return ITIMER_PROF;
43 #else
44         goto not_there;
45 #endif
46       break;
47     }
48     errno = EINVAL;
49     return 0;
50
51 not_there:
52     errno = ENOENT;
53     return 0;
54 }
55
56 #if !defined(HAS_GETTIMEOFDAY) && defined(WIN32)
57 #define HAS_GETTIMEOFDAY
58
59 /* shows up in winsock.h?
60 struct timeval {
61  long tv_sec;
62  long tv_usec;
63 }
64 */
65
66 typedef union {
67     unsigned __int64    ft_i64;
68     FILETIME            ft_val;
69 } FT_t;
70
71 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
72 #ifdef __GNUC__
73 #define Const64(x) x##LL
74 #else
75 #define Const64(x) x##i64
76 #endif
77 #define EPOCH_BIAS  Const64(116444736000000000)
78
79 /* NOTE: This does not compute the timezone info (doing so can be expensive,
80  * and appears to be unsupported even by glibc) */
81 int
82 gettimeofday (struct timeval *tp, void *not_used)
83 {
84     FT_t ft;
85
86     /* this returns time in 100-nanosecond units  (i.e. tens of usecs) */
87     GetSystemTimeAsFileTime(&ft.ft_val);
88
89     /* seconds since epoch */
90     tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
91
92     /* microseconds remaining */
93     tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
94
95     return 0;
96 }
97 #endif
98
99 #if !defined(HAS_GETTIMEOFDAY) && defined(VMS)
100 #define HAS_GETTIMEOFDAY
101
102 #include <lnmdef.h>
103 #include <time.h> /* gettimeofday */
104 #include <stdlib.h> /* qdiv */
105 #include <starlet.h> /* sys$gettim */
106 #include <descrip.h>
107 #ifdef __VAX
108 #include <lib$routines.h> /* lib$ediv() */
109 #endif
110
111 /*
112         VMS binary time is expressed in 100 nano-seconds since
113         system base time which is 17-NOV-1858 00:00:00.00
114 */
115
116 #define DIV_100NS_TO_SECS  10000000L
117 #define DIV_100NS_TO_USECS 10L
118
119 /* 
120         gettimeofday is supposed to return times since the epoch
121         so need to determine this in terms of VMS base time
122 */
123 static $DESCRIPTOR(dscepoch,"01-JAN-1970 00:00:00.00");
124
125 #ifdef __VAX
126 static long base_adjust[2]={0L,0L};
127 #else
128 static __int64 base_adjust=0;
129 #endif
130
131 /* 
132
133    If we don't have gettimeofday, then likely we are on a VMS machine that
134    operates on local time rather than UTC...so we have to zone-adjust.
135    This code gleefully swiped from VMS.C 
136
137 */
138 /* method used to handle UTC conversions:
139  *   1 == CRTL gmtime();  2 == SYS$TIMEZONE_DIFFERENTIAL;  3 == no correction
140  */
141 static int gmtime_emulation_type;
142 /* number of secs to add to UTC POSIX-style time to get local time */
143 static long int utc_offset_secs;
144 static struct dsc$descriptor_s fildevdsc = 
145   { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
146 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
147
148 static time_t toutc_dst(time_t loc) {
149   struct tm *rsltmp;
150
151   if ((rsltmp = localtime(&loc)) == NULL) return -1;
152   loc -= utc_offset_secs;
153   if (rsltmp->tm_isdst) loc -= 3600;
154   return loc;
155 }
156
157 static time_t toloc_dst(time_t utc) {
158   struct tm *rsltmp;
159
160   utc += utc_offset_secs;
161   if ((rsltmp = localtime(&utc)) == NULL) return -1;
162   if (rsltmp->tm_isdst) utc += 3600;
163   return utc;
164 }
165
166 #define _toutc(secs)  ((secs) == (time_t) -1 ? (time_t) -1 : \
167        ((gmtime_emulation_type || timezone_setup()), \
168        (gmtime_emulation_type == 1 ? toutc_dst(secs) : \
169        ((secs) - utc_offset_secs))))
170
171 #define _toloc(secs)  ((secs) == (time_t) -1 ? (time_t) -1 : \
172        ((gmtime_emulation_type || timezone_setup()), \
173        (gmtime_emulation_type == 1 ? toloc_dst(secs) : \
174        ((secs) + utc_offset_secs))))
175
176 static int
177 timezone_setup(void) 
178 {
179   struct tm *tm_p;
180
181   if (gmtime_emulation_type == 0) {
182     int dstnow;
183     time_t base = 15 * 86400; /* 15jan71; to avoid month/year ends between    */
184                               /* results of calls to gmtime() and localtime() */
185                               /* for same &base */
186
187     gmtime_emulation_type++;
188     if ((tm_p = gmtime(&base)) == NULL) { /* CRTL gmtime() is a fake */
189       char off[LNM$C_NAMLENGTH+1];;
190
191       gmtime_emulation_type++;
192       if (!Perl_vmstrnenv("SYS$TIMEZONE_DIFFERENTIAL",off,0,fildev,0)) {
193         gmtime_emulation_type++;
194         utc_offset_secs = 0;
195         Perl_warn(aTHX_ "no UTC offset information; assuming local time is UTC");
196       }
197       else { utc_offset_secs = atol(off); }
198     }
199     else { /* We've got a working gmtime() */
200       struct tm gmt, local;
201
202       gmt = *tm_p;
203       tm_p = localtime(&base);
204       local = *tm_p;
205       utc_offset_secs  = (local.tm_mday - gmt.tm_mday) * 86400;
206       utc_offset_secs += (local.tm_hour - gmt.tm_hour) * 3600;
207       utc_offset_secs += (local.tm_min  - gmt.tm_min)  * 60;
208       utc_offset_secs += (local.tm_sec  - gmt.tm_sec);
209     }
210   }
211   return 1;
212 }
213
214
215 int
216 gettimeofday (struct timeval *tp, void *tpz)
217 {
218  long ret;
219 #ifdef __VAX
220  long quad[2];
221  long quad1[2];
222  long div_100ns_to_secs;
223  long div_100ns_to_usecs;
224  long quo,rem;
225  long quo1,rem1;
226 #else
227  __int64 quad;
228  __qdiv_t ans1,ans2;
229 #endif
230 /*
231         In case of error, tv_usec = 0 and tv_sec = VMS condition code.
232         The return from function is also set to -1.
233         This is not exactly as per the manual page.
234 */
235
236  tp->tv_usec = 0;
237
238 #ifdef __VAX
239  if (base_adjust[0]==0 && base_adjust[1]==0) {
240 #else
241  if (base_adjust==0) { /* Need to determine epoch adjustment */
242 #endif
243         ret=sys$bintim(&dscepoch,&base_adjust);
244         if (1 != (ret &&1)) {
245                 tp->tv_sec = ret;
246                 return -1;
247         }
248  }
249
250  ret=sys$gettim(&quad); /* Get VMS system time */
251  if ((1 && ret) == 1) {
252 #ifdef __VAX
253         quad[0] -= base_adjust[0]; /* convert to epoch offset */
254         quad[1] -= base_adjust[1]; /* convert 2nd half of quadword */
255         div_100ns_to_secs = DIV_100NS_TO_SECS;
256         div_100ns_to_usecs = DIV_100NS_TO_USECS;
257         lib$ediv(&div_100ns_to_secs,&quad,&quo,&rem);
258         quad1[0] = rem;
259         quad1[1] = 0L;
260         lib$ediv(&div_100ns_to_usecs,&quad1,&quo1,&rem1);
261         tp->tv_sec = quo; /* Whole seconds */
262         tp->tv_usec = quo1; /* Micro-seconds */
263 #else
264         quad -= base_adjust; /* convert to epoch offset */
265         ans1=qdiv(quad,DIV_100NS_TO_SECS);
266         ans2=qdiv(ans1.rem,DIV_100NS_TO_USECS);
267         tp->tv_sec = ans1.quot; /* Whole seconds */
268         tp->tv_usec = ans2.quot; /* Micro-seconds */
269 #endif
270  } else {
271         tp->tv_sec = ret;
272         return -1;
273  }
274 # ifdef VMSISH_TIME
275 # ifdef RTL_USES_UTC
276   if (VMSISH_TIME) tp->tv_sec = _toloc(tp->tv_sec);
277 # else
278   if (!VMSISH_TIME) tp->tv_sec = _toutc(tp->tv_sec);
279 # endif
280 # endif
281  return 0;
282 }
283 #endif
284
285 #if !defined(HAS_USLEEP) && defined(HAS_SELECT)
286 #ifndef SELECT_IS_BROKEN
287 #define HAS_USLEEP
288 #define usleep hrt_usleep  /* could conflict with ncurses for static build */
289
290 void
291 hrt_usleep(unsigned long usec)
292 {
293     struct timeval tv;
294     tv.tv_sec = 0;
295     tv.tv_usec = usec;
296     select(0, (Select_fd_set_t)NULL, (Select_fd_set_t)NULL,
297                 (Select_fd_set_t)NULL, &tv);
298 }
299 #endif
300 #endif
301
302 #if !defined(HAS_USLEEP) && defined(WIN32)
303 #define HAS_USLEEP
304 #define usleep hrt_usleep  /* could conflict with ncurses for static build */
305
306 void
307 hrt_usleep(unsigned long usec)
308 {
309     long msec;
310     msec = usec / 1000;
311     Sleep (msec);
312 }
313 #endif
314
315
316 #if !defined(HAS_UALARM) && defined(HAS_SETITIMER)
317 #define HAS_UALARM
318 #define ualarm hrt_ualarm  /* could conflict with ncurses for static build */
319
320 int
321 hrt_ualarm(int usec, int interval)
322 {
323    struct itimerval itv;
324    itv.it_value.tv_sec = usec / 1000000;
325    itv.it_value.tv_usec = usec % 1000000;
326    itv.it_interval.tv_sec = interval / 1000000;
327    itv.it_interval.tv_usec = interval % 1000000;
328    return setitimer(ITIMER_REAL, &itv, 0);
329 }
330 #endif
331
332 #if !defined(HAS_UALARM) && defined(VMS)
333 #define HAS_UALARM
334 #define ualarm vms_ualarm 
335
336 #include <lib$routines.h>
337 #include <ssdef.h>
338 #include <starlet.h>
339 #include <descrip.h>
340 #include <signal.h>
341 #include <jpidef.h>
342 #include <psldef.h>
343
344 #define VMSERR(s)   (!((s)&1))
345
346 static void
347 us_to_VMS(useconds_t mseconds, unsigned long v[])
348 {
349     int iss;
350     unsigned long qq[2];
351
352     qq[0] = mseconds;
353     qq[1] = 0;
354     v[0] = v[1] = 0;
355
356     iss = lib$addx(qq,qq,qq);
357     if (VMSERR(iss)) lib$signal(iss);
358     iss = lib$subx(v,qq,v);
359     if (VMSERR(iss)) lib$signal(iss);
360     iss = lib$addx(qq,qq,qq);
361     if (VMSERR(iss)) lib$signal(iss);
362     iss = lib$subx(v,qq,v);
363     if (VMSERR(iss)) lib$signal(iss);
364     iss = lib$subx(v,qq,v);
365     if (VMSERR(iss)) lib$signal(iss);
366 }
367
368 static int
369 VMS_to_us(unsigned long v[])
370 {
371     int iss;
372     unsigned long div=10,quot, rem;
373
374     iss = lib$ediv(&div,v,&quot,&rem);
375     if (VMSERR(iss)) lib$signal(iss);
376
377     return quot;
378 }
379
380 typedef unsigned short word;
381 typedef struct _ualarm {
382     int function;
383     int repeat;
384     unsigned long delay[2];
385     unsigned long interval[2];
386     unsigned long remain[2];
387 } Alarm;
388
389
390 static int alarm_ef;
391 static Alarm *a0, alarm_base;
392 #define UAL_NULL   0
393 #define UAL_SET    1
394 #define UAL_CLEAR  2
395 #define UAL_ACTIVE 4
396 static void ualarm_AST(Alarm *a);
397
398 static int 
399 vms_ualarm(int mseconds, int interval)
400 {
401     Alarm *a, abase;
402     struct item_list3 {
403         word length;
404         word code;
405         void *bufaddr;
406         void *retlenaddr;
407     } ;
408     static struct item_list3 itmlst[2];
409     static int first = 1;
410     unsigned long asten;
411     int iss, enabled;
412
413     if (first) {
414         first = 0;
415         itmlst[0].code       = JPI$_ASTEN;
416         itmlst[0].length     = sizeof(asten);
417         itmlst[0].retlenaddr = NULL;
418         itmlst[1].code       = 0;
419         itmlst[1].length     = 0;
420         itmlst[1].bufaddr    = NULL;
421         itmlst[1].retlenaddr = NULL;
422
423         iss = lib$get_ef(&alarm_ef);
424         if (VMSERR(iss)) lib$signal(iss);
425
426         a0 = &alarm_base;
427         a0->function = UAL_NULL;
428     }
429     itmlst[0].bufaddr    = &asten;
430     
431     iss = sys$getjpiw(0,0,0,itmlst,0,0,0);
432     if (VMSERR(iss)) lib$signal(iss);
433     if (!(asten&0x08)) return -1;
434
435     a = &abase;
436     if (mseconds) {
437         a->function = UAL_SET;
438     } else {
439         a->function = UAL_CLEAR;
440     }
441
442     us_to_VMS(mseconds, a->delay);
443     if (interval) {
444         us_to_VMS(interval, a->interval);
445         a->repeat = 1;
446     } else 
447         a->repeat = 0;
448
449     iss = sys$clref(alarm_ef);
450     if (VMSERR(iss)) lib$signal(iss);
451
452     iss = sys$dclast(ualarm_AST,a,0);
453     if (VMSERR(iss)) lib$signal(iss);
454
455     iss = sys$waitfr(alarm_ef);
456     if (VMSERR(iss)) lib$signal(iss);
457
458     if (a->function == UAL_ACTIVE) 
459         return VMS_to_us(a->remain);
460     else
461         return 0;
462 }
463
464
465
466 static void
467 ualarm_AST(Alarm *a)
468 {
469     int iss;
470     unsigned long now[2];
471
472     iss = sys$gettim(now);
473     if (VMSERR(iss)) lib$signal(iss);
474
475     if (a->function == UAL_SET || a->function == UAL_CLEAR) {
476         if (a0->function == UAL_ACTIVE) {
477             iss = sys$cantim(a0,PSL$C_USER);
478             if (VMSERR(iss)) lib$signal(iss);
479
480             iss = lib$subx(a0->remain, now, a->remain);
481             if (VMSERR(iss)) lib$signal(iss);
482
483             if (a->remain[1] & 0x80000000) 
484                 a->remain[0] = a->remain[1] = 0;
485         }
486
487         if (a->function == UAL_SET) {
488             a->function = a0->function;
489             a0->function = UAL_ACTIVE;
490             a0->repeat = a->repeat;
491             if (a0->repeat) {
492                 a0->interval[0] = a->interval[0];
493                 a0->interval[1] = a->interval[1];
494             }
495             a0->delay[0] = a->delay[0];
496             a0->delay[1] = a->delay[1];
497
498             iss = lib$subx(now, a0->delay, a0->remain);
499             if (VMSERR(iss)) lib$signal(iss);
500
501             iss = sys$setimr(0,a0->delay,ualarm_AST,a0);
502             if (VMSERR(iss)) lib$signal(iss);
503         } else {
504             a->function = a0->function;
505             a0->function = UAL_NULL;
506         }
507         iss = sys$setef(alarm_ef);
508         if (VMSERR(iss)) lib$signal(iss);
509     } else if (a->function == UAL_ACTIVE) {
510         if (a->repeat) {
511             iss = lib$subx(now, a->interval, a->remain);
512             if (VMSERR(iss)) lib$signal(iss);
513
514             iss = sys$setimr(0,a->interval,ualarm_AST,a);
515             if (VMSERR(iss)) lib$signal(iss);
516         } else {
517             a->function = UAL_NULL;
518         }
519         iss = sys$wake(0,0);
520         if (VMSERR(iss)) lib$signal(iss);
521         lib$signal(SS$_ASTFLT);
522     } else {
523         lib$signal(SS$_BADPARAM);
524     }
525 }
526
527 #endif /* !HAS_UALARM && VMS */
528
529
530
531 #ifdef HAS_GETTIMEOFDAY
532
533 static int
534 myU2time(UV *ret)
535 {
536   struct timeval Tp;
537   int status;
538   status = gettimeofday (&Tp, NULL);
539   ret[0] = Tp.tv_sec;
540   ret[1] = Tp.tv_usec;
541   return status;
542 }
543
544 static NV
545 myNVtime()
546 {
547   struct timeval Tp;
548   int status;
549   status = gettimeofday (&Tp, NULL);
550   return status == 0 ? Tp.tv_sec + (Tp.tv_usec / 1000000.) : -1.0;
551 }
552
553 #endif
554
555 MODULE = Time::HiRes            PACKAGE = Time::HiRes
556
557 PROTOTYPES: ENABLE
558
559 BOOT:
560 #ifdef HAS_GETTIMEOFDAY
561 {
562   UV auv[2];
563   hv_store(PL_modglobal, "Time::NVtime", 12, newSViv((IV) myNVtime()), 0);
564   if (myU2time(auv) == 0)
565     hv_store(PL_modglobal, "Time::U2time", 12, newSViv((IV) auv[0]), 0);
566 }
567 #endif
568
569 IV
570 constant(name, arg)
571         char *          name
572         int             arg
573
574 #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY)
575
576 NV
577 usleep(useconds)
578         NV useconds
579         PREINIT:
580         struct timeval Ta, Tb;
581         CODE:
582         gettimeofday(&Ta, NULL);
583         if (items > 0) {
584             if (useconds > 1E6) {
585                 IV seconds = (IV) (useconds / 1E6);
586                 /* If usleep() has been implemented using setitimer()
587                  * then this contortion is unnecessary-- but usleep()
588                  * may be implemented in some other way, so let's contort. */
589                 if (seconds) {
590                     sleep(seconds);
591                     useconds -= 1E6 * seconds;
592                 }
593             } else if (useconds < 0.0)
594                 croak("Time::HiRes::usleep(%"NVgf"): negative time not invented yet", useconds);
595             usleep((UV)useconds);
596         } else
597             PerlProc_pause();
598         gettimeofday(&Tb, NULL);
599 #if 0
600         printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec);
601 #endif
602         RETVAL = 1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec);
603
604         OUTPUT:
605         RETVAL
606
607 NV
608 sleep(...)
609         PREINIT:
610         struct timeval Ta, Tb;
611         CODE:
612         gettimeofday(&Ta, NULL);
613         if (items > 0) {
614             NV seconds  = SvNV(ST(0));
615             if (seconds >= 0.0) {
616                  UV useconds = 1E6 * (seconds - (UV)seconds);
617                  sleep((UV)seconds);
618                  usleep(useconds);
619             } else
620                 croak("Time::HiRes::sleep(%"NVgf"): negative time not invented yet", seconds);
621         } else
622             PerlProc_pause();
623         gettimeofday(&Tb, NULL);
624 #if 0
625         printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec, Ta.tv_usec);
626 #endif
627         RETVAL = (NV)(Tb.tv_sec-Ta.tv_sec)+0.000001*(NV)(Tb.tv_usec-Ta.tv_usec);
628
629         OUTPUT:
630         RETVAL
631
632 #endif
633
634 #ifdef HAS_UALARM
635
636 int
637 ualarm(useconds,interval=0)
638         int useconds
639         int interval
640         CODE:
641         if (useconds < 0 || interval < 0)
642             croak("Time::HiRes::ualarm(%d, %d): negative time not invented yet", useconds, interval);
643         RETVAL = ualarm(useconds, interval);
644
645         OUTPUT:
646         RETVAL
647
648 NV
649 alarm(seconds,interval=0)
650         NV seconds
651         NV interval
652         CODE:
653         if (seconds < 0.0 || interval < 0.0)
654             croak("Time::HiRes::alarm(%"NVgf", %"NVgf"): negative time not invented yet", seconds, interval);
655         RETVAL = (NV)ualarm(seconds  * 1000000,
656                             interval * 1000000) / 1E6;
657
658         OUTPUT:
659         RETVAL
660
661 #endif
662
663 #ifdef HAS_GETTIMEOFDAY
664 #    ifdef MACOS_TRADITIONAL    /* fix epoch TZ and use unsigned time_t */
665 void
666 gettimeofday()
667         PREINIT:
668         struct timeval Tp;
669         struct timezone Tz;
670         PPCODE:
671         int status;
672         status = gettimeofday (&Tp, &Tz);
673         Tp.tv_sec += Tz.tz_minuteswest * 60;    /* adjust for TZ */
674
675         if (GIMME == G_ARRAY) {
676              EXTEND(sp, 2);
677              /* Mac OS (Classic) has unsigned time_t */
678              PUSHs(sv_2mortal(newSVuv(Tp.tv_sec)));
679              PUSHs(sv_2mortal(newSViv(Tp.tv_usec)));
680         } else {
681              EXTEND(sp, 1);
682              PUSHs(sv_2mortal(newSVnv(Tp.tv_sec + (Tp.tv_usec / 1000000.0))));
683         }
684
685 NV
686 time()
687         PREINIT:
688         struct timeval Tp;
689         struct timezone Tz;
690         CODE:
691         int status;
692         status = gettimeofday (&Tp, &Tz);
693         Tp.tv_sec += Tz.tz_minuteswest * 60;    /* adjust for TZ */
694         RETVAL = Tp.tv_sec + (Tp.tv_usec / 1000000.0);
695         OUTPUT:
696         RETVAL
697
698 #    else       /* MACOS_TRADITIONAL */
699 void
700 gettimeofday()
701         PREINIT:
702         struct timeval Tp;
703         PPCODE:
704         int status;
705         status = gettimeofday (&Tp, NULL);
706         if (GIMME == G_ARRAY) {
707              EXTEND(sp, 2);
708              PUSHs(sv_2mortal(newSViv(Tp.tv_sec)));
709              PUSHs(sv_2mortal(newSViv(Tp.tv_usec)));
710         } else {
711              EXTEND(sp, 1);
712              PUSHs(sv_2mortal(newSVnv(Tp.tv_sec + (Tp.tv_usec / 1000000.0))));
713         }
714
715 NV
716 time()
717         PREINIT:
718         struct timeval Tp;
719         CODE:
720         int status;
721         status = gettimeofday (&Tp, NULL);
722         RETVAL = Tp.tv_sec + (Tp.tv_usec / 1000000.);
723         OUTPUT:
724         RETVAL
725
726 #    endif      /* MACOS_TRADITIONAL */
727 #endif
728
729 #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER)
730
731 #define TV2NV(tv) ((NV)((tv).tv_sec) + 0.000001 * (NV)((tv).tv_usec))
732
733 void
734 setitimer(which, seconds, interval = 0)
735         int which
736         NV seconds
737         NV interval
738     PREINIT:
739         struct itimerval newit;
740         struct itimerval oldit;
741     PPCODE:
742         if (seconds < 0.0 || interval < 0.0)
743             croak("Time::HiRes::setitimer(%"IVdf", %"NVgf", %"NVgf"): negative time not invented yet", which, seconds, interval);
744         newit.it_value.tv_sec  = seconds;
745         newit.it_value.tv_usec =
746           (seconds  - (NV)newit.it_value.tv_sec)    * 1000000.0;
747         newit.it_interval.tv_sec  = interval;
748         newit.it_interval.tv_usec =
749           (interval - (NV)newit.it_interval.tv_sec) * 1000000.0;
750         if (setitimer(which, &newit, &oldit) == 0) {
751           EXTEND(sp, 1);
752           PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_value))));
753           if (GIMME == G_ARRAY) {
754             EXTEND(sp, 1);
755             PUSHs(sv_2mortal(newSVnv(TV2NV(oldit.it_interval))));
756           }
757         }
758
759 void
760 getitimer(which)
761         int which
762     PREINIT:
763         struct itimerval nowit;
764     PPCODE:
765         if (getitimer(which, &nowit) == 0) {
766           EXTEND(sp, 1);
767           PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_value))));
768           if (GIMME == G_ARRAY) {
769             EXTEND(sp, 1);
770             PUSHs(sv_2mortal(newSVnv(TV2NV(nowit.it_interval))));
771           }
772         }
773
774 #endif
775
776 # $Id: HiRes.xs,v 1.11 1999/03/16 02:27:38 wegscd Exp wegscd $
777
778 # $Log: HiRes.xs,v $
779 # Revision 1.11  1999/03/16 02:27:38  wegscd
780 # Add U2time, NVtime. Fix symbols for static link.
781 #
782 # Revision 1.10  1998/09/30 02:36:25  wegscd
783 # Add VMS changes.
784 #
785 # Revision 1.9  1998/07/07 02:42:06  wegscd
786 # Win32 usleep()
787 #
788 # Revision 1.8  1998/07/02 01:47:26  wegscd
789 # Add Win32 code for gettimeofday.
790 #
791 # Revision 1.7  1997/11/13 02:08:12  wegscd
792 # Add missing EXTEND in gettimeofday() scalar code.
793 #
794 # Revision 1.6  1997/11/11 02:32:35  wegscd
795 # Do something useful when calling gettimeofday() in a scalar context.
796 # The patch is courtesy of Gisle Aas.
797 #
798 # Revision 1.5  1997/11/06 03:10:47  wegscd
799 # Fake ualarm() if we have setitimer.
800 #
801 # Revision 1.4  1997/11/05 05:41:23  wegscd
802 # Turn prototypes ON (suggested by Gisle Aas)
803 #
804 # Revision 1.3  1997/10/13 20:56:15  wegscd
805 # Add PROTOTYPES: DISABLE
806 #
807 # Revision 1.2  1997/05/23 01:01:38  wegscd
808 # Conditional compilation, depending on what the OS gives us.
809 #
810 # Revision 1.1  1996/09/03 18:26:35  wegscd
811 # Initial revision
812 #
813 #