/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

/*---------------------------------------------------------------------------
 *		
 * MODULE NAME:	rciTaskCtrl
 *
 * DESCRIPTION:	Top level interface to the RCI task control primitives.
 *
 * AUTHOR/DATE:	John LLoyd, Fall 1987
 *
 * MODIFICATION HISTORY:
 *
 *--------------------------------------------------------------------------*/
		
#if 0
#include <sys/file.h>
#include <signal.h>
#endif

#include "../h/cdefs.h"
#include "../h/rciTask.h"
#include "../h/rciMacros.h"
#include "../h/errorCodes.h"
#include "../h/IOdevice.h"

#include "../rci/monitorCom.h"
#include "../h/rciConfig.h"
#include "../rci/interruptDev.h"
#include "../rci/rciAutoAbort.h"

extern int errno;

extern RCI_DESC rciTaskTable[];
extern int rciNumTasks;
extern int taskInitDone;
extern int rciSimOnly;

#define TASKNAME(id)		(rciTaskName(&rciTaskTable[id]))

typedef struct {
	INTERDEV *idev;
} TASK_PARAMS;

TASK_PARAMS taskParams[MAX_RCI_TASKS];
unsigned long activeArbiterTasks = 0; /* to decide if we need heartbeat */

#define DEFAULT_RUN_TIME	500

/* ----- Error Messages. Defined externally to save space ----- */

static char *taskIsActive	= "%s -- task is presently active\n";
static char *badSchedDisp	= "%s -- bad scheduling discipline (%d)\n";
static char *cantAttachToSig	= "%s -- ON_SIGNAL given for aux CPU task\n";
static char *cantDereferIntr	= "%s -- can't dereference interrupt\n";
static char *outOfTaskEntries	= "%s -- out of task entries\n";
static char *cantDereferSig	= "%s -- can't dereference signal\n";
static char *cantAttachSig	= "%s -- can't attach task to signal\n";
static char *cantAttachIntr	= "%s -- can't attach task to interrupt\n";
static char *badRateValues	= "%s -- bad interval or offset: (%d,%d)\n";
static char *badFxnPtr		= "%s -- bad pointer (0x%x) for %s fxn\n";
static char *cantAllocDev	= "%s -- error allocating device\n";
static char *deviceIsBusy	= "%s -- device %s at 0x%x is busy\n";
static char *cantExecArbMon	= "%s -- can't execute arbiter monitor\n";
static char *noMonResponse	= "%s -- no monitor response for task %s\n";
static char *noSchedDisp	= "%s -- task %s: no scheduling disp given\n";
static char *noRateInfo		= "%s -- task %s: rate info incomplete\n";
static char *noHeartbeatOn	= "%s -- can't turn on heartbeat\n";
static char *noHeartbeatOff	= "%s -- can't turn off heartbeat\n";
static char *onSignalOnly	= 
	"%s -- this host system can only run tasks ON_SIGNAL\n";

clearTaskParams ()
{
	/* called only at initialization time, before any rciCreates() */

	register int i;

	for (i=0; i<MAX_RCI_TASKS; i++)
	 { taskParams[i].idev = NULL;
	 }	
	activeArbiterTasks = 0;
}

rciScheduling (td, disp, dev)
RCI_DESC *td;
int disp;
int dev;
{
	char *fxnName = "rciScheduling()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (setupScheduling (fxnName, td, disp, dev) < 0)
	 { RETURN_ERROR(-1);
	 }
	return (1);
}

extern TASK_ENTRY *residentTaskQueue;
extern TASK_ENTRY *signalTaskQueue;

setupScheduling (fxnName, td, disp, devnum)
char *fxnName;
RCI_DESC *td;
int disp;
int devnum;
{
	register RCI_TCB *tcb = td->tcb;

	if (tcb->controlMode == ACTIVE)
         { errorMsg (ETaskActive, taskIsActive, fxnName);
	   return (-1);
	 }

	/* check to make sure the scheduling discipline is valid */

#ifdef SIMONLY_CFG
	if (disp != ON_SIGNAL)
	 { errorMsg (ENotSupported, onSignalOnly, fxnName);
	   return (-1);
	 }
#else
	if (rciSimOnly && disp != ON_SIGNAL)
	 { errorMsg (ENotSupported, onSignalOnly, fxnName);
	   return (-1);
	 }
	if (disp != ON_CLOCK &&
	    disp != ON_TRIGGER &&
	    disp != ON_FUNCTION &&
	    disp != ON_SIGNAL)
	 { errorMsg (ENotDefined, badSchedDisp, fxnName, disp);
	   return (-1);
	 }
#endif
	if (disp == ON_SIGNAL)
	 { 
	   /* for the SIGNAL discipline, we must be running on the arbiter
	      CPU. */

	   if (td->cpu != ARBITER_CPU)
	    { errorMsg (ENotAvail, cantAttachToSig, fxnName);
	      return (-1);
	    }
	   if (tcb->scheduleDisp != ON_SIGNAL)
	    {
	      /* dereference any existing interrupt and remove the task
		 from the resident tasks queue */

	      if (td->interruptNumber != UNDEF)
	       { if (dereferenceInterrupt (td, td->interruptNumber) < 0)
		  { errorMsg (EInternal, cantDereferIntr, fxnName);
		    return (-1);
		  }
		 td->interruptNumber = UNDEF;
	       }
	      deleteTaskEntry (td, residentTaskQueue);
	      if (insertTaskEntry (td, signalTaskQueue) < 0)
	       { errorMsg (EInternal, outOfTaskEntries, fxnName);
		 return (-1);
	       }
	    }
	   else
	    { /* dereference the present signal if it is different */

	      if (td->signalNumber != devnum)
	       { if (dereferenceSignal (td, td->signalNumber) < 0)
		  { errorMsg (EInternal, cantDereferSig, fxnName);
		    return (-1);
		  }
	       }
	    }
	   if (referenceSignal (td, devnum) < 0)
	    { errorMsg (getErrorCode(0), cantAttachSig, fxnName);
	      return (-1);
	    }
	   td->signalNumber = devnum;
	 }
	else 
	 { if (tcb->scheduleDisp == ON_SIGNAL)
	    { if (dereferenceSignal (td, td->signalNumber) < 0)
	       { errorMsg (EInternal, cantDereferSig, fxnName);
		 return (-1);
	       }
	      td->signalNumber = 0;
	      deleteTaskEntry (td, signalTaskQueue);
	      if (insertTaskEntry (td, residentTaskQueue) < 0)
	       { errorMsg (EInternal, outOfTaskEntries, fxnName);
		 return (-1);
	       }
	    }
	   if ((disp == ON_FUNCTION || disp == ON_TRIGGER) &&
	       td->cpu == ARBITER_CPU)
	    { if (td->interruptNumber != UNDEF && 
		  td->interruptNumber != devnum)
	       { if (dereferenceInterrupt (td, td->interruptNumber) < 0)
		  { errorMsg (EInternal, cantDereferIntr, fxnName);
		    return (-1);
		  }
	       }
	      if (devnum != UNDEF)
	       { if (referenceInterrupt (td, devnum) < 0)
		  { errorMsg (getErrorCode(0), cantAttachIntr, fxnName);
		    return (-1);
		  }
	       }
	      td->interruptNumber = devnum;
	    }
	 }

	tcb->scheduleDisp = disp;

	return (1);
}


rciRate (td, interval, offset)
RCI_DESC *td;
int interval, offset;
{
	char *fxnName = "rciRate()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (setupRate (fxnName, td, interval, offset) < 0)
	 { RETURN_ERROR (-1);
	 }
	return (1);
}

setupRate (fxnName, td, interval, offset)
char *fxnName;
RCI_DESC *td;
int interval, offset;
{
	register RCI_TCB *tcb = td->tcb;

	if (interval <= 0 || offset < 0)
  	 { errorMsg (ERange, badRateValues, fxnName, interval, offset);
	   return (-1);
	 }
	if (tcb->controlMode == ACTIVE)
	 {
	   tcb->newInterval = interval;
	   tcb->newOffset = offset % interval;
	   tcb->nrateReq = YES;
	 }
	else
	 { tcb->interval = interval;
	   tcb->offset = offset % interval;
	 }
	return (1);
}

rciTimeout (td, blkCount, lagCount, lagWindow)
RCI_DESC *td;
int blkCount, lagCount, lagWindow;
{
	char *fxnName = "rciTimeout()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (setupTimeout (fxnName, td, blkCount, lagCount, lagWindow) < 0)
	 { RETURN_ERROR (-1);
	 }
	return (1);
}

setupTimeout (fxnName, td, blkCount, lagCount, lagWindow)
char *fxnName;
RCI_DESC *td;
int blkCount, lagCount, lagWindow;
{
	register RCI_TCB *tcb = td->tcb;

	if (blkCount >= 0)
	 { tcb->maxBlkCount = blkCount;
	 }
	else if (blkCount == DEFAULTVALUE)
	 { tcb->maxBlkCount = DEFAULT_BLK_COUNT;
	 }

	if (lagCount >= 0)
	 { tcb->maxLagCount = lagCount;
	 }
	else if (lagCount == DEFAULTVALUE)
	 { tcb->maxLagCount = DEFAULT_LAG_COUNT;
	 }

	if (lagWindow >= 1)
	 { tcb->lagWindow = lagWindow;
	 }
	else if (lagWindow == DEFAULTVALUE)
	 { tcb->lagWindow = DEFAULT_LAG_WINDOW;
	 }

	return (1);
}

rciControlFxns (td, startup, control, release, arg)
RCI_DESC *td;
int (*startup)();
int (*control)();
int (*release)();
int arg;
{
	char *fxnName = "rciControlFxns()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (setupControlFxns(fxnName, td, startup, control, release, arg) < 0)
	 { RETURN_ERROR (-1);
	 }
	return (1);
}

setupControlFxns (fxnName, td, startup, control, release, arg)
char *fxnName;
RCI_DESC *td;
int (*startup)();
int (*control)();
int (*release)();
int arg;
{
	register RCI_TCB *tcb = td->tcb;

	if (tcb->controlMode == ACTIVE)
	 { errorMsg (ETaskActive, taskIsActive, fxnName);
	   return (-1);
	 }
	if (startup && !(validControlText (startup)))
	 { errorMsg (ERange, badFxnPtr, fxnName, startup, "startup");
	   return (-1);
	 }
	if (control && !(validControlText (control)))
	 { errorMsg (ERange, badFxnPtr, fxnName, control, "control");
	   return (-1);
	 }
	if (release && !(validControlText (release)))
	 { errorMsg (ERange, badFxnPtr, fxnName, release, "release");
	   return (-1);
	 }

	tcb->startupFxn = startup;
	tcb->controlFxn = control;
	tcb->releaseFxn = release;
	tcb->controlArg = arg;

	return (1);
}

rciAllocDevice (td, devAddr, access)
RCI_DESC *td;
struct devAddr *devAddr;
int access;
{
	char *fxnName = "rciAllocDevice()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (setupDevice(fxnName, td, devAddr, access)<0)
	 { RETURN_ERROR (-1);
	 }
	return (1);
}

rciDeallocDevice (td)
RCI_DESC *td;
{
	char *fxnName = "rciDeallocDevice()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (td->devAttached)
	 { deallocIOdevice (td->devAttached);
	   td->devAttached = 0;
	   return (1);
	 }
	else
	 { return (0);
	 }
}


setupDevice (fxnName, td, devAddr, access)
char *fxnName;
RCI_DESC *td;
struct devAddr *devAddr;
int access;
{
	IO_DEVICE dev;
	int status;
	
	if (td->tcb->controlMode == ACTIVE)
	 { errorMsg (ETaskActive, taskIsActive, fxnName);
	   return (-1);
	 }
	if (td->devAttached)
	 { deallocIOdevice (td->devAttached);
	   td->devAttached = 0;
	 }
	if ((status = allocIOdevice (&dev, devAddr, access)) < 0)
	 { errorMsg (getErrorCode(0), cantAllocDev, fxnName);
	   return (-1);
	 }
	if (status == 0)
	 { errorMsg (EBusy, deviceIsBusy, fxnName,
			    devAddr->name, devAddr->address);
	   return (-1);
	 }
	dev.defined = YES;		/* this line probably obsolete */
	*(IO_DEVICE*)td->dev = dev;
	td->devAttached = status;
	return (1);
}

#define MONITOR_TIMEOUT	1000000	/* spin out; also defined in loadtask.c */
#define MONITOR_NAPTIME	0.01	/* wait for monitor at .01 sec. intervals */
#define MSEC_PER_SEC	1000	/* 1000 msec. per second */

monitorTimeoutTime(tcb)
RCI_TCB *tcb;
{
	/* Try to intelligently compute a timeout count based 
	   on the length of time we block for and whatever rate
	   or timeout parameters have been specified for the task */

	int fiveSecondCount;
	int rateCount;

	fiveSecondCount = 5 / MONITOR_NAPTIME;
	if (tcb->interval > 0 && tcb->maxBlkCount > 0)
	 { rateCount = (tcb->interval*tcb->maxBlkCount)
		       / (MSEC_PER_SEC * MONITOR_NAPTIME);

	   return (MAX(fiveSecondCount, rateCount));
	 }
	else
	 { return (fiveSecondCount);
	 }
}	

rciExecute (td, fxn, arg, ret)
RCI_DESC *td;
int (*fxn)();
int arg;
int *ret;
{
	RCI_TCB *tcb = td->tcb;
	char *fxnName = "rciExecute()";

	int k;

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (fxn && !(validControlText (fxn)))
	 { errorMsg (ERange, badFxnPtr, fxnName, fxn, "execute");
	   RETURN_ERROR (-1);
	 }

	tcb->executeArg = arg;
	tcb->executeFxn = fxn;

	if (td->cpu == ARBITER_CPU)
	 { if (td->signalNumber)
	    { blockRciSignals();
	      monitorRun (signalTaskQueue);
	      unblockRciSignals();
	    }
	   else
	    { if (arbMonitorRun() < 0)
	       { errorMsg (EInternal, cantExecArbMon, fxnName);
		 RETURN_ERROR (-1);
	       }
	    }
	 }

	k = monitorTimeoutTime (tcb);
	while (tcb->executeFxn && --k)
	 { nap (MONITOR_NAPTIME);
	 }
	if (k == 0)
	 { errorMsg (EInternal, noMonResponse, fxnName, TASKNAME(td->taskID));
	   RETURN_ERROR (-1);
	 }
	
	if (ret != NULL)
	 { *ret = tcb->executeRet;
	 }
	return (1);	
}

rciBlock (td)
RCI_DESC *td;
{
	RCI_TCB *tcb = td->tcb;
	char *fxnName = "rciBlock()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (tcb->controlMode == ACTIVE)
	 { tcb->blockReq = 1;
	   while (tcb->blockReq && tcb->controlMode == ACTIVE)
	    { nap(0.01);
	    }
	 }
	return (1);
}

extern INTERDEV *schedulerInterruptDev();

rciStart (taskMask)
unsigned long taskMask;
{
	register int k, id;
	register unsigned long mask;
	int arbiterTaskSpecified;
	int signalTaskSpecified;
	unsigned long previousActiveArbiterTasks;

	char *fxnName = "rciStart()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
#ifdef sun
	sunTouchMemoryHack();	/* XXX needed because Sun's #$@#&^% mlock is */
			/* busted!!!! */
#endif
	taskMask &= ((1<<rciNumTasks)-1) & ~1;
	previousActiveArbiterTasks = activeArbiterTasks;

	/* now go through the indicated tasks, perform sanity checking, 
	   and make a list of thoses tasks that have to be started */

	arbiterTaskSpecified = 0;
	signalTaskSpecified = 0;

	id = 0;
 	for (mask = taskMask; mask; mask >>= 1)
	 { if (mask & 1)
	    { RCI_DESC *td = &rciTaskTable[id];
	      RCI_TCB *tcb = td->tcb;

	      if (tcb->controlMode == IDLE)
	       { if (tcb->scheduleDisp == UNDEF)
		  { errorMsg (ENoSpecify, noSchedDisp, fxnName, TASKNAME(id));
		    RETURN_ERROR (-1);
		  }
		 if (tcb->scheduleDisp == ON_CLOCK ||
		     tcb->scheduleDisp == ON_TRIGGER)
		  { if (tcb->interval == UNDEF || tcb->offset == UNDEF)
		     { errorMsg (ENoSpecify, noRateInfo,fxnName,TASKNAME(id));
		       RETURN_ERROR (-1);
		     }
		  }

		 tcb->newInterval = tcb->interval;
		 tcb->newOffset = tcb->offset;
		 tcb->nrateReq = YES;

		 if (td->cpu == ARBITER_CPU)
		  { 	    
		    if (td->signalNumber)
		     { signalTaskSpecified = YES;
		     }
		    else
		     { arbiterTaskSpecified = YES;
		     }
		  }
	       }
	      else
	       { taskMask &= ~(1<<id);	/* forget about the task */
	       }	      
	    }
	   id++;
	 }

	/* Now execute all the startup functions, and tell the things to
	   start right away if they are ON_FUNCTION or ON_SIGNAL */

	id = 0;
	for (mask = taskMask; mask; mask >>= 1)
	 { if (mask & 1)
	    { RCI_TCB *tcb = rciTaskTable[id].tcb;
	      if (tcb->scheduleDisp == ON_FUNCTION ||
		  tcb->scheduleDisp == ON_SIGNAL)
	       { tcb->cmodeReq = SET_ACTIVE_GO;
	       }
	      else
	       { tcb->cmodeReq = SET_ACTIVE_WAIT;
	       }
	    }
	   id++;
	 }

	if (arbiterTaskSpecified)
	 { if (arbMonitorRun() < 0)
	    { errorMsg (EInternal, cantExecArbMon, fxnName);
	      RETURN_ERROR (-1);
	    }
	 }
	if (signalTaskSpecified)
	 { blockRciSignals();
	   monitorRun (signalTaskQueue);
	   unblockRciSignals();
	 }

	/* ---- wait for the startup functions to finish ---- */

	k = MONITOR_TIMEOUT;
	id = 0;
	for (mask = taskMask; mask; mask >>= 1)
	 { if (mask & 1)
	    { while (rciTaskTable[id].tcb->cmodeReq && --k)
		 ;
	      if (k == 0)
	       { errorMsg (EInternal, noMonResponse, fxnName, TASKNAME(id));
		 RETURN_ERROR (-1);
	       }
	    }
	   id++;
	 }

	/* ---- now start up all the tasks ---- */

	 { int cpu;
	   struct startTasksMsg msg;
	   extern char moncomCmd[];

	   for (cpu=0; cpu<MAX_CPUS; cpu++)
	    { msg.activate[cpu] = 0;
	    }

	   id = 0;
	   for (mask = taskMask; mask; mask >>= 1)
	    { if (mask & 1)
	       { RCI_DESC *td = &rciTaskTable[id];
		 
		 if (td->tcb->scheduleDisp == ON_CLOCK ||
		     td->tcb->scheduleDisp == ON_TRIGGER)
		  { td->tcb->cmodeReq = SET_ACTIVE_SYNC;
		    msg.activate[td->cpu] = 1;
		  }
	       }
	      id++;
	    }
	   PUT_MSG (msg, startTasksMsg, ARBITER_CPU);

	   moncomCmd[ARBITER_CPU] = MON_START_TASKS;

	   if (arbMonitorCommand () < 0)
	    { errorMsg (EInternal,
	      "%s trouble trying to start tasks 0x%x\n", fxnName, taskMask);
	      RETURN_ERROR (-1);
	    }
	 }

	/* ---- wait for the tasks to respond ---- */

	k = MONITOR_TIMEOUT;
	id = 0;
	for (mask = taskMask; mask; mask >>= 1)
	 { if (mask & 1)
	    { while (rciTaskTable[id].tcb->controlMode != ACTIVE && --k)
		 ;
	      if (k == 0)
	       { errorMsg (EInternal, noMonResponse, fxnName, TASKNAME(id));
		 RETURN_ERROR (-1);
	       }
	      if (rciTaskTable[id].cpu == ARBITER_CPU &&
		  !rciTaskTable[id].signalNumber)
	       { activeArbiterTasks |= (1<<id);
	       }
	    }
	   id++;
	 }

	if (activeArbiterTasks && !previousActiveArbiterTasks)
	 { if (arbMonitorHeartbeat (1) < 0)
	    { errorMsg (EInternal, noHeartbeatOn, fxnName);
	      RETURN_ERROR (-1);
	    }
	 }

	return (1);
}

rciRelease (taskMask)
unsigned long taskMask;
{
	register int k, id;
	register unsigned long mask;
	int arbiterTaskSpecified;
	int signalTaskSpecified;
	unsigned long previousActiveArbiterTasks;

	char *fxnName = "rciRelease()";

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	taskMask &= ((1<<rciNumTasks)-1) & ~1;
	previousActiveArbiterTasks = activeArbiterTasks;

	/* now go through the indicated tasks, perform sanity checking, 
	   and make a list of thoses tasks that have to be released */

	arbiterTaskSpecified = 0;
	signalTaskSpecified = 0;

	id = 0;
 	for (mask = taskMask; mask; mask >>= 1)
	 { if (mask & 1)
	    { RCI_DESC *td = &rciTaskTable[id];
	      RCI_TCB *tcb = td->tcb;

	      if (tcb->controlMode == ACTIVE)
	       { if (td->cpu == ARBITER_CPU)
		  { if (td->signalNumber)
		     { signalTaskSpecified = YES;
		     }
		    else
		     { arbiterTaskSpecified = YES;
		     }
		  }
	       }
	      else
	       { taskMask &= ~(1<<id);	/* forget about the task */
	       }	      
	    }
	   id++;
	 }

	/* Now turn off the requested tasks */

	id = 0;
	for (mask = taskMask; mask; mask >>= 1)
	 { if (mask & 1)
	    { rciTaskTable[id].tcb->cmodeReq = SET_IDLE;
	    }
	   id++;
	 }

	if (arbiterTaskSpecified)
	 { if (arbMonitorRun() < 0)
	    { errorMsg (EInternal, cantExecArbMon, fxnName);
	      RETURN_ERROR (-1);
	    }
	 }
	if (signalTaskSpecified)
	 { blockRciSignals();
	   monitorRun (signalTaskQueue);
	   unblockRciSignals();
	 }

	/* ---- wait for the monitors to respond ---- */

	k = MONITOR_TIMEOUT;
	id = 0;
	for (mask = taskMask; mask; mask >>= 1)
	 { if (mask & 1)
	    { while (rciTaskTable[id].tcb->controlMode != IDLE)
		 ;
	      if (k == 0)
	       { errorMsg (EInternal, noMonResponse, fxnName, TASKNAME(id));
		 RETURN_ERROR (-1);
	       }
	      if (rciTaskTable[id].cpu == ARBITER_CPU &&
		  !rciTaskTable[id].signalNumber)
	       { activeArbiterTasks &= ~(1<<id);
	       }
	    }
	   id++;
	 }

	if (previousActiveArbiterTasks && !activeArbiterTasks)
	 { if (arbMonitorHeartbeat (0) < 0)
	    { errorMsg (EInternal, noHeartbeatOff, fxnName);
	      RETURN_ERROR (-1);
	    }
	 }
	/* MS Not sure why this is on there, could be based on earlier
	   versions parent death automatically killed child.  No longer
	   the case with the __clone command */

	rciHostClose();
	return (1);
}

abortRelease()
{
	int id, k;
	char *fxnName = "abortRelease()";
	int arbiterTaskPresent = 0;
	int signalTaskPresent = 0;

	for (id=1; id<rciNumTasks; id++)
	 { RCI_DESC *td = &rciTaskTable[id];

	   if (td->tcb->controlMode == ACTIVE && td->cpu == ARBITER_CPU)
	    { if (td->signalNumber)
	       { signalTaskPresent = YES;
	       }
	      else
	       { arbiterTaskPresent = YES;
	       }
	    }
	 }

	if (arbiterTaskPresent)
	 { if (arbMonitorRun() < 0)
	    { errorMsg (EInternal, cantExecArbMon, fxnName);
	      return (-1);
	    }
	 }
	if (signalTaskPresent)
	 { blockRciSignals();
	   monitorRun (signalTaskQueue);
	   unblockRciSignals();
	 }


	k = MONITOR_TIMEOUT;
	for (id=1; id<rciNumTasks; id++)
	 { RCI_TCB *tcb = rciTaskTable[id].tcb;

	   while (tcb->controlMode == ACTIVE && --k)
	      ;
	   if (k == 0)
	    { errorMsg (EInternal,
	      "%s timeout waiting for task %d (cpu %d)\n",
	      id, rciTaskTable[id].cpu);
	      return (-1);
	    }
	 }

	if (activeArbiterTasks)
	 { activeArbiterTasks = 0;
	   if (arbMonitorHeartbeat (0) < 0)
	    { errorMsg (EInternal, noHeartbeatOff, fxnName);
	      return (-1);
	    }
	 }

	for (id=1; id<rciNumTasks; id++)
	 { RCI_DESC *td = &rciTaskTable[id];

	   /* clear the request flags */

	   td->tcb->cmodeReq = 0;
	   td->tcb->abortReq = 0;
	 }
	return (1);
}

validControlData (addr)
void **addr;
{
#if !defined(VXWORKS_CFG) && !defined(SGI_CFG) && !defined(SIMONLY_CFG)
	extern char _RCId_begin;
	extern char _RCId_end;

	if (&_RCId_begin > (char *)addr || &_RCId_end <= (char *)addr)
	 { return (0);
	 }
#else
	if (addr == NULL)
	 { return (0);
	 }
#endif
	return(1);
}

validControlText (addr)
void **addr;
{
#if !defined(VXWORKS_CFG) && !defined(SGI_CFG) && !defined(SIMONLY_CFG)
	extern char _RCIt_begin;
	extern char _RCIt_end;

	if (&_RCIt_begin > (char *)addr || &_RCIt_end <= (char *)addr)
	 { return (0);
	 }
#else
	if (addr == NULL)
	 { return (0);
	 }
#endif
	return(1);
}
