NAME
Lock::Socket - application lock/mutex module based on sockets
VERSION
0.0.3_4 (2014-09-14)
SYNOPSIS
### Function API ###
use Lock::Socket qw/lock_socket try_lock_socket/;
# Raises exception if cannot lock
my $lock = lock_socket(5197);
# Or just return undef
my $lock2 = try_lock_socket(5197)
or die "handle your own error";
### Object API ###
use Lock::Socket;
# Create a socket
my $sock = Lock::Socket->new( port => 5197 );
# Lock or raise an exception
$sock->lock;
# Can check its status in case you forgot
my $status = $sock->is_locked; # 1 (or 0)
my $addr = $sock->addr; # 127.X.Y.1
my $port = $sock->port; # 5197
# Re-locking changes nothing
$sock->lock;
# New lock on same port fails
my $sock2 = Lock::Socket->new( port => 5197 );
eval { $sock2->lock }; # exception
# But trying to get a lock is ok
my $status = $sock2->try_lock; # 0
my $same_status = $sock2->is_locked; # 0
# If you need the underlying filehandle
my $fh = $sock->fh;
# You can manually unlock
$sock->unlock;
# ... or unlocking is automatic on scope exit
undef $sock;
DESCRIPTION
Lock::Socket provides cooperative inter-process locking for applications that need to ensure that only one process is running at a time. This module works by binding an INET socket to a port on a loopback address which the operating system conveniently restricts to a single process.
Note that on most systems the port number needs to be greater than 1024 unless you are running with elevated privileges.
Function Interface
The lock_socket()
and try_lock_socket()
functions both take a mandatory port number and an optional IP address as arguments, and return a Lock::Socket object on success. lock_socket()
will raise an exception if the lock cannot be taken whereas try_lock_socket()
will return undef
.
Object Interface
Objects are instantiated manually as follows.
my $sock = Lock::Socket->new(
port => $PORT, # required
addr => $ADDR, # defaults to 127.X.Y.1
);
As soon as the Lock::Socket object goes out of scope the port is closed and the lock can be obtained by someone else.
System-wide locks
If you need a single system-wide lock across all users then you should specify both the port and the adddress explicitly, because Lock::Socket has a built-in per-user feature as described next.
Per-user locks
By default the loopback address is calculated as follows:
Octet Value
------ ------------------------------
1 127
2 First byte of user ID
3 Second byte of user ID
4 1
This scheme provides something of an automatic per-user lock for a given port, provided there is no user ID greater than 65536. The calculated address can be read back via the addr()
method.
Unfortunately on BSD systems the loopback interface appears to be configured with a /32 netmask so there the above calculation is not performed and the address defaults to 127.0.0.1 resulting in a system-wide lock.
So in order to be sure you have per-user port uniqueness you can dynamically calculate the port number based on the user ID:
my $port = 5197 + $>;
If you do this make sure to pick some random base number instead of 5197, otherwise all applications that use Lock::Socket will be fighting against each other :-)
Holding a lock over 'exec'
If you want to keep holding onto a lock socket after a call to exec
(perhaps after forking) you should read about the $^F
variable in perlvar, as you have to set it before creating a lock socket to ensure the socket will not be closed on exec.
Example application
See the example/solo file in the distribution for a Lock::Socket demonstration which provides a command-line lock:
usage: solo PORT COMMAND...
# terminal 1
$ example/solo 1414 sleep 10 # Have lock on 127.3.232.1:1414
# terminal 2
$ example/solo 1414 sleep 10 # bind error
CAVEATS
Most operating systems implement the Ephemeral Port concept. If you select a port from that range it could be possible that some unrelated process uses, if temporarily, the port that your application defines for locking.
Unfortunately the ephemeral port range varies from system to system. Based on the wikipedia page mentioned above, chances are good that a port between 5001 and 32767 will work, particularly if your system loopback device is configured with a /8 netmask (i.e. supports the 127.X.Y.1 scheme). To be sure you should investigate the platorms your application runs on, and possibly choose an appropriate value at runtime.
SEE ALSO
There are many other locking modules available on CPAN, but most of them use some kind of file or flock-based locking.
AUTHOR
Mark Lawrence <nomad@null.net>. This module was inspired by the solo.pl script by Andres Erbsen.
COPYRIGHT AND LICENSE
Copyright (C) 2014 Mark Lawrence <nomad@null.net>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.