viewvcs: handle exceptions in on_destroy cb
[public-inbox.git] / t / sigfd.t
blob91d1103485fe3c98132283ce2050ea6bb4996a87
1 #!perl -w
2 # Copyright (C) all contributors <meta@public-inbox.org>
3 use v5.12;
4 use Test::More;
5 use IO::Handle;
6 use POSIX qw(:signal_h);
7 use Errno qw(ENOSYS);
8 require_ok 'PublicInbox::Sigfd';
9 use PublicInbox::DS;
10 my ($linux_sigfd, $has_sigfd);
11 use autodie qw(kill);
13 SKIP: {
14         if ($^O ne 'linux' && !eval { require IO::KQueue }) {
15                 skip 'signalfd requires Linux or IO::KQueue to emulate', 10;
16         }
18         my $old = PublicInbox::DS::block_signals();
19         my $hit = {};
20         my $sig = {};
21         local $SIG{USR2} = sub { $hit->{USR2}++ };
22         local $SIG{HUP} = sub { $hit->{HUP}++ };
23         local $SIG{TERM} = sub { $hit->{TERM}++ };
24         local $SIG{INT} = sub { $hit->{INT}++ };
25         local $SIG{WINCH} = sub { $hit->{WINCH}++ };
26         for my $s (qw(USR2 HUP TERM INT WINCH)) {
27                 $sig->{$s} = sub { die "SHOULD NOT BE CALLED ($s)" }
28         }
29         my $PID = $$;
30         kill 'USR2', $PID;
31         ok(!defined($hit->{USR2}), 'no USR2 yet') or diag explain($hit);
32         PublicInbox::DS->Reset;
33         ok($PublicInbox::Syscall::SIGNUM{WINCH}, 'SIGWINCH number defined');
34         my $sigfd = PublicInbox::Sigfd->new($sig);
35         if ($sigfd) {
36                 $linux_sigfd = 1 if $^O eq 'linux';
37                 $has_sigfd = 1;
38                 ok($sigfd, 'Sigfd->new works');
39                 kill 'HUP', $PID;
40                 kill 'INT', $PID;
41                 kill 'WINCH', $PID;
42                 my $fd = fileno($sigfd->{sock});
43                 ok($fd >= 0, 'fileno(Sigfd->{sock}) works');
44                 my $rvec = '';
45                 vec($rvec, $fd, 1) = 1;
46                 is(select($rvec, undef, undef, undef), 1, 'select() works');
47                 ok($sigfd->wait_once, 'wait_once reported success');
48                 for my $s (qw(HUP INT)) {
49                         is $hit->{$s}, 1, "sigfd fired $s";
50                 }
51                 SKIP: {
52                         skip 'Linux sigfd-only behavior', 1 if !$linux_sigfd;
53                         is $hit->{USR2}, 1,
54                                 'USR2 sent before signalfd created received';
55                 }
56                 PublicInbox::DS->Reset;
57                 $sigfd = undef;
59                 my $nbsig = PublicInbox::Sigfd->new($sig);
60                 ok($nbsig, 'Sigfd->new SFD_NONBLOCK works');
61                 is($nbsig->wait_once, undef, 'nonblocking ->wait_once');
62                 ok($! == Errno::EAGAIN, 'got EAGAIN');
63                 kill 'HUP', $PID;
64                 local @PublicInbox::DS::post_loop_do = (sub {}); # loop once
65                 PublicInbox::DS::event_loop();
66                 is $hit->{HUP}, 2, 'HUP sigfd fired in event loop' or
67                         diag explain($hit); # sometimes fails on FreeBSD 11.x
68                 kill 'TERM', $PID;
69                 kill 'HUP', $PID;
70                 PublicInbox::DS::event_loop();
71                 PublicInbox::DS->Reset;
72                 is $hit->{TERM}, 1, 'TERM sigfd fired in event loop';
73                 is $hit->{HUP}, 3, 'HUP sigfd fired in event loop';
74                 ok $hit->{WINCH}, 'WINCH sigfd fired in event loop';
76                 my $restore = PublicInbox::DS::allow_sigs 'HUP';
77                 kill 'HUP', $PID;
78                 select undef, undef, undef, 0;
79                 is $hit->{HUP}, 4, 'HUP sigfd fired after allow_sigs';
81                 undef $restore;
82                 kill 'HUP', $PID;
83                 vec($rvec = '', fileno($nbsig->{sock}), 1) = 1;
84                 ok select($rvec, undef, undef, 1),
85                         'select reports sigfd readiness';
86                 is $hit->{HUP}, 4, 'HUP not fired when sigs blocked';
87                 $nbsig->event_step;
88                 is $hit->{HUP}, 5, 'HUP fires only on ->event_step';
90                 kill 'HUP', $PID;
91                 is $hit->{HUP}, 5, 'HUP not fired, yet';
92                 $restore = PublicInbox::DS::allow_sigs 'HUP';
93                 select(undef, undef, undef, 0);
94                 is $hit->{HUP}, 6, 'HUP fires from allow_sigs';
95         } else {
96                 skip('signalfd disabled?', 10);
97         }
98         PublicInbox::DS::sig_setmask($old);
101 done_testing;