3 use Test::More tests => 10;
4 BEGIN { push @INC, '.' }
7 BEGIN { require_ok "Time::HiRes"; }
11 my $limit = 0.25; # 25% is acceptable slosh for testing timers
14 if (open(XDEFINE, "<", "xdefine")) {
15 chomp($xdefine = <XDEFINE> || "");
19 my $can_subsecond_alarm =
20 defined &Time::HiRes::gettimeofday &&
21 defined &Time::HiRes::ualarm &&
22 defined &Time::HiRes::usleep &&
23 ($Config{d_ualarm} || $xdefine =~ /-DHAS_UALARM/);
26 skip "no subsecond alarm", 1 unless $can_subsecond_alarm;
27 eval { require POSIX };
29 !$@ && defined &POSIX::sigaction && &POSIX::SIGALRM > 0;
31 my ($r, $i, $not, $ok);
35 $r = [Time::HiRes::gettimeofday()];
39 $oldaction = new POSIX::SigAction;
40 printf("# sigaction tick, ALRM = %d\n", &POSIX::SIGALRM);
42 # Perl's deferred signals may be too wimpy to break through
43 # a restartable select(), so use POSIX::sigaction if available.
45 POSIX::sigaction(&POSIX::SIGALRM,
46 POSIX::SigAction->new("tick"),
48 or die "Error setting SIGALRM handler with sigaction: $!\n";
50 print("# SIG tick\n");
54 # On VMS timers can not interrupt select.
56 $ok = "Skip: VMS select() does not get interrupted.";
59 Time::HiRes::alarm(0.3);
60 select (undef, undef, undef, 3);
61 my $ival = Time::HiRes::tv_interval ($r);
62 print("# Select returned! $i $ival\n");
63 printf("# %s\n", abs($ival/3 - 1));
64 # Whether select() gets restarted after signals is
65 # implementation dependent. If it is restarted, we
66 # will get about 3.3 seconds: 3 from the select, 0.3
67 # from the alarm. If this happens, let's just skip
68 # this particular test. --jhi
69 if (abs($ival/3.3 - 1) < $limit) {
70 $ok = "Skip: your select() may get restarted by your SIGALRM (or just retry test)";
74 my $exp = 0.3 * (5 - $i);
76 $not = "while: divisor became zero";
79 # This test is more sensitive, so impose a softer limit.
80 if (abs($ival/$exp - 1) > 4*$limit) {
81 my $ratio = abs($ival/$exp);
82 $not = "while: $exp sleep took $ival ratio $ratio";
91 my $ival = Time::HiRes::tv_interval ($r);
92 print("# Tick! $i $ival\n");
93 my $exp = 0.3 * (5 - $i);
95 $not = "tick: divisor became zero";
98 # This test is more sensitive, so impose a softer limit.
99 if (abs($ival/$exp - 1) > 4*$limit) {
100 my $ratio = abs($ival/$exp);
101 $not = "tick: $exp sleep took $ival ratio $ratio";
106 if ($use_sigaction) {
107 POSIX::sigaction(&POSIX::SIGALRM, $oldaction);
109 Time::HiRes::alarm(0); # can't cancel usig %SIG
117 skip "no ualarm", 1 unless &Time::HiRes::d_ualarm;
118 eval { Time::HiRes::alarm(-3) };
119 like $@, qr/::alarm\(-3, 0\): negative time not invented yet/,
120 "negative time error";
123 # Find the loop size N (a for() loop 0..N-1)
124 # that will take more than T seconds.
127 skip "no ualarm", 1 unless &Time::HiRes::d_ualarm;
128 skip "perl bug", 1 unless $] >= 5.008001;
129 # http://groups.google.com/group/perl.perl5.porters/browse_thread/thread/adaffaaf939b042e/20dafc298df737f0%2320dafc298df737f0?sa=X&oi=groupsr&start=0&num=3
130 # Perl changes [18765] and [18770], perl bug [perl #20920]
132 print("# Finding delay loop...\n");
139 my $t0 = Time::HiRes::time();
140 for ($i = 0; $i < $DelayN; $i++) { }
141 my $t1 = Time::HiRes::time();
143 print("# N = $DelayN, t1 = $t1, t0 = $t0, dt = $dt\n");
149 # The time-burner which takes at least T (default 1) seconds.
151 my $c = @_ ? shift : 1;
152 my $n = $c * $DelayN;
154 for ($i = 0; $i < $n; $i++) { }
157 # Next setup a periodic timer (the two-argument alarm() of
158 # Time::HiRes, behind the curtains the libc getitimer() or
159 # ualarm()) which has a signal handler that takes so much time (on
160 # the first initial invocation) that the first periodic invocation
161 # (second invocation) will happen before the first invocation has
162 # finished. In Perl 5.8.0 the "safe signals" concept was
163 # implemented, with unfortunately at least one bug that caused a
164 # core dump on reentering the handler. This bug was fixed by the
165 # time of Perl 5.8.1.
167 # Do not try mixing sleep() and alarm() for testing this.
169 my $a = 0; # Number of alarms we receive.
170 my $A = 2; # Number of alarms we will handle before disarming.
171 # (We may well get $A + 1 alarms.)
175 printf("# Alarm $a - %s\n", Time::HiRes::time());
176 Time::HiRes::alarm(0) if $a >= $A; # Disarm the alarm.
177 $Delay->(2); # Try burning CPU at least for 2T seconds.
180 Time::HiRes::alarm($T, $T); # Arm the alarm.
182 $Delay->(10); # Try burning CPU at least for 10T seconds.
184 ok 1; # Not core dumping by now is considered to be the success.
188 skip "no subsecond alarm", 6 unless $can_subsecond_alarm;
191 $SIG{ALRM} = sub { $alrm++ };
192 Time::HiRes::alarm(0.1);
193 my $t0 = Time::HiRes::time();
194 1 while Time::HiRes::time() - $t0 <= 1;
199 $SIG{ALRM} = sub { $alrm++ };
200 Time::HiRes::alarm(1.1);
201 my $t0 = Time::HiRes::time();
202 1 while Time::HiRes::time() - $t0 <= 2;
208 $SIG{ALRM} = sub { $alrm++ };
209 my $got = Time::HiRes::alarm(2.7);
210 ok $got == 0 or print("# $got\n");
212 my $t0 = Time::HiRes::time();
213 1 while Time::HiRes::time() - $t0 <= 1;
215 $got = Time::HiRes::alarm(0);
216 ok $got > 0 && $got < 1.8 or print("# $got\n");
218 ok $alrm == 0 or print("# $alrm\n");
220 $got = Time::HiRes::alarm(0);
221 ok $got == 0 or print("# $got\n");