File:  [MW Coherent from dump] / coherent / d / 286_KERNEL / USRSRC / coh / clock.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* $Header: /var/lib/cvsd/repos/coherent/coherent/d/286_KERNEL/USRSRC/coh/clock.c,v 1.1.1.1 2019/05/29 04:56:39 root Exp $ */
/* (lgl-
 *	The information contained herein is a trade secret of Mark Williams
 *	Company, and  is confidential information.  It is provided  under a
 *	license agreement,  and may be  copied or disclosed  only under the
 *	terms of  that agreement.  Any  reproduction or disclosure  of this
 *	material without the express written authorization of Mark Williams
 *	Company or persuant to the license agreement is unlawful.
 *
 *	COHERENT Version 2.3.37
 *	Copyright (c) 1982, 1983, 1984.
 *	An unpublished work by Mark Williams Company, Chicago.
 *	All rights reserved.
 -lgl) */
/*
 * Coherent.
 * Clock.
 * The clock comes in two parts.  There is the routine `clock' which
 * gets called every tick at high priority.  It does the minimum it
 * can and returns as soon as possible.  The second routine, `stand',
 * gets called whenever we are about to return from an interrupt to
 * user mode a low priority.  It can look at flags that the clock set
 * and do the things the clock really wanted to do but didn't have time.
 * Stand is truly the kernel of the system.
 *
 * 90/08/13	Hal Snyder		/usr/src/sys/coh/clock.c
 * Add external altclk to allow polled device drivers.
 * (extern'ed in coherent.h)
 * 
 * 87/10/26	Allan cornish		/usr/src/sys/coh/clock.c
 * Timed functions are now invoked with TIM * tp as second argument.
 * This facilitates the use of timed functions within loadable drivers.
 *
 * 87/07/07	Allan Cornish		/usr/src/sys/coh/clock.c
 * Clocks static variable added - incremented by clock, decremented by stand().
 * Lbolt variable added - clock ticks since startup - incremented by stand().
 * Support for multiple timing queues ported from RTX.
 *
 * 87/01/05	Allan Cornish		/usr/src/sys/coh/clock.c
 * stand() now only wakes &stimer if swap timer is active.
 *
 * 86/11/24	Allan Cornish		/usr/src/sys/coh/clock.c
 * Added support for new t_last field in tim struct.
 *
 * 86/11/19	Allan Cornish		/usr/src/sys/coh/clock.c
 * Stand() calls defend() to execute functions deferred from interrupt level.
 */
#include <sys/coherent.h>
#include <sys/con.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/stat.h>
#include <sys/timeout.h>
#include <sys/uproc.h>
#include <sys/mdata.h>

int (*altclk)();	/* pointer to higher-speed clock function */
int altsel;	/* if nonzero, CS for LOADABLE driver owning altclk() */

static int clocks;

/*
 * This routine is called once every tick (1/HZ seconds).
 * It gets called with the programme counter that was interrupted
 * a flag telling whether we were in user or kernel mode and the
 * previous priority we were in.
 */
clock(pc, umode)
vaddr_t pc;
{
	register PROC *pp;
	/*
	 * Ignore clock interrupts till we are ready.
	 */
	if (batflag == 0)
		return;

	/*
	 * Hook for alternate clock interrupt;
	 * Call polling function ("altclk") if there is one.
	 *
	 * For near function, "altsel" is 0 and "altclk" is offset.
	 * For far function, "altsel" is the CS selector and "altclk"
	 * is the offset.
	 *
	 * Since the polling function ends with a near rather than
	 * far return, far invocation is via ld_call() (ldas.s) which uses
	 * the despatch routine at CS:4 (ld.s) in any loadable driver.
	 */
	if (altclk) {
		if (altsel) {	/* will do far call to altclk fn */
			if (ld_call(altsel, altclk))
				return;
		} else
			if ((*altclk)())
				return;
	}

	/*
	 * Update timers.  Decrement time slice.
	 */
	utimer += 1;
	clocks += 1;
	timer.t_tick += 1;
	quantum -= 1;

	/*
	 * Give processes their schedule values per tick.
	 */
	if (procq.p_lforw->p_cval > CVCLOCK) {
		procq.p_lforw->p_cval -= CVCLOCK;
		procq.p_cval += CVCLOCK;
	}

	/*
	 * Tax current process and update his times.
	 */
	pp = SELF;
	pp->p_cval >>= 1;
	if (umode == 0)
		pp->p_stime++;
	else {
		pp->p_utime++;
		u.u_ppc = pc;
	}
}

/*
 * Do everything the clock wanted to do but couldn't as it would have
 * taken too long.
 * Also perform any system bookkeeping required at regular intervals.
 */
stand()
{
	int s;

	u.u_error = 0;

	/*
	 * Update the clock.
	 */
	while (timer.t_tick >= HZ) {
		timer.t_time++;
		timer.t_tick -= HZ;
		outflag = 1;
	}

	/*
	 * Check expiration of quantum.
	 */
	if (quantum <= 0) {
		quantum = 0;
		disflag = 1;
	}

	/*
	 * Check the timed function queue if necessary.
	 */
	if ( clocks > 0 )
	do {
		register TIM * np;
		register TIM * tp;

		/*
		 * Update [serviced] clock ticks since startup.
		 */
		lbolt++;

		/*
		 * Remove timing list from queue, creating new temporary queue.
		 */
		tp = (TIM *) &timq[ lbolt % nel(timq) ];
		s  = sphi();

		/*
		 * Scan timing list.
		 */
		for ( np = tp->t_next; tp = np; ) {

			/*
			 * Remember next function in timing list.
			 * NOTE: Must be done before function is invoked,
			 *	 since it may start a new timer.
			 */
			np = tp->t_next;

			/*
			 * Function has not timed out: leave it on timing list.
			 */
			if ( tp->t_lbolt != lbolt )
				continue;

			/*
			 * Remove function from timing list.
			 */
			if ( tp->t_last->t_next = tp->t_next )
				tp->t_next->t_last = tp->t_last;
			tp->t_last = NULL;

			/*
			 * Invoke function.
			 */
			spl(s);
			(*tp->t_func)( tp->t_farg, tp );
			sphi();
		}

		spl( s );

	} while ( --clocks > 0 );

	/*
	 * Timeout any devices.
	 */
	if (outflag) {
		register int n;

		outflag = 0;
		for (n=0; n<drvn; n++) {
			if (drvl[n].d_time == 0)
				continue;
			s = sphi();
			dtime((dev_t)makedev(n, 0));
			spl(s);
		}
	}

	/*
	 * Do profiling.
	 */
	if (u.u_pscale != 0) {
		register unsigned p;
		register vaddr_t a;

		p = u.u_pscale;
		a = (int *)u.u_pbase +
		    pscale(u.u_ppc-u.u_pofft, p/sizeof (int));
		if (a < u.u_pbend)
			putuwd(a, getuwd(a)+1);
	}

	/*
	 * Check for signals and execute them.
	 */
	if (SELF->p_ssig)
		actvsig();

	/*
	 * Execute deferred functions.
	 */
	defend();

	/*
	 * Should we dispatch?
	 */
	if ((SELF->p_flags&PFDISP) != 0) {
		SELF->p_flags &= ~PFDISP;
		disflag = 1;
		if ( stimer.t_last != 0 )
			wakeup((char *)&stimer);
	}

#ifdef QWAKEUP
	/*
	 * Dispatch pending wakeups.
	 */
	while (ntowake)
		wakeup2();

#endif
	/*
	 * Redispatch.
	 * This used to be a function call in tsave,
	 * expanded in line here.
	 */
	if (disflag) {
		register PROC *pp;

#ifndef QWAKEUP
		s=sphi();
#endif
		if ((pp=SELF)!=iprocp)
			setrun(pp);
		dispatch();
#ifndef QWAKEUP
		spl(s);
#endif
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.