~kris/9p

9hist

fec5850e4249b1f81830724a442eadc9206a4db0 — David du Colombier 35 years ago 77899d5
Plan 9 from Bell Labs 1990-10-04
M gnot/clock.c => gnot/clock.c +6 -8
@@ 102,7 102,8 @@ clock(Ureg *ur)
	p = m->proc;
	if(p){
		p->pc = ur->pc;
		p->time[p->insyscall]++;
		if (p->state==Running)
			p->time[p->insyscall]++;
	}
	if(canlock(&m->alarmlock)){
		if(m->alarm){


@@ 127,12 128,9 @@ clock(Ureg *ur)
	}
	kbdclock();
	mouseclock();
	if((ur->sr&SPL(7)) == 0){
		spllo();
		if(p && p->state==Running){
			checksched();
			if(u->nnote && (ur->sr&SUPER)==0)
				notify(ur);
		}
	if((ur->sr&SPL(7)) == 0 && p && p->state==Running){
		sched();
		if(u->nnote && (ur->sr&SUPER)==0)
			notify(ur);
	}
}

M gnot/dat.h => gnot/dat.h +21 -1
@@ 101,7 101,7 @@ struct Chan
	Mount	*mnt;			/* mount point that derived Chan */
	ulong	mountid;
	int	fid;			/* for devmnt */
	union{
	union {
		Stream	*stream;	/* for stream channels */
		void	*aux;
	};


@@ 205,9 205,11 @@ struct KMap
struct Mach
{
	int	machno;			/* physical id of processor */
	ulong	splpc;			/* pc of last caller to splhi */
	int	mmask;			/* 1<<m->machno */
	ulong	ticks;			/* of the clock since boot time */
	Proc	*proc;			/* current process on this processor */
	Proc	*lproc;			/* last process on this processor */
	Label	sched;			/* scheduler wakeup */
	Lock	alarmlock;		/* access to alarm list */
	void	*alarm;			/* alarms bound to this clock */


@@ 316,6 318,7 @@ struct Proc
	Proc	*qnext;			/* next process on queue for a QLock */
	QLock	*qlock;			/* address of qlock being queued for DEBUG */
	int	state;
	int	spin;			/* spinning instead of unscheduled */
	Page	*upage;			/* BUG: should be unlinked from page list */
	Seg	seg[NSEG];
	ulong	bssend;			/* initial top of bss seg */


@@ 340,6 343,20 @@ struct Proc
	Rendez	sleep;			/* place for tsleep and syssleep */
	int	wokeup;			/* whether sleep was interrupted */
	ulong	pc;			/* DEBUG only */
	int	kp;			/* true if a kernel process */
};

struct MMU
{
	ulong	va;
	ulong	pa;
};

#define NMMU 16
struct MMUCache
{
	ulong	next;
	MMU	mmu[NMMU];
};

#define	NERR	15


@@ 365,6 382,7 @@ struct User
	short	nnote;
	short	notified;		/* sysnoted is due */
	int	(*notify)(void*, char*);
	MMUCache mc;
	void	*ureg;
};



@@ 565,3 583,5 @@ extern	Dev	devtab[];
extern	char	devchar[];
extern	FPsave	initfp;
extern	Mach	mach0;

extern  void	(*kprofp)(ulong);

M gnot/devdk.c => gnot/devdk.c +8 -13
@@ 499,6 499,14 @@ dkmuxconfig(Dk *dp, Block *bp)
	dp->csc = c;

	/*
	 *  tell datakit we've rebooted. It should close all channels.
	 */
	if(dp->restart) {
		DPRINT("dkmuxconfig: restart %s\n", dp->name);
		dkmesg(dp, T_ALIVE, D_RESTART, 0, 0);
	}

	/*
	 *  start a process to deal with it
	 */
	sprint(buf, "csc.%s.%d", dp->name, dp->ncsc);


@@ 1100,9 1108,7 @@ dklisten(Chan *c)
		n = streamread(dc, dialstr, sizeof(dialstr)-1);
		DPRINT("returns %d\n", n);
		if(n <= 0)
{print("bad n\n");
			error(0, Eio);
}
		dialstr[n] = 0;
		DPRINT("dialstr = %s\n", dialstr);



@@ 1112,7 1118,6 @@ dklisten(Chan *c)
		n = getfields(dialstr, line, 12, '\n');
		if (n < 2) {
			DPRINT("bad dialstr from dk (1 line)\n");
print("bad dialstr %d '%s'\n", n, dialstr);
			error(0, Eio);
		}



@@ 1319,16 1324,6 @@ dkcsckproc(void *a)
	dp = (Dk *)a;

	/*
	 *  tell datakit we've rebooted. It should close all channels.
	 */
	if(dp->restart) {
		DPRINT("dkcsckproc: restart %s\n", dp->name);
		dkmesg(dp, T_ALIVE, D_RESTART, 0, 0);
	}
	DPRINT("dkcsckproc: closeall %s\n", dp->name);
	dkmesg(dp, T_CHG, D_CLOSEALL, 0, 0);

	/*
	 *  loop forever listening
	 */
	for(;;){

M gnot/fns.h => gnot/fns.h +2 -2
@@ 81,7 81,6 @@ void	kmapinit(void);
KMap	*kmap(Page*);
int	kprint(char*, ...);
void	kproc(char*, void(*)(void*), void*);
void	kproftimer(ulong);
void	kunmap(KMap*);
void	lock(Lock*);
void	lockinit(void);


@@ 136,7 135,7 @@ void	qlock(QLock*);
void	qunlock(QLock*);
void	restartprint(Alarm*);
void	restfpregs(FPsave*);
Proc	*runproc(void);
void	restore(void);
void	savefpregs(FPsave*);
void	sched(void);
void	schedinit(void);


@@ 151,6 150,7 @@ void	sleep(Rendez*, int(*)(void*), void*);
int	splhi(void);
int	spllo(void);
void	splx(int);
void	spldone(void);
Devgen	streamgen;
void	streamclose(Chan*);
int	streamenter(Stream*);

M gnot/l.s => gnot/l.s +5 -0
@@ 45,6 45,8 @@ TEXT	touser(SB), $-4

TEXT	splhi(SB), $0

	MOVL	m(SB), A0
	MOVL	(A7), 4(A0)
	MOVL	$0, R0
	MOVW	SR, R0
	MOVW	$(SUPER|SPL(7)), SR


@@ 63,6 65,9 @@ TEXT	splx(SB), $0
	MOVW	R0, SR
	RTS

TEXT	spldone(SB), $0

	RTS

TEXT	flushcpucache(SB), $0


M gnot/main.c => gnot/main.c +3 -7
@@ 101,11 101,7 @@ init0(void)
{
	Chan *c;

	u->nerrlab = 0;
	m->proc = u->p;
	u->p->state = Running;
	u->p->mach = m;
	spllo();
	restore();
	chandevinit();
	
	u->slash = (*devtab[0].attach)(0);


@@ 139,14 135,13 @@ userinit(void)
	p->pgrp = newpgrp();
	strcpy(p->text, "*init*");
	strcpy(p->pgrp->user, protouser);
	p->fpstate = FPinit;

	/*
	 * Kernel Stack
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = USERADDR+BY2PG-20;	/* BUG */
	p->sched.sr = SUPER|SPL(7);
	p->sched.sr = SUPER|SPL(0);
	p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF));

	/*


@@ 180,6 175,7 @@ userinit(void)
	s->minva = UTZERO;
	s->maxva = UTZERO+BY2PG;

	m->proc = p;
	ready(p);
}


M gnot/mmu.c => gnot/mmu.c +46 -4
@@ 19,15 19,37 @@ void
mapstack(Proc *p)
{
	ulong tlbvirt, tlbphys;
	ulong i;
	ulong next;
	MMU *mm, *mn, *me;

	if(p->upage->va != (USERADDR|(p->pid&0xFFFF)))
		panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va);
	tlbvirt = USERADDR;
	tlbphys = PPN(p->upage->pa) | PTEVALID | PTEKERNEL;
	putkmmu(tlbvirt, tlbphys);
	flushmmu();
	u = (User*)USERADDR;

	/*
	 *  if not a kernel process and this process was not the 
	 *  last process on this machine, flush & preload mmu
	 */
	if(!p->kp && p!=m->lproc){
		flushmmu();

		/*
		 *  preload the MMU with the last (up to) NMMU user entries
		 *  previously faulted into it for this process.
		 */
		mn = &u->mc.mmu[u->mc.next&(NMMU-1)];
		me = &u->mc.mmu[NMMU];
		if(u->mc.next >= NMMU){
			for(mm = mn; mm < me; mm++)
				UMAP[mm->va] = mm->pa;
		}
		for(mm = u->mc.mmu; mm < mn; mm++)
			UMAP[mm->va] = mm->pa;

		m->lproc = p;
	}
}

void


@@ 45,7 67,19 @@ putmmu(ulong tlbvirt, ulong tlbphys)
	if(tlbvirt&KZERO)
		panic("putmmu");
	tlbphys |= VTAG(tlbvirt)<<24;
	UMAP[(tlbvirt&0x003FE000L)>>2] = tlbphys;
	tlbvirt = (tlbvirt&0x003FE000L)>>2;
	if(u){
		MMU *mp;
		int s;

		s = splhi();
		mp = &(u->mc.mmu[u->mc.next&(NMMU-1)]);
		mp->pa = tlbphys;
		mp->va = tlbvirt;
		u->mc.next++;
		splx(s);
	}
	UMAP[tlbvirt] = tlbphys;
}

void


@@ 57,6 91,14 @@ flushmmu(void)
}

void
clearmmucache(void)
{
	if(u == 0)
		panic("flushmmucache");
	u->mc.next = 0;
}

void
kmapinit(void)
{
	KMap *k;

M gnot/proc.c => gnot/proc.c +197 -108
@@ 43,91 43,206 @@ char *statename[]={	/* BUG: generate automatically */
	"Broken",
};

int page_alloc(int);	/* !ORIG */
void page_free(int, int);

/*
 * Always splhi()'ed.
 * Called as the last routine in main().  Wait for a process on the run queue, grab it,
 * and run it.  Note that in this routine the interrupts are enabled for the first time.
 */
void
schedinit(void)		/* never returns */
{
	Proc *p;

	/*
	 * At init time:  wait for a process on the run queue.
	 */
	for (;;) {
		spllo();
		while (runq.head == 0)
			/* idle loop */;
		splhi();
		lock(&runq);
		if (runq.head != 0)
			break;
		unlock(&runq);
	}

	/*
	 * Set the u pointer and leave it there.  In fact, it might as well be a define.
	 */
	u = (User *) USERADDR;

	/*
	 * For later rescheduling.  Jumped to by sched() on stack switch.
	 */
	setlabel(&m->sched);
	if(u){
		m->proc = 0;
		p = u->p;
		putkmmu(USERADDR, INVALIDPTE);	/* safety first */
		u = 0;
		if(p->state == Running)
			ready(p);
		else if(p->state == Moribund){
			p->pid = 0;
			unlock(&p->debug);
			p->upage->ref--;
			/* procalloc already locked */
			p->qnext = procalloc.free;
			procalloc.free = p;
			p->upage = 0;
			unlock(&procalloc);
			p->state = Dead;
		}
		p->mach = 0;

	/*
	 * Take a process from the run queue.  The run queue is locked here, and guaranteed
	 * to have a process on it.
	 */
	p = runq.head;
	if ((runq.head = p->rnext) == 0)
		runq.tail = 0;
	unlock(&runq);

	/*
	 * Ok, here we go.  We have a process and we can start running.
	 */
	mapstack(p);
	gotolabel(&p->sched);
}

/*
 * Complete the restoring of a process after mapstack().  The interrupt level here is low.
 * However, since the process is not Running, it cannot be rescheduled at this point.  We
 * set the process state to Running.  If the previous process was dead, clean it up.
 */
void
restore(void)
{
	Proc *p = m->proc;	/* previous process */

	u->p->mach = m;
	m->proc = u->p;
	u->p->state = Running;
	if (p->state == Moribund) {
		p->pid = 0;
		unlock(&p->debug);		/* set in pexit */
		p->upage->ref--;
		p->upage = 0;
		p->qnext = procalloc.free;
		procalloc.free = p;
		unlock(&procalloc);		/* set in pexit */
		p->state = Dead;
	}
	sched();
}

/*
 * Save part of the process state.  Note: this is not the counterpart of restore().
 */
void
save(Balu *balu)
{
	fpsave(&u->fpsave);
	if (u->fpsave.type) {
		if(u->fpsave.size > sizeof u->fpsave.junk)
			panic("fpsize %d max %d\n", u->fpsave.size, sizeof u->fpsave.junk);
		fpregsave(u->fpsave.reg);
		u->p->fpstate = FPactive;
		m->fpstate = FPdirty;
	}
	if (BALU->cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(balu, BALU, sizeof *balu);
	else {
		balu->cr0 = 0xFFFFFFFF;
		BALU->cr0 = 0xFFFFFFFF;
	}
}

/*
 * Reschedule the process.  We do not know whether the interrupt level is low or high
 * here, but we set it to low in any case.  If there is no other process to run, and
 * this process is Running, return immediately.  If this process is blocked, and there
 * is no other process to run, keep spinning until either this process or another
 * process becomes runnable.  If it was this process, we can return immediately.
 */
void
sched(void)
{
	Proc *p;
	ulong tlbvirt, tlbphys;
	Proc *p = u->p;
	long initfp;
	Balu balu;
	int saved = 0;

	if(u){
		splhi();
	/*
	 * Record that the process is spinning instead of blocked.  Ready() uses this
	 * information to decide what to do with the process.
	 */
	p->spin = 1;

		fpsave(&u->fpsave);
		if(u->fpsave.type){
			if(u->fpsave.size > sizeof u->fpsave.junk)
				panic("fpsize %d max %d\n", u->fpsave.size, sizeof u->fpsave.junk);
			fpregsave(u->fpsave.reg);
			u->p->fpstate = FPactive;
			m->fpstate = FPdirty;
		}
		if(BALU->cr0 != 0xFFFFFFFF)	/* balu busy */
			memcpy(&balu, BALU, sizeof balu);
		else{
			balu.cr0 = 0xFFFFFFFF;
			BALU->cr0 = 0xFFFFFFFF;
		}
		if(setlabel(&u->p->sched)){	/* woke up */
if(u->p->mach)panic("mach non zero");
			p = u->p;
			p->state = Running;
			p->mach = m;
			m->proc = p;
			if(p->fpstate != m->fpstate){
				if(p->fpstate == FPinit){
					u->p->fpstate = FPinit;
					fprestore(&initfp);
					m->fpstate = FPinit;
				}else{
					fpregrestore(u->fpsave.reg);
					fprestore(&u->fpsave);
					m->fpstate = FPdirty;
				}
	/*
	 * Look for a new process to be run.
	 */
	for (;;) {
		spllo();

		/*
		 * Idle loop.  Return when this process becomes runnable.  If nothing else
		 * to do, start saving some of the process state.
		 */
		while (runq.head == 0)
			if (p->state == Running)
				return;
			else if (!saved) {
				save(&balu);
				saved = 1;
			}
			if(balu.cr0 != 0xFFFFFFFF)	/* balu busy */
				memcpy(BALU, &balu, sizeof balu);
			spllo();
			return;
		}
		gotolabel(&m->sched);
	
		/*
		 * Disable clock interrupts so that there will be no rescheduling in this
		 * section (on this machine).  If there is still a process on the run
		 * queue, break out of this loop.
		 */
		splhi();
		lock(&runq);
		if (runq.head != 0)
			break;
		unlock(&runq);
	}
	p->spin = 0;

	/*
	 * The first process on the run queue is the process we are going to run.  First
	 * save our state before we jump to schedinit.  If this process was running, put
	 * it on the run queue.
	 */
	if (p->state == Running) {
		p->state = Ready;
		p->rnext = 0;
		runq.tail->rnext = p;
		runq.tail = p;
	}

	/*
	 * Save some process state (if we haven't done that already) and save/restore
	 * pc and sp.  We have to jump to schedinit() because we are going to remap the
	 * stack.
	 */
	if (!saved)
		save(&balu);
	if (setlabel(&p->sched) == 0)
		gotolabel(&m->sched);

	/*
	 * Interrupts are ok now.  Note that the process state is still not Running,
	 * so no rescheduling.
	 */
	spllo();
	p = runproc();
	splhi();
	mapstack(p);
	gotolabel(&p->sched);

	/*
	 * Jumped to by schedinit.  Restore the process state.
	 */
	if (p->fpstate != m->fpstate)
		if (p->fpstate == FPinit) {
			initfp = 0;
			fprestore((FPsave *) &initfp);
			m->fpstate = FPinit;
		}
		else {
			fpregrestore(u->fpsave.reg);
			fprestore(&u->fpsave);
			m->fpstate = FPdirty;
		}
	if (balu.cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(BALU, &balu, sizeof balu);

	/*
	 * Complete restoring the process.
	 */
	restore();
}

void


@@ 135,6 250,10 @@ ready(Proc *p)
{
	int s;

	if (p->spin) {
		p->state = Running;
		return;
	}
	s = splhi();
	lock(&runq);
	p->rnext = 0;


@@ 148,42 267,6 @@ ready(Proc *p)
	splx(s);
}

void
checksched(void)		/* just for efficiency; don't sched if no need */
{
	if(runq.head)
		sched();
}

/*
 * Always called spllo
 */
Proc*
runproc(void)
{
	Proc *p;

loop:
	do; while(runq.head == 0);
	splhi();
	lock(&runq);
	p = runq.head;
	if(p==0 || p->mach){	/* p->mach==0 only when process state is saved */
		unlock(&runq);
		spllo();
		goto loop;
	}
	if(p->rnext == 0)
		runq.tail = 0;
	runq.head = p->rnext;
	if(p->state != Ready)
		print("runproc %s %d %s\n", p->text, p->pid, statename[p->state]);
	unlock(&runq);
	p->state = Scheding;
	spllo();
	return p;
}

Proc*
newproc(void)
{


@@ 204,6 287,7 @@ loop:
		p->child = 0;
		p->exiting = 0;
		p->fpstate = FPinit;
		p->kp = 0;
		memset(p->seg, 0, sizeof p->seg);
		lock(&pidalloc);
		p->pid = ++pidalloc.pid;


@@ 530,6 614,12 @@ pexit(char *s, int freemem)
	lock(&procalloc);	/* sched() can't do this */
	lock(&c->debug);	/* sched() can't do this */
	c->state = Moribund;

	/*
	 * Call the scheduler.  This process gets cleaned up in restore() by the next
	 * process that runs.  That means that if there is no other process, we'll
	 * hang around for a little while.
	 */
	sched();	/* never returns */
}



@@ 582,7 672,8 @@ proctab(int i)
}

#include <ureg.h>
DEBUG()
void
DEBUG(void)
{
	int i;
	Proc *p;


@@ 612,15 703,16 @@ kproc(char *name, void (*func)(void *), void *arg)
	 * Kernel stack
	 */
	p = newproc();
	p->kp = 1;
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));
	k = kmap(p->upage);
	upa = VA(k);
	up = (User*)upa;
	up->p = p;

	/*
	 * Save time: only copy u-> data and useful stack
	 */
	clearmmucache();
	memcpy(up, u, sizeof(User));
	n = USERADDR+BY2PG - (ulong)&lastvar;
	n = (n+32) & ~(BY2WD-1);	/* be safe & word align */


@@ 633,17 725,14 @@ kproc(char *name, void (*func)(void *), void *arg)
	for(n=0; n<=up->maxfd; n++)
		up->fd[n] = 0;
	up->maxfd = 0;
	up->p = p;
	kunmap(k);

	/*
	 * Sched
	 */
	if(setlabel(&p->sched)){
		u->p = p;
		p->state = Running;
		p->mach = m;
		m->proc = p;
		spllo();
		restore();
		(*func)(arg);
		pexit(0, 1);
	}

M gnot/screen.c => gnot/screen.c +5 -2
@@ 24,6 24,8 @@ void	duartinit(void);
int	duartacr;
int	duartimr;

void	(*kprofp)(ulong);

GBitmap	gscreen =
{
	(ulong*)((4*1024*1024-256*1024)|KZERO),	/* BUG */


@@ 287,7 289,7 @@ duartbreak(int ms)
}

enum{
	Kptime=200		/* about once per ms */
	Kptime=200
};
void
duartstarttimer(void)


@@ 349,7 351,8 @@ duartintr(Ureg *ur)
	 * Is it 0?
	 */
	if(cause & IM_CRDY){
/*		kproftimer(ur->pc);/**/
		if(kprofp)
			(*kprofp)(ur->pc);
		c = duart[1].scc_ropbc;
		duart[0].ctur = (Kptime)>>8;
		duart[0].ctlr = (Kptime)&255;

M gnot/sturp.c => gnot/sturp.c +14 -8
@@ 11,7 11,7 @@ enum {
	Nmask=		0x7,
};

#define DPRINT if(q->flag&QDEBUG)kprint
#define DPRINT if(q->flag&QDEBUG)print

typedef struct Urp	Urp;



@@ 33,7 33,7 @@ struct urpstat {
} urpstat;

struct Urp {
	QLock;
	Lock;
	short	state;		/* flags */
	Rendez	r;		/* process waiting for close */



@@ 140,10 140,10 @@ urpopen(Queue *q, Stream *s)
	 *  find a free urp structure
	 */
	for(up = urp; up < &urp[conf.nurp]; up++){
		qlock(up);
		lock(up);
		if(up->state == 0)
			break;
		qunlock(up);
		unlock(up);
	}
	if(up == &urp[conf.nurp]){
		q->ptr = 0;


@@ 155,7 155,7 @@ urpopen(Queue *q, Stream *s)
	up->rq = q;
	up->wq = q->other;
	up->state = OPEN;
	qunlock(up);
	unlock(up);
	initinput(up, 0);
	initoutput(up, 0);



@@ 236,7 236,10 @@ urpclose(Queue *q)
	while(up->kstarted)
		sleep(&up->r, isdead, up);

	lock(up);
	up->state = 0;
	up->rq = 0;
	unlock(up);
}

/*


@@ 990,15 993,18 @@ urptimer(Alarm *a)
{
	Urp *up;
	Urp *last;
	Queue *q;

	cancel(a);
	alarm(500, urptimer, 0);
	for(up = urp, last = &urp[conf.nurp]; up < last; up++){
		if(up->state==0)
			continue;
		if(up->rq && todo(up))
			wakeup(&up->rq->r);
		if(up->rq && canlock(up)){
			if(up->rq && NOW>up->timer
			   && ((up->state&INITING) || up->unechoed!=up->next))
				wakeup(&up->rq->r);
			unlock(up);
		}
	}
}


M gnot/sysproc.c => gnot/sysproc.c +5 -5
@@ 41,6 41,7 @@ sysfork(ulong *arg)
	/*
	 * Save time: only copy u-> data and useful stack
	 */
	clearmmucache();
	memcpy((void*)upa, u, sizeof(User));
	n = USERADDR+BY2PG - (ulong)&lastvar;
	n = (n+32) & ~(BY2WD-1);	/* be safe & word align */


@@ 128,11 129,8 @@ sysfork(ulong *arg)
	 * Sched
	 */
	if(setlabel(&p->sched)){
		u->p = p;
		p->state = Running;
		p->mach = m;
		m->proc = p;
		spllo();
		clearmmucache();
		restore();
		return 0;
	}
	p->pop = u->p;


@@ 147,6 145,7 @@ sysfork(ulong *arg)
	memcpy(p->text, u->p->text, NAMELEN);
	ready(p);
	flushmmu();
	clearmmucache();
	return pid;
}



@@ 361,6 360,7 @@ sysexec(ulong *arg)
	unlock(o);

	flushmmu();
	clearmmucache();
	((Ureg*)UREGADDR)->pc = exec.entry;
	sp = (ulong*)(USTKTOP - ssize);
	*--sp = nargs;

M port/devdk.c => port/devdk.c +8 -10
@@ 499,6 499,14 @@ dkmuxconfig(Dk *dp, Block *bp)
	dp->csc = c;

	/*
	 *  tell datakit we've rebooted. It should close all channels.
	 */
	if(dp->restart) {
		DPRINT("dkmuxconfig: restart %s\n", dp->name);
		dkmesg(dp, T_ALIVE, D_RESTART, 0, 0);
	}

	/*
	 *  start a process to deal with it
	 */
	sprint(buf, "csc.%s.%d", dp->name, dp->ncsc);


@@ 1316,16 1324,6 @@ dkcsckproc(void *a)
	dp = (Dk *)a;

	/*
	 *  tell datakit we've rebooted. It should close all channels.
	 */
	if(dp->restart) {
		DPRINT("dkcsckproc: restart %s\n", dp->name);
		dkmesg(dp, T_ALIVE, D_RESTART, 0, 0);
	}
	DPRINT("dkcsckproc: closeall %s\n", dp->name);
	dkmesg(dp, T_CHG, D_CLOSEALL, 0, 0);

	/*
	 *  loop forever listening
	 */
	for(;;){

M port/devkprof.c => port/devkprof.c +9 -1
@@ 30,9 30,12 @@ Dirtab kproftab[Nkproftab]={
	"kpstop",	Kprofstopqid,		0,		0600,
};

void kproftimer(ulong);

void
kprofreset(void)
{
	kprofp = kproftimer;
}

void


@@ 157,7 160,12 @@ kprofwrite(Chan *c, char *a, long n)
void
kproftimer(ulong pc)
{
	extern ulong splpc;
	/*
	 *  if the pc is coming out of slplo pr splx, then use
	 *  the pc saved when we went splhi.
	 */
	if(pc>=(ulong)spllo && pc<=(ulong)spldone)
		pc = m->splpc;

	timerbuf[0]++;
	if(KTZERO<=pc && pc<KTZERO+MAXPC){

M port/devmnt.c => port/devmnt.c +1 -4
@@ 747,11 747,8 @@ mntxmit(Mnt *m, Mnthdr *mh)
	/*
	 * Copy out on read
	 */
	if(mh->thdr.type == Tread){
		if(mh->rhdr.count>497 && mh->rhdr.data[497]==011)
			print("*497==11 %lux\n", &mh->rhdr.data[497]);
	if(mh->thdr.type == Tread)
		memcpy(mh->thdr.data, mh->rhdr.data, mh->rhdr.count);
	}
	mbfree(mh->mbr);
	mbfree(mbw);
	poperror();

M port/sturp.c => port/sturp.c +27 -14
@@ 33,7 33,7 @@ struct urpstat {
} urpstat;

struct Urp {
	QLock;
	Lock;
	short	state;		/* flags */
	Rendez	r;		/* process waiting for close */



@@ 140,10 140,10 @@ urpopen(Queue *q, Stream *s)
	 *  find a free urp structure
	 */
	for(up = urp; up < &urp[conf.nurp]; up++){
		qlock(up);
		lock(up);
		if(up->state == 0)
			break;
		qunlock(up);
		unlock(up);
	}
	if(up == &urp[conf.nurp]){
		q->ptr = 0;


@@ 155,7 155,7 @@ urpopen(Queue *q, Stream *s)
	up->rq = q;
	up->wq = q->other;
	up->state = OPEN;
	qunlock(up);
	unlock(up);
	initinput(up, 0);
	initoutput(up, 0);



@@ 236,7 236,10 @@ urpclose(Queue *q)
	while(up->kstarted)
		sleep(&up->r, isdead, up);

	lock(up);
	up->state = 0;
	up->rq = 0;
	unlock(up);
}

/*


@@ 465,6 468,7 @@ urpiput(Queue *q, Block *bp)
	case ACK+4: case ACK+5: case ACK+6: case ACK+7:
	case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3:
	case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7:
		DPRINT("rACK %ux\n", ctl);
		rcvack(up, ctl);
		break;



@@ 695,15 699,18 @@ static void
sendctl(Urp *up, int ctl)
{
	Block *bp;
	Queue *q;

	if(QFULL(up->wq->next))
	q = up->wq;
	if(QFULL(q->next))
		return;
	bp = allocb(1);
	bp->wptr = bp->lim;
	bp->rptr = bp->lim-1;
	*bp->rptr = ctl;
	bp->flags |= S_DELIM;
	PUTNEXT(up->wq, bp);
	PUTNEXT(q, bp);
	DPRINT("sCTL %ulx\n", ctl);
}

/*


@@ 762,9 769,11 @@ sendblock(Urp *up, int bn)
{
	Block *bp, *m, *nbp;
	int n;
	Queue *q;

	q = up->wq;
	up->timer = NOW + MSrexmit;
	if(QFULL(up->wq->next))
	if(QFULL(q->next))
		return;

	/*


@@ 781,7 790,7 @@ sendblock(Urp *up, int bn)
	nbp->rptr = bp->rptr;
	nbp->wptr = bp->wptr;
	nbp->flags |= S_DELIM;
	PUTNEXT(up->wq, m);
	PUTNEXT(q, m);

	/*
	 *  message 2, the block length and the SEQ


@@ 794,7 803,8 @@ sendblock(Urp *up, int bn)
	m->rptr[1] = n;
	m->rptr[2] = n<<8;
	m->flags |= S_DELIM;
	PUTNEXT(up->wq, m);
	PUTNEXT(q, m);
	DPRINT("sb %d\n", bn);
}

/*


@@ 945,8 955,8 @@ todo(void *arg)
	return (up->state&INITING)
	? NOW>up->timer					/* time to INIT1 */
	: ((up->unechoed!=up->next && NOW>up->timer)	/* time to ENQ */
	  || WINDOW(up)>0 && up->next!=up->nxb
	  || (!QFULL(up->rq->next) && up->iseq!=(up->lastecho&7))); /* time to ECHO */
	  || (WINDOW(up)>0 && (up->next!=up->nxb || up->wq->first)) /* open xmit window */
	  || (up->iseq!=(up->lastecho&7) && !QFULL(up->rq->next))); /* time to ECHO */
}
static void
urpkproc(void *arg)


@@ 983,15 993,18 @@ urptimer(Alarm *a)
{
	Urp *up;
	Urp *last;
	Queue *q;

	cancel(a);
	alarm(500, urptimer, 0);
	for(up = urp, last = &urp[conf.nurp]; up < last; up++){
		if(up->state==0)
			continue;
		if(up->rq && todo(up))
			wakeup(&up->rq->r);
		if(up->rq && canlock(up)){
			if(up->rq && NOW>up->timer
			   && ((up->state&INITING) || up->unechoed!=up->next))
				wakeup(&up->rq->r);
			unlock(up);
		}
	}
}


M port/sysfile.c => port/sysfile.c +1 -1
@@ 181,7 181,7 @@ sysread(ulong *arg)
	long n;

	c = fdtochan(arg[0], 0);
	validaddr(arg[1], arg[2], 0);
	validaddr(arg[1], arg[2], 1);
	qlock(c);
	if(waserror()){
		qunlock(c);

M power/main.c => power/main.c +1 -2
@@ 121,7 121,6 @@ ioboardinit(void)
		maxlevel = 8;
		noforce = 0;
	}
	print("IO %d\n", ioid);

	/*
	 *  reset VME bus (MODEREG is on the IO2)


@@ 590,7 589,7 @@ confinit(void)
	/*
	 *  set minimal default values
	 */
	conf.nmach = 1;
	conf.nmach = 2;
	conf.nmod = 2000;
	conf.nalarm = 10000;
	conf.norig = 500;