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