File: 20-zombie.t

package info (click to toggle)
libsystem-command-perl 1.07-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 144 kB
  • sloc: perl: 170; makefile: 2
file content (100 lines) | stat: -rw-r--r-- 2,991 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use strict;
use warnings;
use Test::More;
use System::Command;
use File::Spec;
use Time::HiRes qw( time );

my @cmd = ( $^X, File::Spec->catfile( t => 'fail.pl' ) );

plan tests => 28;

my $status = 1;
my $delay  = 2;

# catch warnings
my $expect_CHLD_warning;
$SIG{__WARN__} = sub {
    my ($warning) = @_;
    if ($expect_CHLD_warning) {
        like(
            $warning,
            qr/^Child process already reaped, check for a SIGCHLD handler /,
            'Warning about $SIG{CHLD}'
        );
    }
    else {
        ok( 0, "Unexpected warning: $warning" );
    }
};

# just started the command
my $cmd = System::Command->new( @cmd, $status, $delay );
ok( !$cmd->is_terminated, 'child still alive' );
is( $cmd->exit, undef, 'no exit status' );

# leave it time to die
sleep $delay + 1;
ok( $cmd->is_terminated, 'child is dead now' );    # was a zombie
is( $cmd->exit, $status, 'exit status collected' );

# yes, our handles are still open
ok( $cmd->is_terminated,  'child is still dead' );
ok( $cmd->stdout->opened, 'stdout still opened' );
ok( $cmd->stderr->opened, 'stderr still opened' );

# close our handles now
$cmd->close;
ok( $cmd->is_terminated,   'child is still dead' );
ok( !$cmd->stdout->opened, 'stdout closed' );
ok( !$cmd->stderr->opened, 'stderr closed' );

# what if our user decided to reap children automatically?
diag q{$SIG{CHLD} = 'IGNORE'};
local $SIG{CHLD} = 'IGNORE';
$expect_CHLD_warning = 1;
$cmd = System::Command->new( @cmd, $status, $delay );
ok( !$cmd->is_terminated, 'child still alive' );
is( $cmd->exit, undef, 'no exit status' );

# leave it time to die
sleep $delay + 1;
ok( $cmd->is_terminated, 'child was reaped' );    # was dead and gone
is( $cmd->exit, -1, 'BOGUS exit status collected' );

# yes, our handles are still open
ok( $cmd->is_terminated,  'child is still dead' );
ok( $cmd->stdout->opened, 'stdout still opened' );
ok( $cmd->stderr->opened, 'stderr still opened' );

# close our handles now
$cmd->close;
ok( $cmd->is_terminated,   'child is still dead' );
ok( !$cmd->stdout->opened, 'stdout closed' );
ok( !$cmd->stderr->opened, 'stderr closed' );

# close first
$cmd = System::Command->new( @cmd, $status, $delay );
ok( !$cmd->is_terminated, 'child still alive' );
is( $cmd->exit, undef, 'no exit status' );

# don't leave it time, just choke it now
$cmd->close;

# See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666631#17
# Under load, there can be a window of time during which the child
# process is still reachable via kill(0), even though waitpid() returned
my ( $start, $pid, $attempts ) = ( time, $cmd->pid, 0 );
$attempts++ while kill 0, $pid;
diag sprintf '%d kill( 0, $pid ) attempts succeeded in %f seconds', $attempts,
    time - $start
    if $attempts;

ok( $cmd->is_terminated, 'child was reaped' );    # was dead and gone
is( $cmd->exit, -1, 'BOGUS exit status collected' );
ok( !$cmd->stdout->opened, 'stdout closed' );
ok( !$cmd->stderr->opened, 'stderr closed' );

# don't confuse Test::More
$? = 0;