This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
new perldelta
[perl5.git] / t / io / eintr.t
... / ...
CommitLineData
1#!./perl
2
3# If a read or write is interrupted by a signal, Perl will call the
4# signal handler and then attempt to restart the call. If the handler does
5# something nasty like close the handle or pop layers, make sure that the
6# read/write handles this gracefully (for some definition of 'graceful':
7# principally, don't segfault).
8
9BEGIN {
10 chdir 't' if -d 't';
11 require './test.pl';
12 set_up_inc('../lib');
13 skip_all_without_dynamic_extension('Fcntl');
14}
15
16use warnings;
17use strict;
18use Config;
19
20my $piped;
21eval {
22 pipe my $in, my $out;
23 $piped = 1;
24};
25if (!$piped) {
26 skip_all('pipe not implemented');
27 exit 0;
28}
29unless (exists $Config{'d_alarm'}) {
30 skip_all('alarm not implemented');
31 exit 0;
32}
33
34# XXX for some reason the stdio layer doesn't seem to interrupt
35# write system call when the alarm triggers. This makes the tests
36# hang.
37
38if (exists $ENV{PERLIO} && $ENV{PERLIO} =~ /stdio/ ) {
39 skip_all('stdio not supported for this script');
40 exit 0;
41}
42
43# on Win32, alarm() won't interrupt the read/write call.
44# Similar issues with VMS.
45# On FreeBSD, writes to pipes of 8192 bytes or more use a mechanism
46# that is not interruptible (see perl #85842 and #84688).
47# "close during print" also hangs on Solaris 8 (but not 10 or 11).
48#
49# Also skip on release builds, to avoid other possibly problematic
50# platforms
51
52my ($osmajmin) = $Config{osvers} =~ /^(\d+\.\d+)/;
53if ($^O eq 'VMS' || $^O eq 'MSWin32' || $^O eq 'cygwin' || $^O =~ /freebsd/ || $^O eq 'midnightbsd' ||
54 ($^O eq 'solaris' && $Config{osvers} eq '2.8') || $^O eq 'nto' ||
55 ($^O eq 'darwin' && $osmajmin < 9) ||
56 ((int($]*1000) & 1) == 0)
57) {
58 skip_all('various portability issues');
59 exit 0;
60}
61
62
63
64my ($in, $out, $st, $sigst, $buf, $pipe_buf_size, $pipe_buf_err);
65
66plan(tests => 10);
67
68
69# make two handles that will always block
70
71sub fresh_io {
72 close $in if $in; close $out if $out;
73 undef $in; undef $out; # use fresh handles each time
74 pipe $in, $out;
75 $sigst = "";
76 $pipe_buf_err = "";
77
78 # This used to be 1_000_000, but on Linux/ppc64 (POWER7) this kept
79 # consistently failing. At exactly 0x100000 it started passing
80 # again. Now we're asking the kernel what the pipe buffer is, and if
81 # that fails, hoping this number is bigger than any pipe buffer.
82 $pipe_buf_size = eval {
83 use Fcntl qw(F_GETPIPE_SZ);
84 # When F_GETPIPE_SZ isn't implemented then fcntl() raises an exception:
85 # "Your vendor has not defined Fcntl macro F_GETPIPE_SZ ..."
86 # When F_GETPIPE_SZ is implemented then errors are still possible
87 # (EINVAL, EBADF, ...). These are not exceptions (i.e. these don't die)
88 # but instead these set $! and make fcntl() return undef.
89 fcntl($out, F_GETPIPE_SZ, 0) or die "$!\n";
90 };
91 if ($@ or not $pipe_buf_size) {
92 my $err = $@;;
93 chomp $err;
94 $pipe_buf_size = 0xfffff;
95 $pipe_buf_err = "fcntl F_GETPIPE_SZ failed" . ($err ? " ($err)" : "") .
96 ", falling back to $pipe_buf_size";
97 };
98 $pipe_buf_size++; # goal is to completely fill the buffer so write one
99 # byte more then the buffer size
100}
101
102$SIG{PIPE} = 'IGNORE';
103
104# close during read
105
106fresh_io;
107$SIG{ALRM} = sub { $sigst = close($in) ? "ok" : "nok" };
108alarm(1);
109$st = read($in, $buf, 1);
110alarm(0);
111my $result = is($sigst, 'ok', 'read/close: sig handler close status');
112$result &= ok(!$st, 'read/close: read status');
113$result &= ok(!close($in), 'read/close: close status');
114diag($pipe_buf_err) if (not $result and $pipe_buf_err);
115
116# die during read
117
118fresh_io;
119$SIG{ALRM} = sub { die };
120alarm(1);
121$st = eval { read($in, $buf, 1) };
122alarm(0);
123$result = ok(!$st, 'read/die: read status');
124$result &= ok(close($in), 'read/die: close status');
125diag($pipe_buf_err) if (not $result and $pipe_buf_err);
126
127SKIP: {
128 skip "Tests hang on older versions of Darwin", 5
129 if $^O eq 'darwin' && $osmajmin < 16;
130
131 # close during print
132
133 fresh_io;
134 $SIG{ALRM} = sub { $sigst = close($out) ? "ok" : "nok" };
135 $buf = "a" x $pipe_buf_size . "\n";
136 select $out; $| = 1; select STDOUT;
137 alarm(1);
138 $st = print $out $buf;
139 alarm(0);
140 $result = is($sigst, 'nok', 'print/close: sig handler close status');
141 $result &= ok(!$st, 'print/close: print status');
142 $result &= ok(!close($out), 'print/close: close status');
143 diag($pipe_buf_err) if (not $result and $pipe_buf_err);
144
145 # die during print
146
147 fresh_io;
148 $SIG{ALRM} = sub { die };
149 $buf = "a" x $pipe_buf_size . "\n";
150 select $out; $| = 1; select STDOUT;
151 alarm(1);
152 $st = eval { print $out $buf };
153 alarm(0);
154 $result = ok(!$st, 'print/die: print status');
155 # the close will hang since there's data to flush, so use alarm
156 alarm(1);
157 $result &= ok(!eval {close($out)}, 'print/die: close status');
158 alarm(0);
159 diag($pipe_buf_err) if (not $result and $pipe_buf_err);
160
161 # close during close
162
163 # Apparently there's nothing in standard Linux that can cause an
164 # EINTR in close(2); but run the code below just in case it does on some
165 # platform, just to see if it segfaults.
166 fresh_io;
167 $SIG{ALRM} = sub { $sigst = close($in) ? "ok" : "nok" };
168 alarm(1);
169 close $in;
170 alarm(0);
171
172 # die during close
173
174 fresh_io;
175 $SIG{ALRM} = sub { die };
176 alarm(1);
177 eval { close $in };
178 alarm(0);
179}
180
181# vim: ts=4 sts=4 sw=4: