File Coverage

blib/arch/Proc/PID/File/Fcntl.pm
Criterion Covered Total %
statement 28 38 73.6
branch 6 22 27.2
condition 2 6 33.3
subroutine 5 6 83.3
pod 2 2 100.0
total 43 74 58.1


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             # Proc::PID::File::Fcntl - pidfile manager
3             #
4              
5             package Proc::PID::File::Fcntl;
6              
7             =head1 NAME
8              
9             Proc::PID::File::Fcntl - Manage PID files using fcntl() locks
10              
11             =head1 SYNOPSIS
12              
13             use Proc::PID::File::Fcntl;
14             my $pidfile = new Proc::PID::File::Fcntl;
15              
16             =head1 DESCRIPTION
17              
18             This Perl module permits callers to prevent multiple simultaneous
19             instantiations of themselves. The module accomplishes this using a
20             I, which is used to obtain a lock.
21              
22             Unlike the traditional I locking protocol, which uses the
23             existence and content of the file to indicate the lock, this module
24             uses fcntl() locking of the file. This locking protocol is free of
25             races and, assuming the lock file is not in a networked filesystem, is
26             safe across OS crashes.
27              
28             =head1 METHODS
29              
30             =cut
31              
32 1     1   27867 use strict;
  1         2  
  1         46  
33 1     1   5 use warnings;
  1         2  
  1         38  
34 1     1   741 use POSIX qw(F_SETLK F_GETLK O_RDWR O_CREAT);
  1         33428  
  1         8  
35              
36             our $VERSION = "1.01";
37              
38             our $_flock_init = "\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
39             our $_flock_pid_template = "x24L";
40              
41             =head2 $pidfile = Proc::PID::File::Fcntl->new(opt => val, ... )
42              
43             Creates and locks a new I, returning an object holding the
44             lock. When the returned object goes out of scope, the lock is
45             released.
46              
47             Calls C if the file cannot be opened or is locked by another process.
48              
49             Must not be called when the calling process already has a lock on the
50             I, otherwise that lock will be released.
51              
52             The options available include the following:
53              
54             =over
55              
56             =item I
57              
58             Specifies the path name of the I. Defaults to I<$0>. If the
59             value does not start with F then F is prepended. If the
60             value does not end with F<.pid> then F<.pid> is appended.
61              
62             =back
63              
64             =cut
65              
66             sub new ($) {
67 1     1 1 3835 my $self = bless({}, shift);
68 1         22 %$self = @_;
69              
70 1 50       12 $self->{path} = $0 unless defined($self->{path});
71 1 50       22 $self->{path} = "/var/run/".$self->{path} unless $self->{path} =~ m|^/|;
72 1 50       12 $self->{path} .= '.pid' unless $self->{path} =~ /\.pid$/;
73            
74 1         4 my $fd;
75              
76 1   33     4 do {
77 1 50       142 sysopen($fd, $self->{path}, O_RDWR|O_CREAT)
78             || die "Cannot open pid file $self->{path}: $!\n";
79              
80 1         4 my $flock = $_flock_init;
81 1 50       54 fcntl($fd, F_SETLK, $flock) || die "pidfile ".$self->{path}." already locked\n";
82             } while ((! -f $self->{path}) || (stat _)[1] != (stat $fd)[1] );
83              
84 1         12 my $data = "$$\n";
85 1         64 syswrite $fd, $data, length($data);
86              
87 1         7 $self->{fd} = $fd;
88 1         6 $self->{pid} = $$;
89 1         12 return $self;
90             }
91              
92             =head2 $pid = Proc::PID::File::Fcntl->getlocker(opt => val, ... )
93              
94             Returns the PID of the process holding the lock on a I or
95             C<0> if there is no such process.
96              
97             Must not be called when the calling process already has a lock on the
98             I, otherwise that lock will be released.
99              
100             The options available include the following:
101              
102             =over
103              
104             =item I
105              
106             Specifies the path name of the I. Defaults to I<$0>. If the
107             value does not start with F then F is prepended. If the
108             value does not end with F<.pid> then F<.pid> is appended.
109              
110             =back
111              
112             =cut
113              
114             sub getlocker {
115 0     0 1 0 my $class = shift;
116 0 0       0 die "Must be called as class method" if ref($class);
117              
118 0         0 my %opts = @_;
119              
120 0 0       0 $opts{path} = $0 unless defined($opts{path});
121 0 0       0 $opts{path} = "/var/run/".$opts{path} unless $opts{path} =~ m|^/|;
122 0 0       0 $opts{path} .= '.pid' unless $opts{path} =~ /\.pid$/;
123            
124 0 0       0 sysopen(my $fd, $opts{path}, O_RDWR) || return 0;
125              
126 0         0 my $flock = $_flock_init;
127 0         0 fcntl($fd, F_GETLK, $flock);
128 0         0 return unpack $_flock_pid_template, $flock;
129             }
130              
131             sub DESTROY {
132 1     1   3 my $self = shift;
133 1 50 33     17 if ($self->{fd} && ($$ == $self->{pid})) {
134             # Must unlink BEFORE releasing lock, otherwise we might unlink
135             # some other process's file
136 1         60 unlink $self->{path};
137 1         450 delete $self->{fd};
138             }
139             }
140              
141             =head1 AUTHOR
142              
143             John Gardiner Myers
144              
145             =head1 SUPPORT
146              
147             For help and thank you notes, e-mail the author directly. To report a
148             bug, submit a patch, or add to the wishlist please visit the CPAN bug
149             manager at: F
150              
151             =head1 COPYRIGHT
152              
153             Copyright (C) 2005, 2006 Proofpoint, Inc.
154              
155             This library is free software; you can redistribute it and/or modify it under
156             the same terms as Perl itself
157              
158             =cut
159              
160             1;