This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix dist/Time-HiRes/t/*.t that assumed '.' in @INC
[perl5.git] / dist / Time-HiRes / t / alarm.t
CommitLineData
90e44bf6
Z
1use strict;
2
c4a535af 3use Test::More tests => 10;
465db51d 4BEGIN { push @INC, '.' }
90e44bf6
Z
5use t::Watchdog;
6
7BEGIN { require_ok "Time::HiRes"; }
8
9use Config;
10
11my $limit = 0.25; # 25% is acceptable slosh for testing timers
12
13my $xdefine = '';
1ae6ead9 14if (open(XDEFINE, "<", "xdefine")) {
90e44bf6
Z
15 chomp($xdefine = <XDEFINE> || "");
16 close(XDEFINE);
17}
18
19my $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/);
24
25SKIP: {
26 skip "no subsecond alarm", 1 unless $can_subsecond_alarm;
27 eval { require POSIX };
28 my $use_sigaction =
29 !$@ && defined &POSIX::sigaction && &POSIX::SIGALRM > 0;
30
31 my ($r, $i, $not, $ok);
32
c4a535af
SH
33 $not = "";
34
90e44bf6
Z
35 $r = [Time::HiRes::gettimeofday()];
36 $i = 5;
37 my $oldaction;
38 if ($use_sigaction) {
39 $oldaction = new POSIX::SigAction;
c4a535af 40 printf("# sigaction tick, ALRM = %d\n", &POSIX::SIGALRM);
90e44bf6
Z
41
42 # Perl's deferred signals may be too wimpy to break through
43 # a restartable select(), so use POSIX::sigaction if available.
44
45 POSIX::sigaction(&POSIX::SIGALRM,
46 POSIX::SigAction->new("tick"),
47 $oldaction)
48 or die "Error setting SIGALRM handler with sigaction: $!\n";
49 } else {
c4a535af 50 print("# SIG tick\n");
90e44bf6
Z
51 $SIG{ALRM} = "tick";
52 }
53
54 # On VMS timers can not interrupt select.
55 if ($^O eq 'VMS') {
56 $ok = "Skip: VMS select() does not get interrupted.";
57 } else {
58 while ($i > 0) {
59 Time::HiRes::alarm(0.3);
60 select (undef, undef, undef, 3);
61 my $ival = Time::HiRes::tv_interval ($r);
c4a535af
SH
62 print("# Select returned! $i $ival\n");
63 printf("# %s\n", abs($ival/3 - 1));
90e44bf6
Z
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)";
71 undef $not;
72 last;
73 }
74 my $exp = 0.3 * (5 - $i);
75 if ($exp == 0) {
76 $not = "while: divisor became zero";
77 last;
78 }
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";
83 last;
84 }
85 $ok = $i;
86 }
87 }
88
89 sub tick {
90 $i--;
91 my $ival = Time::HiRes::tv_interval ($r);
c4a535af 92 print("# Tick! $i $ival\n");
90e44bf6
Z
93 my $exp = 0.3 * (5 - $i);
94 if ($exp == 0) {
95 $not = "tick: divisor became zero";
96 last;
97 }
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";
102 $i = 0;
103 }
104 }
105
106 if ($use_sigaction) {
107 POSIX::sigaction(&POSIX::SIGALRM, $oldaction);
108 } else {
109 Time::HiRes::alarm(0); # can't cancel usig %SIG
110 }
111
c4a535af 112 print("# $not\n");
90e44bf6 113 ok !$not;
90e44bf6
Z
114}
115
116SKIP: {
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";
121}
122
123# Find the loop size N (a for() loop 0..N-1)
124# that will take more than T seconds.
125
126SKIP: {
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]
131
c4a535af 132 print("# Finding delay loop...\n");
90e44bf6
Z
133
134 my $T = 0.01;
135 my $DelayN = 1024;
136 my $i;
137 N: {
138 do {
139 my $t0 = Time::HiRes::time();
140 for ($i = 0; $i < $DelayN; $i++) { }
141 my $t1 = Time::HiRes::time();
142 my $dt = $t1 - $t0;
c4a535af 143 print("# N = $DelayN, t1 = $t1, t0 = $t0, dt = $dt\n");
90e44bf6
Z
144 last N if $dt > $T;
145 $DelayN *= 2;
146 } while (1);
147 }
148
149 # The time-burner which takes at least T (default 1) seconds.
150 my $Delay = sub {
151 my $c = @_ ? shift : 1;
152 my $n = $c * $DelayN;
153 my $i;
154 for ($i = 0; $i < $n; $i++) { }
155 };
156
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.
166
167 # Do not try mixing sleep() and alarm() for testing this.
168
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.)
172
173 $SIG{ALRM} = sub {
174 $a++;
c4a535af 175 printf("# Alarm $a - %s\n", Time::HiRes::time());
90e44bf6
Z
176 Time::HiRes::alarm(0) if $a >= $A; # Disarm the alarm.
177 $Delay->(2); # Try burning CPU at least for 2T seconds.
178 };
179
180 Time::HiRes::alarm($T, $T); # Arm the alarm.
181
182 $Delay->(10); # Try burning CPU at least for 10T seconds.
183
184 ok 1; # Not core dumping by now is considered to be the success.
185}
186
187SKIP: {
188 skip "no subsecond alarm", 6 unless $can_subsecond_alarm;
189 {
190 my $alrm;
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;
195 ok $alrm;
196 }
197 {
198 my $alrm;
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;
203 ok $alrm;
204 }
205
206 {
207 my $alrm = 0;
208 $SIG{ALRM} = sub { $alrm++ };
209 my $got = Time::HiRes::alarm(2.7);
c4a535af 210 ok $got == 0 or print("# $got\n");
90e44bf6
Z
211
212 my $t0 = Time::HiRes::time();
213 1 while Time::HiRes::time() - $t0 <= 1;
214
215 $got = Time::HiRes::alarm(0);
c4a535af 216 ok $got > 0 && $got < 1.8 or print("# $got\n");
90e44bf6 217
c4a535af 218 ok $alrm == 0 or print("# $alrm\n");
90e44bf6
Z
219
220 $got = Time::HiRes::alarm(0);
c4a535af 221 ok $got == 0 or print("# $got\n");
90e44bf6
Z
222 }
223}
224
2251;