File Coverage

blib/lib/Proc/Pidfile.pm
Criterion Covered Total %
statement 110 119 92.4
branch 36 50 72.0
condition 7 15 46.6
subroutine 17 18 94.4
pod 0 2 0.0
total 170 204 83.3


line stmt bran cond sub pod time code
1             package Proc::Pidfile;
2             $Proc::Pidfile::VERSION = '1.10';
3 4     4   277420 use 5.006;
  4         16  
4 4     4   24 use strict;
  4         8  
  4         116  
5 4     4   24 use warnings;
  4         8  
  4         120  
6              
7 4     4   16 use Fcntl qw/ :flock /;
  4         8  
  4         668  
8 4     4   28 use File::Basename qw/ basename /;
  4         8  
  4         276  
9 4     4   28 use Carp qw/ carp croak /;
  4         4  
  4         192  
10 4     4   2532 use Time::HiRes qw/ usleep /;
  4         5988  
  4         20  
11 4     4   968 use File::Spec::Functions qw/ catfile tmpdir /;
  4         16  
  4         3056  
12              
13             sub new
14             {
15 24     24 0 1205580 my $class = shift;
16 24         229 my %args = @_;
17 24         119 my $self = bless \%args, $class;
18              
19 24 100       162 $self->{retries} = 2 unless defined($self->{retries});
20 24 100   0   359 $self->{backoff} = sub { 100 + rand(300) } unless defined($self->{backoff});
  0         0  
21              
22 24 100       70 unless ( $self->{pidfile} ) {
23 19         2684 my $basename = basename( $0 );
24 19         201 my $dir = tmpdir();
25              
26 19 50       1012 croak "Can't write to $dir\n" unless -w $dir;
27              
28 19         208 my $pidfile = catfile($dir, "$basename.pid");
29              
30             # untaint the path, since it includes externally generated info
31             # TODO: should we be a bit more pedantic on "valid path"?
32 19 50       239 $pidfile = $1 if ($pidfile =~ /^\s*(.*)\s*/);
33              
34 19         112 $self->_verbose( "pidfile: $pidfile\n" );
35 19         65 $self->{pidfile} = $pidfile;
36             }
37 24         175 $self->_create_pidfile();
38 21         82 return $self;
39             }
40              
41             sub DESTROY
42             {
43 24     24   760864 my $self = shift;
44              
45 24         169 $self->_destroy_pidfile();
46             }
47              
48             sub pidfile
49             {
50 12     12 0 48 my $self = shift;
51 12         40 return $self->{pidfile};
52             }
53              
54             sub _verbose
55             {
56 200     200   364 my $self = shift;
57 200 100       548 return unless $self->{verbose};
58 25         77 print STDERR @_;
59             }
60              
61             sub _get_pid
62             {
63 28     28   56 my $self = shift;
64 28         55 my $pidfile = $self->{pidfile};
65 28         100 $self->_verbose( "get pid from $pidfile\n" );
66 28 50       1244 open( PID, $pidfile ) or croak "can't read pid file $pidfile\n";
67 28 50       372 flock( PID, LOCK_SH ) or croak "can't lock pid file $pidfile\n";
68 28         790 my $pid = ;
69 28 50 33     506 if (defined($pid) && $pid =~ /([0-9]+)/) {
70 28         143 $pid = $1;
71             }
72             else {
73 0         0 croak "can't get pid from pidfile $pidfile\n";
74             }
75 28         69 chomp( $pid );
76 28         229 flock( PID, LOCK_UN );
77 28         721 close( PID );
78 28         173 $self->_verbose( "pid = $pid\n" );
79 28         144 return $pid;
80             }
81              
82             sub _is_running
83             {
84 8     8   38 my $pid = shift;
85              
86 8 50       113 if ($^O eq 'riscos') {
87 0         0 require Proc::ProcessTable;
88              
89 0         0 my $table = Proc::ProcessTable->new()->table;
90 0         0 my %processes = map { $_->pid => $_ } @$table;
  0         0  
91 0         0 return exists $processes{$pid};
92             }
93             else {
94 4   66 4   1948 return kill(0, $pid) || $!{'EPERM'};
  4         5444  
  4         32  
  8         369  
95             }
96             }
97              
98             sub _create_pidfile
99             {
100 24     24   46 my $self = shift;
101 24         89 my $pidfile = $self->{pidfile};
102 24         46 my $attempt = 1;
103              
104 24         496 while ( -e $pidfile ) {
105 8         188 $self->_verbose( "pidfile $pidfile exists\n" );
106 8         91 my $pid = $self->_get_pid();
107 8         108 $self->_verbose( "pid in pidfile $pidfile = $pid\n" );
108 8 100       67 if ( _is_running( $pid ) ) {
109            
110             # this might be a race condition, or parallel smoke testers,
111             # so we'll back off a random amount of time and try again
112 7 100       59 if ($attempt <= $self->{retries}) {
113 4         12 ++$attempt;
114             # TODO: let's try this. Guessing we don't have to
115             # bother with increasing backoff times
116 4         14 my $backoff = $self->{backoff}->();
117 4         27 $self->_verbose("backing off for $backoff microseconds before trying again");
118 4         414 usleep($backoff);
119 4         65 next;
120             }
121              
122 3 100       58 if ( $self->{silent} ) {
123 1         46 exit;
124             }
125             else {
126 2         1053 croak "$0 already running: $pid ($pidfile)\n";
127             }
128             }
129             else {
130 1         41 $self->_verbose( "$pid has died - replacing pidfile\n" );
131 1 50       81 open( PID, ">$pidfile" ) or croak "Can't write to $pidfile\n";
132 1         15 print PID "$$\n";
133 1         118 close( PID );
134 1         9 last;
135             }
136             }
137              
138 21 100       218 if (not -e $pidfile) {
139 20         109 $self->_verbose( "no pidfile $pidfile\n" );
140 20 50       1675 open( PID, ">$pidfile" ) or croak "Can't write to $pidfile: $!\n";
141 20 50       286 flock( PID, LOCK_EX ) or croak "Can't lock pid file $pidfile\n";
142 20 50       338 print PID "$$\n" or croak "Can't write to pid file $pidfile\n";
143 20         734 flock( PID, LOCK_UN );
144 20 50       258 close( PID ) or croak "Can't close pid file $pidfile: $!\n";
145 20         117 $self->_verbose( "pidfile $pidfile created\n" );
146             }
147              
148 21         59 $self->{created} = 1;
149             }
150              
151             sub _destroy_pidfile
152             {
153 24     24   49 my $self = shift;
154              
155 24 100       147 return unless $self->{created};
156 21         71 my $pidfile = $self->{pidfile};
157 21         115 $self->_verbose( "destroy $pidfile\n" );
158 21 100 66     833 if ( $pidfile and -e $pidfile ) {
159 20         80 my $pid = $self->_get_pid();
160 20         120 $self->_verbose( "pid in $pidfile = $pid\n" );
161 20 100 33     298 if ( $pid == $$ ) {
    50          
162 17         59 $self->_verbose( "remove pidfile: $pidfile\n" );
163 17 50 33     2429 unlink( $pidfile ) if $pidfile and -e $pidfile;
164             }
165             elsif ($^O ne 'MSWin32' && $^O ne 'riscos') {
166 3         105 $self->_verbose( "$pidfile not my pidfile - maybe my parent's?\n" );
167 3         99 my $ppid = getppid();
168 3         74 $self->_verbose( "parent pid = $ppid\n" );
169 3 50       964 if ( $ppid != $pid ) {
170 0         0 carp "pid $pid in $pidfile is not mine ($$) - I am $0 - or my parents ($ppid)\n";
171             }
172             }
173             else {
174 0         0 $self->_verbose( "$pidfile not my pidfile - can't check if it's my parent's on this OS\n" );
175             }
176             }
177             else {
178 1         421 carp "pidfile $pidfile doesn't exist\n";
179             }
180             }
181              
182             #------------------------------------------------------------------------------
183             #
184             # Start of POD
185             #
186             #------------------------------------------------------------------------------
187              
188             =head1 NAME
189              
190             Proc::Pidfile - a simple OO Perl module for maintaining a process id file for
191             the current process
192              
193             =head1 SYNOPSIS
194              
195             my $pp = Proc::Pidfile->new( pidfile => "/path/to/your/pidfile" );
196             # if the pidfile already exists, die here
197             $pidfile = $pp->pidfile();
198             undef $pp;
199             # unlink $pidfile here
200              
201             my $pp = Proc::Pidfile->new();
202             # creates pidfile in default location
203             my $pidfile = $pp->pidfile();
204             # tells you where this pidfile is ...
205              
206             my $pp = Proc::Pidfile->new( silent => 1 );
207             # if the pidfile already exists, exit silently here
208             ...
209             undef $pp;
210              
211             =head1 DESCRIPTION
212              
213             Proc::Pidfile is a very simple OO interface which manages a pidfile for the
214             current process.
215             You can pass the path to a pidfile to use as an argument to the constructor,
216             or you can let Proc::Pidfile choose one
217             ("/$tmpdir/$basename", where C<$tmpdir> is from C).
218              
219             Pidfiles created by Proc::Pidfile are automatically removed on destruction of
220             the object. At destruction, the module checks the process id in the pidfile
221             against its own, and against its parents (in case it is a spawned child of the
222             process that originally created the Proc::Pidfile object), and barfs if it
223             doesn't match either.
224              
225             If you pass a "silent" parameter to the constructor, then it will still check
226             for the existence of a pidfile, but will exit silently if one is found. This is
227             useful for, for example, cron jobs, where you don't want to create a new
228             process if one is already running, but you don't necessarily want to be
229             informed of this by cron.
230              
231             =head2 Retries
232              
233             If another instance of your script is already running,
234             we'll retry a couple of times,
235             with a random number of microseconds between each attempt.
236              
237             You can specify the number of retries, for example if you
238             want to try more times for some reason:
239              
240             my $pp = Proc::Pidfile->new(retries => 4);
241              
242             By default this is set to 2,
243             which means if the first attempt to set up a pidfile fails,
244             it will try 2 more times, so three attempts in total.
245              
246             Setting retries to 0 (zero) will disable this feature.
247              
248             If you want to generate the number of microseconds to wait yourself,
249             you can pass a code reference generating it to the constructor.
250              
251             my $backoff = 100;
252             my $pp = Proc::Pidfile->new(retries => 4,
253             backoff => sub { $backoff *= 2 });
254              
255             =head1 SEE ALSO
256              
257             L - provides a similar interface.
258              
259             L - provides effectively the same functionality,
260             but via class methods. Hasn't been updated since 2011,
261             and has quite a few CPAN Testers fails.
262              
263             L - provides a simple interface, but has some restrictions,
264             and its documentation even recommends you consider a different module,
265             as it has a race condition.
266              
267             L - very simple interface, and uses a different mechanism:
268             it tries to lock the script file which used the module.
269             The trouble with that is that you might be running someone else's script,
270             and thus can't lock it.
271              
272             L - another one with a simple default interface,
273             but can be configured to retry. Based on locking, rather than a pid file.
274             Doesn't work on Windows.
275              
276             L - Linux-specific solution.
277              
278             =head1 REPOSITORY
279              
280             L
281              
282             =head1 AUTHOR
283              
284             Ave Wrigley Eawrigley@cpan.orgE
285              
286             Now maintained by Neil Bowers Eneilb@cpan.orgE
287              
288             =head1 COPYRIGHT
289              
290             Copyright (c) 2003 Ave Wrigley. All rights reserved. This program is free
291             software; you can redistribute it and/or modify it under the same terms as Perl
292             itself.
293              
294             =cut
295              
296             #------------------------------------------------------------------------------
297             #
298             # End of POD
299             #
300             #------------------------------------------------------------------------------
301              
302              
303             #------------------------------------------------------------------------------
304             #
305             # True ...
306             #
307             #------------------------------------------------------------------------------
308              
309             1;
310