File Coverage

blib/lib/Proc/Pidfile.pm
Criterion Covered Total %
statement 103 117 88.0
branch 32 48 66.6
condition 7 15 46.6
subroutine 17 17 100.0
pod 0 2 0.0
total 159 199 79.9


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