#!/usr/bin/perl
package FileLock;
use 5.00800;
use strict;
use warnings;
use Fcntl qw(:flock);
our $VERSION = 1.00;
use constant NO_LOCK => 0;
use constant SH_LOCK => 1;
use constant EX_LOCK => 2;
our $lock_stat = NO_LOCK;
our $fh;
sub new {
# save off the class
my $class = shift;
# check for and save file
if(scalar @_ < 1) {
die("No file argument specified for FileLock->new().\n");
}
my $file = shift;
# open the file
open($fh, '+<', $file) or die("Could not open '$file' in preparation for lock.\n");
# create the object
my $self = {'fh' => $fh,
'stat' => NO_LOCK};
bless($self, $class);
return $self;
}
sub shared_lock {
my $self = shift;
# return if already an shared lock
if($self->{'stat'} == SH_LOCK) {
return 1;
}
# get the timeout if specified
my $timeout = 0;
if(scalar @_ > 0) {
$timeout = shift;
}
# release existing lock before trying to take new
if($self->{'stat'} != NO_LOCK) {
$self->unlock or die("Could not unlock in preparation for shared lock.\n");
}
# try and get a lock with the specified timeout
eval {
local $SIG{ALRM} = sub {die("timeout\n")};
alarm($timeout);
flock(($self->{'fh'}), LOCK_SH) or die("flock failed during shared lock.\n");
alarm(0);
};
if ($@) {
# if it was not a timeout then propogate it
unless ($@ eq "timeout\n") {
die;
}
# propogate the timeout
die("Could not get shared lock within $timeout seconds.\n");
};
# got the lock, update status and done
$self->{'stat'} = SH_LOCK;
return 1;
}
sub exclusive_lock {
my $self = shift;
# return if already an exclusive lock
if($self->{'stat'} == EX_LOCK) {
return 1;
}
# get the timeout if specified
my $timeout = 0;
if(scalar @_ > 0) {
$timeout = shift;
}
# release existing lock before trying to take new
if($self->{'stat'} != NO_LOCK) {
$self->unlock or die("Could not unlock in preparation for shared lock.\n");
}
# try and get a lock with the specified timeout
eval {
local $SIG{ALRM} = sub {die("timeout\n")};
alarm($timeout);
print " Doing flock\n";
flock(($self->{'fh'}), LOCK_EX) or die("flock failed during exclusive lock.\n");
print " Reset timeout\n";
alarm (0);
};
if ($@) {
# if it was not a timeout then propogate it
unless ($@ eq "timeout\n") {
die($@);
}
# propogate the timeout
die("Could not get exclusive lock within $timeout seconds.\n");
};
# got the lock, update status and done
$self->{'stat'} = EX_LOCK;
return 1;
}
sub unlock {
my $self = shift;
# return if already unlocked
if($self->{'stat'} == NO_LOCK) {
return 1;
}
# try the unlock
flock(($self->{'fh'}), LOCK_UN) or die("Could not release lock.");
return 1;
}
1;
__END__
####
#!/usr/bin/perl -w
# setup path to local modules
BEGIN
{
use File::Basename;
use Cwd;
File::Basename::fileparse_set_fstype($^O);
my $include = (File::Basename::fileparse($0))[1];
$include = $include eq '' ? '.' : $include;
$include = Cwd::abs_path($include);
unshift @INC, $include;
}
use strict;
use FileLock;
my $file = "filelock.sem";
my $lock = FileLock->new($file);
print "Created FileLock obj for '$file'.\n";
# try a shared lock
$lock->shared_lock(10);
print "Got shared lock on '$file'.\n";
# try exclusive lock
$lock->exclusive_lock(10);
print "Got exclusive lock on '$file'.\n";
# try unlock
$lock->unlock();
print "Unlocked '$file'.\n";
####
#!/usr/bin/perl -w
# setup path to local modules
BEGIN
{
use File::Basename;
use Cwd;
File::Basename::fileparse_set_fstype($^O);
my $include = (File::Basename::fileparse($0))[1];
$include = $include eq '' ? '.' : $include;
$include = Cwd::abs_path($include);
unshift @INC, $include;
}
use strict;
use FileLock;
my $file = "filelock.sem";
my $lock = FileLock->new($file);
print "Created FileLock obj for '$file'.\n";
# try a shared lock
$lock->shared_lock(10);
print "Got shared lock on '$file'.\n";
# hold the lock
eval {
while (1) {
# do nothing
}
};
####
Created FileLock obj for 'filelock.sem'.
Got shared lock on 'filelock.sem'.
Doing flock
Reset timeout
Got exclusive lock on 'filelock.sem'.
Unlocked 'filelock.sem'.
####
Before 10 seconds:
Created FileLock obj for 'filelock.sem'.
Got shared lock on 'filelock.sem'.
Doing flock
Reset timeout
Got exclusive lock on 'filelock.sem'.
Unlocked 'filelock.sem'.
After ten seconds:
Created FileLock obj for 'filelock.sem'.
Got shared lock on 'filelock.sem'.
Doing flock
Could not get exclusive lock within 10 seconds.