1 # Copyright (C) 1996, 1998 David Muir Sharnoff
7 @EXPORT = qw(lock unlock lock_rename);
10 use POSIX qw(EAGAIN EACCES EWOULDBLOCK ENOENT EEXIST O_EXCL O_CREAT O_RDWR);
11 use Fcntl qw(LOCK_SH LOCK_EX LOCK_NB LOCK_UN);
14 use vars qw($VERSION $debug $av0debug);
25 my %locks; # did we create the file?
33 my ($pkg, $file, $shared, $nonblocking) = @_;
34 &lock($file, $shared, $nonblocking) or return undef;
35 return bless \$file, $pkg;
46 my ($file, $shared, $nonblocking) = @_;
51 my $previous = exists $locks{$file};
53 # the file may be springing in and out of existance...
57 unless (sysopen($f, $file, O_RDWR)) {
58 redo OPEN if $! == ENOENT;
59 croak "open $file: $!";
62 unless (sysopen($f, $file, O_CREAT|O_EXCL|O_RDWR)) {
63 redo OPEN if $! == EEXIST;
64 croak "open >$file: $!";
66 print STDERR " {$$ " if $debug; # }
71 $locks{$file} = $created || $locks{$file} || 0;
72 $shared{$file} = $shared;
75 $lockHandle{$file} = $f;
79 $flags = $shared ? LOCK_SH : LOCK_EX;
83 local($0) = "$0 - locking $file" if $av0debug && ! $nonblocking;
84 my $r = flock($f, $flags);
86 print STDERR " ($$ " if $debug and $r;
89 # let's check to make sure the file wasn't
92 my $ifile = (stat($file))[1];
94 eval { $ihandle = (stat($f))[1] };
97 return 1 if defined $ifile
99 and $ifile == $ihandle;
104 return File::Flock::lock($file);
111 or ($! == EWOULDBLOCK)))
114 delete $locks{$file};
115 delete $lockHandle{$file};
116 delete $shared{$file};
120 # oops, a bad thing just happened.
121 # We don't want to block, but we made the file.
122 &background_remove($f, $file);
127 croak "flock $f $flags: $!";
131 # get a lock on a file and remove it if it's empty. This is to
132 # remove files that were created just so that they could be locked.
134 # To do this without blocking, defer any files that are locked to the
137 sub background_remove
141 if (flock($f, LOCK_EX|LOCK_NB)) {
148 unless exists $rm{$file};
157 if (ref $file eq 'File::Flock') {
158 bless $file, 'UNIVERSAL'; # avoid destructor later
162 croak "no lock on $file" unless exists $locks{$file};
163 my $created = $locks{$file};
168 if ($created && defined($size) && $size == 0) {
169 if ($shared{$file}) {
171 &background_remove($lockHandle{$file}, $file);
174 print STDERR " $$} " if $debug;
176 or croak "unlink $file: $!";
179 delete $locks{$file};
182 my $f = $lockHandle{$file};
184 delete $lockHandle{$file};
186 return 0 unless defined $f;
188 print STDERR " $$) " if $debug;
189 $unlocked or flock($f, LOCK_UN)
190 or croak "flock $file UN: $!";
198 my ($oldfile, $newfile) = @_;
200 if (exists $locks{$newfile}) {
203 delete $locks{$newfile};
204 delete $shared{$newfile};
205 delete $pid{$newfile};
206 delete $lockHandle{$newfile};
207 delete $rm{$newfile};
209 $locks{$newfile} = $locks{$oldfile} if exists $locks{$oldfile};
210 $shared{$newfile} = $shared{$oldfile} if exists $shared{$oldfile};
211 $pid{$newfile} = $pid{$oldfile} if exists $pid{$oldfile};
212 $lockHandle{$newfile} = $lockHandle{$oldfile} if exists $lockHandle{$oldfile};
213 $rm{$newfile} = $rm{$oldfile} if exists $rm{$oldfile};
215 delete $locks{$oldfile};
216 delete $shared{$oldfile};
217 delete $pid{$oldfile};
218 delete $lockHandle{$oldfile};
219 delete $rm{$oldfile};
223 # Unlock any files that are still locked and remove any files
224 # that were created just so that they could be locked.
228 for $f (keys %locks) {
234 for my $file (keys %rm) {
235 my $f = new IO::File;
236 if (sysopen($f, $file, O_RDWR)) {
237 if (flock($f, LOCK_EX|LOCK_NB)) {
249 croak "cannot fork" unless defined $ppid;
252 $0 = "$b0: waiting for child ($ppid) to fork()";
255 croak "cannot fork" unless defined $pid;
257 for my $file (keys %bgrm) {
258 my $f = new IO::File;
259 if (sysopen($f, $file, O_RDWR)) {
260 if (flock($f, LOCK_EX)) {
268 print STDERR " $pppid] $pppid)" if $debug;
270 kill(9, $$); # exit w/o END or anything else
273 kill(9, $$); # exit w/o END or anything else
283 File::Flock - file locking with flock
291 lock($filename, 'shared');
293 lock($filename, undef, 'nonblocking');
295 lock($filename, 'shared', 'nonblocking');
299 my $lock = new File::Flock '/somefile';
301 lock_rename($oldfilename, $newfilename)
305 Lock files using the flock() call. If the file to be locked does not
306 exist, then the file is created. If the file was created then it will
307 be removed when it is unlocked assuming it's still an empty file.
309 Locks can be created by new'ing a B<File::Flock> object. Such locks
310 are automatically removed when the object goes out of scope. The
311 B<unlock()> method may also be used.
313 B<lock_rename()> is used to tell File::Flock when a file has been
314 renamed (and thus the internal locking data that is stored based
315 on the filename should be moved to a new name). B<unlock()> the
316 new name rather than the original name.
320 File::Flock may be used/modified/distibuted on the same terms
325 David Muir Sharnoff <muir@idiom.org>