File Coverage

blib/lib/Proc/Background/Unix.pm
Criterion Covered Total %
statement 88 108 81.4
branch 52 76 68.4
condition 11 23 47.8
subroutine 9 13 69.2
pod n/a
total 160 220 72.7


line stmt bran cond sub pod time code
1             package Proc::Background::Unix;
2             $Proc::Background::Unix::VERSION = '1.32';
3             # ABSTRACT: Unix-specific implementation of process create/wait/kill
4             require 5.004_04;
5              
6 22     22   139 use strict;
  22         57  
  22         626  
7 22     22   511 use Exporter;
  22         64  
  22         757  
8 22     22   136 use Carp;
  22         43  
  22         1058  
9 22     22   11048 use POSIX qw( :errno_h :sys_wait_h );
  22         181582  
  22         92  
10              
11             # Test for existence of FD_CLOEXEC, needed for child-error-through-pipe trick
12             my ($FD_CLOEXEC);
13             eval {
14             require Fcntl;
15             $FD_CLOEXEC= Fcntl::FD_CLOEXEC();
16             };
17              
18             # For un-explained mysterious reasons, Time::HiRes::alarm seem to misbehave on 5.10 and earlier
19             # but core alarm works fine.
20             my $alarm= ($] >= 5.012)? do { require Time::HiRes; \&Time::HiRes::alarm; }
21             : sub {
22             # round up to whole seconds
23             CORE::alarm(POSIX::ceil($_[0]));
24             };
25              
26             @Proc::Background::Unix::ISA = qw(Exporter);
27              
28             # Start the background process. If it is started sucessfully, then record
29             # the process id in $self->{_os_obj}.
30             sub _start {
31 108     108   479 my ($self, $options)= @_;
32              
33             # There are three main scenarios for how-to-exec:
34             # * single-string command, to be handled by shell
35             # * arrayref command, to be handled by execve
36             # * arrayref command with 'exe' (fake argv0)
37             # and one that isn't logical:
38             # * single-string command with exe
39             # throw an error for that last one rather than trying something awkward
40             # like splitting the command string.
41              
42 108         276 my @argv;
43 108         311 my ($cmd, $exe)= @{$self}{'_command','_exe'};
  108         565  
44              
45 108 100       657 if (ref $cmd eq 'ARRAY') {
    50          
46 103         455 @argv= @$cmd;
47 103 50       996 ($exe, my $err) = Proc::Background::_resolve_path(defined $exe? $exe : $argv[0]);
48 103 100       944 return $self->_fatal($err) unless defined $exe;
49 101         681 $self->{_exe}= $exe;
50             } elsif (defined $exe) {
51 0         0 croak "Can't combine 'exe' option with single-string 'command', use arrayref 'command' instead.";
52             }
53              
54 106 100       652 if (defined $options->{cwd}) {
55             -d $options->{cwd}
56 7 100       107 or return $self->_fatal("directory does not exist: '$options->{cwd}'");
57             }
58              
59 104         322 my ($new_stdin, $new_stdout, $new_stderr);
60             $new_stdin= _resolve_file_handle($options->{stdin}, '<', \*STDIN)
61 104 100       461 if exists $options->{stdin};
62             $new_stdout= _resolve_file_handle($options->{stdout}, '>>', \*STDOUT)
63 104 100       605 if exists $options->{stdout};
64             $new_stderr= _resolve_file_handle($options->{stderr}, '>>', \*STDERR)
65 104 100       605 if exists $options->{stderr};
66              
67             # Fork a child process.
68 104         313 my ($pipe_r, $pipe_w);
69 104 50       476 if (defined $FD_CLOEXEC) {
70             # use a pipe for the child to report exec() errors
71 104 50       7339 pipe $pipe_r, $pipe_w or return $self->_fatal("pipe: $!");
72             # This pipe needs to be in the non-preserved range that doesn't exist after exec().
73             # In the edge case where a pipe received a FD less than $^F, the CLOEXEC flag isn't set.
74             # Try again on higher descriptors, then close the lower ones.
75 104         476 my @rejects;
76 104   33     1934 while (fileno $pipe_r <= $^F or fileno $pipe_w <= $^F) {
77 0         0 push @rejects, $pipe_r, $pipe_w;
78 0 0       0 pipe $pipe_r, $pipe_w or return $self->_fatal("pipe: $!");
79             }
80             }
81 104         319 my $pid;
82             {
83 104 100       200 if ($pid = fork()) {
  104 50       106423  
    0          
84             # parent
85 87         3920 $self->{_os_obj} = $pid;
86 87         1912 $self->{_pid} = $pid;
87 87 50       1310 if (defined $pipe_r) {
88 87         4026 close $pipe_w;
89             # wait for child to reply or close the pipe
90 87     0   14429 local $SIG{PIPE}= sub {};
91 87         1009 my $msg= '';
92 87         30701605 while (0 < read $pipe_r, $msg, 1024, length $msg) {}
93 87         3769 close $pipe_r;
94             # If child wrote anything to the pipe, it failed to exec.
95             # Reap it before dying.
96 87 50       4299 if (length $msg) {
97 0         0 waitpid $pid, 0;
98 0         0 return $self->_fatal($msg);
99             }
100             }
101 87         499 last;
102             } elsif (defined $pid) {
103             # child
104             # Make absolutely sure nothing in this block interacts with the rest of the
105             # process state, and that flow control never skips the _exit().
106 17     0   5372 $SIG{$_}= sub{die;} for qw( INT HUP QUIT TERM ); # clear custom signal handlers
  0         0  
107 17         1718 $SIG{$_}= 'DEFAULT' for qw( __WARN__ __DIE__ );
108 17         594 eval {
109 17         334 eval {
110             chdir($options->{cwd}) or die "chdir($options->{cwd}): $!\n"
111 17 100 50     1369 if defined $options->{cwd};
112              
113 17 100 50     1226 open STDIN, '<&'.fileno($new_stdin) or die "Can't redirect STDIN: $!\n"
114             if defined $new_stdin;
115 17 100 50     1176 open STDOUT, '>&'.fileno($new_stdout) or die "Can't redirect STDOUT: $!\n"
116             if defined $new_stdout;
117 17 100 50     538 open STDERR, '>&'.fileno($new_stderr) or die "Can't redirect STDERR: $!\n"
118             if defined $new_stderr;
119              
120 17 100       369 if (defined $exe) {
121 16 0       108 exec { $exe } @argv or die "$0: exec failed: $!\n";
  16         0  
122             } else {
123 1 0       0 exec $cmd or die "$0: exec failed: $!\n";
124             }
125             };
126 0 0       0 if (defined $pipe_w) {
127 0         0 print $pipe_w $@;
128 0         0 close $pipe_w; # force it to flush. Nothing else needs closed because we are about to _exit
129             } else {
130 0         0 print STDERR $@;
131             }
132             };
133 0         0 POSIX::_exit(1);
134             } elsif ($! == EAGAIN) {
135 0         0 sleep 5;
136 0         0 redo;
137             } else {
138 0         0 return $self->_fatal("fork: $!");
139             }
140             }
141              
142 87         7564 $self;
143             }
144              
145             sub _resolve_file_handle {
146 32     32   221 my ($thing, $mode, $default)= @_;
147 32 100       169 if (!defined $thing) {
    100          
148 11 50       743 open my $fh, $mode, '/dev/null' or croak "open(/dev/null): $!";
149 11         114 return $fh;
150             } elsif (ref $thing) {
151             # use 'undef' to mean no-change
152 19 100       98 return (fileno($thing) == fileno($default))? undef : $thing;
153             } else {
154 2 50       196 open my $fh, $mode, $thing or croak "open($thing): $!";
155 2         172 return $fh;
156             }
157             }
158              
159             # Wait for the child.
160             # (0, exit_value) : sucessfully waited on.
161             # (1, undef) : process already reaped and exit value lost.
162             # (2, undef) : process still running.
163             sub _waitpid {
164 204     204   961 my ($self, $blocking, $wait_seconds) = @_;
165              
166             {
167             # Try to wait on the process.
168             # Implement the optional timeout with the 'alarm' call.
169 204         572 my $result= 0;
  204         527  
170 204 100 100     1664 if ($blocking && $wait_seconds) {
171 57     14   2796 local $SIG{ALRM}= sub { die "alarm\n" };
  14         671  
172 57         1236 $alarm->($wait_seconds);
173 57         800 eval { $result= waitpid($self->{_os_obj}, 0); };
  57         14566561  
174 57         2387 $alarm->(0);
175             }
176             else {
177 147 100       22115063 $result= waitpid($self->{_os_obj}, $blocking? 0 : WNOHANG);
178             }
179              
180             # Process finished. Grab the exit value.
181 204 100 33     2547 if ($result == $self->{_os_obj}) {
    50          
    50          
182 87         356 delete $self->{_suspended};
183 87         2834 return (0, $?);
184             }
185             # Process already reaped. We don't know the exist status.
186             elsif ($result == -1 and $! == ECHILD) {
187 0         0 return (1, 0);
188             }
189             # Process still running.
190             elsif ($result == 0) {
191 117         972 return (2, 0);
192             }
193             # If we reach here, then waitpid caught a signal, so let's retry it.
194 0         0 redo;
195             }
196 0         0 return 0;
197             }
198              
199             sub _suspend {
200 0     0   0 kill STOP => $_[0]->{_os_obj};
201             }
202              
203             sub _resume {
204 0     0   0 kill CONT => $_[0]->{_os_obj};
205             }
206              
207             sub _terminate {
208 26     26   183 my $self = shift;
209 26 50 33     1288 my @kill_sequence= @_ && ref $_[0] eq 'ARRAY'? @{ $_[0] } : qw( TERM 2 TERM 8 KILL 3 KILL 7 );
  0         0  
210             # Try to kill the process with different signals. Calling alive() will
211             # collect the exit status of the program.
212 26   33     1371 while (@kill_sequence and $self->alive) {
213 26         275 my $sig= shift @kill_sequence;
214 26         125 my $delay= shift @kill_sequence;
215 26         2045 kill($sig, $self->{_os_obj});
216 26 50       247 next unless defined $delay;
217 26 50       315 last if $self->_reap(1, $delay); # block before sending next signal
218             }
219             }
220              
221             1;
222              
223             __END__