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