#ifdef SGI_CFG

#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/schedctl.h>
#include <sys/time.h>
#include <sys/lock.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <signal.h>

#define HIGH_PRI	1

#define TIMER_BEAT	1
#define TIMER_AST	2
#define TASK_EXEC	3

int timerCount;
int beatCount;
int beatPeriod;
int astCount;

#define READ_CHAN	0
#define WRITE_CHAN	1

int timerControlPipe[2];
int controlTimerPipe[2];
int planControlPipe[2];
int controlPlanPipe[2];

int (*beatFxn)();
int beatArg;
int (*astFxn)();
int astArg;
int (*taskFxn)();
int taskArg;

int planPid;
int controlPid;
int timerPid;

int exitSig = SIGCLD;

timer()
{
	char com = 0;

	timerCount++;
	if (beatCount && beatCount <= timerCount)
	 { com |= TIMER_BEAT;
	   beatCount += beatPeriod;
	 }
	if (astCount && astCount <= timerCount)
	 { com |= TIMER_AST;
	   astCount = 0;
	 }
	if (com)
	 { write (timerControlPipe[WRITE_CHAN], &com, 1);
	 }
}

setAstFxn(time, fxn, arg)
int time;
int (*fxn)();
int arg;
{
	char com;

	blockproc(timerPid);
	if (fxn)
	 { if (time <= timerCount)
	    { com = TIMER_AST;
	      write (timerControlPipe[WRITE_CHAN], &com, 1);
	    }
	   else
	    { astCount = time;
	    }
	   astFxn = fxn;
	   astArg = arg;
	 }
	else
	 { astCount = 0;
	 }
	unblockproc(timerPid);
}

setBeatFxn(period, fxn, arg)
int period;
int (*fxn)();
int arg;
{
	char com;

	blockproc(timerPid);
	if (fxn)
	 { beatCount = timerCount + period;
	   beatPeriod = period;
	   beatFxn = fxn;
	   beatArg = arg;
	 }
	else
	 { beatCount = 0;
	 }
	unblockproc(timerPid);
}

timerTask()
{
	struct itimerval tval;
	char ack;
	printf ("starting timer task\n");

#if HIGH_PRI
	if (schedctl(NDPRI, 0, NDPHIMIN-1) < 0)
	 { perror("timer task -- schedctl:");
	 }
#endif
	prctl (PR_RESIDENT);
/*	prctl (PR_SETEXITSIG); */
	signal (SIGALRM, timer);

	tval.it_value.tv_sec = 0;
	tval.it_value.tv_usec = 10000;
	tval.it_interval = tval.it_value;
	setitimer (ITIMER_REAL, &tval, (struct itimerval*)0);

	while (timerCount == 0)
	 { select (0, (fd_set*)0, (fd_set*)0, (fd_set*)0, (struct timeval*)0);
	 }
	ack = 1;
	write (timerControlPipe[WRITE_CHAN], &ack, 1);
	while (1)
	 { pause();
	 }

}

controlTask()
{
	fd_set rfds;
	char ack = 1;
	char com;
	struct itimerval tval;

	printf ("starting controlTask\n");
	
	if (plock(PROCLOCK) < 0)
	 { perror("control task -- plock:");
	   exit (-1);
	 }
#if HIGH_PRI
	if (schedctl(NDPRI, 0, NDPHIMIN) < 0)
	 { perror("control task -- schedctl:");
	   exit (-1);
	 }
#endif
	prctl (PR_RESIDENT);
/*	prctl (PR_SETEXITSIG); */

	if ((timerPid = sproc(timerTask, PR_SADDR|PR_SID|PR_SFDS, 0)) < 0)
	 { perror("control task -- sproc:");
	   exit (-1);
	 }
	/* NEED timeout ? */
	read (timerControlPipe[READ_CHAN], &ack, 1);
	write (controlPlanPipe[WRITE_CHAN], &ack, 1);

	while(1)
	 { int n;
	   FD_ZERO (&rfds);
	   FD_SET (planControlPipe[READ_CHAN], &rfds);
	   FD_SET (timerControlPipe[READ_CHAN], &rfds);
	   if ((n = select (FD_SETSIZE, &rfds, (fd_set*)0, (fd_set*)0, 
					(struct timerval*)0)) < 0)
	    { perror ("control task -- select:");
	      exit (-1);
	    }
	   if (n > 0)
	    { int (*fxn)();
	      int arg;
	      
	      if (FD_ISSET(timerControlPipe[READ_CHAN], &rfds))
	       { read (timerControlPipe[READ_CHAN], &com, 1);
		 if (com & TIMER_AST)
		  { if (fxn = astFxn)
		     { arg = astArg;
		       astFxn = 0;
		       (*fxn)(arg);
		     }
		  }
		 if (com & TIMER_BEAT)
		  { if (beatFxn)
		     { (*beatFxn)(beatArg);
		     }
		  }
	       }
	      if (FD_ISSET(planControlPipe[READ_CHAN], &rfds))
	       { read (planControlPipe[READ_CHAN], &com, 1);
		 if (com == TASK_EXEC)
		  { if (fxn = taskFxn)
		     { arg = taskArg;
		       taskFxn = 0;
		       (*fxn)(arg);
		     }
		  }
		 write (controlPlanPipe[WRITE_CHAN], &ack, 1);
	       }
	    }
	 }
}

typedef struct xyd {
  unsigned char id[0x40];
  unsigned char unused1[0x40];
  unsigned char intin;
  unsigned char csr;
#define XYD_RED       0x01
#define XYD_RED_ON    0x00
#define XYD_RED_OFF   0x01
#define XYD_GREEN     0x02
#define XYD_GREEN_ON  0x02
#define XYD_GREEN_OFF 0x00
#define XYD_INTPEND   0x04
#define XYD_INTENB    0x08
#define XYD_RESET     0x10
#define XYD_USER      0xe0
  unsigned char intpend;
  unsigned char intmask;
  unsigned char intclear;
  unsigned char vector;
  unsigned char out;
  unsigned char dirs;
  unsigned char ports[8];
  unsigned char unused2[0x370];
  } XYD;

XYD *xyd;

char *memdev = "/dev/mmem";
#define XYDBASE 0x9000

monitorRunTime;

monitor()
{
	/* set a bit indicating that we are here. */

	/* SET BIT */

	xyd->ports[4] ^= 0x1;

	monitorRunTime += 2;
	setAstFxn (monitorRunTime, monitor, 0);
/*	printf ("monitor %d 0x%x\n", timerCount, xyd->ports[4]); */
}

beat()
{
	/* set a bit indicating that we are here. */

	/* SET BIT */

	xyd->ports[5] ^= 0x1;
}

main()
{
	/* Create a sub-task, lock it into memory, give it a high
	   priority, and then have it do something every few clock ticks */

	int sid;
	int k, i;
	sigset_t set, oset;
	int cnt = 0;
	char ack;
	char *addr;
	int fd;
	
	fd = open(memdev,O_RDWR,0);
	if (fd < 0)
	 { perror(memdev);
	   exit(1);
	 }
#if 0
	addr = (char*)mmap(0,0x10000,PROT_READ|PROT_WRITE,MAP_PRIVATE,
			     fd,0xbd000000);
	if (addr == (void *)-1)
	 { perror("mmap");
	   exit(1);
	 }
	xyd = (XYD *)(addr+XYDBASE);
	xyd->dirs = 0xf2;
#endif
	if (pipe(planControlPipe) < 0)
	 { perror ("plan -- plan control pipe:");
	   exit (-1);
	 }
	if (pipe(controlPlanPipe) < 0)
	 { perror ("plan -- control plan pipe:");
	   exit (-1);
	 }
	if (pipe(timerControlPipe) < 0)
	 { perror ("plan -- timer control pipe:");
	   exit (-1);
	 }
	if (pipe(controlTimerPipe) < 0)
	 { perror ("plan -- control timer pipe:");
	   exit (-1);
	 }

	prctl (PR_SETEXITSIG, exitSig);
	planPid = getpid();
	if ((controlPid = sproc(controlTask,PR_SADDR|PR_SID|PR_SFDS, 0)) < 0)
	 { perror("sproc:");
	 }
	/* NEED timeout ? */
	read (controlPlanPipe[READ_CHAN], &ack, 1);

	setBeatFxn (10, beat, 0);
	runTaskFxn (monitor, 0);

	while(1)
	 { pause();
	 }
}

runTaskFxn(fxn, arg)
int (*fxn)();
int arg;
{
	char com, ack;

	taskFxn = fxn;
	taskArg = arg;
	com = TASK_EXEC;
	write (planControlPipe[WRITE_CHAN], &com, 1);
	read (controlPlanPipe[READ_CHAN], &ack, 1);
}

nap(sec)
float sec;
{
	struct timeval tv;

	tv.tv_sec = sec;
	tv.tv_usec = (sec-tv.tv_sec)*1e6;
	select (FD_SETSIZE, (fd_set*)0, (fd_set*)0, (fd_set*)0, &tv);
}

#endif
