This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Make PerlIO marginally reentrant
[perl5.git] / t / io / eintr.t
CommitLineData
abf9167d
DM
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 @INC = '../lib';
12}
13
14use warnings;
15use strict;
16use Config;
17
18require './test.pl';
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
43my ($in, $out, $st, $sigst, $buf);
44
45plan(tests => 10);
46
47
48# make two handles that will always block
49
50sub fresh_io {
51 undef $in; undef $out; # use fresh handles each time
52 pipe $in, $out;
53 $sigst = "";
54}
55
56$SIG{PIPE} = 'IGNORE';
57
58# close during read
59
60fresh_io;
61$SIG{ALRM} = sub { $sigst = close($in) ? "ok" : "nok" };
62alarm(1);
63$st = read($in, $buf, 1);
64alarm(0);
65is($sigst, 'ok', 'read/close: sig handler close status');
66ok(!$st, 'read/close: read status');
67ok(!close($in), 'read/close: close status');
68
69# die during read
70
71fresh_io;
72$SIG{ALRM} = sub { die };
73alarm(1);
74$st = eval { read($in, $buf, 1) };
75alarm(0);
76ok(!$st, 'read/die: read status');
77ok(close($in), 'read/die: close status');
78
79# close during print
80
81fresh_io;
82$SIG{ALRM} = sub { $sigst = close($out) ? "ok" : "nok" };
83$buf = "a" x 1_000_000 . "\n"; # bigger than any pipe buffer hopefully
84select $out; $| = 1; select STDOUT;
85alarm(1);
86$st = print $out $buf;
87alarm(0);
88is($sigst, 'nok', 'print/close: sig handler close status');
89ok(!$st, 'print/close: print status');
90ok(!close($out), 'print/close: close status');
91
92# die during print
93
94fresh_io;
95$SIG{ALRM} = sub { die };
96$buf = "a" x 1_000_000 . "\n"; # bigger than any pipe buffer hopefully
97select $out; $| = 1; select STDOUT;
98alarm(1);
99$st = eval { print $out $buf };
100alarm(0);
101ok(!$st, 'print/die: print status');
102# the close will hang since there's data to flush, so use alarm
103alarm(1);
104ok(!eval {close($out)}, 'print/die: close status');
105alarm(0);
106
107# close during close
108
109# Apparently there's nothing in standard Linux that can cause an
110# EINTR in close(2); but run the code below just in case it does on some
111# platform, just to see if it segfaults.
112fresh_io;
113$SIG{ALRM} = sub { $sigst = close($in) ? "ok" : "nok" };
114alarm(1);
115close $in;
116alarm(0);
117
118# die during close
119
120fresh_io;
121$SIG{ALRM} = sub { die };
122alarm(1);
123eval { close $in };
124alarm(0);
125
126# vim: ts=4 sts=4 sw=4: