111
|
1 #! /bin/sh
|
145
|
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.
|
111
|
6
|
145
|
7 self=`basename $0`
|
111
|
8 lockdir="$1" prog="$2"; shift 2 || exit 1
|
|
9
|
|
10 # Remember when we started trying to acquire the lock.
|
|
11 count=0
|
145
|
12
|
|
13 err () {
|
|
14 if test -f $lockdir/lock-$1.$$; then
|
|
15 rm -rf $lockdir
|
|
16 echo "$self: *** (PID $$) removed stale $lockdir" >&2
|
111
|
17
|
145
|
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 }
|
111
|
25
|
|
26 until mkdir "$lockdir" 2>/dev/null; do
|
|
27 # Say something periodically so the user knows what's up.
|
|
28 if [ `expr $count % 30` = 0 ]; then
|
145
|
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
|
111
|
35 else
|
145
|
36 echo "$self: (PID $$) cannot signal $lockdir owner PID $pid" >&2
|
|
37 err dead
|
111
|
38 fi
|
|
39 fi
|
|
40 sleep 1
|
|
41 count=`expr $count + 1`
|
|
42 done
|
|
43
|
145
|
44 trap 'rm -rf "$lockdir"' 0
|
|
45 echo $$ > $lockdir/pidT && mv $lockdir/pidT $lockdir/pid
|
|
46 echo "$self: (PID $$) acquired $lockdir after $count seconds" >&2
|
|
47
|
111
|
48 echo $prog "$@"
|
|
49 $prog "$@"
|
|
50
|
|
51 # The trap runs on exit.
|