~kris/9p

9hist

f00660d2feac2b97bfd2dfe25a0d25da3ad730c7 — David du Colombier 36 years ago bb2e529
Plan 9 from Bell Labs 1990-06-29
M gnot/devcons.c => gnot/devcons.c +77 -23
@@ 17,7 17,7 @@ static struct

typedef struct IOQ	IOQ;

#define	NQ	4096
#define	NQ	1024
struct IOQ{
	union{
		Lock;


@@ 31,6 31,8 @@ struct IOQ{
};

IOQ	lineq;
IOQ	rs232iq;
IOQ	rs232oq;

struct{
	IOQ;		/* qlock to getc; interrupt putc's */


@@ 50,12 52,20 @@ printinit(void)

	kbdq.in = kbdq.buf;
	kbdq.out = kbdq.buf;
	rs232iq.in = rs232iq.buf;
	rs232iq.out = rs232iq.buf;
	rs232oq.in = rs232oq.buf;
	rs232oq.out = rs232oq.buf;
	lineq.in = lineq.buf;
	lineq.out = lineq.buf;
	qlock(&kbdq);		/* allocate qlock */
	qunlock(&kbdq);
	lock(&lineq);		/* allocate lock */
	unlock(&lineq);
	lock(&rs232iq);		/* allocate lock */
	unlock(&rs232iq);
	lock(&rs232oq);		/* allocate lock */
	unlock(&rs232oq);

	screeninit();
}


@@ 114,6 124,14 @@ getc(IOQ *q)
	return c;
}

void
putc(IOQ *q, int c)
{
	*q->in++ = c;
	if(q->in == q->buf+sizeof(q->buf))
		q->in = q->buf;
}

int
sprint(char *s, char *fmt, ...)
{


@@ 184,12 202,15 @@ echo(int c)
	 */
	if(c == 0x14)
		DEBUG();
	if(c == 0x16){
		incontoggle();
		urpdump();
		dumpqueues();
	}
	if(raw.ref)
		return;
	if(c == 0x15)
		putstrn("^U\n", 3);
	if(c == 0x16)
		dumpqueues();
	else{
		ch = c;
		putstrn(&ch, 1);


@@ 235,6 256,26 @@ kbdclock(void)
		kbdchar(kbdq.c);
}

void
rs232ichar(int c)
{
	*rs232iq.in++ = c;
	if(rs232iq.in == rs232iq.buf+sizeof(rs232iq.buf))
		rs232iq.in = rs232iq.buf;
	wakeup(&rs232iq.r);
}

int
getrs232o(void)
{
	int c;

	c = getc(&rs232oq);
	if(c == -1)
		rs232oq.state = 0;
	return c;
}

int
consactive(void)
{


@@ 253,6 294,7 @@ enum{
	Qpid,
	Qppid,
	Qrcons,
	Qrs232,
	Qtime,
	Quser,
};


@@ 265,6 307,7 @@ Dirtab consdir[]={
	"pid",		Qpid,		12,	0600,
	"ppid",		Qppid,		12,	0600,
	"rcons",	Qrcons,		0,	0600,
	"rs232",	Qrs232,		0,	0600,
	"time",		Qtime,		12,	0600,
	"user",		Quser,		0,	0600,
};


@@ 356,7 399,7 @@ consopen(Chan *c, int omode)
			error(0, Eperm);
	}
	if(c->qid == Qrcons)
		if(incref(&raw) == 0){
		if(incref(&raw) == 1){
			lock(&lineq);
			while((ch=getc(&kbdq)) != -1){
				*lineq.in++ = ch;


@@ 446,6 489,22 @@ consread(Chan *c, void *buf, long n)
		qunlock(&kbdq);
		return i;

	case Qrs232:
		qlock(&rs232iq);
		if(waserror()){
			qunlock(&rs232iq);
			nexterror();
		}
		while(!cangetc(&rs232iq))
			sleep(&rs232iq.r, (int(*)(void*))cangetc, &rs232iq);
		for(i=0; i<n; i++){
			if((ch=getc(&rs232iq)) == -1)
				break;
			*cbuf++ = ch;
		}
		qunlock(&rs232iq);
		return i;

	case Qcputime:
		k = c->offset;
		if(k >= sizeof tmp)


@@ 513,6 572,20 @@ conswrite(Chan *c, void *va, long n)
		}
		break;

	case Qrs232:
		qlock(&rs232oq);
		l = n;
		while(--l >= 0)
			putc(&rs232oq, *a++);
		splhi();
		if(rs232oq.state == 0){
			rs232oq.state = 1;
			duartstartrs232o();
		}
		spllo();
		qunlock(&rs232oq);
		break;

	case Qtime:
		if(n<=0 || boottime!=0)	/* only one write please */
			return 0;


@@ 571,22 644,3 @@ consuserstr(Error *e, char *buf)
{
	strcpy(buf, u->p->pgrp->user);
}

typedef struct Incon{
	unsigned char	cdata;		unsigned char u0;
	unsigned char	cstatus;	unsigned char u1;
	unsigned char	creset;		unsigned char u2;
	unsigned char	csend;		unsigned char u3;
	unsigned short	data_cntl;	/* data is high byte, cntl is low byte */
	unsigned char	status;		unsigned char u5;
	unsigned char	reset;		unsigned char u6;
	unsigned char	send;		unsigned char u7;
}Incon;

/*
inconintr(Ureg *ur)
{
	int x;
	x = ((Incon*)0x40700000)->status;
}
*/

M gnot/devincon.c => gnot/devincon.c +12 -0
@@ 133,6 133,8 @@ static void inconstopen(Queue*, Stream*);
static void inconstclose(Queue*);
Qinfo inconinfo = { nullput, inconoput, inconstopen, inconstclose, "incon" };

int incondebug;

/*
 *  set the incon parameters
 */


@@ 492,6 494,9 @@ inconoput(Queue *q, Block *bp)
	ctl = bp->rptr[2];
	bp->rptr += 3;

	if(incondebug)
		print("->(%d)%uo %d\n", chan, ctl, bp->wptr - bp->rptr);

	/*
	 *  make sure there's an incon out there
	 */


@@ 677,6 682,8 @@ nextin(Incon *ip, unsigned int c)
	bp->base[0] = ip->chan;
	bp->base[1] = ip->chan>>8;
	bp->base[2] = c;
	if(incondebug)
		print("<-(%d)%uo %d\n", ip->chan, c, bp->wptr-bp->rptr)-3;

	next = (ip->wi+3)%Nin;
	if(next == ip->ri){


@@ 808,3 815,8 @@ inconintr(Ureg *ur)
		ip->state = Dead;
	}
}

incontoggle()
{
	incondebug ^= 1;
}

M gnot/fns.h => gnot/fns.h +3 -0
@@ 31,6 31,7 @@ int	devno(int, int);
Chan*	devopen(Chan*, int, Dirtab*, int, Devgen*);
void	devstat(Chan*, char*, Dirtab*, int, Devgen*);
int	devwalk(Chan*, char*, Dirtab*, int, Devgen*);
void	duartstartrs232o(void);
void	duartstarttimer(void);
void	duartstoptimer(void);
void	dumpregs(Ureg*);


@@ 54,6 55,7 @@ void	freealarm(Alarm*);
Block	*getb(Blist*);
int	getfields(char*, char**, int, char);
Block	*getq(Queue*);
int	getrs232o(void);
void	gotolabel(Label*);
void	growpte(Orig*, ulong);
void	*ialloc(ulong, int);


@@ 114,6 116,7 @@ int	readnum(ulong, char*, ulong, ulong, int);
void	ready(Proc*);
int	return0(void*);
void	rooterrstr(Error*, char*);
void	rs232ichar(int);
void	qlock(QLock*);
void	qunlock(QLock*);
void	restartprint(Alarm*);

M gnot/proc.c => gnot/proc.c +2 -2
@@ 559,9 559,9 @@ DEBUG()
	for(i=0; i<conf.nproc; i++){
		p = procalloc.arena+i;
		if(p->state != Dead)
			print("%d:%s upc %lux %s ut %ld st %ld %lux\n",
			print("%d:%s upc %lux %s ut %ld st %ld q %lux r %lux\n",
				p->pid, p->text, p->pc, statename[p->state],
				p->time[0], p->time[1], p->qlock);
				p->time[0], p->time[1], p->qlock, p->r);
	}
}


M gnot/screen.c => gnot/screen.c +32 -6
@@ 183,7 183,7 @@ duartinit(void)
	duart[0].sr_csr = BD4800;

	/*
	 * Pen
	 * RS232
	 */
	duart[1].cmnd = RESET_RCV|DIS_TX|DIS_RX;
	duart[1].cmnd = RESET_TRANS;


@@ 191,7 191,7 @@ duartinit(void)
	duart[1].cmnd = RESET_MR;
	duart[1].mr1_2 = CHAR_ERR|NO_PAR|CBITS8;
	duart[1].mr1_2 = NORM_OP|ONESTOPB;
	duart[1].sr_csr = BD2400;
	duart[1].sr_csr = BD9600;

	/*
	 * Output port


@@ 240,6 240,27 @@ duartstoptimer(void)
}

void
duartrs232intr(void)
{
	int c;
	Duart *duart;

	duart = DUARTREG;
	c = getrs232o();
	if(c == -1)
		duart[1].cmnd = DIS_TX;
	else
		duart[1].data = c;
}

void
duartstartrs232o(void)
{
	DUARTREG[1].cmnd = ENB_TX;
	duartrs232intr();
}

void
duartintr(Ureg *ur)
{
	int cause, status, c;


@@ 282,14 303,19 @@ duartintr(Ureg *ur)
	/*
	 * Is it 2?
	 */
	if(cause & IM_RRDYB)		/* pen input */
	if(cause & IM_RRDYB){		/* rs232 input */
		status = duart[1].sr_csr;
		c = duart[1].data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart[1].cmnd = RESET_ERR;
		else
			rs232ichar(c);
	}
	/*
	 * Is it 3?
	 */
	if(cause & IM_XRDYB){
		duart[1].cmnd = DIS_TX;
	}
	if(cause & IM_XRDYB)		/* rs232 output */
		duartrs232intr();
	/*
	 * Is it 4?
	 */

M gnot/sturp.c => gnot/sturp.c +61 -14
@@ 65,7 65,7 @@ struct Urp {
};
#define WINDOW(u) ((u)->unechoed>(u)->next ? (u)->unechoed+(u)->maxout-(u)->next-8 :\
			(u)->unechoed+(u)->maxout-(u)->next)
#define IN(x, f, n) (f<=n ? x>=f && x<n : x<n || x>=f)
#define IN(x, f, n) (f<=n ? (x>=f && x<n) : (x<n || x>=f))
#define NEXT(x) (((x)+1)&Nmask)

/*


@@ 117,6 117,7 @@ static void	sendrej(Urp*);
static void	initoutput(Urp*, int);
static void	initinput(Urp*, int);
static void	urpkproc(void *arg);
static void	urpvomit(char*, Urp*);

Qinfo urpinfo = { urpciput, urpoput, urpopen, urpclose, "urp" };



@@ 584,11 585,14 @@ output(Urp *up)
	}

	/*
	 *  fill the transmit buffers
	 *  fill the transmit buffers, `nxb' can never overtake `unechoed'
	 */
	q = up->wq;
	if(up->xb[up->nxb]==0) {
		for(bp=getq(q); bp && up->xb[up->nxb]==0; up->nxb=NEXT(up->nxb)){
	i = NEXT(up->nxb);
	if(i != up->unechoed) {
		for(bp = getq(q); bp && i!=up->unechoed; i = NEXT(i)){
			if(up->xb[up->nxb] != 0)
				urpvomit("output", up);
			if(BLEN(bp) > up->maxblock){
				nbp = up->xb[up->nxb] = allocb(0);
				nbp->rptr = bp->rptr;


@@ 597,17 601,27 @@ output(Urp *up)
				up->xb[up->nxb] = bp;
				bp = getq(q);
			}
			up->nxb = i;
		}
		if(bp)
			putbq(q, bp);
	}
/*	print("output w(%d) up->xb[%d](%ux) up->nxb(%d) up->state(%ux)\n",
		WINDOW(up), up->next, up->xb[up->next], up->nxb, up->state);
/**/

	/*
	 *  if a retransmit time has elapsed since a transmit, send an ENQ
	 *  retransmit cruft
	 */
	if(up->unechoed!=up->next && NOW>up->timer){
	if(up->rexmit){
		/*
		 *  if a retransmit is requested, move next back to
		 *  the unacked blocks
		 */
		up->rexmit = 0;
		up->next = up->unacked;
	} else if(up->unacked!=up->next && NOW>up->timer){
		/*
		 *  if a retransmit time has elapsed since a transmit,
		 *  send an ENQ
		 */
		up->timer = NOW + MSrexmit;
		up->state &= ~REJECTING;
		sendctl(up, ENQ);


@@ 618,12 632,11 @@ output(Urp *up)

	/*
	 *  if there's a window open, push some blocks out
	 *
	 *  the lock is to synchronize with acknowledges that free
	 *  blocks.
	 */
	if(up->rexmit){
		up->rexmit = 0;
		up->next = up->unechoed;
	}
	while(WINDOW(up)>0 && up->xb[up->next]!=0){
	while(WINDOW(up)>0 && up->next!=up->nxb){
		i = up->next;
		qlock(&up->xl[i]);
		if(waserror()){


@@ 722,6 735,10 @@ sendblock(Urp *up, int bn)
	 *  message 1, the BOT and the data
	 */
	bp = up->xb[bn];
	if(bp == 0){
		urpvomit("sendblock", up);
		return;
	}
	m = allocb(1);
	m->rptr = m->lim - 1;
	m->wptr = m->lim;


@@ 768,6 785,8 @@ rcvack(Urp *up, int msg)
			qlock(&up->xl[i]);
			if(up->xb[i])
				freeb(up->xb[i]);
			else
				urpvomit("rcvack", up);
			up->xb[i] = 0;
			qunlock(&up->xl[i]);
		}


@@ 924,3 943,31 @@ urpkproc(void *arg)
	up->kstarted = 0;
	DPRINT("urpkproc %ux\n", up);
}

/*
 *  urp got very confused, complain
 */
static void
urpvomit(char *msg, Urp* up)
{
	print("urpvomit: %s %ux next %d unechoed %d unacked %d nxb %d\n",
		msg, up, up->next, up->unechoed, up->unacked, up->nxb);
	print("\txb: %ux %ux %ux %ux %ux %ux %ux %ux\n",
		up->xb[0], up->xb[1], up->xb[2], up->xb[3], up->xb[4], 
		up->xb[5], up->xb[6], up->xb[7]);
	print("\tiseq: %uo lastecho: %uo trx: %d trbuf: %uo %uo %uo\n",
		up->iseq, up->lastecho, up->trx, up->trbuf[0], up->trbuf[1],
		up->trbuf[2]);
	print("\tupq: %ux %d %d\n", up->rq->next->first,  up->rq->next->nb,
		up->rq->next->len);
}

int
urpdump(void)
{
	Urp *up;

	for(up = urp; up < &urp[Nurp]; up++)
		if(up->rq)
			urpvomit("", up);
}

M port/devbit.c => port/devbit.c +21 -3
@@ 128,7 128,7 @@ Dirtab bitdir[]={
};

#define	NBIT	(sizeof bitdir/sizeof(Dirtab))
#define	NINFO	150
#define	NINFO	257

void
bitreset(void)


@@ 277,7 277,8 @@ bitread(Chan *c, void *va, long n)
	uchar *p, *q;
	long miny, maxy, t, x, y;
	ulong l, nw, ws;
	int off;
	int off, j;
	Fontchar *i;
	Bitmap *src;

	if(c->qid & CHDIR)


@@ 322,6 323,9 @@ bitread(Chan *c, void *va, long n)
			 *	'I'		1
			 *	ldepth		1
			 * 	rectangle	16
			 * if count great enough, also
			 *	font info	3*12
			 *	fontchars	6*(defont->n+1)
			 */
			if(n < 18)
				error(0, Ebadblt);


@@ 331,8 335,22 @@ bitread(Chan *c, void *va, long n)
			PLONG(p+6, screen.r.min.y);
			PLONG(p+10, screen.r.max.x);
			PLONG(p+14, screen.r.max.y);
			if(n >= 18+3*12+6*(defont->n+1)){
				p += 18;
				sprint((char*)p, "%11d %11d %11d ", defont->n,
					defont->height, defont->ascent);
				p += 3*12;
				for(i=defont->info,j=0; j<=defont->n; j++,i++,p+=6){
					PSHORT(p, i->x);
					p[2] = i->top;
					p[3] = i->bottom;
					p[4] = i->left;
					p[5] = i->width;
				}
				n = 18+3*12+6*(defont->n+1);
			}else
				n = 18;
			bit.init = 0;
			n = 18;
			break;
		}
		if(bit.lastid > 0){

M port/devcons.c => port/devcons.c +1 -1
@@ 240,7 240,7 @@ echo(int c)
	if(c == 0x15)
		putstrn("^U\n", 3);
	if(c == 0x16)
		dumpqueues();
		urpdump();
	else{
		ch = c;
		putstrn(&ch, 1);

M port/devmnt.c => port/devmnt.c +4 -0
@@ 810,6 810,10 @@ mntxmit(Mnt *m, Mnthdr *mh)
				wakeup(&w->r);
				goto Read;
			}
print("devmnt: undelivered response fid %d type %d\n", mh->rhdr.fid, mh->rhdr.type);
print("reader pid %d fid %d type %d\n", u->p->pid, mh->thdr.fid, mh->thdr.type);
for(w=q->writer; w; w=w->next)print("writer pid %d fid %d type %d\n",w->p->pid,w->thdr.fid,w->thdr.type);

		goto Read;
	}else{
		mh->p = u->p;

M port/devpipe.c => port/devpipe.c +28 -34
@@ 32,6 32,8 @@ Chan*
pipeattach(char *spec)
{
	Chan *c;
	int i;

	/*
	 *  make the first stream
	 */


@@ 59,8 61,19 @@ pipeclone(Chan *c, Chan *nc)
	/*
	 *  attach it to the first
	 */
	c->stream->devq->ptr = (Stream *)nc->stream;
	nc->stream->devq->ptr = (Stream *)c->stream;
	c->stream->devq->other->next = nc->stream->devq;
	nc->stream->devq->other->next = c->stream->devq;

	/*
	 *  up the inuse count of each stream to reflect the
	 *  pointer from the other stream.
	 */
	if(streamenter(c->stream)<0)
		panic("pipeattach");
	if(streamenter(nc->stream)<0)
		panic("pipeattach");
	return nc;
}



@@ 110,7 123,17 @@ pipewstat(Chan *c, char *db)
void
pipeclose(Chan *c)
{
	streamclose(c);
	Stream *other;

	other = (Stream *)c->stream->devq->ptr;

	if(waserror()){
		streamexit(other, 0);
		nexterror();
	}
	streamclose(c);		/* close this stream */
	streamexit(other, 0);	/* release stream for other half of pipe */
	poperror();
}

long


@@ 164,14 187,7 @@ pipeiput(Queue *q, Block *bp)
static void
pipeoput(Queue *q, Block *bp)
{
	lock(q);
	if(q->next)
		pipeiput(q->next, bp);
	else{
		print("pipeoput losing block\n");
		freeb(bp);
	}
	unlock(q);
	PUTNEXT(q, bp);
}

/*


@@ 193,29 209,7 @@ pipestclose(Queue *q)
	 *  send a hangup
	 */
	q = q->other;
	lock(q);
	if(q->next){
		bp = allocb(0);
		bp->type = M_HANGUP;
		pipeiput(q->next, bp);
	}
	unlock(q);

	/*
	 *  disconnect (possible livelock?)
	 */
	for(;;){
		lock(q);
		if(q->next){
			if(!canlock(q->next->other)){
				unlock(q);
				continue;
			}
			q->next->other->next = 0;
			unlock(q->next->other);
			q->next = 0;
		}
		unlock(q);
		break;
	}
	bp = allocb(0);
	bp->type = M_HANGUP;
	PUTNEXT(q, bp);
}

M port/proc.c => port/proc.c +2 -2
@@ 561,9 561,9 @@ DEBUG()
	for(i=0; i<conf.nproc; i++){
		p = procalloc.arena+i;
		if(p->state != Dead){
			print("%d:%s upc %lux %s ut %ld st %ld\n",
			print("%d:%s upc %lux %s ut %ld st %ld r %lux\n",
				p->pid, p->text, p->pc, statename[p->state],
				p->time[0], p->time[1]);
				p->time[0], p->time[1], p->r);
		}
	}
}

M port/stream.c => port/stream.c +91 -24
@@ 258,6 258,22 @@ allocq(Qinfo *qi)
}

/*
 *  flush a queue
 */
static void
flushq(Queue *q)
{
	Block *bp;

	q = RD(q);
	while(bp = getq(q))
		freeb(bp);
	q = WR(q);
	while(bp = getq(q))
		freeb(bp);
}

/*
 *  free a queue
 */
static void


@@ 515,8 531,12 @@ prepend(Block *bp, int n)
void
nullput(Queue *q, Block *bp)
{
	freeb(bp);
	error(0, Ehungup);
	if(bp->type == M_HANGUP)
		freeb(bp);
	else {
		freeb(bp);
		error(0, Ehungup);
	}
}

/*


@@ 658,8 678,8 @@ streamnew(Chan *c, Qinfo *qi)
 	 *  hang a device and process q off the stream
	 */
	s->inuse = 1;
	s->opens = 1;
	s->hread = 0;
	s->tag[0] = 0;
	q = allocq(&procinfo);
	s->procq = WR(q);
	q = allocq(qi);


@@ 697,6 717,7 @@ streamopen(Chan *c, Qinfo *qi)
			&& s->dev == c->dev
		 	&& s->id == STREAMID(c->qid)){
				s->inuse++;
				s->opens++;
				c->stream = s;
				unlock(s);
				return;


@@ 712,6 733,50 @@ streamopen(Chan *c, Qinfo *qi)
}

/*
 *  Enter a stream.  Increment the reference count so it can't disappear
 *  under foot.
 */
int
streamenter(Stream *s)
{
	lock(s);
	if(s->opens == 0){
		unlock(s);
		return -1;
	}
	s->inuse++;
	unlock(s);
	return 0;
}

/*
 *  Decrement the reference count on a stream.  If the count is
 *  zero, free the stream.
 */
void
streamexit(Stream *s, int locked)
{
	Queue *q;
	Queue *nq;

	if(!locked)
		lock(s);
	if(s->inuse == 1){
		/*
		 *  ascend the stream freeing the queues
		 */
		for(q = s->devq; q; q = nq){
			nq = q->next;
			freeq(q);
		}
		s->id = s->dev = s->type = 0;
	}
	s->inuse--;
	if(!locked)
		unlock(s);
}

/*
 *  On the last close of a stream, for each queue on the
 *  stream release its blocks and call its close routine.
 */


@@ 729,33 794,35 @@ streamclose(Chan *c)
		return;

	/*
	 *  decrement the reference cound
	 *  decrement the reference count
	 */
	lock(s);
	if(s->inuse != 1){
		s->inuse--;
		unlock(c->stream);
		return;
	if(s->opens == 1){
		/*
		 *  descend the stream closing the queues
		 */
		for(q = s->procq; q; q = q->next){
			if(q->info->close)
				(*q->info->close)(q->other);
			/* this may be 2 streams joined device end to device end */
			if(q == s->devq->other)
				break;
		}
	
		/*
		 *  ascend the stream flushing the queues
		 */
		for(q = s->devq; q; q = nq){
			nq = q->next;
			flushq(q);
		}
	}
	s->opens--;

	/*
	 *  descend the stream closing the queues
	 *  leave it and free it
	 */
	for(q = s->procq; q; q = q->next){
		if(q->info->close)
			(*q->info->close)(q->other);
		if(q == s->devq->other)
			break;
	}
	/*
	 *  ascend the stream freeing the queues
	 */
	for(q = s->devq; q; q = nq){
		nq = q->next;
		freeq(q);
	}
	s->id = s->dev = s->type = 0;
	s->inuse--;
	streamexit(s, 1);
	unlock(s);
}


M port/sturp.c => port/sturp.c +61 -14
@@ 65,7 65,7 @@ struct Urp {
};
#define WINDOW(u) ((u)->unechoed>(u)->next ? (u)->unechoed+(u)->maxout-(u)->next-8 :\
			(u)->unechoed+(u)->maxout-(u)->next)
#define IN(x, f, n) (f<=n ? x>=f && x<n : x<n || x>=f)
#define IN(x, f, n) (f<=n ? (x>=f && x<n) : (x<n || x>=f))
#define NEXT(x) (((x)+1)&Nmask)

/*


@@ 117,6 117,7 @@ static void	sendrej(Urp*);
static void	initoutput(Urp*, int);
static void	initinput(Urp*, int);
static void	urpkproc(void *arg);
static void	urpvomit(char*, Urp*);

Qinfo urpinfo = { urpciput, urpoput, urpopen, urpclose, "urp" };



@@ 584,11 585,14 @@ output(Urp *up)
	}

	/*
	 *  fill the transmit buffers
	 *  fill the transmit buffers, `nxb' can never overtake `unechoed'
	 */
	q = up->wq;
	if(up->xb[up->nxb]==0) {
		for(bp=getq(q); bp && up->xb[up->nxb]==0; up->nxb=NEXT(up->nxb)){
	i = NEXT(up->nxb);
	if(i != up->unechoed) {
		for(bp = getq(q); bp && i!=up->unechoed; i = NEXT(i)){
			if(up->xb[up->nxb] != 0)
				urpvomit("output", up);
			if(BLEN(bp) > up->maxblock){
				nbp = up->xb[up->nxb] = allocb(0);
				nbp->rptr = bp->rptr;


@@ 597,17 601,27 @@ output(Urp *up)
				up->xb[up->nxb] = bp;
				bp = getq(q);
			}
			up->nxb = i;
		}
		if(bp)
			putbq(q, bp);
	}
/*	print("output w(%d) up->xb[%d](%ux) up->nxb(%d) up->state(%ux)\n",
		WINDOW(up), up->next, up->xb[up->next], up->nxb, up->state);
/**/

	/*
	 *  if a retransmit time has elapsed since a transmit, send an ENQ
	 *  retransmit cruft
	 */
	if(up->unechoed!=up->next && NOW>up->timer){
	if(up->rexmit){
		/*
		 *  if a retransmit is requested, move next back to
		 *  the unacked blocks
		 */
		up->rexmit = 0;
		up->next = up->unacked;
	} else if(up->unacked!=up->next && NOW>up->timer){
		/*
		 *  if a retransmit time has elapsed since a transmit,
		 *  send an ENQ
		 */
		up->timer = NOW + MSrexmit;
		up->state &= ~REJECTING;
		sendctl(up, ENQ);


@@ 618,12 632,11 @@ output(Urp *up)

	/*
	 *  if there's a window open, push some blocks out
	 *
	 *  the lock is to synchronize with acknowledges that free
	 *  blocks.
	 */
	if(up->rexmit){
		up->rexmit = 0;
		up->next = up->unechoed;
	}
	while(WINDOW(up)>0 && up->xb[up->next]!=0){
	while(WINDOW(up)>0 && up->next!=up->nxb){
		i = up->next;
		qlock(&up->xl[i]);
		if(waserror()){


@@ 722,6 735,10 @@ sendblock(Urp *up, int bn)
	 *  message 1, the BOT and the data
	 */
	bp = up->xb[bn];
	if(bp == 0){
		urpvomit("sendblock", up);
		return;
	}
	m = allocb(1);
	m->rptr = m->lim - 1;
	m->wptr = m->lim;


@@ 768,6 785,8 @@ rcvack(Urp *up, int msg)
			qlock(&up->xl[i]);
			if(up->xb[i])
				freeb(up->xb[i]);
			else
				urpvomit("rcvack", up);
			up->xb[i] = 0;
			qunlock(&up->xl[i]);
		}


@@ 924,3 943,31 @@ urpkproc(void *arg)
	up->kstarted = 0;
	DPRINT("urpkproc %ux\n", up);
}

/*
 *  urp got very confused, complain
 */
static void
urpvomit(char *msg, Urp* up)
{
	print("urpvomit: %s %ux next %d unechoed %d unacked %d nxb %d\n",
		msg, up, up->next, up->unechoed, up->unacked, up->nxb);
	print("\txb: %ux %ux %ux %ux %ux %ux %ux %ux\n",
		up->xb[0], up->xb[1], up->xb[2], up->xb[3], up->xb[4], 
		up->xb[5], up->xb[6], up->xb[7]);
	print("\tiseq: %uo lastecho: %uo trx: %d trbuf: %uo %uo %uo\n",
		up->iseq, up->lastecho, up->trx, up->trbuf[0], up->trbuf[1],
		up->trbuf[2]);
	print("\tupq: %ux %d %d\n", up->rq->next->first,  up->rq->next->nb,
		up->rq->next->len);
}

int
urpdump(void)
{
	Urp *up;

	for(up = urp; up < &urp[Nurp]; up++)
		if(up->rq)
			urpvomit("", up);
}

M power/conf.h => power/conf.h +2 -0
@@ 21,6 21,8 @@ Conftab conftab[] = {
	{"nqueue", &conf.nqueue },
	{"nblock", &conf.nblock },
	{"nsrv", &conf.nsrv },
	{"nnoifc", &conf.nnoifc },
	{"nnoconv", &conf.nnoconv },
	{ 0, 0 },
};


M power/dat.h => power/dat.h +122 -2
@@ 17,7 17,12 @@ typedef struct Lock	Lock;
typedef struct Mach	Mach;
typedef struct Mount	Mount;
typedef struct Mtab	Mtab;
typedef struct Noconv	Noconv;
typedef struct Nohdr	Nohdr;
typedef struct Noifc	Noifc;
typedef struct Note	Note;
typedef struct Nomsg	Nomsg;
typedef struct Nocall	Nocall;
typedef struct Orig	Orig;
typedef struct PTE	PTE;
typedef struct Page	Page;


@@ 137,6 142,8 @@ struct Conf
	ulong	nqueue;		/* stream queues */
	ulong	nblock;		/* stream blocks */
	ulong	nsrv;		/* public servers (devsrv.c) */
	ulong	nnoifc;		/* number of nonet interfaces */
	ulong	nnoconv;	/* number of nonet conversations/ifc */
};

struct Dev


@@ 435,7 442,8 @@ struct Queue {
 */
struct Stream {
	Lock;			/* structure lock */
	int	inuse;		/* use count */
	int	inuse;		/* number of processes in stream */
	int	opens;		/* number of processes with stream open */
	int	hread;		/* number of reads after hangup */
	int	type;		/* correclation with Chan */
	int	dev;		/* ... */


@@ 444,7 452,6 @@ struct Stream {
	QLock	wrlock;		/* write lock */
	Queue	*procq;		/* write queue at process end */
	Queue	*devq;		/* read queue at device end */
	char	tag[32];	/* when reading the tag qid */
};
#define	RD(q)		((q)->other < (q) ? (q->other) : q)
#define	WR(q)		((q)->other > (q) ? (q->other) : q)


@@ 469,6 476,119 @@ enum {
	Streambhi= 16,		/* block count high water mark */
};

/*
 *  nonet constants
 */
enum {
	Nnomsg = 128,		/* max number of outstanding messages */
	Nnocalls = 5,		/* maximum queued incoming calls */
};

/*
 *  generic nonet header
 */
struct Nohdr {
	uchar	circuit[3];	/* circuit number */
	uchar	flag;
	uchar	mid;		/* message id */
	uchar	ack;		/* piggy back ack */
	uchar	remain[2];	/* count of remaing bytes of data */
	uchar	sum[2];		/* checksum (0 means none) */
};
#define HDRSIZE 10
#define NEWCALL	0x1		/* flag bit marking a new circuit */
#define HANGUP 0x2		/* flag bit requesting hangup */
#define ACKME 0x4		/* acknowledge this message */

/*
 *  a buffer describing a nonet message
 */
struct Nomsg {
	QLock;
	Blist;
	int	mid;		/* sequence number */
	int	rem;		/* remaining */
	long	time;
	int	acked;
};

/*
 *  one exists for each Nonet conversation.
 */
struct Noconv {
	QLock;

	Queue	*rq;		/* input queue */
	int	version;	/* incremented each time struct is changed */
	int	state;		/* true if listening */

	Nomsg	in[Nnomsg];	/* messages being received */
	int	rcvcircuit;	/* circuit number of incoming packets */

	uchar	ack[Nnomsg];	/* acknowledgements waiting to be sent */
	long	atime[Nnomsg];
	int	afirst;
	int	anext;

	QLock	xlock;		/* one trasmitter at a time */
	Rendez	r;		/* process waiting for an output mid */
	Nomsg	ctl;		/* for control messages */
	Nomsg	out[Nnomsg];	/* messages being sent */
	int	first;		/* first unacknowledged message */
	int	next;		/* next message buffer to use */
	int	lastacked;	/* last message acked */		
	Block	*media;		/* prototype media output header */
	Nohdr	*hdr;		/* nonet header inside of media header */

	Noifc	*ifc;
	int	kstarted;
	char	raddr[64];	/* remote address */
	int	rexmit;		/* statistics */
	int	retry;
	int	bad;
	int	sent;
	int	rcvd;
};

/*
 *  an incoming call
 */
struct Nocall {
	Block	*msg;
	char	raddr[64];
	long	circuit;
};

/*
 *  a nonet interface.  one exists for every stream that a 
 *  nonet multiplexor is pushed onto.
 */
struct Noifc {
	Lock;
	int	ref;
	char	name[64];	/* interface name */		
	Queue	*wq;		/* interface output queue */
	Noconv	*conv;

	/*
	 *  media dependent
	 */
	int	maxtu;		/* maximum transfer unit */
	int	mintu;		/* minimum transfer unit */
	int	hsize;		/* media header size */
	void	(*connect)(Noconv *, char *);

	/*
	 *  calls and listeners
	 */
	QLock	listenl;
	Rendez	listenr;
	Lock	lock;
	Nocall	call[Nnocalls];
	int	rptr;
	int	wptr;
};

#define	PRINTSIZE	256
struct
{

M power/fns.h => power/fns.h +6 -0
@@ 108,6 108,10 @@ void	newqinfo(Qinfo*);
char	*nextelem(char*, char*);
void	newstart(void);
int	newtlbpid(Proc*);
int	nonetcksum(Block*, int);
void	nonetfreeifc(Noifc*);
Noifc*	nonetnewifc(Queue*, Stream*, int, int, int, void (*)(Noconv*, char*));
void	nonetrcvmsg(Noconv*, Block*);
void	novme(int);
void	nullput(Queue*, Block*);
void	online(void);


@@ 158,6 162,8 @@ int	spllo(void);
void	splx(int);
Devgen	streamgen;
void	streamclose(Chan*);
int	streamenter(Stream*);
void	streamexit(Stream*, int);
void	streaminit(void);
long	streamread(Chan*, void*, long);
long	streamwrite(Chan*, void*, long, int);