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