#!/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.