~kris/9p

9hist

8d1caad4ecb2d4975953932ce0b9cdc4755eac23 — David du Colombier 36 years ago 4ab17bd
Plan 9 from Bell Labs 1990-03-21
M gnot/chan.c => gnot/chan.c +20 -10
@@ 149,7 149,7 @@ mount(Chan *new, Chan *old, int flag)
	Mtab *mt, *mz;
	Mount *mnt, *omnt, *nmnt, *pmnt;
	Pgrp *pg;
	int isnew;
	int islast;

	if(CHDIR & (old->qid^new->qid))
		error(0, Emount);


@@ 157,10 157,15 @@ mount(Chan *new, Chan *old, int flag)
		error(0, Emount);

	mz = 0;
	isnew = 0;
	islast = 0;
	mnt = 0;
	pg = u->p->pgrp;
	lock(pg);
	if(waserror()){
		if(mnt){
			mnt->c = 0;	/* caller will close new */
			closemount(mnt);
		}
		unlock(pg);
		nexterror();
	}


@@ 171,18 176,18 @@ mount(Chan *new, Chan *old, int flag)
	for(i=0; i<pg->nmtab; i++,mt++){
		if(mt->c==0 && mz==0)
			mz = mt;
		else if(eqchan(mt->c, old, CHDIR|QPATH))
		else if(eqchan(mt->c, old, CHDIR|QPATH)){
			mz = 0;
			goto Found;
		}
	}
	isnew = 1;
	if(mz == 0){
		if(i == conf.nmtab)
			error(0, Enomount);
		mz = &pg->mtab[i];
		pg->nmtab++;
		islast++;
	}
	mz->mnt = 0;
	mz->c = old;
	mt = mz;

    Found:


@@ 244,8 249,12 @@ mount(Chan *new, Chan *old, int flag)
	}

	incref(new);
	if(isnew)
	if(mz){
		mz->c = old;
		incref(old);
	}
	if(islast)
		pg->nmtab++;
	unlock(pg);
	poperror();
	return mnt->mountid;


@@ 286,7 295,7 @@ domount(Chan *c)
    Found:
	lock(pg);
	if(!eqchan(mt->c, c, CHDIR|QPATH)){	/* table changed underfoot */
		print("domount: changed underfoot?\n");
		pprint("domount: changed underfoot?\n");
		unlock(pg);
		return c;
	}


@@ 333,7 342,7 @@ walk(Chan *ac, char *name, int domnt)
			goto Notfound;
		}
		if(c->mountid != mnt->mountid){
			print("walk: changed underfoot?\n");
			pprint("walk: changed underfoot?\n");
			unlock(pg);
			goto Notfound;
		}


@@ 353,6 362,7 @@ walk(Chan *ac, char *name, int domnt)
		if(!first)
			close(c);
		nc->mnt = mnt;
		nc->mountid = mnt->mountid;
		c = nc;
		first = 0;
		goto Again;


@@ 391,7 401,7 @@ createdir(Chan *c)
	}
	mnt = c->mnt;
	if(c->mountid != mnt->mountid){
		print("createdir: changed underfoot?\n");
		pprint("createdir: changed underfoot?\n");
		error(0, Enocreate);
	}
	do{

M gnot/clock.c => gnot/clock.c +2 -1
@@ 117,9 117,10 @@ clock(Ureg *ur)
		}
		unlock(&m->alarmlock);
	}
	kbdclock();
	if((ur->sr&SPL(7)) == 0){
		spllo();
		if(p && p->state==Running)
			sched();
			checksched();
	}
}

M gnot/devcons.c => gnot/devcons.c +32 -3
@@ 30,9 30,15 @@ struct IOQ{
	Rendez	r;
};

IOQ	kbdq;		/* qlock to getc; interrupt putc's */
IOQ	lineq;		/* lock to getc; interrupt putc's */

struct{
	IOQ;		/* qlock to getc; interrupt putc's */
	int	c;
	int	repeat;
	int	count;
}kbdq;

void
printinit(void)
{


@@ 142,17 148,18 @@ pprint(char *fmt, ...)

	c = u->fd[2];
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
		return;
		return 0;
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);
	n = donprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	qlock(c);
	if(waserror()){
		qunlock(c);
		return;
		return 0;
	}
	(*devtab[c->type].write)(c, buf, n);
	c->offset += n;
	qunlock(c);
	poperror();
	return n;
}



@@ 185,9 192,15 @@ echo(int c)
 * Put character into read queue at interrupt time.
 * Always called splhi from proc 0.
 */

void
kbdchar(int c)
{
	if(kbdq.repeat == 1){
		kbdq.c = c;
		kbdq.count = 0;
		kbdq.repeat = 2;
	}
	if(c == '\r')
		c = '\n';
	echo(c);


@@ 198,6 211,22 @@ kbdchar(int c)
		wakeup(&kbdq.r);
}

void
kbdrepeat(int rep)
{
	if(rep)
		kbdq.repeat = 1;
	else
		kbdq.repeat = 0;
}

void
kbdclock(void)
{
	if(kbdq.repeat==2 && (++kbdq.count&1))
		kbdchar(kbdq.c);
}

int
consactive(void)
{

M gnot/devdk.c => gnot/devdk.c +2 -0
@@ 538,6 538,8 @@ Dirtab dksubdir[]={
void
dkreset(void)
{
	newqinfo(&dkmuxinfo);
	newqinfo(&urpinfo);
}

/*

M gnot/devincon.c => gnot/devincon.c +32 -26
@@ 23,8 23,9 @@ enum {
	Minstation=	2,	/* lowest station # to poll */
	Maxstation=	15,	/* highest station # to poll */
	Nincon=		1,	/* number of incons */
	Nin=		16,	/* Blocks in the input ring */
	Nin=		64,	/* Blocks in the input ring */
	Bsize=		128,	/* size of an input ring block */
	Mfifo=		0xff	/* a mask, must be 2^n-1, must be > Nin */
};

/*


@@ 631,7 632,7 @@ inconkproc(void *arg)
}

/*
 *  drop an input packet on the floor
 *  drop a single packet
 */
static void
droppacket(Device *dev)


@@ 639,17 640,24 @@ droppacket(Device *dev)
	int i;
	int c;

	screenputc('!');
	while(!(dev->status & RCV_EMPTY)){
		for(i = 0; i < 17; i++){
			c = dev->data_cntl;
			if(c==0)
				break;
		}
	for(i = 0; i < 17; i++){
		c = dev->data_cntl;
		if(c==0)
			break;
	}
}

/*
 *  flush the input fifo
 */
static void
flushfifo(Device *dev)
{
	while(!(dev->status & RCV_EMPTY))
		droppacket(dev);
}

/*
 *  advance the queue. if we've run out of staged input blocks,
 *  drop the packet and return 0.  otherwise return the next input
 *  block to fill.


@@ 657,19 665,20 @@ droppacket(Device *dev)
static Block *
nextin(Incon *ip, unsigned int c)
{
	Block *bp = ip->inb[ip->wi];
	Block *bp;
	int next;

	next = (ip->wi+1)%Nin;
	if(next == ip->ri){
		bp->wptr = bp->base+3;
		droppacket(ip->dev);
		return 0;
	}
	bp = ip->inb[ip->wi];
	bp->base[0] = ip->chan;
	bp->base[1] = ip->chan>>8;
	bp->base[2] = c;
	ip->wi = next;

	next = (ip->wi+3)%Nin;
	if(next == ip->ri){
		bp->wptr = bp->base+3;
		return bp;
	}
	ip->wi = (ip->wi+1)%Nin;

	return ip->inb[ip->wi];
}


@@ 690,8 699,8 @@ rdpackets(Incon *ip)
	dev = ip->dev;
	bp = ip->inb[ip->wi];
	if(bp==0){
		droppacket(ip->dev);
		goto done;
		flushfifo(ip->dev);
		return;
	}
	p = bp->wptr;
	while(!(dev->status & RCV_EMPTY)){


@@ 699,12 708,14 @@ rdpackets(Incon *ip)
		 *  get channel number
		 */
		c = (dev->data_cntl)>>8;
		if(c == 0){
			droppacket(dev);
			continue;
		}
		if(ip->chan != c){
			if(p - bp->rptr > 3){
				bp->wptr = p;
				bp = nextin(ip, 0);
				if(bp == 0)
					goto done;
				p = bp->wptr;
			}
			ip->chan = c;


@@ 725,8 736,6 @@ rdpackets(Incon *ip)
				 */
				bp->wptr = p;
				bp = nextin(ip, c);
				if(bp == 0)
					goto done;
				p = bp->wptr;
			} else {
				/* end of packet */


@@ 741,14 750,11 @@ rdpackets(Incon *ip)
		if(p + 16 > bp->lim){
			bp->wptr = p;
			bp = nextin(ip, 0);
			if(bp == 0)
				goto done;
			p = bp->wptr;
		}
	}	
	bp->wptr = p;

done:
	if(first != ip->wi)/**/
		wakeup(&ip->kr);
}

M gnot/fns.h => gnot/fns.h +4 -0
@@ 8,6 8,7 @@ int	canqlock(QLock*);
void	chaninit(void);
void	chandevreset(void);
void	chandevinit(void);
void	checksched(void);
void	clock(Ureg*);
Chan	*clone(Chan*, Chan*);
void	close(Chan*);


@@ 58,6 59,8 @@ int	incref(Ref*);
void	insert(List**, List*, List*);
void	isdir(Chan*);
void	kbdchar(int);
void	kbdrepeat(int);
void	kbdclock(void);
void	kproc(char*, void(*)(void*), void*);
void	lock(Lock*);
void	lockinit(void);


@@ 76,6 79,7 @@ Orig	*neworig(ulong, ulong, int, Chan*);
Page	*newpage(int, Orig*, ulong);
Pgrp	*newpgrp(void);
Proc	*newproc(void);
void	newqinfo(Qinfo*);
char	*nextelem(char*, char*);
void	nullput(Queue*, Block*);
int	openmode(ulong);

M gnot/main.c => gnot/main.c +5 -5
@@ 240,10 240,10 @@ confinit(void)
	conf.nmod = 50;
	conf.nalarm = 1000;
	conf.norig = 50;
	conf.nchan = 100;
	conf.nenv = 50;
	conf.nenvchar = 4000;
	conf.npgenv = 100;
	conf.nchan = 200;
	conf.nenv = 100;
	conf.nenvchar = 8000;
	conf.npgenv = 200;
	conf.nmtab = 50;
	conf.nmount = 100;
	conf.nmntdev = 5;


@@ 251,6 251,6 @@ confinit(void)
	conf.nmnthdr = 10;
	conf.nstream = 64;
	conf.nqueue = 5 * conf.nstream;
	conf.nblock = 16 * conf.nstream;
	conf.nblock = 32 * conf.nstream;
	conf.nsrv = 32;
}

M gnot/pgrp.c => gnot/pgrp.c +2 -1
@@ 122,7 122,8 @@ closemount(Mount *m)
{
	lock(m);
	if(m->ref == 1){
		close(m->c);
		if(m->c)
			close(m->c);
		if(m->next)
			closemount(m->next);
		unlock(m);

M gnot/proc.c => gnot/proc.c +7 -0
@@ 117,6 117,13 @@ ready(Proc *p)
	splx(s);
}

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

/*
 * Always called spllo
 */

M gnot/screen.c => gnot/screen.c +9 -5
@@ 161,11 161,15 @@ duartintr(void)
		c = duart->data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart->cmnd = RESET_ERR;
		if(c == 0x7F)
			c = 0xFF;	/* VIEW key (bizarre) */
		if(c & 0x80)
			c = keymap[c&0x7F];
		kbdchar(c);
		if(status & PAR_ERR) /* control word: caps lock (0x4) or repeat (0x10) */
			kbdrepeat((c&0x10) == 0);
		else{
			if(c == 0x7F)
				c = 0xFF;	/* VIEW key (bizarre) */
			if(c & 0x80)
				c = keymap[c&0x7F];
			kbdchar(c);
		}
	}
	/*
	 * Is it 2?

M gnot/stream.c => gnot/stream.c +33 -21
@@ 7,6 7,11 @@
#include	"errno.h"
#include	"devtab.h"

enum {
	Nclass=4,	/* number of block classes */
	Nlds=32,	/* max number of pushable line disciplines */
};

/*
 *  process end line discipline
 */


@@ 15,21 20,21 @@ Qinfo procinfo = { stputq, nullput, 0, 0, "process" };

/*
 *  line disciplines that can be pushed
 *
 *  WARNING: this table should be the result of configuration
 */
extern Qinfo noetherinfo;
extern Qinfo dkmuxinfo;
extern Qinfo urpinfo;
static Qinfo *lds[] = {
	&dkmuxinfo,
	&urpinfo,
	0
};
 */
static Qinfo *lds[Nlds+1];

enum {
	Nclass=4,
};
void
newqinfo(Qinfo *qi)
{
	int i;

	for(i=0; i<Nlds && lds[i]; i++)
		if(lds[i] == qi)
			return;
	if(i == Nlds)
		panic("pushable");
	lds[i] = qi;
}

/*
 *  All stream structures are ialloc'd at boot time


@@ 51,8 56,8 @@ typedef struct {
} Bclass;
Bclass bclass[Nclass]={
	{ 0 },
	{ 64 },
	{ 512 },
	{ 68 },
	{ 260 },
	{ 4096 },
};



@@ 88,7 93,6 @@ streaminit(void)
	}
}


/*
 *  allocate a block
 */


@@ 169,7 173,8 @@ freeb(Block *bp)
	}
	bcp->last = bp;
	unlock(bcp);
	wakeup(&bcp->r);
	if(bcp->r.p)
		wakeup(&bcp->r);
}

/*


@@ 716,30 721,37 @@ streamclose(Chan *c)
void
stputq(Queue *q, Block *bp)
{
	int i;
	int delim;

	if(bp->type == M_HANGUP){
		freeb(bp);
		q->flag |= QHUNGUP;
		q->other->flag |= QHUNGUP;
		wakeup(&q->other->r);
		delim = 1;
	} else {
		delim = 0;
		lock(q);
		if(q->first)
			q->last->next = bp;
		else
			q->first = bp;
		q->len += BLEN(bp);
		delim = bp->flags & S_DELIM;
		while(bp->next) {
			bp = bp->next;
			q->len += BLEN(bp);
			delim |= bp->flags & S_DELIM;
		}
		q->last = bp;
		if(q->len >= Streamhi)
		if(q->len >= Streamhi){
			q->flag |= QHIWAT;
			delim = 1;
		}
		unlock(q);
	}
	wakeup(&q->r);
	if(delim)
		wakeup(&q->r);
}

/*

M gnot/sturp.c => gnot/sturp.c +64 -21
@@ 39,12 39,13 @@ struct Urp {
	Rendez	r;		/* process waiting for close */

	/* input */

	QLock	ack;		/* ack lock */
	Queue	*rq;		/* input queue */
	uchar	iseq;		/* last good input sequence number */
	uchar	lastecho;	/* last echo/rej sent */
	uchar	trbuf[3];	/* trailer being collected */
	short	trx;		/* # bytes in trailer being collected */
	int	blocks;

	/* output */



@@ 110,6 111,8 @@ static void	sendblock(Urp*, int);
static void	rcvack(Urp*, int);
static void	flushinput(Urp*);
static void	sendctl(Urp*, int);
static void	sendack(Urp*);
static void	sendrej(Urp*);
static void	initoutput(Urp*, int);
static void	initinput(Urp*, int);
static void	urpkproc(void *arg);


@@ 305,10 308,12 @@ urpciput(Queue *q, Block *bp)

	case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3:
	case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7:
		qlock(&up->ack);
		i = ctl & Nmask;
		if(q->next->len < Streamhi)
			sendctl(up, up->lastecho = ECHO+i);
		up->iseq = i;
		qunlock(&up->ack);
		break;
	}
}


@@ 377,7 382,8 @@ urpiput(Queue *q, Block *bp)
	case 0:
		break;
	case ENQ:
		DPRINT("rENQ %uo %uo\n", up->lastecho, ACK+up->iseq);
		DPRINT("rENQ %d %uo %uo\n", up->blocks, up->lastecho, ACK+up->iseq);
		up->blocks = 0;
		urpstat.enqsr++;
		sendctl(up, up->lastecho);
		sendctl(up, ACK+up->iseq);


@@ 440,25 446,15 @@ urpiput(Queue *q, Block *bp)
		i = ctl & Nmask;
		if(up->trx != 3){
			urpstat.rjtrs++;
			flushinput(up);
			DPRINT("sREJ1 %d\n", up->iseq);
			if((up->lastecho&~7)==ECHO)
				sendctl(up, up->lastecho = REJ+up->iseq);/**/
			sendrej(up);
			break;
		} else if(q->len != up->trbuf[1] + (up->trbuf[2]<<8)){
			urpstat.rjpks++;
			DPRINT("sREJ2 %d %d %d\n", up->iseq, q->len,
				up->trbuf[1] + (up->trbuf[2]<<8));
			flushinput(up);
			if((up->lastecho&~7)==ECHO)
				sendctl(up, up->lastecho = REJ+up->iseq);/**/
			sendrej(up);
			break;
		} else if(i != ((up->iseq+1)&Nmask)) {
			urpstat.rjseq++;
			flushinput(up);
			DPRINT("sREJ3 %d %d\n", i, up->iseq);
			if((up->lastecho&~7)==ECHO)
				sendctl(up, up->lastecho = REJ+up->iseq);/**/
			sendrej(up);
			break;
		}



@@ 480,11 476,11 @@ urpiput(Queue *q, Block *bp)
		/*
		 *  acknowledge receipt
		 */
		if(q->next->len < Streamhi){
			sendctl(up, up->lastecho = ECHO+i);
			wakeup(&up->rq->r);
		}
		qlock(&up->ack);
		up->iseq = i;
		if(q->next->len < Streamhi)
			sendctl(up, up->lastecho = ECHO|i);
		qunlock(&up->ack);
		break;
	}
}


@@ 636,6 632,53 @@ sendctl(Urp *up, int ctl)
}

/*
 *  send a reject
 */
static void
sendrej(Urp *up)
{
	flushinput(up);
	qlock(&up->ack);
	if((up->lastecho&~Nmask) == ECHO){
		DPRINT("REJ %d\n", up->iseq);
		sendctl(up, up->lastecho = REJ|up->iseq);
	}
	qunlock(&up->ack);
}

/*
 *  send an acknowledge
 */
static void
sendack(Urp *up)
{
	Block *bp;

	/*
	 *  check the precondition for acking
	 */
	if(up->rq->next->len>=Streamhi || (up->lastecho&Nmask)==up->iseq)
		return;

	if(!canqlock(&up->ack))
		return;

	/*
	 *  check again now that we've locked
	 */
	if(up->rq->next->len>=Streamhi || (up->lastecho&Nmask)==up->iseq){
		qunlock(&up->ack);
		return;
	}

	/*
	 *  send the ack
	 */
	sendctl(up, up->lastecho = ECHO|up->iseq);
	qunlock(&up->ack);
}

/*
 *  send a block.
 */
static void


@@ 801,6 844,7 @@ initinput(Urp *up, int window)
	/*
	 *  restart all sequence parameters
	 */
	up->blocks = 0;
	up->trx = 0;
	up->iseq = 0;
	up->lastecho = ECHO+0;


@@ 832,8 876,7 @@ urpkproc(void *arg)
			if(up->state & HUNGUP)
				break;
		}
		if((up->lastecho&Nmask)!=up->iseq && up->rq->next->len<Streamhi)
			sendctl(up, up->lastecho = ECHO+up->iseq);
		sendack(up);
		output(up);
		tsleep(&up->rq->r, todo, up, MSrexmit/2);
	}

M gnot/trap.c => gnot/trap.c +1 -0
@@ 270,6 270,7 @@ syscall(Ureg *aur)
	ret = -1;
	if(!waserror())
		ret = (*systab[r0])((ulong*)(sp+BY2WD));
else print("syscall %d err %d %d\n", r0, u->error.type, u->error.code);
	u->nerrlab = 0;
	u->p->insyscall = 0;
	if(r0 == NOTED)	/* ugly hack */

M port/chan.c => port/chan.c +20 -10
@@ 149,7 149,7 @@ mount(Chan *new, Chan *old, int flag)
	Mtab *mt, *mz;
	Mount *mnt, *omnt, *nmnt, *pmnt;
	Pgrp *pg;
	int isnew;
	int islast;

	if(CHDIR & (old->qid^new->qid))
		error(0, Emount);


@@ 157,10 157,15 @@ mount(Chan *new, Chan *old, int flag)
		error(0, Emount);

	mz = 0;
	isnew = 0;
	islast = 0;
	mnt = 0;
	pg = u->p->pgrp;
	lock(pg);
	if(waserror()){
		if(mnt){
			mnt->c = 0;	/* caller will close new */
			closemount(mnt);
		}
		unlock(pg);
		nexterror();
	}


@@ 171,18 176,18 @@ mount(Chan *new, Chan *old, int flag)
	for(i=0; i<pg->nmtab; i++,mt++){
		if(mt->c==0 && mz==0)
			mz = mt;
		else if(eqchan(mt->c, old, CHDIR|QPATH))
		else if(eqchan(mt->c, old, CHDIR|QPATH)){
			mz = 0;
			goto Found;
		}
	}
	isnew = 1;
	if(mz == 0){
		if(i == conf.nmtab)
			error(0, Enomount);
		mz = &pg->mtab[i];
		pg->nmtab++;
		islast++;
	}
	mz->mnt = 0;
	mz->c = old;
	mt = mz;

    Found:


@@ 244,8 249,12 @@ mount(Chan *new, Chan *old, int flag)
	}

	incref(new);
	if(isnew)
	if(mz){
		mz->c = old;
		incref(old);
	}
	if(islast)
		pg->nmtab++;
	unlock(pg);
	poperror();
	return mnt->mountid;


@@ 286,7 295,7 @@ domount(Chan *c)
    Found:
	lock(pg);
	if(!eqchan(mt->c, c, CHDIR|QPATH)){	/* table changed underfoot */
		print("domount: changed underfoot?\n");
		pprint("domount: changed underfoot?\n");
		unlock(pg);
		return c;
	}


@@ 333,7 342,7 @@ walk(Chan *ac, char *name, int domnt)
			goto Notfound;
		}
		if(c->mountid != mnt->mountid){
			print("walk: changed underfoot?\n");
			pprint("walk: changed underfoot?\n");
			unlock(pg);
			goto Notfound;
		}


@@ 353,6 362,7 @@ walk(Chan *ac, char *name, int domnt)
		if(!first)
			close(c);
		nc->mnt = mnt;
		nc->mountid = mnt->mountid;
		c = nc;
		first = 0;
		goto Again;


@@ 391,7 401,7 @@ createdir(Chan *c)
	}
	mnt = c->mnt;
	if(c->mountid != mnt->mountid){
		print("createdir: changed underfoot?\n");
		pprint("createdir: changed underfoot?\n");
		error(0, Enocreate);
	}
	do{

M port/devcons.c => port/devcons.c +3 -2
@@ 180,17 180,18 @@ pprint(char *fmt, ...)

	c = u->fd[2];
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
		return;
		return 0;
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);
	n = donprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	qlock(c);
	if(waserror()){
		qunlock(c);
		return;
		return 0;
	}
	(*devtab[c->type].write)(c, buf, n);
	c->offset += n;
	qunlock(c);
	poperror();
	return n;
}


M port/devdk.c => port/devdk.c +2 -0
@@ 538,6 538,8 @@ Dirtab dksubdir[]={
void
dkreset(void)
{
	newqinfo(&dkmuxinfo);
	newqinfo(&urpinfo);
}

/*

M port/pgrp.c => port/pgrp.c +2 -1
@@ 122,7 122,8 @@ closemount(Mount *m)
{
	lock(m);
	if(m->ref == 1){
		close(m->c);
		if(m->c)
			close(m->c);
		if(m->next)
			closemount(m->next);
		unlock(m);

M port/stream.c => port/stream.c +33 -22
@@ 7,6 7,11 @@
#include	"errno.h"
#include	"devtab.h"

enum {
	Nclass=4,	/* number of block classes */
	Nlds=32,	/* max number of pushable line disciplines */
};

/*
 *  process end line discipline
 */


@@ 15,22 20,21 @@ Qinfo procinfo = { stputq, nullput, 0, 0, "process" };

/*
 *  line disciplines that can be pushed
 *
 *  WARNING: this table should be the result of configuration
 */
extern Qinfo noetherinfo;
extern Qinfo dkmuxinfo;
extern Qinfo urpinfo;
static Qinfo *lds[] = {
	&noetherinfo,
	&dkmuxinfo,
	&urpinfo,
	0
};
 */
static Qinfo *lds[Nlds+1];

enum {
	Nclass=4,
};
void
newqinfo(Qinfo *qi)
{
	int i;

	for(i=0; i<Nlds && lds[i]; i++)
		if(lds[i] == qi)
			return;
	if(i == Nlds)
		panic("pushable");
	lds[i] = qi;
}

/*
 *  All stream structures are ialloc'd at boot time


@@ 52,8 56,8 @@ typedef struct {
} Bclass;
Bclass bclass[Nclass]={
	{ 0 },
	{ 64 },
	{ 512 },
	{ 68 },
	{ 260 },
	{ 4096 },
};



@@ 89,7 93,6 @@ streaminit(void)
	}
}


/*
 *  allocate a block
 */


@@ 170,7 173,8 @@ freeb(Block *bp)
	}
	bcp->last = bp;
	unlock(bcp);
	wakeup(&bcp->r);
	if(bcp->r.p)
		wakeup(&bcp->r);
}

/*


@@ 717,30 721,37 @@ streamclose(Chan *c)
void
stputq(Queue *q, Block *bp)
{
	int i;
	int delim;

	if(bp->type == M_HANGUP){
		freeb(bp);
		q->flag |= QHUNGUP;
		q->other->flag |= QHUNGUP;
		wakeup(&q->other->r);
		delim = 1;
	} else {
		delim = 0;
		lock(q);
		if(q->first)
			q->last->next = bp;
		else
			q->first = bp;
		q->len += BLEN(bp);
		delim = bp->flags & S_DELIM;
		while(bp->next) {
			bp = bp->next;
			q->len += BLEN(bp);
			delim |= bp->flags & S_DELIM;
		}
		q->last = bp;
		if(q->len >= Streamhi)
		if(q->len >= Streamhi){
			q->flag |= QHIWAT;
			delim = 1;
		}
		unlock(q);
	}
	wakeup(&q->r);
	if(delim)
		wakeup(&q->r);
}

/*

M port/sturp.c => port/sturp.c +66 -27
@@ 39,12 39,13 @@ struct Urp {
	Rendez	r;		/* process waiting for close */

	/* input */

	QLock	ack;		/* ack lock */
	Queue	*rq;		/* input queue */
	uchar	iseq;		/* last good input sequence number */
	uchar	lastecho;	/* last echo/rej sent */
	uchar	trbuf[3];	/* trailer being collected */
	short	trx;		/* # bytes in trailer being collected */
	int	blocks;

	/* output */



@@ 110,6 111,8 @@ static void	sendblock(Urp*, int);
static void	rcvack(Urp*, int);
static void	flushinput(Urp*);
static void	sendctl(Urp*, int);
static void	sendack(Urp*);
static void	sendrej(Urp*);
static void	initoutput(Urp*, int);
static void	initinput(Urp*, int);
static void	urpkproc(void *arg);


@@ 123,8 126,6 @@ urpopen(Queue *q, Stream *s)
	int i;
	char name[128];

	DPRINT("urpopen\n");

	/*
	 *  find a free urp structure
	 */


@@ 200,13 201,11 @@ urpclose(Queue *q)
		i = 7;
	rcvack(up, ECHO+i);
	qunlock(&up->xmit);
	DPRINT("urpclose(%ux)\n", up);

	/*
	 *  kill off the kernel process
	 */
	wakeup(&up->rq->r);
	DPRINT("urpclosed(%ux)\n", up);
}

/*


@@ 309,10 308,12 @@ urpciput(Queue *q, Block *bp)

	case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3:
	case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7:
		qlock(&up->ack);
		i = ctl & Nmask;
		if(q->next->len < Streamhi)
			sendctl(up, up->lastecho = ECHO+i);
		up->iseq = i;
		qunlock(&up->ack);
		break;
	}
}


@@ 381,7 382,8 @@ urpiput(Queue *q, Block *bp)
	case 0:
		break;
	case ENQ:
		print("rENQ %uo %uo\n", up->lastecho, ACK+up->iseq);
		DPRINT("rENQ %d %uo %uo\n", up->blocks, up->lastecho, ACK+up->iseq);
		up->blocks = 0;
		urpstat.enqsr++;
		sendctl(up, up->lastecho);
		sendctl(up, ACK+up->iseq);


@@ 422,7 424,7 @@ urpiput(Queue *q, Block *bp)

	case REJ+0: case REJ+1: case REJ+2: case REJ+3:
	case REJ+4: case REJ+5: case REJ+6: case REJ+7:
		print("rREJ\n");
		DPRINT("rREJ\n");
		rcvack(up, ctl);
		break;
	


@@ 444,21 446,15 @@ urpiput(Queue *q, Block *bp)
		i = ctl & Nmask;
		if(up->trx != 3){
			urpstat.rjtrs++;
			flushinput(up);
			print("sREJ1 %d\n", up->iseq);
			sendctl(up, up->lastecho = REJ+up->iseq);
			sendrej(up);
			break;
		} else if(q->len != up->trbuf[1] + (up->trbuf[2]<<8)){
			urpstat.rjpks++;
			flushinput(up);
			print("sREJ2 %d\n", up->iseq);
			sendctl(up, up->lastecho = REJ+up->iseq);
			sendrej(up);
			break;
		} else if(i != ((up->iseq+1)&Nmask)) {
			urpstat.rjseq++;
			flushinput(up);
			print("sREJ3 %d %d\n", i, up->iseq);
			sendctl(up, up->lastecho = REJ+up->iseq);
			sendrej(up);
			break;
		}



@@ 480,12 476,11 @@ urpiput(Queue *q, Block *bp)
		/*
		 *  acknowledge receipt
		 */
		if(q->next->len < Streamhi){
			sendctl(up, ECHO+i);
			up->lastecho = ECHO+i;
			wakeup(&up->rq->r);
		}
		qlock(&up->ack);
		up->iseq = i;
		if(q->next->len < Streamhi)
			sendctl(up, up->lastecho = ECHO|i);
		qunlock(&up->ack);
		break;
	}
}


@@ 510,7 505,6 @@ urpctloput(Urp *up, Queue *q, Block *bp)
				outwin = strtoul(fields[0], 0, 0);
			}
/*			initinput(up, inwin); */
			DPRINT("initoutput %d\n", outwin);
			initoutput(up, outwin);
			freeb(bp);
			return;


@@ 596,7 590,7 @@ output(Urp *up)
	 *  if a retransmit time has elapsed since a transmit, send an ENQ
	 */
	if(up->unechoed != up->next && NOW > up->timer){
		print("sENQ\n");
		DPRINT("sENQ\n");
		up->timer = NOW + MSrexmit;
		up->state &= ~REJECTING;
		sendctl(up, ENQ);


@@ 638,6 632,53 @@ sendctl(Urp *up, int ctl)
}

/*
 *  send a reject
 */
static void
sendrej(Urp *up)
{
	flushinput(up);
	qlock(&up->ack);
	if((up->lastecho&~Nmask) == ECHO){
		DPRINT("REJ %d\n", up->iseq);
		sendctl(up, up->lastecho = REJ|up->iseq);
	}
	qunlock(&up->ack);
}

/*
 *  send an acknowledge
 */
static void
sendack(Urp *up)
{
	Block *bp;

	/*
	 *  check the precondition for acking
	 */
	if(up->rq->next->len>=Streamhi || (up->lastecho&Nmask)==up->iseq)
		return;

	if(!canqlock(&up->ack))
		return;

	/*
	 *  check again now that we've locked
	 */
	if(up->rq->next->len>=Streamhi || (up->lastecho&Nmask)==up->iseq){
		qunlock(&up->ack);
		return;
	}

	/*
	 *  send the ack
	 */
	sendctl(up, up->lastecho = ECHO|up->iseq);
	qunlock(&up->ack);
}

/*
 *  send a block.
 */
static void


@@ 803,6 844,7 @@ initinput(Urp *up, int window)
	/*
	 *  restart all sequence parameters
	 */
	up->blocks = 0;
	up->trx = 0;
	up->iseq = 0;
	up->lastecho = ECHO+0;


@@ 826,7 868,6 @@ urpkproc(void *arg)
	Urp *up;

	up = (Urp *)arg;
	DPRINT("urpkproc started\n");

	for(;;){
		if(up->state & (HUNGUP|CLOSING)){


@@ 835,12 876,10 @@ urpkproc(void *arg)
			if(up->state & HUNGUP)
				break;
		}
		if((up->lastecho&Nmask)!=up->iseq && up->rq->next->len<Streamhi)
			sendctl(up, up->lastecho = ECHO+up->iseq);
		sendack(up);
		output(up);
		tsleep(&up->rq->r, todo, up, MSrexmit/2);
	}
	DPRINT("urpkproc exiting %ux\n", up);
	up->kstarted = 0;
	up->state = 0;
}

M port/sysfile.c => port/sysfile.c +1 -1
@@ 126,7 126,7 @@ unionread(Chan *c, void *va, long n)
	mnt = c->mnt;
	lock(pg);
	if(c->mountid != mnt->mountid){
		print("unionread: changed underfoot?\n");
		pprint("unionread: changed underfoot?\n");
		unlock(pg);
		return 0;
	}

M power/devbit.c => power/devbit.c +4 -27
@@ 26,21 26,17 @@ enum
	WRITE,
};

long	hold, wait, hang;

void
bitsend(Bitmsg *bp, ulong cmd, void *addr, ulong count)
{
	do wait++; while(*BITADDR);
	do; while(*BITADDR);
	bp->cmd = cmd;
	bp->addr = (ulong)addr;
	bp->count = count;
/* print("%d %lux %d ", cmd, addr, count); /**/
	*BITADDR = bp;
	wbflush();
	do hold++; while(*BITHOLD);
	do; while(*BITHOLD);
	*BITINTR = 0x20;
/* print("done\n");  /**/
}

void


@@ 153,21 149,11 @@ bitread(Chan *c, void *buf, long n)
			docpy = 1;
		}
		qunlock(&bit);
		do{
		do
			n = bp->rcount;
			hang++;
		}while(n == 0);
		while(n == 0);
		if(docpy)
			memcpy(buf, bit.buf, n);
if(0 && n > 512){
	int i;
	char *cp=buf;
	for(i=9; i<n; i++)
		if(cp[i] != cp[i-1]){
			print("r %d %x %x\n", i, cp[i-1], cp[i]);
			break;
		}
}
		return n;
	}
	error(0, Egreg);


@@ 184,15 170,6 @@ bitwrite(Chan *c, void *buf, long n)
	case 1:
		if(n > sizeof bit.buf)
			error(0, Egreg);
if(0 && n > 512){
	int i;
	char *cp=buf;
	for(i=15; i<n; i++)
		if(cp[i] != cp[i-1]){
			print("w %d %x %x\n", i, cp[i-1], cp[i]);
			break;
		}
}
		qlock(&bit);
		if((((ulong)buf)&(KSEGM|3)) == KSEG0)
			bitsend(bp, WRITE, buf, n);

M power/fns.h => power/fns.h +1 -0
@@ 97,6 97,7 @@ Orig	*neworig(ulong, ulong, int, Chan*);
Page	*newpage(int, Orig*, ulong);
Pgrp	*newpgrp(void);
Proc	*newproc(void);
void	newqinfo(Qinfo*);
char	*nextelem(char*, char*);
void	newstart(void);
int	newtlbpid(Proc*);

M power/main.c => power/main.c +3 -3
@@ 375,9 375,9 @@ confinit(void)
	conf.nalarm = 1000;
	conf.norig = 500;
	conf.nchan = 500;
	conf.nenv = 200;
	conf.nenvchar = 10000;
	conf.npgenv = 200;
	conf.nenv = 400;
	conf.nenvchar = 20000;
	conf.npgenv = 400;
	conf.nmtab = 100;
	conf.nmount = 500;
	conf.nmntdev = 30;