X-Git-Url: https://git.p6c8.net/selfforum.git/blobdiff_plain/2427a7a4ff1fe48d61d649a0c1618f3528a95231..920bb240f2bab1555b7a45cfae4f15d0ddb8df97:/selfforum-cgi/shared/Lock.pm?ds=sidebyside diff --git a/selfforum-cgi/shared/Lock.pm b/selfforum-cgi/shared/Lock.pm index f3291c6..88f9a5a 100644 --- a/selfforum-cgi/shared/Lock.pm +++ b/selfforum-cgi/shared/Lock.pm @@ -11,16 +11,26 @@ package Lock; ################################################################################ use strict; -use Carp; use vars qw( @EXPORT_OK %EXPORT_TAGS + %LOCKED $Timeout $violentTimeout $masterTimeout $iAmMaster + $VERSION ); +use Carp; +use Fcntl; + +################################################################################ +# +# Version check +# +$VERSION = do { my @r =(q$Revision$ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; + ################################################################################ # # Export @@ -35,6 +45,7 @@ use base qw(Exporter); violent_unlock_file set_master_lock release_file + file_removed ); %EXPORT_TAGS = ( @@ -48,23 +59,32 @@ use base qw(Exporter); write_unlock_file violent_unlock_file )], - ALL => [qw( - lock_file - unlock_file - write_lock_file - write_unlock_file - violent_unlock_file - set_master_lock - release_file - )] + ALL => \@EXPORT_OK ); +### ~file () ################################################################### +# +# create lock file names +# +sub reffile ($) { + return $_[0].'.lock.ref'; +} +sub lockfile ($) { + return $_[0].'.lock'; +} +sub masterfile ($) { + return $_[0].'.master'; +} +sub masterlockfile ($) { + return lockfile(masterfile $_[0]); +} + ################################################################################ # # Windows section (no symlinks) # -### sub w_lock_file ($;$) ###################################################### +### w_lock_file () ############################################################# # # set read lock (shared lock) # (for no-symlink-systems) @@ -78,21 +98,23 @@ sub w_lock_file ($;$) { my $filename = shift; my $timeout = +shift || $Timeout; - if (-f &masterlockfile($filename)) { - for (0..$timeout) { - - # try to increment the reference counter - # - &set_ref($filename,1,$timeout) and return 1; - sleep (1); + unless ($LOCKED{$filename}) { + if (-f masterlockfile($filename)) { + for (1..$timeout) { + + # try to increment the reference counter + # + if (set_ref($filename,1,$timeout)) { + $LOCKED{$filename}=1; + return 1; + } + sleep (1); + } + } + else { + # master lock is set or file has not been released yet + return; } - } - - else { - # master lock is set - # or file has not been realeased yet - # - return; } # time out @@ -100,7 +122,7 @@ sub w_lock_file ($;$) { 0; } -### sub w_unlock_file ($;$) #################################################### +### w_unlock_file () ########################################################### # # remove read lock (shared lock) # (for no-symlink-systems) @@ -114,21 +136,29 @@ sub w_unlock_file ($;$) { my $filename = shift; my $timeout = shift || $Timeout; - if (-f &masterlockfile($filename)) { - - # try do decrement the reference counter - # - &set_ref($filename,-1,$timeout) and return 1; + if ($LOCKED{$filename}) { + if ($LOCKED{$filename} == 3) { + return unless write_unlock_file($filename, $timeout); + $LOCKED{$filename} = 1; + } + if ($LOCKED{$filename} == 1) { + if (-f masterlockfile($filename)) { + + # try do decrement the reference counter + # + if (set_ref($filename, -1, $timeout)) { + delete $LOCKED{$filename}; + return 1; + } + } + } } # time out - # maybe the system is occupied - # or file has not been released yet - # return; } -### sub w_write_lock_file ($;$) ################################################ +### w_write_lock_file () ####################################################### # # set write lock (exclusive lock) # (for no-symlink-systems) @@ -141,32 +171,36 @@ sub w_unlock_file ($;$) { sub w_write_lock_file ($;$) { my $filename=shift; my $timeout= shift || $Timeout; + my $rest = ($LOCKED{$filename} and $LOCKED{$filename} == 1) ? 1 : 0; - if (-f &masterlockfile($filename) or $iAmMaster) { + if (-f masterlockfile($filename) or $iAmMaster) { # announce the write lock # and wait $timeout seconds for # references == 0 (no shared locks set) # - &simple_lock ($filename,$timeout) or return 0; - for (0..$timeout) { + simple_lock ($filename,$timeout) or return 0; + for (1..$timeout) { # lock reference counter # or fail # - unless (&simple_lock (&reffile($filename),$timeout)) { - &simple_unlock($filename,$timeout); + unless (simple_lock (reffile($filename),$timeout)) { + simple_unlock($filename,$timeout); return 0; } # ready if we have no shared locks # - return 1 if (&get_ref ($filename) == 0); + if (get_ref ($filename) == $rest) { + $LOCKED{$filename} = 2 | ($rest ? 1 : 0); + return 1; + }; # release reference counter # shared locks get the chance to be removed # - unless (&simple_unlock (&reffile($filename),$timeout)) { - &simple_unlock($filename,$timeout); + unless (simple_unlock (reffile($filename),$timeout)) { + simple_unlock($filename,$timeout); return 0; } sleep(1); @@ -175,21 +209,19 @@ sub w_write_lock_file ($;$) { # write lock failed # remove the announcement # - &simple_unlock ($filename);} + simple_unlock ($filename); + } else { - # master lock is set - # or file has not been released yet - # - return;} + # master lock is set or file has not been released yet + return; + } # time out - # maybe the system is occupied - # 0; } -### sub w_write_unlock_file ($;$) ############################################## +### w_write_unlock_file () ##################################################### # # remove write lock (exclusive lock) # (for no-symlink-systems) @@ -203,21 +235,23 @@ sub w_write_unlock_file ($;$) { my $filename = shift; my $timeout = shift || $Timeout; - if (-f &masterlockfile($filename) or $iAmMaster) { + if (-f masterlockfile($filename) or $iAmMaster) { # remove reference counter lock # - &simple_unlock (&reffile($filename),$timeout) or return; + simple_unlock (reffile($filename),$timeout) or return; # remove the write lock announce # - &simple_unlock ($filename,$timeout) or return;} + simple_unlock ($filename,$timeout) or return; + } # done + delete $LOCKED{$filename}; 1; } -### sub w_violent_unlock_file ($) ############################################## +### w_violent_unlock_file () ################################################### # # remove any lock violent (excl. master lock) # (for no-symlink-systems) @@ -229,25 +263,27 @@ sub w_write_unlock_file ($;$) { sub w_violent_unlock_file ($) { my $filename = shift; - if (-f &masterlockfile($filename)) { + if (-f masterlockfile($filename)) { # find out last modification time # and do nothing unless 'violent-timout' is over # my $reffile; - if (-f ($reffile = $filename) or -f ($reffile = &lockfile($filename))) { + if (-f ($reffile = $filename) or -f ($reffile = lockfile($filename))) { my $time = (stat $reffile)[9]; - return if ((time - $time) < $violentTimeout);} + (time - $time) >= $violentTimeout or return; + } write_lock_file ($filename,1); # last try, to set an exclusive lock on $filename - unlink (&reffile($filename)); # reference counter = 0 - simple_unlock (&reffile($filename)); # release reference counter file + unlink (reffile($filename)); # reference counter = 0 + simple_unlock (reffile($filename)); # release reference counter file simple_unlock ($filename);} # release file + delete $LOCKED{$filename}; return; } -### sub w_set_master_lock ($;$) ################################################ +### w_set_master_lock () ####################################################### # # set master lock # (for no-symlink-systems) @@ -263,17 +299,17 @@ sub w_set_master_lock ($;$) { # set exclusive lock or fail # - return unless (&write_lock_file ($filename,$timeout)); + return unless (write_lock_file ($filename,$timeout)); # set master lock # - unlink &masterlockfile($filename) and return 1; + unlink masterlockfile($filename) and return 1; # no chance (occupied?, master lock set yet?) return; } -### sub w_release_file ($) ##################################################### +### w_release_file () ########################################################## # # remove any locks (incl. master lock) # (for no-symlink-systems) @@ -286,22 +322,32 @@ sub w_set_master_lock ($;$) { sub w_release_file ($) { my $filename=shift; - unlink (&reffile($filename)); # reference counter = 0 - return if (-f &reffile($filename)); # really? - return unless (simple_unlock (&reffile($filename))); # release reference counter - return unless (&simple_unlock ($filename)); # remove any write lock announce - return unless (&simple_unlock (&masterfile($filename))); # remove master lock + unlink (reffile($filename)); # reference counter = 0 + return if (-f reffile($filename)); # really? + return unless (simple_unlock (reffile($filename))); # release reference counter + return unless (simple_unlock ($filename)); # remove any write lock announce + return unless (simple_unlock (masterfile($filename))); # remove master lock + delete $LOCKED{$filename}; # done 1; } +sub w_file_removed ($) { + my $filename = shift; + + unlink reffile($filename); + unlink lockfile($filename); + unlink lockfile(reffile($filename)); + unlink masterlockfile($filename); +} + ################################################################################ # # *n*x section (symlinks possible) # -### sub x_lock_file ($;$) ###################################################### +### x_lock_file () ############################################################# # # set read lock (shared lock) # (symlinks possible) @@ -315,29 +361,31 @@ sub x_lock_file ($;$) { my $filename = shift; my $timeout = shift || $Timeout; - unless (-l &masterlockfile($filename)) { - for (0..$timeout) { - - # try to increment the reference counter - # - &set_ref($filename,1,$timeout) and return 1; - sleep (1); + unless ($LOCKED{$filename}) { + unless (-l masterlockfile($filename)) { + for (1..$timeout) { + + # try to increment the reference counter + # + if (set_ref($filename,1,$timeout)) { + $LOCKED{$filename} = 1; + return 1; + } + sleep (1); + } } - } - else { - # master lock is set - # or file has not been realeased yet - # - return; + else { + # master lock is set or file has not been realeased yet + return; + } } # time out - # maybe the system is occupied 0; } -### sub x_unlock_file ($;$) #################################################### +### x_unlock_file () ########################################################### # # remove read lock (shared lock) # (symlinks possible) @@ -351,19 +399,28 @@ sub x_unlock_file ($;$) { my $filename=shift; my ($timeout)=(shift (@_) or $Timeout); - unless (-l &masterlockfile($filename)) { - # try do decrement the reference counter - # - &set_ref($filename,-1,$timeout) and return 1;} + if ($LOCKED{$filename}) { + if ($LOCKED{$filename} == 3) { + return unless write_unlock_file($filename, $timeout); + $LOCKED{$filename} = 1; + } + if ($LOCKED{$filename} == 1) { + unless (-l masterlockfile($filename)) { + # try to decrement the reference counter + # + set_ref($filename,-1,$timeout) and do { + delete $LOCKED{$filename}; + return 1; + } + } - # time out - # maybe the system is occupied - # or file has not been released yet - # - return; + # time out + return; + } + } } -### sub x_write_lock_file ($;$) ################################################ +### x_write_lock_file () ####################################################### # # set write lock (exclusive lock) # (symlinks possible) @@ -376,32 +433,36 @@ sub x_unlock_file ($;$) { sub x_write_lock_file ($;$) { my $filename = shift; my $timeout = shift || $Timeout; + my $rest = ($LOCKED{$filename} and $LOCKED{$filename} == 1) ? 1 : 0; - unless (-l &masterlockfile($filename) and not $iAmMaster) { + unless (-l masterlockfile($filename) and not $iAmMaster) { # announce the write lock # and wait $timeout seconds for # references == 0 (no shared locks set) # - &simple_lock ($filename,$timeout) or return 0; - for (0..$timeout) { + simple_lock ($filename,$timeout) or return 0; + for (1..$timeout) { # lock reference counter # or fail # - unless (&simple_lock (&reffile($filename),$timeout)) { - &simple_unlock($filename,$timeout); + unless (simple_lock (&reffile($filename),$timeout)) { + simple_unlock($filename,$timeout); return 0; } # ready if we have no shared locks # - return 1 if (&get_ref ($filename) == 0); + if (get_ref ($filename) == $rest) { + $LOCKED{$filename} = 2 | ($rest ? 1 : 0); + return 1; + }; # release reference counter # shared locks get the chance to be removed # - unless (&simple_unlock (&reffile($filename),$timeout)) { - &simple_unlock($filename,$timeout); + unless (simple_unlock (&reffile($filename),$timeout)) { + simple_unlock($filename,$timeout); return 0; } sleep(1); @@ -410,7 +471,8 @@ sub x_write_lock_file ($;$) { # write lock failed # remove the announcement # - &simple_unlock ($filename);} + simple_unlock ($filename); + } else { # master lock is set @@ -425,7 +487,7 @@ sub x_write_lock_file ($;$) { 0; } -### sub x_write_unlock_file ($;$) ############################################## +### x_write_unlock_file () ##################################################### # # remove write lock (exclusive lock) # (symlinks possible) @@ -442,18 +504,19 @@ sub x_write_unlock_file ($;$) { unless (-l &masterlockfile($filename) and not $iAmMaster) { # remove reference counter lock # - &simple_unlock (&reffile($filename),$timeout) or return; + simple_unlock (reffile($filename),$timeout) or return; # remove the write lock announce # - &simple_unlock ($filename,$timeout) or return; + simple_unlock ($filename,$timeout) or return; } # done + delete $LOCKED{$filename}; 1; } -### sub x_violent_unlock_file ($) ############################################## +### x_violent_unlock_file () ################################################### # # remove any lock violent (excl. master lock) # (symlinks possible) @@ -475,19 +538,20 @@ sub x_violent_unlock_file ($) { if (-f ($reffile = $filename)) { $time = (stat $reffile)[9];} - elsif (-l ($reffile = &lockfile($filename))) { + elsif (-l ($reffile = lockfile($filename))) { $time = (lstat $reffile)[9];} if ($reffile) { return if ((time - $time) < $violentTimeout);} write_lock_file ($filename,1); # last try, to set an exclusive lock on $filename - unlink (&reffile($filename)); # reference counter = 0 - simple_unlock (&reffile($filename)); # release reference counter file + unlink (reffile($filename)); # reference counter = 0 + simple_unlock (reffile($filename)); # release reference counter file simple_unlock ($filename);} # release file + delete $LOCKED{$filename}; } -### sub x_set_master_lock ($;$) ################################################ +### x_set_master_lock () ####################################################### # # set master lock # (symlinks possible) @@ -503,17 +567,17 @@ sub x_set_master_lock ($;$) { # set exclusive lock or fail # - return unless (&write_lock_file ($filename,$timeout)); + return unless (write_lock_file ($filename,$timeout)); # set master lock # - symlink $filename, &masterlockfile($filename) and return 1; + symlink $filename, masterlockfile($filename) and return 1; # no chance (occupied?, master lock set yet?) return; } -### sub x_release_file ($) ##################################################### +### x_release_file () ########################################################## # # remove any locks (incl. master lock) # (symlinks possible) @@ -526,41 +590,23 @@ sub x_set_master_lock ($;$) { sub x_release_file ($) { my $filename=shift; - unlink (&reffile($filename)); # reference counter = 0 - return if (-f &reffile($filename)); # really? - return unless (simple_unlock (&reffile($filename))); # release reference counter - return unless (&simple_unlock ($filename)); # remove any write lock announce - return unless (&simple_unlock (&masterfile($filename))); # remove master lock + unlink (reffile($filename)); # reference counter = 0 + return if (-f reffile($filename)); # really? + return unless (simple_unlock (reffile($filename))); # release reference counter + return unless (simple_unlock ($filename)); # remove any write lock announce + return unless (simple_unlock (masterfile($filename))); # remove master lock + delete $LOCKED{$filename}; # done 1; } -################################################################################ -# -# private subs -# - -### sub ~file ($) ############################################################## -# -# create lock file names -# -sub reffile ($) { - "$_[0].lock.ref"; -} -sub lockfile ($) { - "$_[0].lock"; -} -sub masterlockfile ($) { - &lockfile(&masterfile($_[0])); -} -sub masterfile ($) { - confess unless defined $_[0]; - "$_[0].master"; +sub x_file_removed ($) { + release_file (shift); } -### sub w_simple_lock ($;$) #################################################### -### sub w_simple_unlock ($) #################################################### +### w_simple_lock () ########################################################### +### w_simple_unlock () ######################################################### # # simple file lock/unlock # (for no-symlink-systems: kill/create lockfile) @@ -590,7 +636,7 @@ sub w_simple_unlock ($) { my $lockfile = lockfile $filename; local *LF; - if (open(LF, "> $lockfile")) { + if (sysopen(LF, $lockfile, O_WRONLY|O_CREAT|O_TRUNC)) { return 1 if close (LF); } @@ -599,8 +645,8 @@ sub w_simple_unlock ($) { return; } -### sub w_simple_lock ($;$) #################################################### -### sub w_simple_unlock ($) #################################################### +### x_simple_lock () ########################################################### +### x_simple_unlock () ######################################################### # # simple file lock/unlock # (symlinks possible: create/unlink symlink) @@ -621,22 +667,20 @@ sub x_simple_lock ($;$) { } # time out - # locking failed (occupied?) - # return; } sub x_simple_unlock ($) { my $filename=shift; - unlink (&lockfile($filename)) and return 1; + unlink (lockfile $filename) and return 1; # not able to unlink symlink, hmmm... # return; } -### sub w_set_ref ($$$) ######################################################## +### w_set_ref () ############################################################### # # add $_[1] to reference counter # (may be negative...) @@ -652,30 +696,20 @@ sub w_set_ref ($$$) { my $filename = shift; my $z = shift; my $timeout = shift || $Timeout; - my $old; - my $reffile = reffile $filename; + my $reffile = reffile $filename; local *REF; # if write lock announced, only count down allowed # - if ($z > 0) { - return unless(-f lockfile($filename)); - } + ($z < 0 or -f lockfile ($filename)) or return; # lock reference counter file # - return unless(&simple_lock ($reffile,$timeout)); + simple_lock ($reffile,$timeout) or return; # load reference counter # - unless (open REF,"<$reffile") { - $old=0; - } - else { - $old=; - chomp $old; - close REF or return; - } + my $old = get_ref ($filename); # compute and write new ref. counter # @@ -686,23 +720,27 @@ sub w_set_ref ($$$) { # if ref. counter == 0 # if ($old == 0) { - unlink $reffile or return; + unlink $reffile or return; } else { - open REF,">$reffile" or return; - print REF $old or return; - close REF or return; + local $\; + sysopen (REF, $reffile, O_WRONLY | O_TRUNC | O_CREAT) or return; + print REF $old or do { + close REF; + return + }; + close REF or return; } # release ref. counter file # - return unless(&simple_unlock($reffile)); + simple_unlock($reffile) or return; # done 1; } -### sub x_set_ref ($$$) ######################################################## +### x_set_ref () ############################################################### # # add $_[1] to reference counter # (may be negative...) @@ -718,53 +756,50 @@ sub x_set_ref ($$$) { my $filename = shift; my $z = shift; my $timeout = shift || $Timeout; - my $old; - my $reffile = reffile $filename; + my $reffile = reffile $filename; local *REF; # if write lock announced, only count down allowed # if ($z > 0) { - return if(-l &lockfile($filename)); + return if(-l lockfile($filename)); } # lock reference counter file # - return unless(&simple_lock ($reffile,$timeout)); + return unless(simple_lock ($reffile,$timeout)); # load reference counter # - unless (open REF,"<$reffile") { - $old=0; - } - else { - $old=; - chomp $old; - close REF or return; - } + my $old = get_ref ($filename); # compute and write new ref. counter # $old += $z; $old = 0 if ($old < 0); + if ($old == 0) { - unlink $reffile or return; + unlink $reffile or return; } else { - open REF,">$reffile" or return; - print REF $old or return; - close REF or return; + local $\; + sysopen (REF, $reffile, O_WRONLY | O_TRUNC | O_CREAT) or return; + print REF $old or do { + close REF; + return + }; + close REF or return; } # release ref. counter file # - return unless(&simple_unlock($reffile)); + simple_unlock($reffile) or return; # done 1; } -### sub get_ref ($) ############################################################ +### get_ref () ################################################################# # # read out the reference counter # (system independant) @@ -774,20 +809,16 @@ sub x_set_ref ($$$) { # # Return: reference counter # -sub get_ref ($$) { +sub get_ref ($) { my $filename = shift; my $reffile = reffile $filename; my $old; local *REF; + local $/; - unless (open REF,"< $reffile") { - $old = 0; - } - else { - $old=; - chomp $old; - close REF; - } + sysopen (REF, $reffile, O_RDONLY) or return 0; + $old = ; + close REF; # return value $old; @@ -806,6 +837,8 @@ BEGIN { $iAmMaster = 0; # default: I am nobody + %LOCKED = (); + # assign the aliases to the needed functions # (perldoc -f symlink) @@ -817,6 +850,7 @@ BEGIN { *violent_unlock_file = \&x_violent_unlock_file; *set_master_lock = \&x_set_master_lock; *release_file = \&x_release_file; + *file_removed = \&x_file_removed; *simple_lock = \&x_simple_lock; *simple_unlock = \&x_simple_unlock; @@ -831,6 +865,7 @@ BEGIN { *violent_unlock_file = \&w_violent_unlock_file; *set_master_lock = \&w_set_master_lock; *release_file = \&w_release_file; + *file_removed = \&w_file_removed; *simple_lock = \&w_simple_lock; *simple_unlock = \&w_simple_unlock; @@ -838,7 +873,7 @@ BEGIN { } } -# keeping require happy +# keep 'require' happy 1; #