about summary refs log tree commit homepage
path: root/lib/PublicInbox/MboxLock.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/MboxLock.pm')
-rw-r--r--lib/PublicInbox/MboxLock.pm61
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;