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