File Coverage

blib/lib/File/NFSLock.pm
Criterion Covered Total %
statement 180 197 91.3
branch 66 86 76.7
condition 46 69 66.6
subroutine 17 17 100.0
pod 4 11 36.3
total 313 380 82.3


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # File::NFSLock - bdpO - NFS compatible (safe) locking utility
4             #
5             # $Id: NFSLock.pm,v 1.29 2018/11/01 14:00:00 bbb Exp $
6             #
7             # Copyright (C) 2002, Paul T Seamons
8             # paul@seamons.com
9             # http://seamons.com/
10             #
11             # Rob B Brown
12             # bbb@cpan.org
13             #
14             # This package may be distributed under the terms of either the
15             # GNU General Public License
16             # or the
17             # Perl Artistic License
18             #
19             # All rights reserved.
20             #
21             # Please read the perldoc File::NFSLock
22             #
23             ################################################################
24              
25             package File::NFSLock;
26              
27 78     78   6747738 use strict;
  78         1022  
  78         2262  
28 78     78   422 use warnings;
  78         130  
  78         2247  
29              
30 78     78   411 use Carp qw(croak confess);
  78         155  
  78         4855  
31             our $errstr;
32 78     78   492 use base 'Exporter';
  78         171  
  78         14084  
33             our @EXPORT_OK = qw(uncache);
34              
35             our $VERSION = '1.29';
36              
37             #Get constants, but without the bloat of
38             #use Fcntl qw(LOCK_SH LOCK_EX LOCK_NB);
39             use constant {
40 78         193793 LOCK_SH => 1,
41             LOCK_EX => 2,
42             LOCK_NB => 4,
43 78     78   570 };
  78         158  
44              
45             ### Convert lock_type to a number
46             our $TYPES = {
47             BLOCKING => LOCK_EX,
48             BL => LOCK_EX,
49             EXCLUSIVE => LOCK_EX,
50             EX => LOCK_EX,
51             NONBLOCKING => LOCK_EX | LOCK_NB,
52             NB => LOCK_EX | LOCK_NB,
53             SHARED => LOCK_SH,
54             SH => LOCK_SH,
55             };
56             our $LOCK_EXTENSION = '.NFSLock'; # customizable extension
57             our $HOSTNAME = undef;
58             our $SHARE_BIT = 1;
59              
60             ###----------------------------------------------------------------###
61              
62             my $graceful_sig = sub {
63             print STDERR "Received SIG$_[0]\n" if @_;
64             # Perl's exit should safely DESTROY any objects
65             # still "alive" before calling the real _exit().
66             exit 1;
67             };
68              
69             our @CATCH_SIGS = qw(TERM INT);
70              
71             sub new {
72 1167     1167 0 82523906 $errstr = undef;
73              
74 1167         3855 my $type = shift;
75 1167   50     9753 my $class = ref($type) || $type || __PACKAGE__;
76 1167         3211 my $self = {};
77              
78             ### allow for arguments by hash ref or serially
79 1167 100 66     7406 if( @_ && ref $_[0] ){
80 1134         2708 $self = shift;
81             }else{
82 33         287 $self->{file} = shift;
83 33         252 $self->{lock_type} = shift;
84 33         196 $self->{blocking_timeout} = shift;
85 33         185 $self->{stale_lock_timeout} = shift;
86             }
87 1167   50     3755 $self->{file} ||= "";
88 1167   50     3723 $self->{lock_type} ||= 0;
89 1167   100     5502 $self->{blocking_timeout} ||= 0;
90 1167   100     6019 $self->{stale_lock_timeout} ||= 0;
91 1167         4745 $self->{lock_pid} = $$;
92 1167         5443 $self->{unlocked} = 1;
93 1167         4398 foreach my $signal (@CATCH_SIGS) {
94 2334 100 66     10171 if (!$SIG{$signal} ||
95             $SIG{$signal} eq "DEFAULT") {
96 2246         34310 $SIG{$signal} = $graceful_sig;
97             }
98             }
99              
100             ### force lock_type to be numerical
101 1167 50 33     13992 if( $self->{lock_type} &&
      33        
102             $self->{lock_type} !~ /^\d+/ &&
103             exists $TYPES->{$self->{lock_type}} ){
104 0         0 $self->{lock_type} = $TYPES->{$self->{lock_type}};
105             }
106              
107             ### need the hostname
108 1167 100       3173 if( !$HOSTNAME ){
109 68         74569 require Sys::Hostname;
110 68         118772 $HOSTNAME = Sys::Hostname::hostname();
111             }
112              
113             ### quick usage check
114             croak ($errstr = "Usage: my \$f = $class->new('/pathtofile/file',\n"
115             ."'BLOCKING|EXCLUSIVE|NONBLOCKING|SHARED', [blocking_timeout, stale_lock_timeout]);\n"
116             ."(You passed \"$self->{file}\" and \"$self->{lock_type}\")")
117 1167 50       4462 unless length($self->{file});
118              
119             croak ($errstr = "Unrecognized lock_type operation setting [$self->{lock_type}]")
120 1167 50 33     8829 unless $self->{lock_type} && $self->{lock_type} =~ /^\d+$/;
121              
122             ### Input syntax checking passed, ready to bless
123 1167         3037 bless $self, $class;
124              
125             ### choose a random filename
126 1167         3511 $self->{rand_file} = rand_file( $self->{file} );
127              
128             ### choose the lock filename
129 1167         4640 $self->{lock_file} = $self->{file} . $LOCK_EXTENSION;
130              
131             my $quit_time = $self->{blocking_timeout} &&
132             !($self->{lock_type} & LOCK_NB) ?
133 1167 100 66     4522 time() + $self->{blocking_timeout} : 0;
134              
135             ### remove an old lockfile if it is older than the stale_timeout
136 1167 50 100     22996 if( -e $self->{lock_file} &&
      66        
137             $self->{stale_lock_timeout} > 0 &&
138             time() - (stat _)[9] > $self->{stale_lock_timeout} ){
139 0         0 unlink $self->{lock_file};
140             }
141              
142 1167         2909 while (1) {
143             ### open the temporary file
144 1373 50       6039 $self->create_magic
145             or return undef;
146              
147 1373 100       5331 if ( $self->{lock_type} & LOCK_EX ) {
    50          
148 1344 100       4291 last if $self->do_lock;
149             } elsif ( $self->{lock_type} & LOCK_SH ) {
150 29 100       125 last if $self->do_lock_shared;
151             } else {
152 0         0 $errstr = "Unknown lock_type [$self->{lock_type}]";
153 0         0 return undef;
154             }
155              
156             ### Lock failed!
157              
158             ### I know this may be a race condition, but it's okay. It is just a
159             ### stab in the dark to possibly find long dead processes.
160              
161             ### If lock exists and is readable, see who is mooching on the lock
162              
163 218         572 my $fh;
164 218 100 100     10711 if ( -e $self->{lock_file} &&
165             open ($fh,'+<', $self->{lock_file}) ){
166              
167 166         736 my @mine = ();
168 166         407 my @them = ();
169 166         385 my @dead = ();
170              
171 166         858 my $has_lock_exclusive = !((stat _)[2] & $SHARE_BIT);
172 166         584 my $try_lock_exclusive = !($self->{lock_type} & LOCK_SH);
173              
174 166         2850 while(defined(my $line=<$fh>)){
175 166 50       4476 if ($line =~ /^\Q$HOSTNAME\E (-?\d+) /) {
176 166         1373 my $pid = $1;
177 166 100       2770 if ($pid == $$) { # This is me.
    100          
178 1         13 push @mine, $line;
179             }elsif(kill 0, $pid) { # Still running on this host.
180 163         2328 push @them, $line;
181             }else{ # Finished running on this host.
182 2         29 push @dead, $line;
183             }
184             } else { # Running on another host, so
185 0         0 push @them, $line; # assume it is still running.
186             }
187             }
188              
189             ### If there was at least one stale lock discovered...
190 166 100       881 if (@dead) {
191             # Lock lock_file to avoid a race condition.
192 2         18 local $LOCK_EXTENSION = ".shared";
193             my $lock = new File::NFSLock {
194             file => $self->{lock_file},
195 2         66 lock_type => LOCK_EX,
196             blocking_timeout => 62,
197             stale_lock_timeout => 60,
198             };
199              
200             ### Rescan in case lock contents were modified between time stale lock
201             ### was discovered and lockfile lock was acquired.
202 2         23 seek ($fh, 0, 0);
203 2         14 my $content = '';
204 2         26 while(defined(my $line=<$fh>)){
205 2 50       73 if ($line =~ /^\Q$HOSTNAME\E (-?\d+) /) {
206 2         10 my $pid = $1;
207 2 50       45 next if (!kill 0, $pid); # Skip dead locks from this host
208             }
209 0         0 $content .= $line; # Save valid locks
210             }
211              
212             ### Save any valid locks or wipe file.
213 2 50       12 if( length($content) ){
214 0         0 seek $fh, 0, 0;
215 0         0 print $fh $content;
216 0         0 truncate $fh, length($content);
217 0         0 close $fh;
218             }else{
219 2         18 close $fh;
220 2         96 unlink $self->{lock_file};
221             }
222              
223             ### No "dead" or stale locks found.
224             } else {
225 164         2903 close $fh;
226             }
227              
228             ### If attempting to acquire the same type of lock
229             ### that it is already locked with, and I've already
230             ### locked it myself, then it is safe to lock again.
231             ### Just kick out successfully without really locking.
232             ### Assumes locks will be released in the reverse
233             ### order from how they were established.
234 166 100 100     1695 if ($try_lock_exclusive eq $has_lock_exclusive && @mine){
235 1         8 return $self;
236             }
237             }
238              
239             ### If non-blocking, then kick out now.
240             ### ($errstr might already be set to the reason.)
241 217 100       1056 if ($self->{lock_type} & LOCK_NB) {
242 11   50     139 $errstr ||= "NONBLOCKING lock failed!";
243 11         85 return undef;
244             }
245              
246             ### wait a moment
247 206         206047494 sleep(1);
248              
249             ### but don't wait past the time out
250 206 50 66     5596 if( $quit_time && (time > $quit_time) ){
251 0         0 $errstr = "Timed out waiting for blocking lock";
252 0         0 return undef;
253             }
254              
255             # BLOCKING Lock, So Keep Trying
256             }
257              
258             ### clear up the NFS cache
259 1155         5762 $self->uncache;
260              
261             ### Yes, the lock has been acquired.
262 1155         4827 delete $self->{unlocked};
263              
264 1155         4130 return $self;
265             }
266              
267             sub DESTROY {
268 1167     1167   36093930 shift()->unlock();
269             }
270              
271             sub unlock ($) {
272 1187     1187 1 100015469 my $self = shift;
273 1187 100       3656 if (!$self->{unlocked}) {
274 1155 50       19555 unlink( $self->{rand_file} ) if -e $self->{rand_file};
275 1155 100       4797 if( $self->{lock_type} & LOCK_SH ){
276 33         355 $self->do_unlock_shared;
277             }else{
278 1122         3230 $self->do_unlock;
279             }
280 1155         4727 $self->{unlocked} = 1;
281 1155         3383 foreach my $signal (@CATCH_SIGS) {
282 2310 100 66     16101 if ($SIG{$signal} &&
283             ($SIG{$signal} eq $graceful_sig)) {
284             # Revert handler back to how it used to be.
285             # Unfortunately, this will restore the
286             # handler back even if there are other
287             # locks still in tact, but for most cases,
288             # it will still be an improvement.
289 2240         32439 delete $SIG{$signal};
290             }
291             }
292             }
293 1187         17449 return 1;
294             }
295              
296             ###----------------------------------------------------------------###
297              
298             # concepts for these routines were taken from Mail::Box which
299             # took the concepts from Mail::Folder
300              
301              
302             sub rand_file ($) {
303 2322     2322 0 4179 my $file = shift;
304 2322         17810 "$file.tmp.". time()%10000 .'.'. $$ .'.'. int(rand()*10000);
305             }
306              
307             sub create_magic ($;$) {
308 1401     1401 0 2965 $errstr = undef;
309 1401         2606 my $self = shift;
310 1401   66     7406 my $append_file = shift || $self->{rand_file};
311 1401   66     11611 $self->{lock_line} ||= "$HOSTNAME $self->{lock_pid} ".time()." ".int(rand()*10000)."\n";
312 1401 50       106237 open (my $fh,'>>', $append_file) or do { $errstr = "Couldn't open \"$append_file\" [$!]"; return undef; };
  0         0  
  0         0  
313 1401         12078 print $fh $self->{lock_line};
314 1401         45362 close $fh;
315 1401         10581 return 1;
316             }
317              
318             sub do_lock {
319 1344     1344 0 2645 $errstr = undef;
320 1344         2573 my $self = shift;
321 1344         2628 my $lock_file = $self->{lock_file};
322 1344         2247 my $rand_file = $self->{rand_file};
323 1344         2125 my $chmod = 0600;
324 1344 50       23139 chmod( $chmod, $rand_file)
325             || die "I need ability to chmod files to adequatetly perform locking";
326              
327             ### try a hard link, if it worked
328             ### two files are pointing to $rand_file
329 1344   66     46148 my $success = link( $rand_file, $lock_file )
330             && -e $rand_file && (stat _)[3] == 2;
331 1344         38895 unlink $rand_file;
332              
333 1344         8905 return $success;
334             }
335              
336             sub do_lock_shared {
337 29     29 0 56 $errstr = undef;
338 29         61 my $self = shift;
339 29         66 my $lock_file = $self->{lock_file};
340 29         78 my $rand_file = $self->{rand_file};
341              
342             ### chmod local file to make sure we know before
343 29         46 my $chmod = 0600;
344 29         54 $chmod |= $SHARE_BIT;
345 29 50       590 chmod( $chmod, $rand_file)
346             || die "I need ability to chmod files to adequatetly perform locking";
347              
348             ### lock the locking process
349 29         389 local $LOCK_EXTENSION = ".shared";
350 29         658 my $lock = new File::NFSLock {
351             file => $lock_file,
352             lock_type => LOCK_EX,
353             blocking_timeout => 62,
354             stale_lock_timeout => 60,
355             };
356             # The ".shared" lock will be released as this status
357             # is returned, whether or not the status is successful.
358              
359             ### If I didn't have exclusive and the shared bit is not
360             ### set, I have failed
361              
362             ### Try to create $lock_file from the special
363             ### file with the magic $SHARE_BIT set.
364 29         409 my $success = link( $rand_file, $lock_file);
365 29         1201 unlink $rand_file;
366 29 100 66     1183 if ( !$success &&
    100 100        
367             -e $lock_file &&
368             ((stat _)[2] & $SHARE_BIT) != $SHARE_BIT ){
369              
370 2         15 $errstr = 'Exclusive lock exists.';
371 2         17 return undef;
372              
373             } elsif ( !$success ) {
374             ### Shared lock exists, append my lock
375 20         159 $self->create_magic ($self->{lock_file});
376             }
377              
378             # Success
379 27         212 return 1;
380             }
381              
382             sub do_unlock ($) {
383 1122     1122 0 42681 return unlink shift->{lock_file};
384             }
385              
386             sub do_unlock_shared ($) {
387 33     33 0 223 $errstr = undef;
388 33         175 my $self = shift;
389 33         189 my $lock_file = $self->{lock_file};
390 33         201 my $lock_line = $self->{lock_line};
391              
392             ### lock the locking process
393 33         630 local $LOCK_EXTENSION = '.shared';
394 33         903 my $lock = new File::NFSLock ($lock_file,LOCK_EX,62,60);
395              
396             ### get the handle on the lock file
397 33         168 my $fh;
398 33 50       1387 if( ! open ($fh,'+<', $lock_file) ){
399 0 0       0 if( ! -e $lock_file ){
400 0         0 return 1;
401             }else{
402 0         0 die "Could not open for writing shared lock file $lock_file ($!)";
403             }
404             }
405              
406             ### read existing file
407 33         175 my $content = '';
408 33         823 while(defined(my $line=<$fh>)){
409 251 100       814 next if $line eq $lock_line;
410 218         931 $content .= $line;
411             }
412              
413             ### other shared locks exist
414 33 100       296 if( length($content) ){
415 28         281 seek $fh, 0, 0;
416 28         224 print $fh $content;
417 28         1540 truncate $fh, length($content);
418 28         905 close $fh;
419              
420             ### only I exist
421             }else{
422 5         60 close $fh;
423 5         503 unlink $lock_file;
424             }
425              
426             }
427              
428             sub uncache ($;$) {
429             # allow as method call
430 1155     1155 1 2309 my $file = pop;
431 1155 50       4194 ref $file && ($file = $file->{file});
432 1155         2550 my $rand_file = rand_file( $file );
433              
434             ### hard link to the actual file which will bring it up to date
435 1155   66     64325 return ( link( $file, $rand_file) && unlink($rand_file) );
436             }
437              
438             sub newpid {
439 12     12 1 8014559 my $self = shift;
440             # Detect if this is the parent or the child
441 12 100       506 if ($self->{lock_pid} == $$) {
442             # This is the parent
443              
444             # Must wait for child to call newpid before processing.
445             # A little patience for the child to call newpid
446 4         37 my $patience = time + 10;
447 4         75 while (time < $patience) {
448 46 100       2482 if (rename("$self->{lock_file}.fork",$self->{rand_file})) {
449             # Child finished its newpid call.
450             # Wipe the signal file.
451 4         255 unlink $self->{rand_file};
452 4         71 last;
453             }
454             # Brief pause before checking again
455             # to avoid intensive IO across NFS.
456 42         4210402 select(undef,undef,undef,0.1);
457             }
458              
459             # Child finished running newpid() and acquired shared lock
460             # So now we're safe to continue without risk of
461             # blowing away the lock prematurely.
462 4 100       131 unless ( $self->{lock_type} & LOCK_SH ) {
463             # If it's not already a SHared lock, then
464             # just switch it from EXclusive to SHared
465             # from this process's point of view.
466             # Then the child will still hold the lock
467             # if the parent releases it first.
468             # (Don't chmod the lock file.)
469 2         64 $self->{lock_type} |= LOCK_SH;
470             }
471             } else {
472             # This is the new child
473              
474             # Fix lock_pid to the new pid.
475 8         171 $self->{lock_pid} = $$;
476              
477             # We can leave the old lock_line in the lock_file
478             # But we need to add the new lock_line for this pid.
479              
480             # Clear lock_line to create a fresh one.
481 8         434 delete $self->{lock_line};
482             # Append a new lock_line to the lock_file.
483 8         317 $self->create_magic($self->{lock_file});
484              
485 8 100       157 unless ( $self->{lock_type} & LOCK_SH ) {
486             # If it's not already a SHared lock, then
487             # just switch it from EXclusive to SHared
488             # from this process's point of view.
489             # Then the parent will still hold the lock
490             # if this child releases it first.
491             # (Don't chmod the lock file.)
492 4         56 $self->{lock_type} |= LOCK_SH;
493             }
494              
495             # Create signal file to notify parent that
496             # the lock_line entry has been delegated.
497 8         663 open (my $fh, '>', "$self->{lock_file}.fork");
498 8         222 close($fh);
499             }
500             }
501              
502             sub fork {
503 6     6 1 1838 my $self = shift;
504             # Store fork response.
505 6         5297 my $pid = CORE::fork();
506 6 50 33     646 if (defined $pid and !$self->{unlocked}) {
507             # Fork worked and we really have a lock to deal with
508             # So upgrade to shared lock across both parent and child
509 6         192 $self->newpid;
510             }
511             # Return original fork response
512 6         187 return $pid;
513             }
514              
515             1;
516              
517              
518             =pod
519              
520             =head1 NAME
521              
522             File::NFSLock - perl module to do NFS (or not) locking
523              
524             =head1 SYNOPSIS
525              
526             use File::NFSLock qw(uncache);
527             use Fcntl qw(LOCK_EX LOCK_NB);
528              
529             my $file = "somefile";
530              
531             ### set up a lock - lasts until object looses scope
532             if (my $lock = new File::NFSLock {
533             file => $file,
534             lock_type => LOCK_EX|LOCK_NB,
535             blocking_timeout => 10, # 10 sec
536             stale_lock_timeout => 30 * 60, # 30 min
537             }) {
538              
539             ### OR
540             ### my $lock = File::NFSLock->new($file,LOCK_EX|LOCK_NB,10,30*60);
541              
542             ### do write protected stuff on $file
543             ### at this point $file is uncached from NFS (most recent)
544             open(FILE, "+<$file") || die $!;
545              
546             ### or open it any way you like
547             ### my $fh = IO::File->open( $file, 'w' ) || die $!
548              
549             ### update (uncache across NFS) other files
550             uncache("someotherfile1");
551             uncache("someotherfile2");
552             # open(FILE2,"someotherfile1");
553              
554             ### unlock it
555             $lock->unlock();
556             ### OR
557             ### undef $lock;
558             ### OR let $lock go out of scope
559             }else{
560             die "I couldn't lock the file [$File::NFSLock::errstr]";
561             }
562              
563              
564             =head1 DESCRIPTION
565              
566             Program based of concept of hard linking of files being atomic across
567             NFS. This concept was mentioned in Mail::Box::Locker (which was
568             originally presented in Mail::Folder::Maildir). Some routine flow is
569             taken from there -- particularly the idea of creating a random local
570             file, hard linking a common file to the local file, and then checking
571             the nlink status. Some ideologies were not complete (uncache
572             mechanism, shared locking) and some coding was even incorrect (wrong
573             stat index). File::NFSLock was written to be light, generic,
574             and fast.
575              
576              
577             =head1 USAGE
578              
579             Locking occurs by creating a File::NFSLock object. If the object
580             is created successfully, a lock is currently in place and remains in
581             place until the lock object goes out of scope (or calls the unlock
582             method).
583              
584             A lock object is created by calling the new method and passing two
585             to four parameters in the following manner:
586              
587             my $lock = File::NFSLock->new($file,
588             $lock_type,
589             $blocking_timeout,
590             $stale_lock_timeout,
591             );
592              
593             Additionally, parameters may be passed as a hashref:
594              
595             my $lock = File::NFSLock->new({
596             file => $file,
597             lock_type => $lock_type,
598             blocking_timeout => $blocking_timeout,
599             stale_lock_timeout => $stale_lock_timeout,
600             });
601              
602             =head1 PARAMETERS
603              
604             =over 4
605              
606             =item Parameter 1: file
607              
608             Filename of the file upon which it is anticipated that a write will
609             happen to. Locking will provide the most recent version (uncached)
610             of this file upon a successful file lock. It is not necessary
611             for this file to exist.
612              
613             =item Parameter 2: lock_type
614              
615             Lock type must be one of the following:
616              
617             BLOCKING
618             BL
619             EXCLUSIVE (BLOCKING)
620             EX
621             NONBLOCKING
622             NB
623             SHARED
624             SH
625              
626             Or else one or more of the following joined with '|':
627              
628             Fcntl::LOCK_EX() (BLOCKING)
629             Fcntl::LOCK_NB() (NONBLOCKING)
630             Fcntl::LOCK_SH() (SHARED)
631              
632             Lock type determines whether the lock will be blocking, non blocking,
633             or shared. Blocking locks will wait until other locks are removed
634             before the process continues. Non blocking locks will return undef if
635             another process currently has the lock. Shared will allow other
636             process to do a shared lock at the same time as long as there is not
637             already an exclusive lock obtained.
638              
639             =item Parameter 3: blocking_timeout (optional)
640              
641             Timeout is used in conjunction with a blocking timeout. If specified,
642             File::NFSLock will block up to the number of seconds specified in
643             timeout before returning undef (could not get a lock).
644              
645              
646             =item Parameter 4: stale_lock_timeout (optional)
647              
648             Timeout is used to see if an existing lock file is older than the stale
649             lock timeout. If do_lock fails to get a lock, the modified time is checked
650             and do_lock is attempted again. If the stale_lock_timeout is set to low, a
651             recursion load could exist so do_lock will only recurse 10 times (this is only
652             a problem if the stale_lock_timeout is set too low -- on the order of one or two
653             seconds).
654              
655             =back
656              
657             =head1 METHODS
658              
659             After the $lock object is instantiated with new,
660             as outlined above, some methods may be used for
661             additional functionality.
662              
663             =head2 unlock
664              
665             $lock->unlock;
666              
667             This method may be used to explicitly release a lock
668             that is acquired. In most cases, it is not necessary
669             to call unlock directly since it will implicitly be
670             called when the object leaves whatever scope it is in.
671              
672             =head2 uncache
673              
674             $lock->uncache;
675             $lock->uncache("otherfile1");
676             uncache("otherfile2");
677              
678             This method is used to freshen up the contents of a
679             file across NFS, ignoring what is contained in the
680             NFS client cache. It is always called from within
681             the new constructor on the file that the lock is
682             being attempted. uncache may be used as either an
683             object method or as a stand alone subroutine.
684              
685             =head2 fork
686              
687             my $pid = $lock->fork;
688             if (!defined $pid) {
689             # Fork Failed
690             } elsif ($pid) {
691             # Parent ...
692             } else {
693             # Child ...
694             }
695              
696             fork() is a convenience method that acts just like the normal
697             CORE::fork() except it safely ensures the lock is retained
698             within both parent and child processes. WITHOUT this, then when
699             either the parent or child process releases the lock, then the
700             entire lock will be lost, allowing external processes to
701             re-acquire a lock on the same file, even if the other process
702             still has the lock object in scope. This can cause corruption
703             since both processes might think they have exclusive access to
704             the file.
705              
706             =head2 newpid
707              
708             my $pid = fork;
709             if (!defined $pid) {
710             # Fork Failed
711             } elsif ($pid) {
712             $lock->newpid;
713             # Parent ...
714             } else {
715             $lock->newpid;
716             # Child ...
717             }
718              
719             The newpid() synopsis shown above is equivalent to the
720             one used for the fork() method, but it's not intended
721             to be called directly. It is called internally by the
722             fork() method. To be safe, it is recommended to use
723             $lock->fork() from now on.
724              
725             =head1 FAILURE
726              
727             On failure, a global variable, $File::NFSLock::errstr, should be set and should
728             contain the cause for the failure to get a lock. Useful primarily for debugging.
729              
730             =head1 LOCK_EXTENSION
731              
732             By default File::NFSLock will use a lock file extension of ".NFSLock". This is
733             in a global variable $File::NFSLock::LOCK_EXTENSION that may be changed to
734             suit other purposes (such as compatibility in mail systems).
735              
736             =head1 REPO
737              
738             The source is now on github:
739              
740             git clone https://github.com/hookbot/File-NFSLock
741              
742             =head1 BUGS
743              
744             If you spot anything, please submit a pull request on
745             github and/or submit a ticket with RT:
746             https://rt.cpan.org/Dist/Display.html?Queue=File-NFSLock
747              
748             =head2 FIFO
749              
750             Locks are not necessarily obtained on a first come first serve basis.
751             Not only does this not seem fair to new processes trying to obtain a lock,
752             but it may cause a process starvation condition on heavily locked files.
753              
754             =head2 DIRECTORIES
755              
756             Locks cannot be obtained on directory nodes, nor can a directory node be
757             uncached with the uncache routine because hard links do not work with
758             directory nodes. Some other algorithm might be used to uncache a
759             directory, but I am unaware of the best way to do it. The biggest use I
760             can see would be to avoid NFS cache of directory modified and last accessed
761             timestamps.
762              
763             =head1 INSTALL
764              
765             Download and extract tarball before running
766             these commands in its base directory:
767              
768             perl Makefile.PL
769             make
770             make test
771             make install
772              
773             For RPM installation, download tarball before
774             running these commands in your _topdir:
775              
776             rpm -ta SOURCES/File-NFSLock-*.tar.gz
777             rpm -ih RPMS/noarch/perl-File-NFSLock-*.rpm
778              
779             =head1 AUTHORS
780              
781             Paul T Seamons (paul@seamons.com) - Performed majority of the
782             programming with copious amounts of input from Rob Brown.
783              
784             Rob B Brown (bbb@cpan.org) - In addition to helping in the
785             programming, Rob Brown provided most of the core testing to make sure
786             implementation worked properly. He is now the current maintainer.
787              
788             Also Mark Overmeer (mark@overmeer.net) - Author of Mail::Box::Locker,
789             from which some key concepts for File::NFSLock were taken.
790              
791             Also Kevin Johnson (kjj@pobox.com) - Author of Mail::Folder::Maildir,
792             from which Mark Overmeer based Mail::Box::Locker.
793              
794             =head1 COPYRIGHT
795              
796             Copyright (C) 2001
797             Paul T Seamons
798             paul@seamons.com
799             http://seamons.com/
800              
801             Copyright (C) 2002-2018,
802             Rob B Brown
803             bbb@cpan.org
804              
805             This package may be distributed under the terms of either the
806             GNU General Public License
807             or the
808             Perl Artistic License
809              
810             All rights reserved.
811              
812             =cut