Search:

putlock - create lockfiles

Creating lockfiles is another task that is sometimes required from within awk but not easy to solve. Of course the is lockfile(1) that comes with the procmail packages. But (as for temporary files) the question is how to make sure that the lockfile is removed when the awk script terminates. A second question (but this arises because I want to solve this task with a shell script) is how to make the lock operation "atomic", avoiding race conditions (two programs locking at the same time both thinking they successfully placed the lock etc).

The first question (reliable lockfile removal) is addressed by

  1. trapping the usual process termination signals (lines #46, #98) and cleaning the lockfiles (line #9), and
  2. detection that the caller script terminated by waiting for input from it (line #123).

Especially #2 is the reason why putlock is used as a co-process:

cmd = "putlock " filetolock;
printf ("\n") |& cmd;
cmd |& getline status;
if (status != "OK") {
	-- do some error handling --
	exit (1);
	}

-- proceed with the locked file --

Of course it is possible to send real text to putlock but it is not neccessary. Any input is ignored but waiting gives the most reliable way to detect that the calling awk script terminated (for whatever reason).

  1 #!/bin/sh
  2 #
  3 
  4 #
  5 # putlock -- create one or more lockfiles, based on rtc
  6 #
  7 
  8 
  9 cleanup() {
 10 	if [ "$LOCKFILES" != "" ]; then
 11 		rm $LOCKFILES
 12 	fi
 13 
 14 	trap - $trapsignals
 15 	if [ "$cmdpid" != "" ]; then
 16 		kill $cmdpid >/dev/null 2>&1
 17 	fi
 18 
 19 	if [ "$alarmpid" != "" ]; then
 20 		kill $alarmpid >/dev/null 2>&1
 21 	fi
 22 	}
 23 
 24 setalarm() {
 25 	trap sigalrmhandler 14
 26 	sleep $1  &&  kill -s 14 $$  &
 27 	alarmpid=$!
 28 	}
 29 
 30 sigalrmhandler() {
 31 	if [ "$silent" = "no" ]; then
 32 		echo $program: alarm clock >&2
 33 	fi
 34 
 35 	alarmpid=''
 36 	if [ "$cmdpid" != '' ]; then
 37 		kill -ALRM $cmdpid
 38 	fi
 39 
 40 	exit 1
 41 	}
 42 
 43 
 44 
 45 program=`basename $0`
 46 trapsignals="0 1 2 3 15"
 47 
 48 TIMEOUT=10
 49 
 50 options=`getopt dt: $*`  ||  exit 1
 51 set -- $options
 52 while true; do
 53 	opt=$1
 54 	case $opt in
 55 	  -d)
 56 		set -x
 57 		shift
 58 		;;
 59 
 60 	  -t)
 61 	  	TIMEOUT=$2
 62 		shift 2
 63 		;;
 64 
 65 	  --)
 66 	  	shift
 67 		break
 68 		;;
 69 
 70 	  -*)
 71 	  	echo $program: unknown option: $opt 1>&2
 72 		exit 1
 73 		;;
 74 
 75 	  *)
 76 		break
 77 		;;
 78 
 79 	esac
 80 done
 81 
 82 
 83 
 84 #
 85 # Check parameters ...
 86 #
 87 
 88 if [ "$#" '<' 1 ]; then
 89 	echo usage: $program '[<options>] <filename> [...]' 1>&2
 90 	exit 1
 91 fi
 92 
 93 
 94 #
 95 # ... capture some signals and set clock.
 96 #
 97 
 98 trap 'cleanup; exit' $trapsignals
 99 setalarm $TIMEOUT
100 
101 
102 #
103 # Put the lockfiles
104 #
105 
106 for file in $*; do
107 	lock=$file.lock
108 	while (! ln -s $file $lock >/dev/null 2>&1); do
109 		sleep 1
110 	done
111 	LOCKFILES="$LOCKFILES $lock"
112 done
113 
114 
115 #
116 # Turn off the alarm and wait for input, send ok to caller
117 # and wait for termination.
118 #
119 
120 kill $alarmpid
121 echo OK
122 
123 while read line; do
124 	x=x		# do nothing
125 done
126 
127 exit 0
128 
129 

The second question the script has to solve was "How can the lock action be most atomic?" The best thing I found is the ln(1) command (see line #108). I'm not really sure it is or not because neither ln(1) or link(2) says it.

The whole process of locking all files from the comamand line (line #106) is gouverned by a timeout (lines #99, #24, #30): if after a certain amount of time (default is 10 seconds, see line #48) not all requested files are locked the shell script receives an ALRM signal (line #37) and terminates without having send the "OK" to the caller. The alarm can only be terminated after all lockfiles are created.

< dag | at | awk-scripting.de >