#include <u.h>
#include <libc.h>
#include "time.h"

char *	T = "10s";
char *	D = "5s";
char *	C = "1.5s";
char *	S = nil;
char *	s = "250ms";
char *	R = "";
int		verbose, debug, tset, dset, cset, sset;
int		nproc = 1;

uvlong v;

char *clonedev = "#R/realtime/clone";
char missstr[] = "sys: deadline miss: runtime";

int notefd;
int
rthandler(void*, char *s)
{
	static int umpteenth;

	if (!umpteenth++)
		fprint(2, "note received: %s\n", s);
	if (strncmp(missstr, s, strlen(missstr)) == 0)
		return 1;

	/* On any other note */
	if (fprint(notefd, "remove") < 0)
		sysfatal("Could not remove task: %r");
	sysfatal("Removed task");
	return 1;
}

static int
schedpars(char *period, char *deadline, char *cost)
{
	int fd;

	if ((fd = open(clonedev, ORDWR)) < 0) 
		sysfatal("%s: %r", clonedev);

	fprint(2, "T=%s D=%s C=%s procs=%d resources=%q %sadmit\n",
		period, deadline, cost, getpid(), R, verbose?"verbose ":"");
	if (fprint(fd, "T=%s D=%s C=%s procs=%d resources=%q %sadmit",
		period, deadline, cost, getpid(), R, verbose?"verbose ":"") < 0)
			sysfatal("%s: %r", clonedev);
	notefd = fd;
	atnotify(rthandler, 1);
	return fd;
}

static void
usage(void)
{
	fprint(2, "Usage: %s [-T period] [-D deadline] [-D cost] [-S sleepinterval] [-s sleeptime] [-R resources] [-v]\n", argv0);
	exits(nil);
}

void
main(int argc, char *argv[])
{
	Time sleepinterval;
	Time sleeptime;
	Time now, when;
	int i, j, fd;
	char *e;

	quotefmtinstall();

	ARGBEGIN {
	case 'T':
		T = EARGF(usage());
		tset++;
		break;
	case 'D':
		D = EARGF(usage());
		dset++;
		break;
	case 'C':
		C = EARGF(usage());
		cset++;
		break;
	case 'S':
		S = EARGF(usage());
		break;
	case 's':
		s = EARGF(usage());
		sset++;
		break;
	case 'R':
		R = EARGF(usage());
		break;
	case 'n':
		nproc = atoi(EARGF(usage()));
		if (nproc <= 0 || nproc > 10)
			sysfatal("%d processes?", nproc);
		break;
	case 'v':
		verbose++;
		break;
	case 'd':
		debug++;
		break;
	default:
		usage();
	}
	ARGEND;

	if (S){
		if (e = parsetime(&sleepinterval, S))
			sysfatal("%s: Sleep interval: %s\n", argv0, e);
		if (e = parsetime(&sleeptime, s))
			sysfatal("%s: Sleep time: %s\n", argv0, e);
	}

	sleeptime /= 1000000;
	if (S && sleeptime == 0)
		sysfatal("%s: Sleep time too small\n", argv0);

	if (tset && !dset) D = T;

	fd = schedpars(T, D, C);

	for (j = 1; j < nproc; j++){
		switch(fork()){
		case -1:
			sysfatal("fork: %r");
		case 0:
			fprint(2, "procs+=%d\n", getpid());
			if (fprint(fd, "procs+=%d", getpid()) < 0)
			sysfatal("%s: %r", clonedev);
			for (;;){
				for(i = 0; i < 10000; i++)
					v+=1LL;
				if (S){
					now = nsec();
					if (now >= when){
						sleep((long)sleeptime);
						when = now + sleepinterval;
					}
				}
			}
		default:
			break;
		}
	}
	when = nsec() + sleepinterval;
	for (;;){
		for(i = 0; i < 100000; i++)
			v+=1LL;
		if (verbose)
			fprint(2, ".");
		if (S){
			now = nsec();
			if (now >= when){
				sleep((long)sleeptime);
				when = now + sleepinterval;
			}
		}
	}
}
