Article Listing 1 Sidebar aug2005.tar

Listing 1 qjob

#!/bin/ksh
# qjob.  Listing 1
# qjob and semaphore are both in /usr/local/bin,
# so make sure /usr/local/bin/ is in the PATH.

PATH="$PATH:/usr/local/bin"

# Return Codes

SUCCESS=0
COMMAND_RETURNED_NON_ZERO=1
CLONES_ALREADY_QUEUED=2
MISSING_COMMAND=3
QUEUE_SHUT_DOWN=4

# The queue_job Function

queue_job()
{
    # Imagine $job_name has walked into a bank called $queue_name.
    # Customers at the $queue_name bank must queue up in one line.
    # The bank has $num_tellers teller windows. $job_name wants to
    # submit a request called $command. If $num_clones > 1, then
    # the theme to the Twilight Zone is playing in the background.

    local job_name=$1
    local queue_name=$2
    local num_tellers=$3
    local num_clones=$4
    local command="$5"

    if semaphore -t 0 -I $num_clones -P ${job_name}_already_queued
    then
        # If there are NOT $num_clones instances of $job_name already running
        # or waiting in line, then $job_name grabs a resource and gets in line.
        if semaphore -q -s 10 -I $num_tellers -P $queue_name
        then
            # When a teller is free, $job_name executes.
            if [[ ${DEBUG} = TRUE ]]
            then
                echo "Now serving job ${job_name} from queue ${queue_name}."
            fi
            $command
            command_return_code=$?

            # $job_name releases the resource so another instance of $job_name
            # can use it.
            semaphore -V ${job_name}_already_queued

            # $job_name walks away so his teller can service someone else.
            semaphore -V $queue_name

            if (( $command_return_code == 0 ))
            then
                # $job_name's request appears to have been fulfilled.
                return $SUCCESS
            else
                return $COMMAND_RETURNED_NON_ZERO
            fi
        else
            # Sorry, the bank just closed.
            # $job_name throws away his number and goes home empty handed.
            semaphore -V ${job_name}_already_queued
            if [[ ${DEBUG} = TRUE ]]
            then
                echo "Job ${job_name} didn't reach the head of queue \
                      ${queue_name}."
            fi
            return $QUEUE_SHUT_DOWN
        fi
    else
        if [[ ${DEBUG} = TRUE ]]
        then
            echo "Can't put job ${job_name} in queue ${queue_name}."
        if (( $num_clones <= 0 ))
        then
            echo "Job ${job_name} is not allowed\c"
        elif (( $num_clones == 1 ))
        then
            echo "$num_clones instance of job ${job_name} is waiting\c"
        else
            echo "$num_clones instances of job ${job_name} are waiting\c"
        fi
            echo " in queue ${queue_name}."
        fi
        return $CLONES_ALREADY_QUEUED
    fi
}

# Variables

local job_name=""
local queue_name=""
local command=""
integer num_clones=1
integer num_tellers=1
DEBUG=FALSE

# Get the command line options.

while getopts c:dj:n:q: option
do
case $option in
    d) DEBUG=TRUE ;;
    c) num_clones=$OPTARG ;;
    j) job_name=$OPTARG ;;
    n) num_tellers=$OPTARG ;;
    q) queue_name=$OPTARG ;;
    esac
done

shift $(($OPTIND-1))

# Get the command including any arguements.

command="$@"

# Generate some default values.

if [[ -z $job_name ]]
then
    job_name=$(basename $1)
fi

if [[ -z $queue_name ]]
then
    queue_name=default_queue
fi

# Verify that a command was specified, and queue the job.

if [[ -n "$command" ]]
then
    queue_job $job_name $queue_name $num_tellers $num_clones "$command"
    return $?
else
    return $MISSING_COMMAND
fi