Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions lib/System/Command.pm
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,49 @@ sub close {
return $_[0];
}

sub DESTROY {

# ensure that all FH are closed. IO objects are special, and
# sometimes are not destroyed when references to them disappear.

# Here's some example code:

# {
# my $cmd = System::Command->new( 'cat' );
# $cmd->stdin->say( $_ ) for 0 ... 100;
# };

# When the block ends, $cmd will be destroyed. Sometimes the
# order of destruction is

# System::Command, IO::Handle, System::Command::Reaper

# and sometimes it is

# System::Command, System::Command::Reaper

# experimentally, when the Reaper object is destroyed ( regardless
# of whether the IO::Handles are destroyed first) it never has
# access to its cached IO::Handle objects; when the Command object
# is destroyed, it releases its references to them, and because
# the Reaper object only has weak references to them, they
# disappear.

# So, if the IO::Handle destructor isn't called, the handles still
# exist, but Reaper doesn't close them, and if the subprocess is
# waiting on input, it will never exit, cannot be reaped,
# and Reaper::_reap will hang forever.

# note that explicitly closing the handles via $cmd->close
# is not safe, as, if the program is interrupted before the close,
# and the signal handler throws, e.g. $SIG{INT} = sub { die },
# the $cmd->close does not get fired.

# so, just make sure things are closed

$_[0]{reaper} and $_[0]->close;
}

1;

__END__
Expand Down