#=============================================================================
#  
#  P_semaphore - implementation of P_semaphore for ../bin/semaphore
#  semaphore - a Korn shell implementation of a counting semaphore
#  Copyright (C) 2004 Intel Corporation
#  
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the Free
#  Software Foundation; either version 2 of the License, or (at your option)
#  any later version.
#  
#  This program is distributed in the hope that it will be useful, but
#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
#  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
#  for more details.
#  
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, see http://www.gnu.org/copyleft/gpl.html or
#  write to:
#  
#  The Free Software Foundation, Inc.,
#  59 Temple Place
#  Suite 330, Boston, MA 02111-1307
#  USA
#  
#  Author:
#  
#  John Spurgeon
#  5200 NE Elam Young Parkway
#  Hillsboro, OR 97124
#  
#  john.p.spurgeon@intel.com
#  
#=============================================================================

keep_trying()
{
	# Keep "trying" the semaphore until a resource is obtained or until the
	# program times out.

	local FUNC_NAME=keep_trying
	${TRACE:-trace $FUNC_NAME $@}

	local semaphore=$1
	integer num_resources=$2
	integer pid=$3
	integer remaining_tries=$4

	assert_semaphore $semaphore

	wipe_semaphore $semaphore
	while ! P_semaphore $semaphore $num_resources $pid
	do
		sleep $SLEEP_SECONDS
		if (( $remaining_tries >= 0 ))
		then
			if (( $remaining_tries == 0 ))
			then
				total=$(($TIMEOUT_TRIES*$SLEEP_SECONDS))
${INFO:-info "PID $$ timed out after $TIMEOUT_TRIES tries and $total seconds."}
				return 1
			else
				remaining_tries=$(( $remaining_tries - 1 ))
			fi
		fi
	done
	return 0
}

grab_resource()
{
	# Caveat Emptor! The implementation of semaphore hinges on the
	# behavior  of  the  ln  command.  To  implement  a  semaphore
	# correctly, the test of a semaphore's value  and  the  decre-
	# menting  of  this  value must be an atomic operation. In the
	# function grab_resource, the act of creating a symbolic  link
	# does  both  things at once. If the ln command is successful,
	# then the semaphore's count is effectively tested and  decre-
	# mented in one atomic step.

	local FUNC_NAME=grab_resource
	${TRACE:-trace $FUNC_NAME $@}

	local semaphore=$1
	integer resource_num=$2
	local symbolic_link=$HOME_DIR/$semaphore/$RESOURCES_DIRNAME/$resource_num
	integer pid=$3

	assert_semaphore $semaphore

	ln -s $pid $symbolic_link >&- 2>&-
	return $?
}

P_semaphore()
{
	# P_semaphore tries to grab a resource. The function effectively
	# decrements the count or value of the semaphore if one is obtained.
	# Returns 0 if a resource is obtained; otherwise, returns 1.

	local FUNC_NAME=P_semaphore
	${TRACE:-trace $FUNC_NAME $@}

	local semaphore=$1
	integer num_resources=$2
	integer pid=$3

	${INFO:-info "Semaphore $semaphore has $num_resources resource(s)."}

	assert_semaphore $semaphore

	integer semaphore_value=$(get_semaphore_value $semaphore)
	${INFO:-info "Value of semaphore $semaphore is: $semaphore_value"}
	if (( $semaphore_value < 1 )) && \
	(( $(time_since_last_wipe $semaphore) > $WIPE_INTERVAL ))
	then
		wipe_semaphore $semaphore
	fi
	${INFO:-info "Trying to grab a resource from semaphore $semaphore ..."}
	integer resource_num=0
	while (( $resource_num < $num_resources ))
	do
		if grab_resource $semaphore $resource_num $pid
		then
			${INFO:-info "PID $pid grabbed resource $resource_num."}
			return 0
		else
			${INFO:-info "Resource $resource_num was in use."}
			resource_num=$(($resource_num+1))
		fi
	done
	${INFO:-info "All resources for semaphore $semaphore were in use."}
	return 1
}
