#=============================================================================
#  
#  queue_functions - queue functions 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
#  
#=============================================================================

put_in_queue()
{
	local FUNC_NAME=put_in_queue
	${TRACE:-trace $FUNC_NAME $@}

	local filename=$(date '+%y%m%d-%H%M%S').$$
	local pid_file=$QUEUE_DIR/$filename

	if ln -s $$ $pid_file 2>&-
	then
		return 0
	else
		return 1
	fi
}

remove_from_head()
{
	local FUNC_NAME=remove_from_head
	${TRACE:-trace $FUNC_NAME $@}

	local filename=$(ls -1 $QUEUE_DIR | head -1)
	local pid_file=$QUEUE_DIR/$filename

	if [[ -L $pid_file ]]
	then
		rm -f $pid_file
		${INFO:-info "Removed PID $pid from the head of the queue."}
		return 0
	else
		return 1
	fi
}

get_queue_head()
{
	local FUNC_NAME=get_queue_head
	${TRACE:-trace $FUNC_NAME $@}

	local filename
	local pid_file

	while true
	do
		filename=$(ls -1 $QUEUE_DIR | head -1)
		pid_file=$QUEUE_DIR/$filename
		if [[ -L $pid_file ]]
		then
			pid=$(get_link_target $pid_file)
			${INFO:-info "PID $pid is at the head of the queue"}
			if ps -p $pid >&- 2>&-
			then
				echo $pid
				return 0
			else
				${INFO:-info "PID $pid is no longer running."}
				remove_from_head
			fi
		else
			${INFO:-info "The queue is empty."}
			return 1
		fi
	done
}

still_in_queue()
{
	local FUNC_NAME=still_in_queue
	${TRACE:-trace $FUNC_NAME $@}

	if ls $QUEUE_DIR/*.$$ 1>&- 2>&-
	then
		return 0
	else
		return 1
	fi
}

wait_in_queue()
{
	# The current process waits until it reaches the head of the queue at
	# which point it tries to grab a resources.Returns 0 if a resource is
	# obtained; otherwise, returns 1.

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

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

	assert_semaphore $semaphore

	while true
	do
		if [[ "$(get_queue_head)" = $$ ]]
		then
			if keep_trying $semaphore $num_resources $pid $remaining_tries
			then
				remove_from_head
				return 0
			else
				return 1
			fi
		elif still_in_queue
		then
			sleep $SLEEP_SECONDS
		else
			return 1
		fi

		if (( $remaining_tries >= 0 ))
		then
			if (( $remaining_tries == 0 ))
			then
				total=$(($TIMEOUT_TRIES*$SLEEP_SECONDS))
${INFO:-info "PID $$ never reached the head of the queue."}
${INFO:-info "PID $$ timed out after $TIMEOUT_TRIES tries and $total seconds."}
				return 1
			else
				remaining_tries=$(( $remaining_tries - 1 ))
			fi
		fi
	done
}
