File Coverage

blib/lib/IO/Async/PID.pm
Criterion Covered Total %
statement 43 46 93.4
branch 8 16 50.0
condition 1 3 33.3
subroutine 11 11 100.0
pod 4 4 100.0
total 67 80 83.7


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2010-2011 -- leonerd@leonerd.org.uk
5              
6             package IO::Async::PID;
7              
8 2     2   169150 use strict;
  2         8  
  2         58  
9 2     2   10 use warnings;
  2         6  
  2         54  
10 2     2   10 use base qw( IO::Async::Notifier );
  2         2  
  2         1040  
11              
12             our $VERSION = '0.79';
13              
14 2     2   16 use Carp;
  2         4  
  2         954  
15              
16             =head1 NAME
17              
18             C - event callback on exit of a child process
19              
20             =head1 SYNOPSIS
21              
22             use IO::Async::PID;
23             use POSIX qw( WEXITSTATUS );
24              
25             use IO::Async::Loop;
26             my $loop = IO::Async::Loop->new;
27              
28             my $kid = $loop->fork(
29             code => sub {
30             print "Child sleeping..\n";
31             sleep 10;
32             print "Child exiting\n";
33             return 20;
34             },
35             );
36              
37             print "Child process $kid started\n";
38              
39             my $pid = IO::Async::PID->new(
40             pid => $kid,
41              
42             on_exit => sub {
43             my ( $self, $exitcode ) = @_;
44             printf "Child process %d exited with status %d\n",
45             $self->pid, WEXITSTATUS($exitcode);
46             },
47             );
48              
49             $loop->add( $pid );
50              
51             $loop->run;
52              
53             =head1 DESCRIPTION
54              
55             This subclass of L invokes its callback when a process
56             exits.
57              
58             For most use cases, a L object provides more control of
59             setting up the process, connecting filehandles to it, sending data to and
60             receiving data from it.
61              
62             =cut
63              
64             =head1 EVENTS
65              
66             The following events are invoked, either using subclass methods or CODE
67             references in parameters:
68              
69             =head2 on_exit $exitcode
70              
71             Invoked when the watched process exits.
72              
73             =cut
74              
75             =head1 PARAMETERS
76              
77             The following named parameters may be passed to C or C:
78              
79             =head2 pid => INT
80              
81             The process ID to watch. Must be given before the object has been added to the
82             containing L object.
83              
84             =head2 on_exit => CODE
85              
86             CODE reference for the C event.
87              
88             Once the C continuation has been invoked, the C
89             object is removed from the containing L object.
90              
91             =cut
92              
93             sub configure
94             {
95 2     2 1 19 my $self = shift;
96 2         38 my %params = @_;
97              
98 2 50       99 if( exists $params{pid} ) {
99 2 50       43 $self->loop and croak "Cannot configure 'pid' after adding to Loop";
100 2         21 $self->{pid} = delete $params{pid};
101             }
102              
103 2 50       28 if( exists $params{on_exit} ) {
104 2         7 $self->{on_exit} = delete $params{on_exit};
105              
106 2         24 undef $self->{cb};
107              
108 2 50       27 if( my $loop = $self->loop ) {
109 0         0 $self->_remove_from_loop( $loop );
110 0         0 $self->_add_to_loop( $loop );
111             }
112             }
113              
114 2         54 $self->SUPER::configure( %params );
115             }
116              
117             sub _add_to_loop
118             {
119 2     2   4 my $self = shift;
120 2         5 my ( $loop ) = @_;
121              
122 2 50       13 $self->pid or croak "Require a 'pid' in $self";
123              
124 2         20 $self->SUPER::_add_to_loop( @_ );
125              
126             # on_exit continuation gets passed PID value; need to replace that with
127             # $self
128             $self->{cb} ||= $self->_replace_weakself( sub {
129 2 50   2   8 my $self = shift or return;
130 2         7 my ( $exitcode ) = @_;
131              
132 2         29 $self->invoke_event( on_exit => $exitcode );
133              
134             # Since this is a oneshot, we'll have to remove it from the loop or
135             # parent Notifier
136 2         26 $self->remove_from_parent;
137 2   33     82 } );
138              
139 2         7 $loop->watch_process( $self->pid, $self->{cb} );
140             }
141              
142             sub _remove_from_loop
143             {
144 2     2   3 my $self = shift;
145 2         6 my ( $loop ) = @_;
146              
147 2         6 $loop->unwatch_process( $self->pid );
148             }
149              
150             sub notifier_name
151             {
152 1     1 1 4 my $self = shift;
153 1 50       24 if( length( my $name = $self->SUPER::notifier_name ) ) {
154 0         0 return $name;
155             }
156              
157 1         7 return $self->{pid};
158             }
159              
160             =head1 METHODS
161              
162             =cut
163              
164             =head2 pid
165              
166             $process_id = $pid->pid
167              
168             Returns the underlying process ID
169              
170             =cut
171              
172             sub pid
173             {
174 8     8 1 2650 my $self = shift;
175 8         140 return $self->{pid};
176             }
177              
178             =head2 kill
179              
180             $pid->kill( $signal )
181              
182             Sends a signal to the process
183              
184             =cut
185              
186             sub kill
187             {
188 1     1 1 38 my $self = shift;
189 1         37 my ( $signal ) = @_;
190              
191 1 50       24 kill $signal, $self->pid or croak "Cannot kill() - $!";
192             }
193              
194             =head1 AUTHOR
195              
196             Paul Evans
197              
198             =cut
199              
200             0x55AA;