1#! /bin/sh
2# Shell-based mutex using mkdir.  This script is used in make to prefer
3# serialized execution to avoid consuming too much RAM.  If reusing it,
4# bear in mind that the lock-breaking logic is not race-free, so disable
5# it in err() if concurrent execution could cause more serious problems.
6
7self=`basename $0`
8lockdir="$1" prog="$2"; shift 2 || exit 1
9
10# Remember when we started trying to acquire the lock.
11count=0
12
13err () {
14    if test -f $lockdir/lock-$1.$$; then
15	rm -rf $lockdir
16	echo "$self: *** (PID $$) removed stale $lockdir" >&2
17
18	# Possible variant for uses where races are more problematic:
19	#echo "$self: *** (PID $$) giving up, maybe rm -r $lockdir" >&2
20	#exit 42
21    else
22	touch $lockdir/lock-$1.$$
23    fi
24}
25
26until mkdir "$lockdir" 2>/dev/null; do
27    # Say something periodically so the user knows what's up.
28    if [ `expr $count % 30` = 0 ]; then
29	# Check for valid lock.
30	if pid=`cat $lockdir/pid 2>/dev/null` && kill -0 $pid 2>/dev/null; then
31	    echo "$self: (PID $$) waiting $count sec to acquire $lockdir from PID $pid" >&2
32	elif test -z "$pid"; then
33	    echo "$self: (PID $$) cannot read $lockdir/pid" >&2
34	    err nopid
35	else
36	    echo "$self: (PID $$) cannot signal $lockdir owner PID $pid" >&2
37	    err dead
38	fi
39    fi
40    sleep 1
41    count=`expr $count + 1`
42done
43
44trap 'rm -rf "$lockdir"' 0
45echo $$ > $lockdir/pidT && mv $lockdir/pidT $lockdir/pid
46echo "$self: (PID $$) acquired $lockdir after $count seconds" >&2
47
48echo $prog "$@"
49$prog "$@"
50
51# The trap runs on exit.
52