App-plockf

 view release on metacpan or  search on metacpan

bin/plockf  view on Meta::CPAN

sub wait_for_lock_bsd {
    sysopen my $fh, $lock_file, &Fcntl::O_EXLOCK;
    # no error handling needed; probably same failure will happen in acquire_lock_bsd
}

sub acquire_lock_other {
    my($block) = @_;
    my $lock_fh;
    if (!sysopen $lock_fh, $lock_file, &Fcntl::O_RDONLY|($nocreat ? 0 : &Fcntl::O_CREAT), 0666) {
	if ($!{EAGAIN} || $!{EINTR}) {
	    return undef;
	}
	if ($nocreat && $!{ENOENT}) {
	    handle_error EX_UNAVAILABLE;
	} else {
	    handle_error EX_CANTCREAT;
	}
    }
    if (!flock $lock_fh, ($block ? 0 : &Fcntl::LOCK_NB)|&Fcntl::LOCK_EX) {
	return undef;
    }
    if (!$keep) {
	my @stat_file = stat $lock_file;
	if (!@stat_file) {
	    # file was unlinked in the meantime
	    return undef;
	}
	if ($^O ne 'MSWin32') { # ino+dev are not meaningful on Windows systems
	    my @stat_fh = stat $lock_fh;
	    if ($stat_fh[1] != $stat_file[1] || $stat_fh[0] != $stat_file[0]) {
		# file was unlinked in the meantime and another plockf process was faster
		return undef;
	    }
	}
    }
    return $lock_fh;
}

sub wait_for_lock_other {
    if (sysopen my $fh, $lock_file, &Fcntl::O_RDONLY) {
	flock $fh, &Fcntl::LOCK_EX;
    }
}

sub wait_for_lock_nonblocking {
    while () {
	last if $timed_out;
	if (sysopen my $fh, $lock_file, &Fcntl::O_RDONLY) {
	    return if flock $fh, &Fcntl::LOCK_EX|&Fcntl::LOCK_NB;
	}
	sleep 1;
    }
}

sub handle_error ($) {
    my $exit = shift;
    unless ($silent) {
	if ($exit == EX_UNAVAILABLE) {
	    warn progname . ": cannot open $lock_file: $!\n";
	} else {
	    warn progname . ": $lock_file: already locked\n";
	}
    }
    exit $exit;
}

sub progname () {
    require File::Basename;
    File::Basename::basename($0);
}

__END__

=head1 NAME

plockf - execute a command while holding a file lock

=head1 SYNOPSIS

    plockf [-kns] [-t seconds] file command [arguments]

=head1 DESCRIPTION

B<plockf> is a perl port of the FreeBSD utility L<lockf(1)>.

The B<plockf> utility acquires an exclusive lock on a I<file>, creating
it if necessary, and removing the file on exit unless explicitly told
not to. While holding the lock, it executes a I<command> with optional
I<arguments>. After the I<command> completes, B<plockf> releases the
lock, and removes the I<file> unless the C<-k> option is specified.
BSD-style locking is used, as described in L<flock(2)>; the mere
existence of the I<file> is not considered to constitute a lock.

If the B<plockf> utility is being used to facilitate concurrency
between a number of processes, it is recommended that the C<-k> option
be used. This will guarantee lock ordering, as well as implement a
performance enhanced algorithm which minimizes CPU load associated
with concurrent unlink, drop and re-acquire activity. It should be
noted that if the C<-k> option is not used, then no guarantees around
lock ordering can be made.

The following options are supported:

=over

=item C<-k>

Causes the lock I<file> to be kept (not removed) after the command
completes.

=item C<-s>

Causes B<plockf> to operate silently. Failure to acquire the lock is
indicated only in the exit status.

=item C<-n>

Causes B<plockf> to fail if the specified lock I<file> does not exist.
If C<-n> is not specified, B<plockf> will create I<file> if necessary.

=item C<-t I<seconds>>

Specifies a timeout for waiting for the lock. By default, B<plockf>
waits indefinitely to acquire the lock. If a timeout is specified with
this option, B<plockf> will wait at most the given number of I<seconds>
before giving up. A timeout of 0 may be given, in which case B<plockf>
will fail unless it can acquire the lock immediately. When a lock
times out, I<command> is not executed.

Unlike the original L<lockf> utility, L<plockf> may handle also
floating point timeouts on systems which implement
C<Time::HiRes::alarm>; on Windows systems only integer timeouts are
supported.

=back

In no event will B<plockf> break a lock that is held by another
process.

=head2 IMPLEMENTATION DETAILS

On systems where L<open(2)> handles C<O_EXLOCK> and C<O_NONBLOCK>
(most notably on *BSD systems) the implementation follows quite
closely the original C implementation of L<lockf(1)>.

On other systems (e.g. Linux) there's a possible race condition
between creation and locking of the lock I<file>. Here an extra check
is done if the lock filehandle is really done on the lock I<file>, and
the lock procedure is re-done if not. Here it's especially recommended
to use the C<-k> option.

On Windows systems this extra check is incomplete, so it's even more
recommended to use C<-k>.

On Windows systems C<alarm()> cannot interrupt blocking system calls,
i.e. C<flock()> (see L<perlport/alarm>). Here the timeout handling is
implemented by periodically checking if the lock can be acquired
(currently the interval is one second).

=head1 EXIT STATUS

If B<plockf> successfully acquires the lock, it returns the exit status
produced by I<command>. Otherwise, it returns one of the exit
codes defined in L<sysexits(3)>, as follows:

=over

=item C<EX_TEMPFAIL> (75)

The specified lock I<file> was already locked by another process.

=item C<EX_CANTCREAT> (73)

The B<plockf> utility was unable to create the lock I<file>, e.g.,
because of insufficient access privileges.

=item C<EX_UNAVAILABLE> (69)

The C<-n> option is specified and the specified lock I<file> does not
exist.

=item C<EX_USAGE> (64)

There was an error on the B<plockf> command line.

=item C<EX_OSERR> (71)

A system call (e.g., fork(2)) failed unexpectedly.

=item C<EX_SOFTWARE> (70)

The I<command> did not exit normally, but may have been signaled or
stopped.

C<EX_SOFTWARE> is not reported on Windows systems.

=back

=head1 SEE ALSO

L<flock(1)>, L<flock(2)>, L<open(2)>, L<sysexits(3)>, L<Fcntl>.

=head1 AUTHORS

Author of the perl port: Slaven Rezic <srezic@cpan.org>

Author of the original FreeBSD utility: John Polstra <jdp@polstra.com>

=cut



( run in 1.895 second using v1.01-cache-2.11-cpan-2398b32b56e )