xref: /titanic_53/usr/src/cmd/ast/libshell/common/scripts/filemutexdemo1.sh (revision 906afcb89d0412cc073b95c2d701a804a8cdb62c)
1*906afcb8SAndy Fiddaman#!/usr/bin/ksh93
2*906afcb8SAndy Fiddaman
3*906afcb8SAndy Fiddaman#
4*906afcb8SAndy Fiddaman# CDDL HEADER START
5*906afcb8SAndy Fiddaman#
6*906afcb8SAndy Fiddaman# The contents of this file are subject to the terms of the
7*906afcb8SAndy Fiddaman# Common Development and Distribution License (the "License").
8*906afcb8SAndy Fiddaman# You may not use this file except in compliance with the License.
9*906afcb8SAndy Fiddaman#
10*906afcb8SAndy Fiddaman# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*906afcb8SAndy Fiddaman# or http://www.opensolaris.org/os/licensing.
12*906afcb8SAndy Fiddaman# See the License for the specific language governing permissions
13*906afcb8SAndy Fiddaman# and limitations under the License.
14*906afcb8SAndy Fiddaman#
15*906afcb8SAndy Fiddaman# When distributing Covered Code, include this CDDL HEADER in each
16*906afcb8SAndy Fiddaman# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*906afcb8SAndy Fiddaman# If applicable, add the following below this CDDL HEADER, with the
18*906afcb8SAndy Fiddaman# fields enclosed by brackets "[]" replaced with your own identifying
19*906afcb8SAndy Fiddaman# information: Portions Copyright [yyyy] [name of copyright owner]
20*906afcb8SAndy Fiddaman#
21*906afcb8SAndy Fiddaman# CDDL HEADER END
22*906afcb8SAndy Fiddaman#
23*906afcb8SAndy Fiddaman
24*906afcb8SAndy Fiddaman#
25*906afcb8SAndy Fiddaman# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26*906afcb8SAndy Fiddaman#
27*906afcb8SAndy Fiddaman
28*906afcb8SAndy Fiddaman#
29*906afcb8SAndy Fiddaman# filemutexdemo1 - a simple locking demo which supports read/write
30*906afcb8SAndy Fiddaman# locks and critical sections (like JAVA's "syncronized" keyword)
31*906afcb8SAndy Fiddaman#
32*906afcb8SAndy Fiddaman
33*906afcb8SAndy Fiddaman# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
34*906afcb8SAndy Fiddamanexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
35*906afcb8SAndy Fiddaman
36*906afcb8SAndy Fiddaman# Make sure all math stuff runs in the "C" locale to avoid problems
37*906afcb8SAndy Fiddaman# with alternative # radix point representations (e.g. ',' instead of
38*906afcb8SAndy Fiddaman# '.' in de_DE.*-locales). This needs to be set _before_ any
39*906afcb8SAndy Fiddaman# floating-point constants are defined in this script).
40*906afcb8SAndy Fiddamanif [[ "${LC_ALL}" != "" ]] ; then
41*906afcb8SAndy Fiddaman    export \
42*906afcb8SAndy Fiddaman        LC_MONETARY="${LC_ALL}" \
43*906afcb8SAndy Fiddaman        LC_MESSAGES="${LC_ALL}" \
44*906afcb8SAndy Fiddaman        LC_COLLATE="${LC_ALL}" \
45*906afcb8SAndy Fiddaman        LC_CTYPE="${LC_ALL}"
46*906afcb8SAndy Fiddaman        unset LC_ALL
47*906afcb8SAndy Fiddamanfi
48*906afcb8SAndy Fiddamanexport LC_NUMERIC=C
49*906afcb8SAndy Fiddaman
50*906afcb8SAndy Fiddaman# Definition for a mutex which uses the filesystem for locking
51*906afcb8SAndy Fiddamantypeset -T filemutex_t=(
52*906afcb8SAndy Fiddaman	typeset name
53*906afcb8SAndy Fiddaman
54*906afcb8SAndy Fiddaman	typeset lock_dirname
55*906afcb8SAndy Fiddaman
56*906afcb8SAndy Fiddaman	typeset locked_exclusive="false"
57*906afcb8SAndy Fiddaman	typeset locked_shared="false"
58*906afcb8SAndy Fiddaman
59*906afcb8SAndy Fiddaman	# keep track of subshell level. The problem is that we do not know a
60*906afcb8SAndy Fiddaman	# way to figure out whether someone calls "unlock" in a subshell and then
61*906afcb8SAndy Fiddaman	# leaves the subshell and calls "unlock" again
62*906afcb8SAndy Fiddaman	integer subshell=-1
63*906afcb8SAndy Fiddaman
64*906afcb8SAndy Fiddaman	typeset lock_dirname
65*906afcb8SAndy Fiddaman
66*906afcb8SAndy Fiddaman	# create a filemutex instance (including lock directory)
67*906afcb8SAndy Fiddaman	function create
68*906afcb8SAndy Fiddaman	{
69*906afcb8SAndy Fiddaman		# make sure we return an error if the init didn't work
70*906afcb8SAndy Fiddaman		set -o errexit
71*906afcb8SAndy Fiddaman
72*906afcb8SAndy Fiddaman		[[ "$1" == "" ]] && return 1
73*906afcb8SAndy Fiddaman
74*906afcb8SAndy Fiddaman		_.name="$1"
75*906afcb8SAndy Fiddaman		_.lock_dirname="/tmp/filemutex_t_${_.name}.lock"
76*906afcb8SAndy Fiddaman
77*906afcb8SAndy Fiddaman		mkdir "${_.lock_dirname}"
78*906afcb8SAndy Fiddaman
79*906afcb8SAndy Fiddaman		# last entry, used to mark the mutex as initalised+valid
80*906afcb8SAndy Fiddaman		(( _.subshell=.sh.subshell ))
81*906afcb8SAndy Fiddaman		return 0
82*906afcb8SAndy Fiddaman	}
83*906afcb8SAndy Fiddaman
84*906afcb8SAndy Fiddaman	# use a filemutex instance (same as "create" but without creating
85*906afcb8SAndy Fiddaman	# the lock directory)
86*906afcb8SAndy Fiddaman	function create_child
87*906afcb8SAndy Fiddaman	{
88*906afcb8SAndy Fiddaman		# make sure we return an error if the init didn't work
89*906afcb8SAndy Fiddaman		set -o errexit
90*906afcb8SAndy Fiddaman
91*906afcb8SAndy Fiddaman		[[ "$1" == "" ]] && return 1
92*906afcb8SAndy Fiddaman
93*906afcb8SAndy Fiddaman		_.name="$1"
94*906afcb8SAndy Fiddaman		_.lock_dirname="/tmp/filemutex_t_${_.name}.lock"
95*906afcb8SAndy Fiddaman
96*906afcb8SAndy Fiddaman		# last entry, used to mark the mutex as initalised+valid
97*906afcb8SAndy Fiddaman		(( _.subshell=.sh.subshell ))
98*906afcb8SAndy Fiddaman		return 0
99*906afcb8SAndy Fiddaman	}
100*906afcb8SAndy Fiddaman
101*906afcb8SAndy Fiddaman	function check_subshell
102*906afcb8SAndy Fiddaman	{
103*906afcb8SAndy Fiddaman		(( _.subshell == .sh.subshell )) && return 0
104*906afcb8SAndy Fiddaman		print -u2 -f "filemutex_t.%s(%s): Wrong subshell level\n" "$1" "${_.name}"
105*906afcb8SAndy Fiddaman		return 1
106*906afcb8SAndy Fiddaman	}
107*906afcb8SAndy Fiddaman
108*906afcb8SAndy Fiddaman	function try_lock_shared
109*906afcb8SAndy Fiddaman	{
110*906afcb8SAndy Fiddaman		_.check_subshell "try_lock_shared" || return 1
111*906afcb8SAndy Fiddaman
112*906afcb8SAndy Fiddaman		mkdir "${_.lock_dirname}/shared_${PPID}_$$" 2>/dev/null || return 1
113*906afcb8SAndy Fiddaman		_.locked_shared="true"
114*906afcb8SAndy Fiddaman		return 0
115*906afcb8SAndy Fiddaman	}
116*906afcb8SAndy Fiddaman
117*906afcb8SAndy Fiddaman	function lock_shared
118*906afcb8SAndy Fiddaman	{
119*906afcb8SAndy Fiddaman		float interval=0.2
120*906afcb8SAndy Fiddaman
121*906afcb8SAndy Fiddaman		_.check_subshell "lock_shared" || return 1
122*906afcb8SAndy Fiddaman
123*906afcb8SAndy Fiddaman		while ! _.try_lock_shared ; do sleep ${interval} ; (( interval+=interval/10. )) ; done
124*906afcb8SAndy Fiddaman		return 0
125*906afcb8SAndy Fiddaman	}
126*906afcb8SAndy Fiddaman
127*906afcb8SAndy Fiddaman	function try_lock_exclusive
128*906afcb8SAndy Fiddaman	{
129*906afcb8SAndy Fiddaman		_.check_subshell "try_lock_exclusive" || return 1
130*906afcb8SAndy Fiddaman
131*906afcb8SAndy Fiddaman		rmdir "${_.lock_dirname}" 2>/dev/null || return 1
132*906afcb8SAndy Fiddaman		_.locked_exclusive="true"
133*906afcb8SAndy Fiddaman		return 0
134*906afcb8SAndy Fiddaman	}
135*906afcb8SAndy Fiddaman
136*906afcb8SAndy Fiddaman	function lock_exclusive
137*906afcb8SAndy Fiddaman	{
138*906afcb8SAndy Fiddaman		float interval=0.2
139*906afcb8SAndy Fiddaman
140*906afcb8SAndy Fiddaman		_.check_subshell "lock_exclusive" || return 1
141*906afcb8SAndy Fiddaman
142*906afcb8SAndy Fiddaman		while ! _.try_lock_exclusive ; do sleep ${interval} ; (( interval+=interval/10. )) ; done
143*906afcb8SAndy Fiddaman		return 0
144*906afcb8SAndy Fiddaman	}
145*906afcb8SAndy Fiddaman
146*906afcb8SAndy Fiddaman	# critical section support (like java's "synchronized" keyword)
147*906afcb8SAndy Fiddaman	function synchronized
148*906afcb8SAndy Fiddaman	{
149*906afcb8SAndy Fiddaman		integer retcode
150*906afcb8SAndy Fiddaman
151*906afcb8SAndy Fiddaman		_.check_subshell "synchronized" || return 1
152*906afcb8SAndy Fiddaman
153*906afcb8SAndy Fiddaman		_.lock_exclusive
154*906afcb8SAndy Fiddaman
155*906afcb8SAndy Fiddaman		"$@"
156*906afcb8SAndy Fiddaman		(( retcode=$? ))
157*906afcb8SAndy Fiddaman
158*906afcb8SAndy Fiddaman		_.unlock
159*906afcb8SAndy Fiddaman
160*906afcb8SAndy Fiddaman		return ${retcode}
161*906afcb8SAndy Fiddaman	}
162*906afcb8SAndy Fiddaman
163*906afcb8SAndy Fiddaman	# critical section support with shared lock
164*906afcb8SAndy Fiddaman	function synchronized_shared
165*906afcb8SAndy Fiddaman	{
166*906afcb8SAndy Fiddaman		integer retcode
167*906afcb8SAndy Fiddaman
168*906afcb8SAndy Fiddaman		_.check_subshell "synchronized_shared" || return 1
169*906afcb8SAndy Fiddaman
170*906afcb8SAndy Fiddaman		_.lock_shared
171*906afcb8SAndy Fiddaman
172*906afcb8SAndy Fiddaman		"$@"
173*906afcb8SAndy Fiddaman		(( retcode=$? ))
174*906afcb8SAndy Fiddaman
175*906afcb8SAndy Fiddaman		_.unlock
176*906afcb8SAndy Fiddaman
177*906afcb8SAndy Fiddaman		return ${retcode}
178*906afcb8SAndy Fiddaman	}
179*906afcb8SAndy Fiddaman
180*906afcb8SAndy Fiddaman	function unlock
181*906afcb8SAndy Fiddaman	{
182*906afcb8SAndy Fiddaman		# return an error if rmdir/mkdir/check_subshell fail...
183*906afcb8SAndy Fiddaman		set -o errexit
184*906afcb8SAndy Fiddaman
185*906afcb8SAndy Fiddaman		_.check_subshell "unlock"
186*906afcb8SAndy Fiddaman
187*906afcb8SAndy Fiddaman		if ${_.locked_shared} ; then
188*906afcb8SAndy Fiddaman			rmdir "${_.lock_dirname}/shared_${PPID}_$$"
189*906afcb8SAndy Fiddaman			_.locked_shared="false"
190*906afcb8SAndy Fiddaman			return 0
191*906afcb8SAndy Fiddaman		elif ${_.locked_exclusive} ; then
192*906afcb8SAndy Fiddaman			mkdir "${_.lock_dirname}"
193*906afcb8SAndy Fiddaman			_.locked_exclusive="false"
194*906afcb8SAndy Fiddaman			return 0
195*906afcb8SAndy Fiddaman		fi
196*906afcb8SAndy Fiddaman
197*906afcb8SAndy Fiddaman		print -u2 -f "filemutex_t.unlock(%s): mutex '%s' not locked." "$1" "${_.name}"
198*906afcb8SAndy Fiddaman		return 1
199*906afcb8SAndy Fiddaman	}
200*906afcb8SAndy Fiddaman
201*906afcb8SAndy Fiddaman	# destroy mutex if noone is using it anymore (not the same as "unset" !!))
202*906afcb8SAndy Fiddaman	function destroy
203*906afcb8SAndy Fiddaman	{
204*906afcb8SAndy Fiddaman		_.check_subshell "destroy" || return 1
205*906afcb8SAndy Fiddaman
206*906afcb8SAndy Fiddaman		(${_.locked_exclusive} || ${_.locked_shared}) && _.unlock
207*906afcb8SAndy Fiddaman		rmdir "${_.lock_dirname}"
208*906afcb8SAndy Fiddaman		return 0
209*906afcb8SAndy Fiddaman	}
210*906afcb8SAndy Fiddaman)
211*906afcb8SAndy Fiddaman
212*906afcb8SAndy Fiddaman# main
213*906afcb8SAndy Fiddamanbuiltin mkdir
214*906afcb8SAndy Fiddamanbuiltin rmdir
215*906afcb8SAndy Fiddaman
216*906afcb8SAndy Fiddamanprint "## Start."
217*906afcb8SAndy Fiddaman
218*906afcb8SAndy Fiddamantypeset -r mymutexname="hello_world"
219*906afcb8SAndy Fiddaman
220*906afcb8SAndy Fiddamanfilemutex_t fs
221*906afcb8SAndy Fiddaman
222*906afcb8SAndy Fiddamanfs.create "${mymutexname}" || print -u2 "Mutex init failed."
223*906afcb8SAndy Fiddaman
224*906afcb8SAndy Fiddamanprint "# Starting child which keeps an exclusive lock for 10 seconds..."
225*906afcb8SAndy Fiddaman(
226*906afcb8SAndy Fiddaman	filemutex_t child_fs
227*906afcb8SAndy Fiddaman
228*906afcb8SAndy Fiddaman	child_fs.create_child "${mymutexname}"
229*906afcb8SAndy Fiddaman
230*906afcb8SAndy Fiddaman	child_fs.lock_exclusive
231*906afcb8SAndy Fiddaman	sleep 10
232*906afcb8SAndy Fiddaman	child_fs.unlock
233*906afcb8SAndy Fiddaman) &
234*906afcb8SAndy Fiddaman
235*906afcb8SAndy Fiddamansleep 1
236*906afcb8SAndy Fiddaman
237*906afcb8SAndy Fiddamanprintf "%T: # Waiting to obtain a shared lock...\n"
238*906afcb8SAndy Fiddamanfs.lock_shared
239*906afcb8SAndy Fiddamanprintf "%T: # Obtained shared lock\n"
240*906afcb8SAndy Fiddaman
241*906afcb8SAndy Fiddamanprintf "fs.locked_exclusive=%s, fs.locked_shared=%s\n" "${fs.locked_exclusive}" "${fs.locked_shared}"
242*906afcb8SAndy Fiddaman
243*906afcb8SAndy Fiddamanls -lad /tmp/filemutex*/*
244*906afcb8SAndy Fiddaman
245*906afcb8SAndy Fiddamanprintf "%T: # Executing child which runs printf '|%%s|\\\n' 'hello' 'world' inside a synchronized section\n"
246*906afcb8SAndy Fiddaman(
247*906afcb8SAndy Fiddaman	filemutex_t child_fs
248*906afcb8SAndy Fiddaman
249*906afcb8SAndy Fiddaman	child_fs.create_child "${mymutexname}"
250*906afcb8SAndy Fiddaman
251*906afcb8SAndy Fiddaman	child_fs.synchronized printf '|%s|\n' 'hello' 'world'
252*906afcb8SAndy Fiddaman) &
253*906afcb8SAndy Fiddaman
254*906afcb8SAndy Fiddamanprintf "%T: # Sleeping 5 secs while holding the shared lock...\n"
255*906afcb8SAndy Fiddamansleep 5.
256*906afcb8SAndy Fiddaman
257*906afcb8SAndy Fiddamanprintf "%T: # Releasing shared lock...\n"
258*906afcb8SAndy Fiddamanfs.unlock
259*906afcb8SAndy Fiddaman
260*906afcb8SAndy Fiddamansleep 5.
261*906afcb8SAndy Fiddamanprint "# Destroying lock..."
262*906afcb8SAndy Fiddamanfs.destroy
263*906afcb8SAndy Fiddaman
264*906afcb8SAndy Fiddamanprint "## Done."
265*906afcb8SAndy Fiddaman
266*906afcb8SAndy Fiddamanexit 0
267