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: 182