3 use Test::More 0.82 tests => 10;
6 BEGIN { require_ok "Time::HiRes"; }
10 my $limit = 0.25; # 25% is acceptable slosh for testing timers
13 if (open(XDEFINE, "xdefine")) {
14 chomp($xdefine = <XDEFINE> || "");
18 my $can_subsecond_alarm =
19 defined &Time::HiRes::gettimeofday &&
20 defined &Time::HiRes::ualarm &&
21 defined &Time::HiRes::usleep &&
22 ($Config{d_ualarm} || $xdefine =~ /-DHAS_UALARM/);
25 skip "no subsecond alarm", 1 unless $can_subsecond_alarm;
26 eval { require POSIX };
28 !$@ && defined &POSIX::sigaction && &POSIX::SIGALRM > 0;
30 my ($r, $i, $not, $ok);
32 $r = [Time::HiRes::gettimeofday()];
36 $oldaction = new POSIX::SigAction;
37 note sprintf "sigaction tick, ALRM = %d", &POSIX::SIGALRM;
39 # Perl's deferred signals may be too wimpy to break through
40 # a restartable select(), so use POSIX::sigaction if available.
42 POSIX::sigaction(&POSIX::SIGALRM,
43 POSIX::SigAction->new("tick"),
45 or die "Error setting SIGALRM handler with sigaction: $!\n";
51 # On VMS timers can not interrupt select.
53 $ok = "Skip: VMS select() does not get interrupted.";
56 Time::HiRes::alarm(0.3);
57 select (undef, undef, undef, 3);
58 my $ival = Time::HiRes::tv_interval ($r);
59 note "Select returned! $i $ival";
60 note abs($ival/3 - 1);
61 # Whether select() gets restarted after signals is
62 # implementation dependent. If it is restarted, we
63 # will get about 3.3 seconds: 3 from the select, 0.3
64 # from the alarm. If this happens, let's just skip
65 # this particular test. --jhi
66 if (abs($ival/3.3 - 1) < $limit) {
67 $ok = "Skip: your select() may get restarted by your SIGALRM (or just retry test)";
71 my $exp = 0.3 * (5 - $i);
73 $not = "while: divisor became zero";
76 # This test is more sensitive, so impose a softer limit.
77 if (abs($ival/$exp - 1) > 4*$limit) {
78 my $ratio = abs($ival/$exp);
79 $not = "while: $exp sleep took $ival ratio $ratio";
88 my $ival = Time::HiRes::tv_interval ($r);
89 note "Tick! $i $ival";
90 my $exp = 0.3 * (5 - $i);
92 $not = "tick: divisor became zero";
95 # This test is more sensitive, so impose a softer limit.
96 if (abs($ival/$exp - 1) > 4*$limit) {
97 my $ratio = abs($ival/$exp);
98 $not = "tick: $exp sleep took $ival ratio $ratio";
103 if ($use_sigaction) {
104 POSIX::sigaction(&POSIX::SIGALRM, $oldaction);
106 Time::HiRes::alarm(0); # can't cancel usig %SIG
114 skip "no ualarm", 1 unless &Time::HiRes::d_ualarm;
115 eval { Time::HiRes::alarm(-3) };
116 like $@, qr/::alarm\(-3, 0\): negative time not invented yet/,
117 "negative time error";
120 # Find the loop size N (a for() loop 0..N-1)
121 # that will take more than T seconds.
124 skip "no ualarm", 1 unless &Time::HiRes::d_ualarm;
125 skip "perl bug", 1 unless $] >= 5.008001;
126 # http://groups.google.com/group/perl.perl5.porters/browse_thread/thread/adaffaaf939b042e/20dafc298df737f0%2320dafc298df737f0?sa=X&oi=groupsr&start=0&num=3
127 # Perl changes [18765] and [18770], perl bug [perl #20920]
129 note "Finding delay loop...";
136 my $t0 = Time::HiRes::time();
137 for ($i = 0; $i < $DelayN; $i++) { }
138 my $t1 = Time::HiRes::time();
140 note "N = $DelayN, t1 = $t1, t0 = $t0, dt = $dt";
146 # The time-burner which takes at least T (default 1) seconds.
148 my $c = @_ ? shift : 1;
149 my $n = $c * $DelayN;
151 for ($i = 0; $i < $n; $i++) { }
154 # Next setup a periodic timer (the two-argument alarm() of
155 # Time::HiRes, behind the curtains the libc getitimer() or
156 # ualarm()) which has a signal handler that takes so much time (on
157 # the first initial invocation) that the first periodic invocation
158 # (second invocation) will happen before the first invocation has
159 # finished. In Perl 5.8.0 the "safe signals" concept was
160 # implemented, with unfortunately at least one bug that caused a
161 # core dump on reentering the handler. This bug was fixed by the
162 # time of Perl 5.8.1.
164 # Do not try mixing sleep() and alarm() for testing this.
166 my $a = 0; # Number of alarms we receive.
167 my $A = 2; # Number of alarms we will handle before disarming.
168 # (We may well get $A + 1 alarms.)
172 note "Alarm $a - ", Time::HiRes::time();
173 Time::HiRes::alarm(0) if $a >= $A; # Disarm the alarm.
174 $Delay->(2); # Try burning CPU at least for 2T seconds.
177 Time::HiRes::alarm($T, $T); # Arm the alarm.
179 $Delay->(10); # Try burning CPU at least for 10T seconds.
181 ok 1; # Not core dumping by now is considered to be the success.
185 skip "no subsecond alarm", 6 unless $can_subsecond_alarm;
188 $SIG{ALRM} = sub { $alrm++ };
189 Time::HiRes::alarm(0.1);
190 my $t0 = Time::HiRes::time();
191 1 while Time::HiRes::time() - $t0 <= 1;
196 $SIG{ALRM} = sub { $alrm++ };
197 Time::HiRes::alarm(1.1);
198 my $t0 = Time::HiRes::time();
199 1 while Time::HiRes::time() - $t0 <= 2;
205 $SIG{ALRM} = sub { $alrm++ };
206 my $got = Time::HiRes::alarm(2.7);
207 ok $got == 0 or note $got;
209 my $t0 = Time::HiRes::time();
210 1 while Time::HiRes::time() - $t0 <= 1;
212 $got = Time::HiRes::alarm(0);
213 ok $got > 0 && $got < 1.8 or note $got;
215 ok $alrm == 0 or note $alrm;
217 $got = Time::HiRes::alarm(0);
218 ok $got == 0 or note $got;