#include "../h/local.h"

#ifdef  SCCS_ID
static char SCCS_ID [] = "@(#)clock.c    	3.1.2.2	 18:41:36 - 83/02/15 ";
#endif  SCCS_ID

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/callo.h"
#include "../h/seg.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/reg.h"

#define	SCHMAG	8/10

#ifdef PROF_KERNEL
int	sysprof[2176];
#endif
/*
 * clock is called straight from
 * the real time clock interrupt.
 *
 * Functions:
 *	reprime clock
 *	copy *switches to display
 *	implement callouts
 *	maintain user/system times
 *	maintain date
 *	profile
 *	lightning bolt wakeup (every second)
 *	alarm clock signals
 *	jab the scheduler
 */

#ifdef DEC
clock(dev, sp, r1, nps, r0, pc, ps)
#else
clock(dev, stat, r0, r1, r2, r3, r4, r5, r6, asp, rf, ps, pc, nps)
#endif
dev_t dev;
caddr_t pc;
{
	register struct callo *p1, *p2;
	register struct proc *pp;
	int a;
	extern caddr_t waitloc;
#ifndef DEC
	static int clkflag;
#endif

#ifdef DEC
	/*
	 * restart clock
	 */

	lks->r[0] = 0115;
#endif

	/*
	 * display register
	 */

#ifdef DEC
	display();
#else
	display(pc);
#endif
	/*
	 * callouts
	 * if none, just continue
	 * else update first non-zero time
	 */

	if(callout[0].c_func == NULL)
		goto out;
	p2 = &callout[0];
	while(p2->c_time<=0 && p2->c_func!=NULL)
		p2++;
	p2->c_time--;

	/*
	 * if ps is high, just return
	 */
#ifdef DEC
	if (BASEPRI(ps))
#else
	if (clkflag)
#endif
		goto out;

	/*
	 * callout
	 */

	spl5();
	if(callout[0].c_time <= 0) {
		p1 = &callout[0];
		while(p1->c_func != 0 && p1->c_time <= 0) {
			(*p1->c_func)(p1->c_arg);
			p1++;
		}
		p2 = &callout[0];
		while(p2->c_func = p1->c_func) {
			p2->c_time = p1->c_time;
			p2->c_arg = p1->c_arg;
			p1++;
			p2++;
		}
	}

	/*
	 * lightning bolt time-out
	 * and time of day
	 */
out:
#ifdef DEC
	a = dk_busy&07;
#else
	a = dk_busy&0xf;
#endif
	if (USERMODE(ps)) {
		u.u_utime++;
		if(u.u_prof.pr_scale)
			addupc(pc, &u.u_prof, 1);
		if(u.u_procp->p_nice > NZERO)
#ifdef DEC
			a += 8;
#else
			a += 16;
#endif
	} else {
#ifdef DEC
		a += 16;
#else
		a += 32;
#endif
		if (pc == waitloc)
#ifdef DEC
			a += 8;
#else
			a += 16;
#endif
#ifdef PROF_KERNEL
		else
			sysprof[(unsigned)pc >> 5]++;
#endif
		u.u_stime++;
	}
	dk_time[a] += 1;
	pp = u.u_procp;
#ifdef DEC
	if(++pp->p_cpu == 0)
#else
	if(++pp->p_cpu > 255)
#endif
		pp->p_cpu--;
	if(++lbolt >= HZ) {
#ifdef DEC
		if (BASEPRI(ps))
#else
		if (clkflag)
#endif
			return;
		lbolt -= HZ;
		++time;
#ifdef DEC
		spl1();
#else
		clkflag = 1;
		spl0();
#endif
		runrun++;
		wakeup((caddr_t)&lbolt);
		for(pp = &proc[0]; pp < procNPROC; pp++)
		if (pp->p_stat && pp->p_stat<SZOMB) {
			if(pp->p_time != 127)
				pp->p_time++;
			if(pp->p_clktim)
				if(--pp->p_clktim == 0)
#ifdef SVC6
					{ if (pp->p_wchan == &pp->p_clktim)
						wakeup(&pp->p_clktim);
					else
						psignal(pp, SIGCLK);
					}
#else
					psignal(pp, SIGCLK);
#endif
			a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
			if(a < 0)
				a = 0;
			if(a > 255)
				a = 255;
			pp->p_cpu = a;
			if(pp->p_pri >= PUSER)
				setpri(pp);
		}
		if(runin!=0) {
			runin = 0;
			wakeup((caddr_t)&runin);
		}
#ifndef DEC
		clkflag = 0;
#endif
	}
}

/*
 * timeout is called to arrange that
 * fun(arg) is called in tim/HZ seconds.
 * An entry is sorted into the callout
 * structure. The time in each structure
 * entry is the number of HZ's more
 * than the previous entry.
 * In this way, decrementing the
 * first entry has the effect of
 * updating all entries.
 *
 * The panic is there because there is nothing
 * intelligent to be done if an entry won't fit.
 */
timeout(fun, arg, tim)
int (*fun)();
caddr_t arg;
{
	register struct callo *p1, *p2;
	register int t;
	int s;

	t = tim;
	p1 = &callout[0];
	s = spl7();
	while(p1->c_func != 0 && p1->c_time <= t) {
		t -= p1->c_time;
		p1++;
	}
	if (p1 >= &calloutNCALL[-1])
		panic("Timeout table overflow");
	p1->c_time -= t;
	p2 = p1;
	while(p2->c_func != 0)
		p2++;
	while(p2 >= p1) {
		(p2+1)->c_time = p2->c_time;
		(p2+1)->c_func = p2->c_func;
		(p2+1)->c_arg = p2->c_arg;
		p2--;
	}
	p1->c_time = t;
	p1->c_func = fun;
	p1->c_arg = arg;
	splx(s);
}
