xref: /titanic_41/usr/src/lib/libshell/common/scripts/filemutexdemo1.sh (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
17c2fbfb3SApril Chin#!/usr/bin/ksh93
27c2fbfb3SApril Chin
37c2fbfb3SApril Chin#
47c2fbfb3SApril Chin# CDDL HEADER START
57c2fbfb3SApril Chin#
67c2fbfb3SApril Chin# The contents of this file are subject to the terms of the
77c2fbfb3SApril Chin# Common Development and Distribution License (the "License").
87c2fbfb3SApril Chin# You may not use this file except in compliance with the License.
97c2fbfb3SApril Chin#
107c2fbfb3SApril Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
117c2fbfb3SApril Chin# or http://www.opensolaris.org/os/licensing.
127c2fbfb3SApril Chin# See the License for the specific language governing permissions
137c2fbfb3SApril Chin# and limitations under the License.
147c2fbfb3SApril Chin#
157c2fbfb3SApril Chin# When distributing Covered Code, include this CDDL HEADER in each
167c2fbfb3SApril Chin# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
177c2fbfb3SApril Chin# If applicable, add the following below this CDDL HEADER, with the
187c2fbfb3SApril Chin# fields enclosed by brackets "[]" replaced with your own identifying
197c2fbfb3SApril Chin# information: Portions Copyright [yyyy] [name of copyright owner]
207c2fbfb3SApril Chin#
217c2fbfb3SApril Chin# CDDL HEADER END
227c2fbfb3SApril Chin#
237c2fbfb3SApril Chin
247c2fbfb3SApril Chin#
25*3e14f97fSRoger A. Faulkner# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
267c2fbfb3SApril Chin#
277c2fbfb3SApril Chin
287c2fbfb3SApril Chin#
297c2fbfb3SApril Chin# filemutexdemo1 - a simple locking demo which supports read/write
307c2fbfb3SApril Chin# locks and critical sections (like JAVA's "syncronized" keyword)
317c2fbfb3SApril Chin#
327c2fbfb3SApril Chin
337c2fbfb3SApril Chin# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
347c2fbfb3SApril Chinexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
357c2fbfb3SApril Chin
367c2fbfb3SApril Chin# Make sure all math stuff runs in the "C" locale to avoid problems
377c2fbfb3SApril Chin# with alternative # radix point representations (e.g. ',' instead of
387c2fbfb3SApril Chin# '.' in de_DE.*-locales). This needs to be set _before_ any
397c2fbfb3SApril Chin# floating-point constants are defined in this script).
407c2fbfb3SApril Chinif [[ "${LC_ALL}" != "" ]] ; then
417c2fbfb3SApril Chin    export \
427c2fbfb3SApril Chin        LC_MONETARY="${LC_ALL}" \
437c2fbfb3SApril Chin        LC_MESSAGES="${LC_ALL}" \
447c2fbfb3SApril Chin        LC_COLLATE="${LC_ALL}" \
457c2fbfb3SApril Chin        LC_CTYPE="${LC_ALL}"
467c2fbfb3SApril Chin        unset LC_ALL
477c2fbfb3SApril Chinfi
487c2fbfb3SApril Chinexport LC_NUMERIC=C
497c2fbfb3SApril Chin
507c2fbfb3SApril Chin# Definition for a mutex which uses the filesystem for locking
517c2fbfb3SApril Chintypeset -T filemutex_t=(
527c2fbfb3SApril Chin	typeset name
537c2fbfb3SApril Chin
547c2fbfb3SApril Chin	typeset lock_dirname
557c2fbfb3SApril Chin
567c2fbfb3SApril Chin	typeset locked_exclusive="false"
577c2fbfb3SApril Chin	typeset locked_shared="false"
587c2fbfb3SApril Chin
597c2fbfb3SApril Chin	# keep track of subshell level. The problem is that we do not know a
607c2fbfb3SApril Chin	# way to figure out whether someone calls "unlock" in a subshell and then
617c2fbfb3SApril Chin	# leaves the subshell and calls "unlock" again
627c2fbfb3SApril Chin	integer subshell=-1
637c2fbfb3SApril Chin
647c2fbfb3SApril Chin	typeset lock_dirname
657c2fbfb3SApril Chin
667c2fbfb3SApril Chin	# create a filemutex instance (including lock directory)
677c2fbfb3SApril Chin	function create
687c2fbfb3SApril Chin	{
697c2fbfb3SApril Chin		# make sure we return an error if the init didn't work
707c2fbfb3SApril Chin		set -o errexit
717c2fbfb3SApril Chin
727c2fbfb3SApril Chin		[[ "$1" == "" ]] && return 1
737c2fbfb3SApril Chin
747c2fbfb3SApril Chin		_.name="$1"
757c2fbfb3SApril Chin		_.lock_dirname="/tmp/filemutex_t_${_.name}.lock"
767c2fbfb3SApril Chin
777c2fbfb3SApril Chin		mkdir "${_.lock_dirname}"
787c2fbfb3SApril Chin
797c2fbfb3SApril Chin		# last entry, used to mark the mutex as initalised+valid
807c2fbfb3SApril Chin		(( _.subshell=.sh.subshell ))
817c2fbfb3SApril Chin		return 0
827c2fbfb3SApril Chin	}
837c2fbfb3SApril Chin
847c2fbfb3SApril Chin	# use a filemutex instance (same as "create" but without creating
857c2fbfb3SApril Chin	# the lock directory)
867c2fbfb3SApril Chin	function create_child
877c2fbfb3SApril Chin	{
887c2fbfb3SApril Chin		# make sure we return an error if the init didn't work
897c2fbfb3SApril Chin		set -o errexit
907c2fbfb3SApril Chin
917c2fbfb3SApril Chin		[[ "$1" == "" ]] && return 1
927c2fbfb3SApril Chin
937c2fbfb3SApril Chin		_.name="$1"
947c2fbfb3SApril Chin		_.lock_dirname="/tmp/filemutex_t_${_.name}.lock"
957c2fbfb3SApril Chin
967c2fbfb3SApril Chin		# last entry, used to mark the mutex as initalised+valid
977c2fbfb3SApril Chin		(( _.subshell=.sh.subshell ))
987c2fbfb3SApril Chin		return 0
997c2fbfb3SApril Chin	}
1007c2fbfb3SApril Chin
1017c2fbfb3SApril Chin	function check_subshell
1027c2fbfb3SApril Chin	{
1037c2fbfb3SApril Chin		(( _.subshell == .sh.subshell )) && return 0
1047c2fbfb3SApril Chin		print -u2 -f "filemutex_t.%s(%s): Wrong subshell level\n" "$1" "${_.name}"
1057c2fbfb3SApril Chin		return 1
1067c2fbfb3SApril Chin	}
1077c2fbfb3SApril Chin
1087c2fbfb3SApril Chin	function try_lock_shared
1097c2fbfb3SApril Chin	{
1107c2fbfb3SApril Chin		_.check_subshell "try_lock_shared" || return 1
1117c2fbfb3SApril Chin
1127c2fbfb3SApril Chin		mkdir "${_.lock_dirname}/shared_${PPID}_$$" 2>/dev/null || return 1
1137c2fbfb3SApril Chin		_.locked_shared="true"
1147c2fbfb3SApril Chin		return 0
1157c2fbfb3SApril Chin	}
1167c2fbfb3SApril Chin
1177c2fbfb3SApril Chin	function lock_shared
1187c2fbfb3SApril Chin	{
1197c2fbfb3SApril Chin		float interval=0.2
1207c2fbfb3SApril Chin
1217c2fbfb3SApril Chin		_.check_subshell "lock_shared" || return 1
1227c2fbfb3SApril Chin
1237c2fbfb3SApril Chin		while ! _.try_lock_shared ; do sleep ${interval} ; (( interval+=interval/10. )) ; done
1247c2fbfb3SApril Chin		return 0
1257c2fbfb3SApril Chin	}
1267c2fbfb3SApril Chin
1277c2fbfb3SApril Chin	function try_lock_exclusive
1287c2fbfb3SApril Chin	{
1297c2fbfb3SApril Chin		_.check_subshell "try_lock_exclusive" || return 1
1307c2fbfb3SApril Chin
1317c2fbfb3SApril Chin		rmdir "${_.lock_dirname}" 2>/dev/null || return 1
1327c2fbfb3SApril Chin		_.locked_exclusive="true"
1337c2fbfb3SApril Chin		return 0
1347c2fbfb3SApril Chin	}
1357c2fbfb3SApril Chin
1367c2fbfb3SApril Chin	function lock_exclusive
1377c2fbfb3SApril Chin	{
1387c2fbfb3SApril Chin		float interval=0.2
1397c2fbfb3SApril Chin
1407c2fbfb3SApril Chin		_.check_subshell "lock_exclusive" || return 1
1417c2fbfb3SApril Chin
1427c2fbfb3SApril Chin		while ! _.try_lock_exclusive ; do sleep ${interval} ; (( interval+=interval/10. )) ; done
1437c2fbfb3SApril Chin		return 0
1447c2fbfb3SApril Chin	}
1457c2fbfb3SApril Chin
1467c2fbfb3SApril Chin	# critical section support (like java's "synchronized" keyword)
1477c2fbfb3SApril Chin	function synchronized
1487c2fbfb3SApril Chin	{
1497c2fbfb3SApril Chin		integer retcode
1507c2fbfb3SApril Chin
1517c2fbfb3SApril Chin		_.check_subshell "synchronized" || return 1
1527c2fbfb3SApril Chin
1537c2fbfb3SApril Chin		_.lock_exclusive
1547c2fbfb3SApril Chin
1557c2fbfb3SApril Chin		"$@"
1567c2fbfb3SApril Chin		(( retcode=$? ))
1577c2fbfb3SApril Chin
1587c2fbfb3SApril Chin		_.unlock
1597c2fbfb3SApril Chin
1607c2fbfb3SApril Chin		return ${retcode}
1617c2fbfb3SApril Chin	}
1627c2fbfb3SApril Chin
1637c2fbfb3SApril Chin	# critical section support with shared lock
1647c2fbfb3SApril Chin	function synchronized_shared
1657c2fbfb3SApril Chin	{
1667c2fbfb3SApril Chin		integer retcode
1677c2fbfb3SApril Chin
1687c2fbfb3SApril Chin		_.check_subshell "synchronized_shared" || return 1
1697c2fbfb3SApril Chin
1707c2fbfb3SApril Chin		_.lock_shared
1717c2fbfb3SApril Chin
1727c2fbfb3SApril Chin		"$@"
1737c2fbfb3SApril Chin		(( retcode=$? ))
1747c2fbfb3SApril Chin
1757c2fbfb3SApril Chin		_.unlock
1767c2fbfb3SApril Chin
1777c2fbfb3SApril Chin		return ${retcode}
1787c2fbfb3SApril Chin	}
1797c2fbfb3SApril Chin
1807c2fbfb3SApril Chin	function unlock
1817c2fbfb3SApril Chin	{
1827c2fbfb3SApril Chin		# return an error if rmdir/mkdir/check_subshell fail...
1837c2fbfb3SApril Chin		set -o errexit
1847c2fbfb3SApril Chin
1857c2fbfb3SApril Chin		_.check_subshell "unlock"
1867c2fbfb3SApril Chin
1877c2fbfb3SApril Chin		if ${_.locked_shared} ; then
1887c2fbfb3SApril Chin			rmdir "${_.lock_dirname}/shared_${PPID}_$$"
1897c2fbfb3SApril Chin			_.locked_shared="false"
1907c2fbfb3SApril Chin			return 0
1917c2fbfb3SApril Chin		elif ${_.locked_exclusive} ; then
1927c2fbfb3SApril Chin			mkdir "${_.lock_dirname}"
1937c2fbfb3SApril Chin			_.locked_exclusive="false"
1947c2fbfb3SApril Chin			return 0
1957c2fbfb3SApril Chin		fi
1967c2fbfb3SApril Chin
1977c2fbfb3SApril Chin		print -u2 -f "filemutex_t.unlock(%s): mutex '%s' not locked." "$1" "${_.name}"
1987c2fbfb3SApril Chin		return 1
1997c2fbfb3SApril Chin	}
2007c2fbfb3SApril Chin
2017c2fbfb3SApril Chin	# destroy mutex if noone is using it anymore (not the same as "unset" !!))
2027c2fbfb3SApril Chin	function destroy
2037c2fbfb3SApril Chin	{
2047c2fbfb3SApril Chin		_.check_subshell "destroy" || return 1
2057c2fbfb3SApril Chin
2067c2fbfb3SApril Chin		(${_.locked_exclusive} || ${_.locked_shared}) && _.unlock
2077c2fbfb3SApril Chin		rmdir "${_.lock_dirname}"
2087c2fbfb3SApril Chin		return 0
2097c2fbfb3SApril Chin	}
2107c2fbfb3SApril Chin)
2117c2fbfb3SApril Chin
2127c2fbfb3SApril Chin# main
2137c2fbfb3SApril Chinbuiltin mkdir
2147c2fbfb3SApril Chinbuiltin rmdir
2157c2fbfb3SApril Chin
2167c2fbfb3SApril Chinprint "## Start."
2177c2fbfb3SApril Chin
2187c2fbfb3SApril Chintypeset -r mymutexname="hello_world"
2197c2fbfb3SApril Chin
2207c2fbfb3SApril Chinfilemutex_t fs
2217c2fbfb3SApril Chin
2227c2fbfb3SApril Chinfs.create "${mymutexname}" || print -u2 "Mutex init failed."
2237c2fbfb3SApril Chin
2247c2fbfb3SApril Chinprint "# Starting child which keeps an exclusive lock for 10 seconds..."
2257c2fbfb3SApril Chin(
2267c2fbfb3SApril Chin	filemutex_t child_fs
2277c2fbfb3SApril Chin
2287c2fbfb3SApril Chin	child_fs.create_child "${mymutexname}"
2297c2fbfb3SApril Chin
2307c2fbfb3SApril Chin	child_fs.lock_exclusive
2317c2fbfb3SApril Chin	sleep 10
2327c2fbfb3SApril Chin	child_fs.unlock
2337c2fbfb3SApril Chin) &
2347c2fbfb3SApril Chin
2357c2fbfb3SApril Chinsleep 1
2367c2fbfb3SApril Chin
2377c2fbfb3SApril Chinprintf "%T: # Waiting to obtain a shared lock...\n"
2387c2fbfb3SApril Chinfs.lock_shared
2397c2fbfb3SApril Chinprintf "%T: # Obtained shared lock\n"
2407c2fbfb3SApril Chin
2417c2fbfb3SApril Chinprintf "fs.locked_exclusive=%s, fs.locked_shared=%s\n" "${fs.locked_exclusive}" "${fs.locked_shared}"
2427c2fbfb3SApril Chin
2437c2fbfb3SApril Chinls -lad /tmp/filemutex*/*
2447c2fbfb3SApril Chin
2457c2fbfb3SApril Chinprintf "%T: # Executing child which runs printf '|%%s|\\\n' 'hello' 'world' inside a synchronized section\n"
2467c2fbfb3SApril Chin(
2477c2fbfb3SApril Chin	filemutex_t child_fs
2487c2fbfb3SApril Chin
2497c2fbfb3SApril Chin	child_fs.create_child "${mymutexname}"
2507c2fbfb3SApril Chin
2517c2fbfb3SApril Chin	child_fs.synchronized printf '|%s|\n' 'hello' 'world'
2527c2fbfb3SApril Chin) &
2537c2fbfb3SApril Chin
2547c2fbfb3SApril Chinprintf "%T: # Sleeping 5 secs while holding the shared lock...\n"
2557c2fbfb3SApril Chinsleep 5.
2567c2fbfb3SApril Chin
2577c2fbfb3SApril Chinprintf "%T: # Releasing shared lock...\n"
2587c2fbfb3SApril Chinfs.unlock
2597c2fbfb3SApril Chin
2607c2fbfb3SApril Chinsleep 5.
2617c2fbfb3SApril Chinprint "# Destroying lock..."
2627c2fbfb3SApril Chinfs.destroy
2637c2fbfb3SApril Chin
2647c2fbfb3SApril Chinprint "## Done."
2657c2fbfb3SApril Chin
2667c2fbfb3SApril Chinexit 0
267