/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  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 1, 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, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR                     Initial version.
*       V01.2   JRR     12-Feb-1992	Fixed static declations of routines.
*       V01.3   JRR     02-Mar-1992	Added Cosmic V2 changes.
*       V01.4   JRR     08-Apr-1992     Added CERN enhancements.
*	V01.5	JRR	17-Jun-1992	Added header.
*	V01.6	JRR	30-Jul-1992	Waiting jobs should stay in first
*					come-first served order.
*	V01.7	JRR	18-Aug-1993	Miniscule change to includes.
*	V01.8	JRR			Placeholder
*	V01.9	JRR	01-Mar-1994	Added support for SOLARIS.
*/
/*++ nqs_a2s.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/src/RCS/nqs_a2s.c,v $
 *
 * DESCRIPTION:
 *
 *
 *	This module contains 7 externally visible procedures which
 *	add the given request to the appropriate queue/request set:
 *
 *		a2s_a2aset():	Add to arriving set;
 *		a2s_a2dset():	Add to departing/exiting
 *				(staging-out) set.
 *		a2s_a2hset():	Add to holding set;
 *		a2s_a2qset():	Add to queued set;
 *		a2s_a2rset():	Add to running set;
 *		a2s_a2sset():	Add to staging-in set;
 *		a2s_a2wset():	Add to waiting set;
 *
 *
 *	Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	March 13, 1986.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.9 $ $Date: 1994/03/30 20:36:26 $ $State: Exp $)
 * $Log: nqs_a2s.c,v $
 * Revision 1.9  1994/03/30  20:36:26  jrroma
 * Version 3.35.6
 *
 * Revision 1.8  94/02/24  21:30:34  jrroma
 * Version 3.35.3
 * 
 * Revision 1.7  93/09/10  13:57:01  jrroma
 * Version 3.35
 * 
 * Revision 1.6  92/12/22  15:39:45  jrroma
 * Version 3.30
 * 
 * Revision 1.5  92/06/18  17:30:51  jrroma
 * Added gnu header
 * 
 * Revision 1.4  92/05/06  10:38:17  jrroma
 *  Version 3.20
 * 
 * Revision 1.3  92/03/02  11:44:01  jrroma
 * Added Cosmic V2 Changes.
 * 
 * Revision 1.2  92/02/12  16:11:34  jrroma
 * *** empty log message ***
 * 
 * Revision 1.1  92/02/12  13:25:11  jrroma
 * Initial revision
 * 
 *
 */
#include "nqs.h"			/* NQS types and definitions */
#include "nqsxvars.h"			/* NQS global vars and dirs */

#ifndef __CEXTRACT__
#if __STDC__

static void a2s_a2dset ( struct request *req, struct nqsqueue *queue );
static void a2s_a2eset ( struct request *req, struct nqsqueue *queue, struct request **addtoset, short *setcount );
static void a2s_a2pset ( struct request *req, struct nqsqueue *queue, struct request **addtoset, short *setcount );
static void a2s_a2sset ( struct request *req, struct nqsqueue *queue );

#else /* __STDC__ */

static void a2s_a2dset (/* struct request *req, struct nqsqueue *queue */);
static void a2s_a2eset (/* struct request *req, struct nqsqueue *queue, struct request **addtoset, short *setcount */);
static void a2s_a2pset (/* struct request *req, struct nqsqueue *queue, struct request **addtoset, short *setcount */);
static void a2s_a2sset (/* struct request *req, struct nqsqueue *queue */);

#endif /* __STDC__ */
#endif /* __CEXTRACT__ */

/*** a2s_a2aset
 *

 *
 *	void a2s_a2aset():
 *
 *	Add the given request to the arrive set in the specified
 *	queue.  The QUE_UPDATE bit is set for the queue.
 */
void a2s_a2aset (
	struct request *req,		/* Request */
	struct nqsqueue *queue)		/* The queue */
{
	/*
	 *  In a load balanced outbound queue, if there is a waiting request, we
	 *  want to follow the order of submission. So the new request
	 *  is not queued but puts on wait.
	 */
	if (queue->waitset != (struct request *)0 &&
	    ( queue->q.status & QUE_LDB_OUT ) ) {
		/*
		 * If not really waiting, fixup the start time. 
		 */
		if ( !(req->status & RQF_AFTER) )
			req->start_time = req->v1.req.state_time + Defdesretwai;
		a2s_a2wset (req, queue);
	} else
		a2s_a2pset (req, queue, &queue->arriveset,
						&queue->q.arrivecount);
}


/*** a2s_a2dset
 *
 *
 *	void a2s_a2dset():
 *
 *	Add the given request to the depart/exiting set in the
 *	specified queue.  The QUE_UPDATE bit is set for the queue.
 */
static
void a2s_a2dset (
	struct request *req,		/* Request */
	struct nqsqueue *queue)		/* The queue */
{

	a2s_a2eset (req, queue, &queue->departset, &queue->q.departcount);
}


/*** a2s_a2hset
 *
 *
 *	void a2s_a2hset():
 *
 *	Add the given request to the hold set in the specified
 *	queue.  The QUE_UPDATE bit is set for the queue.
 */
void a2s_a2hset (
	struct request *req,		/* Request */
	struct nqsqueue *queue)		/* The queue */
{

	a2s_a2pset (req, queue, &queue->holdset, &queue->q.holdcount);
}


/*** a2s_a2qset
 *
 *
 *	void a2s_a2qset():
 *
 *	Add the given request to the queued set in the specified
 *	queue.  The QUE_UPDATE bit is set for the queue.
 */
void a2s_a2qset (
	struct request *req,		/* Request */
	struct nqsqueue *queue)		/* The queue */
{

	a2s_a2pset (req, queue, &queue->queuedset, &queue->q.queuedcount);
}


/*** a2s_a2rset
 *
 *
 *	void a2s_a2rset():
 *
 *	Add the given request to the running set in the specified
 *	queue.  The QUE_UPDATE bit is set for the queue.
 *
 *      Added Device type as per Intergraph Bill Mar    TAC
 */
void a2s_a2rset (
	struct request *req,		/* Request */
	struct nqsqueue *queue)		/* The queue */
{
        register int i;
        struct qcomplex *qcomplex;      /* Queue complex pointer */

        if (queue->q.type == QUE_BATCH) {
                for (i = MAX_COMPLXSPERQ; --i >= 0;) {
                        qcomplex = queue->v1.batch.qcomplex[i];
                        if (qcomplex == (struct qcomplex *)0) continue;
                        qcomplex->runcount++;
                }
        }
        else if (queue->q.type == QUE_DEVICE) {
                for (i = MAX_COMPLXSPERQ; --i >= 0;) {
                        qcomplex = queue->v1.device.qcomplex[i];
                        if (qcomplex == (struct qcomplex *)0) continue;
                        qcomplex->runcount++;
                }
        }
        a2s_a2eset (req, queue, &queue->runset, &queue->q.runcount);
}


/*** a2s_a2sset
 *
 *
 *	void a2s_a2sset():
 *
 *	Add the given request to the staging-in set in the specified
 *	queue.  The QUE_UPDATE bit is set for the queue.
 */
static
void a2s_a2sset (
	struct request *req,		/* Request */
	struct nqsqueue *queue)		/* The queue */
{

	a2s_a2eset (req, queue, &queue->stageset, &queue->q.stagecount);
}


/*** a2s_a2wset
 *
 *
 *	void a2s_a2wset():
 *
 *	Add the given request to the waiting set in the specified
 *	queue.  The QUE_UPDATE bit is set for the queue.
 */
void a2s_a2wset (
	struct request *req,		/* Request */
	struct nqsqueue *queue)		/* The queue */
{
	register struct request *prevreq;
	register struct request *walkreq;
	register struct request *curreq;
	register short pri;

	/*
	 *  Insert the request by -a time and priority.
	 */
	prevreq = (struct request *) 0;
	walkreq = queue->waitset;
	
	if ( !(queue->q.status & QUE_LDB_OUT) ) {
		while (walkreq != (struct request *)0 &&
		       walkreq->start_time < req->start_time) {
	    		prevreq = walkreq;
	    		walkreq = walkreq->next;
		}
	} else {
		/*
		 *  In a load balanced outbound queue, in order to follow the
		 *  order of submission, we have to delay the execution
		 *  of requests that have been submitted after.
		 */
		while (walkreq != (struct request *)0 &&
		       walkreq->v1.req.state_time < req->v1.req.state_time) {
	    		prevreq = walkreq;
	    		walkreq = walkreq->next;
		}
		/*
		 * Just to make sure that the req will get looked at sometime.
		 */
		if (!(req->status & RQF_AFTER) )req->start_time += Defdesretwai;	
	}
	if (walkreq != (struct request *)0) {
	    if (walkreq->start_time == req->start_time) {
		if (queue->q.type == QUE_NET) {
		    /*
		     *  The request is being placed in a network queue,
		     *  and therefore it MUST be a subrequest.  Its priority
		     *  is inherited from its parent.
		     *
		     *  Search to add the request into the -a time
		     *  set by priority.
		     */
		    pri = req->v1.subreq.parent->v1.req.priority;
		    while (walkreq != (struct request *)0 &&
			   walkreq->start_time == req->start_time &&
			   walkreq->v1.subreq.parent->v1.req.priority >= pri) {
			prevreq = walkreq;
			walkreq = walkreq->next;
		    }
		}
		else {
		    /*
		     *  The request is not being place in a network queue,
		     *  and is therefore NOT a subrequest.
		     *
		     *  Search to add the request into the -a time
		     *  set by priority.
		     */
		    pri = req->v1.req.priority;
		    while (walkreq != (struct request *)0 &&
			   walkreq->start_time == req->start_time &&
			   walkreq->v1.req.priority >= pri) {
			prevreq = walkreq;
			walkreq = walkreq->next;
		    }
		}
	    }
	}
	/*
	 *  Add to set.
	 */
	if (prevreq == (struct request *)0) {
	    req->next = queue->waitset;
	    queue->waitset = req;
	}
	else {
	    req->next = prevreq->next;
	    prevreq->next = req;
	}
	queue->q.waitcount++;		/* One more request in the wait set */
	queue->q.status |= QUE_UPDATE;	/* Database image needs to be */
					/* updated */
	req->queue = queue;		/* Each request always has a pointer */
					/* to the queue in which it resides */
	/*
	 *  Set virtual timer to wakeup request.
	 */
	nqs_vtimer (&req->start_time, nqs_wakreq);
}


/*** a2s_a2eset
 *
 *
 *	void a2s_a2eset():
 *
 *	Add the request to the specified set in the given queue.
 *	The requests in the given request set are ordered by
 *	event time (the time at which this procedure is called).
 *
 *	NOTE:	This procedure can only be used for adding requests
 *		to a request set in the DEPARTING/EXITING, RUNNING/ROUTING,
 *		or STAGING states.
 *
 */
static
void a2s_a2eset (
	struct request *req,		/* Request */
	struct nqsqueue *queue,		/* The queue */
	struct request **addtoset,	/* Ptr to the chain of requests into */
					/* into which 'req' must be inserted */
	short *setcount)		/* Ptr to short integer tallying the */
					/* number of requests in the set into*/
					/* 'req' is being inserted */
{
	register struct request *prevreq;
	register struct request *walkreq;

	/*
	 *  Insert the request by event time.
	 */
	prevreq = (struct request *) 0;
	walkreq = *addtoset;
	while (walkreq != (struct request *) 0) {
	    prevreq = walkreq;
	    walkreq = walkreq->next;
	}
	/*
	 *  Add to set.
	 */
	if (prevreq == (struct request *) 0) {
		req->next = *addtoset;
		*addtoset = req;
	}
	else {
		req->next = prevreq->next;
		prevreq->next = req;
	}
	++*setcount;			/* One more request in this set */
	req->queue = queue;		/* Each request always has a pointer */
					/* to the queue in which it resides */
	queue->q.status |= QUE_UPDATE;	/* Database image needs to be */
}					/* updated */


/*** a2s_a2pset
 *
 *
 *	void a2s_a2pset():
 *
 *	Add the request to the specified set in the given queue.
 *	The requests in the given request set are ordered by:
 *
 *		1. priority	AND
 *		2. queued-time (recorded in state_time).
 *
 *	NOTE:	This procedure can only be used for adding requests
 *		to a request set in the QUEUED, HOLDING or ARRIVING
 *		states.
 *
 */
static
void a2s_a2pset (
	struct request *req,		/* Request */
	struct nqsqueue *queue,		/* The queue */
	struct request **addtoset,	/* Ptr to the chain of requests into */
					/* into which 'req' must be inserted */
	short *setcount)		/* Ptr to short integer tallying the */
					/* number of requests in the set into*/
					/* 'req' is being inserted */
{
	register struct request *prevreq;
	register struct request *walkreq;
	register short pri;
	register time_t sta;

	/*
	 *  Insert the request by priority and queued-time (as
	 *  recorded in state_time).
	 */
	prevreq = (struct request *) 0;
	walkreq = *addtoset;
	if (queue->q.type == QUE_NET) {
	    /*
	     *  The request is being placed in a network queue,
	     *  and therefore it MUST be a subrequest.  Its priority
	     *  is inherited from its parent.
	     */
	    pri = req->v1.subreq.parent->v1.req.priority;
	    while (walkreq != (struct request *)0 &&
		   walkreq->v1.subreq.parent->v1.req.priority > pri) {
		prevreq = walkreq;
		walkreq = walkreq->next;
	    }
	    if (walkreq != (struct request *)0) {
		if (walkreq->v1.subreq.parent->v1.req.priority == pri) {
		    /*
		     *  Search to add the request into this
		     *  priority set by the last changed state
		     *  time of its parent.
		     */
		    sta = req->v1.subreq.parent->v1.req.state_time;
		    while (walkreq != (struct request *)0 &&
			   walkreq->v1.subreq.parent->v1.req.priority == pri &&
			   walkreq->v1.subreq.parent->v1.req.state_time <=sta){
			prevreq = walkreq;
			walkreq = walkreq->next;
		    }
		}
	    }
	}
	else {
	    /*
	     *  The request is NOT a subrequest.
	     */
	    pri = req->v1.req.priority;
	    while (walkreq != (struct request *)0 &&
		   walkreq->v1.req.priority > pri) {
		prevreq = walkreq;
		walkreq = walkreq->next;
	    }
	    if (walkreq != (struct request *)0) {
		if (walkreq->v1.req.priority == pri) {
		    /*
		     *  Search to add the request into this
		     *  priority set by its last changed state
		     *  time.
		     */
		    sta = req->v1.req.state_time;
		    while (walkreq != (struct request *)0 &&
			   walkreq->v1.req.priority == pri &&
			   walkreq->v1.req.state_time <= sta) {
			prevreq = walkreq;
			walkreq = walkreq->next;
		    }
		}
	    }
	}
	/*
	 *  Add to set.
	 */
	if (prevreq == (struct request *)0) {
		req->next = *addtoset;
		*addtoset = req;
	}
	else {
		req->next = prevreq->next;
		prevreq->next = req;
	}
	++*setcount;			/* One more request in this set */
	req->queue = queue;		/* Each request always has a pointer */
					/* to the queue in which it resides */
	queue->q.status |= QUE_UPDATE;	/* Database image needs to be */
}					/* updated */
