#!/usr/bin/ksh93 # should work for ksh88/ksh93/bash4 ######################################################################## # # # This software is part of the ast package # # Copyright (c) 2019 Roland Mainz # # and is licensed under the # # Eclipse Public License, Version 1.0 # # by AT&T Intellectual Property # # # # A copy of the License is available at # # http://www.eclipse.org/org/documents/epl-v10.html # # (with md5 checksum b35adb5213ca9657e911e9befb180842) # # # # # # Roland Mainz # # # ######################################################################## # # Copyright (c) 2019, Roland Mainz. All rights reserved. # # # shsemaphore.sh - wait until customers are waiting # at the semaphore # # Usage: # 1. init semaphore ("mysemaname" is the 'semaphore address') # $ shsemaphore.sh init mysemaname # # 2. let two semaphore customers (names are 'Bear' and 'Fox') # wait for each other: # $ shsemaphore.sh wait mysemaname Bear 2 & # $ shsemaphore.sh wait mysemaname Fox 2 # # 3. Cleanup all the mess if you are really done: # $ shsemaphore.sh cleanup mysemaname # # POSIX path for mkdir, ls, rm, rmdir ... export PATH='/bin:/usr/bin' # constants typeset -r SEMA_BASE_DIR='/tmp/' # arguments typeset sema_cmd="$1" typeset sema_address="${SEMA_BASE_DIR}/shsemaphore_$2" typeset sema_name="${sema_address}/$3" typeset -i sema_count="$4" # Debug: #printf "cmd=%s, address=%s, name=%s, count=%d\n" \ # "${sema_cmd}" "${sema_address}" "${sema_name}" "${sema_count}" function sema_cleanup { rm -Rf "${sema_address}" } function sema_init { if [[ -z "$SEMA_BASE_DIR" || -z "$sema_address" ]] ; then printf "%s: Illegal arguments.\n" "$0" 1>&2 return 1 fi mkdir -p "${SEMA_BASE_DIR}" sema_cleanup mkdir "${sema_address}" } function sema_wait { typeset IFS if [[ -z "$SEMA_BASE_DIR" || -z "$sema_address" || -z "$sema_name" || -z "$sema_count" ]] ; then printf "%s: Illegal arguments.\n" "$0" 1>&2 return 1 fi if ! mkdir "${sema_name}" ; then printf "%s: Count not set name.\n" "$0" 1>&2 return 1 fi # is semaphore still valid ? cd "${sema_address}" || return 4 IFS=$'\n' while (( 1 )) ; do # 1. we rely on shell globing to avoid |fork()|/|exec()| # for ls(1) # 2. we count '.' and '..', too. Both special dirs # will disappear if the directory "${sema_address}" # gets removed sfiles=( $(printf "%s\n" */ .*/ 2>'/dev/null') ) # Debug: #printf 'sfiles=|%s| ' "${sfiles[@]}" ; printf '\n' # semaphore condition fullfilled ? (( ${#sfiles[@]} >= (sema_count+2) )) && return 0 # semaphore gone ? # In that case we get only two entries from globbing # above, one for '*/' and one for '.*/' (( ${#sfiles[@]} <= 2 )) && return 4 sleep 2 done # notreached } # main case "${sema_cmd}" in 'init') sema_init exit $? ;; 'wait') sema_wait exit $? ;; 'cleanup') sema_cleanup exit $? ;; *) printf "%s: Unknown command.\n" "$0" 1>&1 exit 1 ;; esac