package Proc::Exists;
use strict;
use Proc::Exists::Configuration;
use vars qw (@ISA @EXPORT_OK $VERSION);
eval { require warnings; }; #it's ok if we can't load warnings
require Exporter;
use base 'Exporter';
@EXPORT_OK = qw( pexists );
@ISA = qw( Exporter );
$VERSION = '1.00';
my $use_pureperl = $Proc::Exists::Configuration::want_pureperl;
if(!$use_pureperl) {
eval {
require XSLoader;
XSLoader::load('Proc::Exists', $VERSION);
$Proc::Exists::_loader = 'XSLoader';
1;
} or do {
require DynaLoader;
push @ISA, 'DynaLoader';
$Proc::Exists::_loader = 'DynaLoader';
bootstrap Proc::Exists $VERSION;
}; if($@) {
#NOTE: don't need to worry about i18n, {XS|Dyna}Loader complain in english.
if($@ =~ /Proc::Exists\s+object\s+version\s+\S+\s+does\s+not\s+match\s+bootstrap\s+parameter/ ) {
warn "WARNING: it looks like you have a previous Proc::Exists ".
"version's object file(s) somewhere in \@INC! you will have ".
"to remove these and reinstall Proc::Exists. for now, we are ".
"falling back to pureperl, expect degraded performance: $@\n";
} else {
warn "WARNING: can't load XS. falling back to pureperl, ".
"expect degraded performance: $@\n";
}
$use_pureperl = 1;
}
}
if($use_pureperl) {
#warn "using pure perl mode, expect degraded performance\n";
my $pp_pexists = sub {
my @pids = @_;
my %args = ref($pids[-1]) ? %{pop(@pids)} : ();
die "can't specify both 'any' and 'all' arg" if($args{all} && $args{any});
if(wantarray) {
die "can't specify 'all' argument in list context" if($args{all});
die "can't specify 'any' argument in list context" if($args{any});
}
my @results;
foreach my $pid (@pids) {
#ASSUMPTION: no systems allow a negative int as a PID
if($pid !~ /^\d+$/) {
if($pid =~ /^-\d+$/) {
die "got negative pid: '$pid'";
} elsif($pid =~ /^-?\d+\./) {
die "got non-integer pid: '$pid'";
} else {
die "got non-number pid: '$pid'";
}
}
my $ret;
if (kill 0, $pid) {
$ret = 1;
} else {
if($! == $Proc::Exists::Configuration::EPERM) {
$ret = 1;
} elsif($! == $Proc::Exists::Configuration::ESRCH) {
$ret = 0;
} elsif($^O eq "MSWin32") {
die "can't do pure perl on MSWin32 - \$!: (".(0+$!)."): $!";
} else {
die "unknown numeric \$!: (".(0+$!)."): $!, pureperl, OS: $^O";
}
}
if($ret) {
return $pid if($args{any});
push @results, $pid;
} elsif($args{all}) {
return 0;
}
}
#NOTE: as documented in the pod, any returns undef for false,
# because some systems use pid==0
return if($args{any});
return wantarray ? @results : scalar @results;
};
*pexists = \&$pp_pexists;
$Proc::Exists::pureperl = 1;
} else {
my $xs_pexists = sub {
my @pids = @_;
my %args = ref($pids[-1]) ? %{pop(@pids)} : ();
if(wantarray) {
die "can't specify 'all' argument in list context" if($args{all});
die "can't specify 'any' argument in list context" if($args{any});
return _list_pexists([@pids]);
} else {
die "can't specify both 'any' and 'all' arg" if($args{all} && $args{any});
return _scalar_pexists([@pids], $args{any} || 0, $args{all} || 0);
}
};
*pexists = \&$xs_pexists;
$Proc::Exists::pureperl = 0;
}
# !wantarray : return number of matches
# !wantarray && any : return pid of first match if any match, else undef
# !wantarray && all : return a true value if all match, else a false value
# wantarray : return list of matching pids
# wantarray && any : undefined, makes no sense
# ALTERNATELY: could return list of size one with first matching pid,
# else bare return
# wantarray && all : undefined, makes no sense
# ALTERNATELY: could return list of all pids on true, else bare return
1;
__END__
=head1 NAME
Proc::Exists - quickly and portably check for process existence
=head1 SYNOPSIS
use Proc::Exists qw(pexists);
my $dead_or_alive = pexists($pid);
my @survivors = pexists(@pid_list);
my $nsurvivors = pexists(@pid_list);
my $all_pids_survived = pexists(@pid_list, {all => 1});
my $pid_of_one_survivor_or_undef_if_all_are_dead =
pexists(@pid_list, {any => 1});
=head1 FUNCTIONS
=head2 pexists( @pids, [ $args_hashref ] )
Supported arguments are 'any' and 'all', as shown above.
In list context, giving the 'any' or 'all' arguments will error out.
The 'any' argument returns the pid of the first process found, or undef
if none are found. Note that on some systems, 0 is a valid and usually
extant pid - see B<CAVEATS> for more information.
=head1 DESCRIPTION
A simple, portable, and fast module for checking whether a process
exists or not, regardless of whether it is a child of this process or
has the same owner.
On POSIX systems, this is implemented by sending a 0 (test) signal to
the pid of the process to check and examining the result and errno. On
Win32, OpenProcess() is used for a similar job.
=head1 DEPENDENCIES
* any os with either a POSIX layer or ( win32 and a compiler )
* Config (needed to run Makefile.PL, but you could theoretically do
without it - it is not needed at run time)
* Test::More if you want to run 'make test'
If you are trying to install the pureperl implementation, and EPERM and
ESRCH are not autodetected properly by POSIX.pm, your best bet is to
look up EPERM and ESRCH (try grepping for them down /usr/include or
wherever your headers are kept). If you get hits back, you can edit
Exists/Configuration.pm, add your values there, and re-run the build
process. Whether you were successful or not, please send a description
of what you tried, as well as the output of perl -V and the output of
perl misc/gather-info.pl and perl t/00-info.t to
B<< <ski-cpan@allafrica.com> >> - making sure to include Proc::Exists in
the subject line (or else I won't read it!) If you had no success,
hopefully I'll be able to provide a patch for you, and a fix/workaround
for the next release of Proc::Exists.
There is no pure perl implementation under Windows. The usual solution
is to use Strawberry Perl L<http://strawberryperl.com/> (although
ActivePerl and MSVC have also been reported to work).
Any other OS without a POSIX emulation layer will probably be
completely non-functional unless it implements C<kill()> in a UNIX-esque
fashion.
=head1 CAVEATS
The 'any' argument returns the pid of the first process found, or undef
if none are found. Note that on some systems (e.g. OSX), 0 is a valid
pid (that almost always exists). Since the 'any' mode will return the
first pid that matches, a return value of 0 can indicate that a pid was
found. To avoid this problem, make sure you check whether 'any' mode
found anything by checking for defined-ness, not whether the result
evaluates to true or false in boolean context, like so:
if(defined(pexists(@pid_list, {any => 1})));
B<< DO NOT >> use this idiom:
if(pexists(@pid_list, {any => 1}));
Note also that this caveat does NOT apply for "plain" pexists() (ie
without 'any' or 'all' arguments), because in scalar context a count is
returned, so pexists(0) returns 1 when pid 0 exists, as expected. we
only get a pid with 'any' or when we are in list context, and in the
latter case, an array of length 1 containing a false value evaluates
true in boolean context.
=head1 BUGS AND LIMITATIONS
Please report any bugs or feature requests through the
web interface at L<http://rt.cpan.org>.
=head1 AUTHOR
Brian Szymanski B<< <ski-cpan@allafrica.com> >> -- be sure to put
Proc::Exists in the subject line if you want me to read your message.
=head1 LICENCE AND COPYRIGHT
Copyright (c) 2008-2009, Brian Szymanski B<< <ski-cpan@allafrica.com> >>.
All rights reserved.
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L<perlartistic>.
=head1 DISCLAIMER OF WARRANTY
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
NECESSARY SERVICING, REPAIR, OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.