X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-utils.git;a=blobdiff_plain;f=scripts%2Fgit-cache-proxy;h=b4b23001cb3ed42686ccaf0c1392c7f4f0bc40c5;hp=520f1e5f28c8cbdf9a2cb0a4406f5d386f974a6e;hb=32c189107d19892ab4730757003c07576f139de5;hpb=eda343442f5440c4a4b23fd2cdf9bd8cb6953761 diff --git a/scripts/git-cache-proxy b/scripts/git-cache-proxy index 520f1e5..b4b2300 100755 --- a/scripts/git-cache-proxy +++ b/scripts/git-cache-proxy @@ -157,6 +157,31 @@ for (;;) { #---------- utility functions ---------- +sub lockfile ($$) { + my ($fh, $fn, $flockmode) = @_; + for (;;) { + close $fh; + open $fh, '+>', $fn or fail "open/create $fn for lock: $!"; + if (!flock $fh, $lockmode) { + if ($lockmode & LOCK_NB and $! == EWOULDBLOCK) { + return 0; # ok then + } + fail "lock $fn". + (($flockmode & ~LOCK_NB) == LOCK_SH ? " (shared)" : ""). + ": $!"; + } + stat $fh or fail "stat opened $fn: $!"; + my $fh_ino = ((stat _)[1]); + if (!stat $fn) { + $! == ENOENT or fail "stat $fn: $!"; + next; + } + my $fn_ino = ((stat _)[1]); + return 1 if $fn_ino == $fh_ino; + # oh dear + } +} + sub xread { my $length = shift; my $buffer = ""; @@ -236,8 +261,7 @@ sub readcommand () { } sub clonefetch () { - open LOCK, "+>", $lock or fail "open/create $lock: $!"; - flock LOCK, LOCK_EX or fail "lock exclusive $lock: $!"; + lockfile \*LOCK, $lock, LOCK_EX; my $exists = lstat $gitd; $exists or $!==ENOENT or fail "lstat $gitd: $!"; @@ -315,10 +339,7 @@ sub clonefetch () { } servinfo "sharing"; - flock LOCK, LOCK_UN or fail "unlock $lock: $!"; - flock LOCK, LOCK_SH or fail "lock shared $lock: $!"; - # actually, just relocking as shared would have the same semantics - # but it's best to be explicit + lockfile \*LOCK, $lock, LOCK_SH; # NB releases and relocks if (chdir $gitd) { return 1; @@ -356,10 +377,9 @@ sub housekeeping () { sub housekeepingcheck ($$) { my ($dofork, $force) = @_; - open HLOCK, "+>", "Housekeeping.lock" or fail "open/create Housekeeping.lock: $!"; if (!$force) { - if (flock HLOCK, LOCK_EX|LOCK_NB) { + if (!lockfile \*HLOCK, "Housekeeping.lock", LOCK_EX|LOCK_NB) { logm 'debug', "housekeeping lock taken, not running"; close HLOCK; return 0;