diff options
Diffstat (limited to 'lib/PublicInbox/MboxLock.pm')
-rw-r--r-- | lib/PublicInbox/MboxLock.pm | 61 |
1 files changed, 30 insertions, 31 deletions
diff --git a/lib/PublicInbox/MboxLock.pm b/lib/PublicInbox/MboxLock.pm index 856b1e21..5e373873 100644 --- a/lib/PublicInbox/MboxLock.pm +++ b/lib/PublicInbox/MboxLock.pm @@ -1,20 +1,24 @@ -# Copyright (C) 2021 all contributors <meta@public-inbox.org> +# Copyright (C) all contributors <meta@public-inbox.org> # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> # Various mbox locking methods package PublicInbox::MboxLock; -use strict; -use v5.10.1; -use PublicInbox::OnDestroy; +use v5.12; +use PublicInbox::OnDestroy (); use Fcntl qw(:flock F_SETLK F_SETLKW F_RDLCK F_WRLCK O_CREAT O_EXCL O_WRONLY SEEK_SET); use Carp qw(croak); use PublicInbox::DS qw(now); # ugh... +use autodie qw(chdir opendir unlink); our $TMPL = do { - if ($^O eq 'linux') { \'s @32' } - elsif ($^O =~ /bsd/) { \'@20 s @256' } # n.b. @32 may be enough... - else { eval { require File::FcntlLock; 1 } } + if ($^O eq 'linux') { + \'s @32' + } elsif ($^O =~ /bsd/ || $^O eq 'dragonfly') { + \'@20 s @256' # n.b. @32 may be enough... + } else { + eval { require File::FcntlLock; 1 } + } }; # This order matches Debian policy on Linux systems. @@ -58,16 +62,13 @@ sub acq_dotlock { rand(0xffffffff), $pid, time); if (sysopen(my $fh, $tmp, O_CREAT|O_EXCL|O_WRONLY)) { if (link($tmp, $dot_lock)) { - unlink($tmp) or die "unlink($tmp): $!"; + unlink($tmp); $self->{".lock$pid"} = $dot_lock; - if (substr($dot_lock, 0, 1) ne '/') { - opendir(my $dh, '.') or - die "opendir . $!"; - $self->{dh} = $dh; - } + substr($dot_lock, 0, 1) eq '/' or + opendir($self->{dh}, '.'); return; } - unlink($tmp) or die "unlink($tmp): $!"; + unlink($tmp); select(undef, undef, undef, $self->{delay}); } else { croak "open $tmp (for $dot_lock): $!" if !$!{EXIST}; @@ -83,18 +84,20 @@ sub acq_flock { my $end = now + $self->{timeout}; do { return if flock($self->{fh}, $op); - select(undef, undef, undef, $self->{delay}); + if ($!{EWOULDBLOCK}) { + select(undef, undef, undef, $self->{delay}); + } elsif (!$!{EINTR}) { + croak "flock($self->{f} ($self->{fh}): $!"; + } } while (now < $end); die "flock timeout $self->{f}: $!\n"; } sub acq { my ($cls, $f, $rw, $methods) = @_; - my $fh; - unless (open $fh, $rw ? '+>>' : '<', $f) { - croak "open($f): $!" if $rw || !$!{ENOENT}; - } - my $self = bless { f => $f, fh => $fh, rw => $rw }, $cls; + my $self = bless { f => $f, rw => $rw }, $cls; + my $ok = open $self->{fh}, $rw ? '+>>' : '<', $f; + croak "open($f): $!" if !$ok && ($rw || !$!{ENOENT}); my $m = "@$methods"; if ($m ne 'none') { my @m = map { @@ -116,20 +119,16 @@ sub acq { $self; } -sub _fchdir { chdir($_[0]) } # OnDestroy callback - sub DESTROY { my ($self) = @_; - if (my $f = $self->{".lock$$"}) { - my $x; - if (my $dh = delete $self->{dh}) { - opendir my $c, '.' or die "opendir . $!"; - $x = PublicInbox::OnDestroy->new(\&_fchdir, $c); - chdir($dh) or die "chdir (for $f): $!"; - } - unlink($f) or die "unlink($f): $! (lock stolen?)"; - undef $x; + my $f = $self->{".lock$$"} or return; + my $od; + if (my $dh = delete $self->{dh}) { + opendir my $c, '.'; + $od = PublicInbox::OnDestroy::all \&chdir, $c; + chdir($dh); } + CORE::unlink($f) or die "unlink($f): $! (lock stolen?)"; } 1; |