SHARED AND EXCLUSIVE LOCKS
2015 January 20Here’s a few snippets to get and release shared and exclusive filesystem locks. I don’t remember where I first found these, but enjoy them anyway:
stalelock_exclusive () {
# Check if exclusive locks are stale, ie the process they point to no
# longer exists
# returns 0 if lock exists and has a running process
# which is really wrong, should be 1 so we can do stalelock_exclusive || return 1
if [ -n "${1}" ] ; then
[ -e "${1}.lock" ] || return 1
read pid < <( readlink -f "${1}.lock" )
[ -z "${pid}" ] && return 1
[ -e "/proc/${pid}" ] && return 0
rm -f "${1}.lock"
return 1
fi
}
stalelock_shared () {
# Check if shared locks are stale, ie the process they point to no
# longer exists
# returns 0 if lock exists and has a running process
# which is really wrong, should be 1 so we can do stalelock_shared || return 1
retval=1
if [ -n "${1}" ] ; then
for sharedlock in ${1}.shared* ; do
[ -f "${sharedlock}" ] || continue
read pid < <( ${sharedlock} )
if [ -e "/proc/${pid}" ] ; then
retval=0
else
rm -f ${sharedlock}
fi
done
fi
return ${retval}
}
getlock_exclusive() {
# Try to get an exclusive lock on a file.
# Returns 0 on success, 1 on fail.
if [ -n "${1}" ] ; then
stalelock_exclusive "${1}"
stalelock_shared "${1}"
# Check if lock exists. If not our own PID, return false.
if [ -e "${1}.lock" ] ; then
read pid < <( readlink -f "${1}.lock" )
if [ ${pid} -ne ${$} ] ; then
return 1
fi
else
# Create lock if it doesn't exist.
ln -s "${$}" "${1}.lock" 2>/dev/null
fi
# Check again if lock is our own to prevent race conditions.
read pid < <( readlink -f "${1}.lock" )
if [ ${pid} -eq ${$} ] ; then
for x in ${1}.shared* ; do
# as long as a shared lock exists, exclusive ones aren't granted, but
# reserved. This prevents new shared locks from being granted.
[ -e "${x}" ] || continue
return 1
done
return 0
else
return 1
fi
fi
}
getlock_shared() {
if [ -n "${1}" ] ; then
stalelock_exclusive "${1}"
stalelock_shared "${1}"
[ -e "${1}.lock" ] && return 1 # no shared locks with an exclusive one in place
ln -s "${$}" "${1}.shared_${$}"
return 0
fi
}
releaselock_shared () {
if [ -n "${1}" ] ; then
[ -e "${1}.shared_${$}" ] || return 0 # no lock, so it's released, no?
rm -f "${1}.shared_${$}"
return 0
fi
}
releaselock_exclusive() {
if [ -n "${1}" ] ; then
[ -e "${1}.lock" ] || return 0 # no lock, so it's released, no?
read pid < <( readlink -f "${1}.lock" )
if [ ${pid} -eq ${$} ] ; then
# our lock. release it
rm -f "${1}.lock"
return 0
else
# uh-oh, not our lock...
# Script shouldn't call release if getting the lock failed in the
# first place.
echo "Tried to release lock not our own!" >&2
echo "LockPID: ${pid} Our pid: ${$} File: ${1}" >&2
exit 1 # Bailing out.
fi
fi
}
while ! getlock_shared "/tmp/foo" ; do
sleep 1
done
# do stuff
releaselock_shared "/tmp/foo"
while ! getlock_exclusive "/tmp/foo" ; do
sleep 1
done
# do stuff
releaselock_shared "/tmp/foo"
EOF
Category: blog