#!/bin/sh

set -e

ME=$(basename $0)
SCRIPT=$(readlink -f ../../../build-tools/pkgos-sbuild-lock)
WORK=$(mktemp -d /tmp/pkgos-sbuild-lock.XXXXXX)
trap 'rm -rf "${WORK}"' EXIT
PKGOS_SBUILD_LOCK_FILE=${WORK}/lock
PKGOS_SBUILD_LOCK_PIDFILE=${WORK}/pid
export PKGOS_SBUILD_LOCK_FILE PKGOS_SBUILD_LOCK_PIDFILE

poll_until () {
	# $1 = file which must exist, within 10 seconds.
	i=0
	while ! [ -f "${1}" ] ; do
		i=$(( ${i} + 1 ))
		if [ "${i}" -gt 100 ] ; then
			return 1
		fi
		sleep 0.1
	done
	return 0
}

# A client which takes the lock and stays alive, so that the lock is
# held: it holds it from the moment acquire returns, as acquire must
# only return once its holder owns the lock.
(
	"${SCRIPT}" acquire
	touch "${WORK}/first-locked"
	sleep 30
) &
CLIENT1=$!

if ! poll_until "${WORK}/first-locked" ; then
	echo "${ME}: the first acquire never returned"
	kill "${CLIENT1}" 2>/dev/null || true
	exit 1
fi

# The PID file holds the holder and the client PIDs, and the holder
# is alive while the lock is held.
read HOLDER CLIENT < "${WORK}/pid"
if ! kill -0 "${HOLDER}" 2>/dev/null ; then
	echo "${ME}: the holder must be alive while the lock is held"
	exit 1
fi
if [ "${CLIENT}" != "${CLIENT1}" ] ; then
	echo "${ME}: the PID file must hold the client PID, got ${CLIENT}"
	exit 1
fi

# A second acquire must not return while the lock is held.
(
	"${SCRIPT}" acquire
	touch "${WORK}/second-locked"
) &
CLIENT2=$!
sleep 1
if [ -f "${WORK}/second-locked" ] ; then
	echo "${ME}: the second acquire must wait while the lock is held"
	kill "${CLIENT1}" "${CLIENT2}" 2>/dev/null || true
	exit 1
fi

# Releasing lets the second acquire through.
"${SCRIPT}" release
if ! poll_until "${WORK}/second-locked" ; then
	echo "${ME}: the second acquire never got the lock after release"
	kill "${CLIENT1}" "${CLIENT2}" 2>/dev/null || true
	exit 1
fi

# The second client is gone, so its holder left a PID file behind:
# this release clears it, and must succeed either way.
"${SCRIPT}" release

kill "${CLIENT1}" "${CLIENT2}" 2>/dev/null || true
exit 0
