xref: /onnv-gate/usr/src/lib/libshell/common/scripts/filemutexdemo1.sh (revision 12068:08a39a083754)
18462SApril.Chin@Sun.COM#!/usr/bin/ksh93
28462SApril.Chin@Sun.COM
38462SApril.Chin@Sun.COM#
48462SApril.Chin@Sun.COM# CDDL HEADER START
58462SApril.Chin@Sun.COM#
68462SApril.Chin@Sun.COM# The contents of this file are subject to the terms of the
78462SApril.Chin@Sun.COM# Common Development and Distribution License (the "License").
88462SApril.Chin@Sun.COM# You may not use this file except in compliance with the License.
98462SApril.Chin@Sun.COM#
108462SApril.Chin@Sun.COM# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
118462SApril.Chin@Sun.COM# or http://www.opensolaris.org/os/licensing.
128462SApril.Chin@Sun.COM# See the License for the specific language governing permissions
138462SApril.Chin@Sun.COM# and limitations under the License.
148462SApril.Chin@Sun.COM#
158462SApril.Chin@Sun.COM# When distributing Covered Code, include this CDDL HEADER in each
168462SApril.Chin@Sun.COM# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
178462SApril.Chin@Sun.COM# If applicable, add the following below this CDDL HEADER, with the
188462SApril.Chin@Sun.COM# fields enclosed by brackets "[]" replaced with your own identifying
198462SApril.Chin@Sun.COM# information: Portions Copyright [yyyy] [name of copyright owner]
208462SApril.Chin@Sun.COM#
218462SApril.Chin@Sun.COM# CDDL HEADER END
228462SApril.Chin@Sun.COM#
238462SApril.Chin@Sun.COM
248462SApril.Chin@Sun.COM#
25*12068SRoger.Faulkner@Oracle.COM# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
268462SApril.Chin@Sun.COM#
278462SApril.Chin@Sun.COM
288462SApril.Chin@Sun.COM#
298462SApril.Chin@Sun.COM# filemutexdemo1 - a simple locking demo which supports read/write
308462SApril.Chin@Sun.COM# locks and critical sections (like JAVA's "syncronized" keyword)
318462SApril.Chin@Sun.COM#
328462SApril.Chin@Sun.COM
338462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
348462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
358462SApril.Chin@Sun.COM
368462SApril.Chin@Sun.COM# Make sure all math stuff runs in the "C" locale to avoid problems
378462SApril.Chin@Sun.COM# with alternative # radix point representations (e.g. ',' instead of
388462SApril.Chin@Sun.COM# '.' in de_DE.*-locales). This needs to be set _before_ any
398462SApril.Chin@Sun.COM# floating-point constants are defined in this script).
408462SApril.Chin@Sun.COMif [[ "${LC_ALL}" != "" ]] ; then
418462SApril.Chin@Sun.COM    export \
428462SApril.Chin@Sun.COM        LC_MONETARY="${LC_ALL}" \
438462SApril.Chin@Sun.COM        LC_MESSAGES="${LC_ALL}" \
448462SApril.Chin@Sun.COM        LC_COLLATE="${LC_ALL}" \
458462SApril.Chin@Sun.COM        LC_CTYPE="${LC_ALL}"
468462SApril.Chin@Sun.COM        unset LC_ALL
478462SApril.Chin@Sun.COMfi
488462SApril.Chin@Sun.COMexport LC_NUMERIC=C
498462SApril.Chin@Sun.COM
508462SApril.Chin@Sun.COM# Definition for a mutex which uses the filesystem for locking
518462SApril.Chin@Sun.COMtypeset -T filemutex_t=(
528462SApril.Chin@Sun.COM	typeset name
538462SApril.Chin@Sun.COM
548462SApril.Chin@Sun.COM	typeset lock_dirname
558462SApril.Chin@Sun.COM
568462SApril.Chin@Sun.COM	typeset locked_exclusive="false"
578462SApril.Chin@Sun.COM	typeset locked_shared="false"
588462SApril.Chin@Sun.COM
598462SApril.Chin@Sun.COM	# keep track of subshell level. The problem is that we do not know a
608462SApril.Chin@Sun.COM	# way to figure out whether someone calls "unlock" in a subshell and then
618462SApril.Chin@Sun.COM	# leaves the subshell and calls "unlock" again
628462SApril.Chin@Sun.COM	integer subshell=-1
638462SApril.Chin@Sun.COM
648462SApril.Chin@Sun.COM	typeset lock_dirname
658462SApril.Chin@Sun.COM
668462SApril.Chin@Sun.COM	# create a filemutex instance (including lock directory)
678462SApril.Chin@Sun.COM	function create
688462SApril.Chin@Sun.COM	{
698462SApril.Chin@Sun.COM		# make sure we return an error if the init didn't work
708462SApril.Chin@Sun.COM		set -o errexit
718462SApril.Chin@Sun.COM
728462SApril.Chin@Sun.COM		[[ "$1" == "" ]] && return 1
738462SApril.Chin@Sun.COM
748462SApril.Chin@Sun.COM		_.name="$1"
758462SApril.Chin@Sun.COM		_.lock_dirname="/tmp/filemutex_t_${_.name}.lock"
768462SApril.Chin@Sun.COM
778462SApril.Chin@Sun.COM		mkdir "${_.lock_dirname}"
788462SApril.Chin@Sun.COM
798462SApril.Chin@Sun.COM		# last entry, used to mark the mutex as initalised+valid
808462SApril.Chin@Sun.COM		(( _.subshell=.sh.subshell ))
818462SApril.Chin@Sun.COM		return 0
828462SApril.Chin@Sun.COM	}
838462SApril.Chin@Sun.COM
848462SApril.Chin@Sun.COM	# use a filemutex instance (same as "create" but without creating
858462SApril.Chin@Sun.COM	# the lock directory)
868462SApril.Chin@Sun.COM	function create_child
878462SApril.Chin@Sun.COM	{
888462SApril.Chin@Sun.COM		# make sure we return an error if the init didn't work
898462SApril.Chin@Sun.COM		set -o errexit
908462SApril.Chin@Sun.COM
918462SApril.Chin@Sun.COM		[[ "$1" == "" ]] && return 1
928462SApril.Chin@Sun.COM
938462SApril.Chin@Sun.COM		_.name="$1"
948462SApril.Chin@Sun.COM		_.lock_dirname="/tmp/filemutex_t_${_.name}.lock"
958462SApril.Chin@Sun.COM
968462SApril.Chin@Sun.COM		# last entry, used to mark the mutex as initalised+valid
978462SApril.Chin@Sun.COM		(( _.subshell=.sh.subshell ))
988462SApril.Chin@Sun.COM		return 0
998462SApril.Chin@Sun.COM	}
1008462SApril.Chin@Sun.COM
1018462SApril.Chin@Sun.COM	function check_subshell
1028462SApril.Chin@Sun.COM	{
1038462SApril.Chin@Sun.COM		(( _.subshell == .sh.subshell )) && return 0
1048462SApril.Chin@Sun.COM		print -u2 -f "filemutex_t.%s(%s): Wrong subshell level\n" "$1" "${_.name}"
1058462SApril.Chin@Sun.COM		return 1
1068462SApril.Chin@Sun.COM	}
1078462SApril.Chin@Sun.COM
1088462SApril.Chin@Sun.COM	function try_lock_shared
1098462SApril.Chin@Sun.COM	{
1108462SApril.Chin@Sun.COM		_.check_subshell "try_lock_shared" || return 1
1118462SApril.Chin@Sun.COM
1128462SApril.Chin@Sun.COM		mkdir "${_.lock_dirname}/shared_${PPID}_$$" 2>/dev/null || return 1
1138462SApril.Chin@Sun.COM		_.locked_shared="true"
1148462SApril.Chin@Sun.COM		return 0
1158462SApril.Chin@Sun.COM	}
1168462SApril.Chin@Sun.COM
1178462SApril.Chin@Sun.COM	function lock_shared
1188462SApril.Chin@Sun.COM	{
1198462SApril.Chin@Sun.COM		float interval=0.2
1208462SApril.Chin@Sun.COM
1218462SApril.Chin@Sun.COM		_.check_subshell "lock_shared" || return 1
1228462SApril.Chin@Sun.COM
1238462SApril.Chin@Sun.COM		while ! _.try_lock_shared ; do sleep ${interval} ; (( interval+=interval/10. )) ; done
1248462SApril.Chin@Sun.COM		return 0
1258462SApril.Chin@Sun.COM	}
1268462SApril.Chin@Sun.COM
1278462SApril.Chin@Sun.COM	function try_lock_exclusive
1288462SApril.Chin@Sun.COM	{
1298462SApril.Chin@Sun.COM		_.check_subshell "try_lock_exclusive" || return 1
1308462SApril.Chin@Sun.COM
1318462SApril.Chin@Sun.COM		rmdir "${_.lock_dirname}" 2>/dev/null || return 1
1328462SApril.Chin@Sun.COM		_.locked_exclusive="true"
1338462SApril.Chin@Sun.COM		return 0
1348462SApril.Chin@Sun.COM	}
1358462SApril.Chin@Sun.COM
1368462SApril.Chin@Sun.COM	function lock_exclusive
1378462SApril.Chin@Sun.COM	{
1388462SApril.Chin@Sun.COM		float interval=0.2
1398462SApril.Chin@Sun.COM
1408462SApril.Chin@Sun.COM		_.check_subshell "lock_exclusive" || return 1
1418462SApril.Chin@Sun.COM
1428462SApril.Chin@Sun.COM		while ! _.try_lock_exclusive ; do sleep ${interval} ; (( interval+=interval/10. )) ; done
1438462SApril.Chin@Sun.COM		return 0
1448462SApril.Chin@Sun.COM	}
1458462SApril.Chin@Sun.COM
1468462SApril.Chin@Sun.COM	# critical section support (like java's "synchronized" keyword)
1478462SApril.Chin@Sun.COM	function synchronized
1488462SApril.Chin@Sun.COM	{
1498462SApril.Chin@Sun.COM		integer retcode
1508462SApril.Chin@Sun.COM
1518462SApril.Chin@Sun.COM		_.check_subshell "synchronized" || return 1
1528462SApril.Chin@Sun.COM
1538462SApril.Chin@Sun.COM		_.lock_exclusive
1548462SApril.Chin@Sun.COM
1558462SApril.Chin@Sun.COM		"$@"
1568462SApril.Chin@Sun.COM		(( retcode=$? ))
1578462SApril.Chin@Sun.COM
1588462SApril.Chin@Sun.COM		_.unlock
1598462SApril.Chin@Sun.COM
1608462SApril.Chin@Sun.COM		return ${retcode}
1618462SApril.Chin@Sun.COM	}
1628462SApril.Chin@Sun.COM
1638462SApril.Chin@Sun.COM	# critical section support with shared lock
1648462SApril.Chin@Sun.COM	function synchronized_shared
1658462SApril.Chin@Sun.COM	{
1668462SApril.Chin@Sun.COM		integer retcode
1678462SApril.Chin@Sun.COM
1688462SApril.Chin@Sun.COM		_.check_subshell "synchronized_shared" || return 1
1698462SApril.Chin@Sun.COM
1708462SApril.Chin@Sun.COM		_.lock_shared
1718462SApril.Chin@Sun.COM
1728462SApril.Chin@Sun.COM		"$@"
1738462SApril.Chin@Sun.COM		(( retcode=$? ))
1748462SApril.Chin@Sun.COM
1758462SApril.Chin@Sun.COM		_.unlock
1768462SApril.Chin@Sun.COM
1778462SApril.Chin@Sun.COM		return ${retcode}
1788462SApril.Chin@Sun.COM	}
1798462SApril.Chin@Sun.COM
1808462SApril.Chin@Sun.COM	function unlock
1818462SApril.Chin@Sun.COM	{
1828462SApril.Chin@Sun.COM		# return an error if rmdir/mkdir/check_subshell fail...
1838462SApril.Chin@Sun.COM		set -o errexit
1848462SApril.Chin@Sun.COM
1858462SApril.Chin@Sun.COM		_.check_subshell "unlock"
1868462SApril.Chin@Sun.COM
1878462SApril.Chin@Sun.COM		if ${_.locked_shared} ; then
1888462SApril.Chin@Sun.COM			rmdir "${_.lock_dirname}/shared_${PPID}_$$"
1898462SApril.Chin@Sun.COM			_.locked_shared="false"
1908462SApril.Chin@Sun.COM			return 0
1918462SApril.Chin@Sun.COM		elif ${_.locked_exclusive} ; then
1928462SApril.Chin@Sun.COM			mkdir "${_.lock_dirname}"
1938462SApril.Chin@Sun.COM			_.locked_exclusive="false"
1948462SApril.Chin@Sun.COM			return 0
1958462SApril.Chin@Sun.COM		fi
1968462SApril.Chin@Sun.COM
1978462SApril.Chin@Sun.COM		print -u2 -f "filemutex_t.unlock(%s): mutex '%s' not locked." "$1" "${_.name}"
1988462SApril.Chin@Sun.COM		return 1
1998462SApril.Chin@Sun.COM	}
2008462SApril.Chin@Sun.COM
2018462SApril.Chin@Sun.COM	# destroy mutex if noone is using it anymore (not the same as "unset" !!))
2028462SApril.Chin@Sun.COM	function destroy
2038462SApril.Chin@Sun.COM	{
2048462SApril.Chin@Sun.COM		_.check_subshell "destroy" || return 1
2058462SApril.Chin@Sun.COM
2068462SApril.Chin@Sun.COM		(${_.locked_exclusive} || ${_.locked_shared}) && _.unlock
2078462SApril.Chin@Sun.COM		rmdir "${_.lock_dirname}"
2088462SApril.Chin@Sun.COM		return 0
2098462SApril.Chin@Sun.COM	}
2108462SApril.Chin@Sun.COM)
2118462SApril.Chin@Sun.COM
2128462SApril.Chin@Sun.COM# main
2138462SApril.Chin@Sun.COMbuiltin mkdir
2148462SApril.Chin@Sun.COMbuiltin rmdir
2158462SApril.Chin@Sun.COM
2168462SApril.Chin@Sun.COMprint "## Start."
2178462SApril.Chin@Sun.COM
2188462SApril.Chin@Sun.COMtypeset -r mymutexname="hello_world"
2198462SApril.Chin@Sun.COM
2208462SApril.Chin@Sun.COMfilemutex_t fs
2218462SApril.Chin@Sun.COM
2228462SApril.Chin@Sun.COMfs.create "${mymutexname}" || print -u2 "Mutex init failed."
2238462SApril.Chin@Sun.COM
2248462SApril.Chin@Sun.COMprint "# Starting child which keeps an exclusive lock for 10 seconds..."
2258462SApril.Chin@Sun.COM(
2268462SApril.Chin@Sun.COM	filemutex_t child_fs
2278462SApril.Chin@Sun.COM
2288462SApril.Chin@Sun.COM	child_fs.create_child "${mymutexname}"
2298462SApril.Chin@Sun.COM
2308462SApril.Chin@Sun.COM	child_fs.lock_exclusive
2318462SApril.Chin@Sun.COM	sleep 10
2328462SApril.Chin@Sun.COM	child_fs.unlock
2338462SApril.Chin@Sun.COM) &
2348462SApril.Chin@Sun.COM
2358462SApril.Chin@Sun.COMsleep 1
2368462SApril.Chin@Sun.COM
2378462SApril.Chin@Sun.COMprintf "%T: # Waiting to obtain a shared lock...\n"
2388462SApril.Chin@Sun.COMfs.lock_shared
2398462SApril.Chin@Sun.COMprintf "%T: # Obtained shared lock\n"
2408462SApril.Chin@Sun.COM
2418462SApril.Chin@Sun.COMprintf "fs.locked_exclusive=%s, fs.locked_shared=%s\n" "${fs.locked_exclusive}" "${fs.locked_shared}"
2428462SApril.Chin@Sun.COM
2438462SApril.Chin@Sun.COMls -lad /tmp/filemutex*/*
2448462SApril.Chin@Sun.COM
2458462SApril.Chin@Sun.COMprintf "%T: # Executing child which runs printf '|%%s|\\\n' 'hello' 'world' inside a synchronized section\n"
2468462SApril.Chin@Sun.COM(
2478462SApril.Chin@Sun.COM	filemutex_t child_fs
2488462SApril.Chin@Sun.COM
2498462SApril.Chin@Sun.COM	child_fs.create_child "${mymutexname}"
2508462SApril.Chin@Sun.COM
2518462SApril.Chin@Sun.COM	child_fs.synchronized printf '|%s|\n' 'hello' 'world'
2528462SApril.Chin@Sun.COM) &
2538462SApril.Chin@Sun.COM
2548462SApril.Chin@Sun.COMprintf "%T: # Sleeping 5 secs while holding the shared lock...\n"
2558462SApril.Chin@Sun.COMsleep 5.
2568462SApril.Chin@Sun.COM
2578462SApril.Chin@Sun.COMprintf "%T: # Releasing shared lock...\n"
2588462SApril.Chin@Sun.COMfs.unlock
2598462SApril.Chin@Sun.COM
2608462SApril.Chin@Sun.COMsleep 5.
2618462SApril.Chin@Sun.COMprint "# Destroying lock..."
2628462SApril.Chin@Sun.COMfs.destroy
2638462SApril.Chin@Sun.COM
2648462SApril.Chin@Sun.COMprint "## Done."
2658462SApril.Chin@Sun.COM
2668462SApril.Chin@Sun.COMexit 0
267