This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
re-implement OPpASSIGN_COMMON mechanism
[perl5.git] / t / op / sigdispatch.t
1 #!perl -w
2
3 # We assume that TestInit has been used.
4
5 BEGIN {
6       chdir 't' if -d 't';
7       require './test.pl';
8 }
9
10 use strict;
11 use Config;
12
13 plan tests => 29;
14 $| = 1;
15
16 watchdog(25);
17
18 $SIG{ALRM} = sub {
19     die "Alarm!\n";
20 };
21
22 pass('before the first loop');
23
24 alarm 2;
25
26 eval {
27     1 while 1;
28 };
29
30 is($@, "Alarm!\n", 'after the first loop');
31
32 pass('before the second loop');
33
34 alarm 2;
35
36 eval {
37     while (1) {
38     }
39 };
40
41 is($@, "Alarm!\n", 'after the second loop');
42
43 SKIP: {
44     skip('We can\'t test blocking without sigprocmask', 17)
45         if is_miniperl() || !$Config{d_sigprocmask};
46     skip("This doesn\'t work on $^O threaded builds RT#88814", 17)
47         if ($^O =~ /cygwin/ || $^O eq "openbsd" && $Config{osvers} < 5.2)
48             && $Config{useithreads};
49
50     require POSIX;
51     my $pending = POSIX::SigSet->new();
52     is POSIX::sigpending($pending), '0 but true', 'sigpending';
53     is $pending->ismember(&POSIX::SIGUSR1), 0, 'SIGUSR1 is not pending';
54     my $new = POSIX::SigSet->new(&POSIX::SIGUSR1);
55     POSIX::sigprocmask(&POSIX::SIG_BLOCK, $new);
56     
57     my $gotit = 0;
58     $SIG{USR1} = sub { $gotit++ };
59     kill 'SIGUSR1', $$;
60     is $gotit, 0, 'Haven\'t received third signal yet';
61
62     diag "2nd sigpending crashes on cygwin" if $^O eq 'cygwin';
63     is POSIX::sigpending($pending), '0 but true', 'sigpending';
64     is $pending->ismember(&POSIX::SIGUSR1), 1, 'SIGUSR1 is pending';
65     
66     my $old = POSIX::SigSet->new();
67     POSIX::sigsuspend($old);
68     is $gotit, 1, 'Received third signal';
69     is POSIX::sigpending($pending), '0 but true', 'sigpending';
70     is $pending->ismember(&POSIX::SIGUSR1), 0, 'SIGUSR1 is no longer pending';
71     
72         {
73                 kill 'SIGUSR1', $$;
74                 local $SIG{USR1} = sub { die "FAIL\n" };
75                 POSIX::sigprocmask(&POSIX::SIG_BLOCK, undef, $old);
76                 ok $old->ismember(&POSIX::SIGUSR1), 'SIGUSR1 is blocked';
77                 eval { POSIX::sigsuspend(POSIX::SigSet->new) };
78                 is $@, "FAIL\n", 'Exception is thrown, so received fourth signal';
79                 POSIX::sigprocmask(&POSIX::SIG_BLOCK, undef, $old);
80 TODO:
81             {
82                 local $::TODO = "Needs investigation" if $^O eq 'VMS';
83                 ok $old->ismember(&POSIX::SIGUSR1), 'SIGUSR1 is still blocked';
84             }
85         }
86
87     POSIX::sigprocmask(&POSIX::SIG_BLOCK, $new);
88     kill 'SIGUSR1', $$;
89     is $gotit, 1, 'Haven\'t received fifth signal yet';
90     POSIX::sigprocmask(&POSIX::SIG_UNBLOCK, $new, $old);
91     ok $old->ismember(&POSIX::SIGUSR1), 'SIGUSR1 was still blocked';
92     is $gotit, 2, 'Received fifth signal';
93
94     # test unsafe signal handlers in combination with exceptions
95
96     SKIP: {
97         # #89718: on old linux kernels, this test hangs. No-ones thought
98         # of a reliable way to probe for this, so for now, just skip the
99         # tests on production releases
100         skip("some OSes hang here", 3) if (int($]*1000) & 1) == 0;
101     
102   SKIP: {
103         skip("Issues on Android", 3) if $^O =~ /android/;
104         my $action = POSIX::SigAction->new(sub { $gotit--, die }, POSIX::SigSet->new, 0);
105         POSIX::sigaction(&POSIX::SIGALRM, $action);
106         eval {
107             alarm 1;
108             my $set = POSIX::SigSet->new;
109             POSIX::sigprocmask(&POSIX::SIG_BLOCK, undef, $set);
110             is $set->ismember(&POSIX::SIGALRM), 0, "SIGALRM is not blocked on attempt $_";
111             POSIX::sigsuspend($set);
112         } for 1..2;
113         is $gotit, 0, 'Received both signals';
114     }
115 }
116 }
117
118 SKIP: {
119     skip("alarm cannot interrupt blocking system calls on $^O", 2)
120         if $^O =~ /MSWin32|cygwin|VMS/;
121     # RT #88774
122     # make sure the signal handler's called in an eval block *before*
123     # the eval is popped
124
125     $SIG{'ALRM'} = sub { die "HANDLER CALLED\n" };
126
127     eval {
128         alarm(2);
129         select(undef,undef,undef,10);
130     };
131     alarm(0);
132     is($@, "HANDLER CALLED\n", 'block eval');
133
134     eval q{
135         alarm(2);
136         select(undef,undef,undef,10);
137     };
138     alarm(0);
139     is($@, "HANDLER CALLED\n", 'string eval');
140 }
141
142 eval { $SIG{"__WARN__\0"} = sub { 1 } };
143 like $@, qr/No such hook: __WARN__\\0 at/, q!Fetching %SIG hooks with an extra trailing nul is nul-clean!;
144
145 eval { $SIG{"__DIE__\0whoops"} = sub { 1 } };
146 like $@, qr/No such hook: __DIE__\\0whoops at/;
147
148 {
149     use warnings;
150     my $w;
151     local $SIG{__WARN__} = sub { $w = shift };
152
153     $SIG{"KILL\0"} = sub { 1 };
154     like $w, qr/No such signal: SIGKILL\\0 at/, 'Arbitrary signal lookup through %SIG is clean';
155 }
156
157 # [perl #45173]
158 {
159     my $int_called;
160     local $SIG{INT} = sub { $int_called = 1; };
161     $@ = "died";
162     is($@, "died");
163     kill 'INT', $$;
164     # this is needed to ensure signal delivery on MSWin32
165     sleep(1);
166     is($int_called, 1);
167     is($@, "died");
168 }