Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/sturp.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/sturp.c 1990/0227
## diff -e /dev/null /n/bootesdump/1990/0227/sys/src/9/mips/sturp.c
0a
#include "syslibc.h"
#include "lock.h"
#include "chan.h"
#include "proc.h"
#include "user.h"
#include "errno.h"
#include "lint.h"
#include "mem.h"
#include "mempool.h"
#include "stream.h"
#include "dkparam.h"
#include "misc.h"

enum {
	Nurp=		32,
	MSrexmit=	1000,
};

typedef struct Urp	Urp;

/*
 * URP status
 */
struct urpstat {
	ulong	input;		/* bytes read from urp */
	ulong	output;		/* bytes output to urp */
	ulong	rxmit;		/* retransmit rejected urp msg */
	ulong	rjtrs;		/* reject, trailer size */
	ulong	rjpks;		/* reject, packet size */
	ulong	rjseq;		/* reject, sequence number */
	ulong	levelb;		/* unknown level b */
	ulong	enqsx;		/* enqs sent */
	ulong	enqsr;		/* enqs rcved */
} urpstat;

struct Urp {
	Qlock;
	short	state;		/* flags */

	/* input */

	ulong	iwindow;	/* input window */
	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 */

	/* output */

	Queue	*rq;
	Queue	*wq;
	int	XW;		/* blocks per xmit window */
	int	maxblock;	/* max block size */
	int	timeout;	/* a timeout has occurred */
	int	WS;		/* start of current window */
	int	WACK;		/* first non-acknowledged message */
	int	WNX;		/* next message to be sent */
	Rendez	r;		/* process waiting in urpoput */
	Rendez	kr;		/* process waiting in urpoput */
	Block	*xb[8];		/* the xmit window buffer */
	uchar	timer;		/* timeout for xmit */
};
#define WINDOW(u) ((u->WS + u->XW - u->WNX)%8)
#define BETWEEN(x, s, n) (s<=n ? x>=s && x<n : x<n || x>=s)
#define UNACKED(x, u) (BETWEEN(x, u->WACK, u->WNX)

/*
 *  Protocol control bytes
 */
#define	SEQ	0010		/* sequence number, ends trailers */
#undef	ECHO
#define	ECHO	0020		/* echos, data given to next queue */
#define	REJ	0030		/* rejections, transmission error */
#define	ACK	0040		/* acknowledgments */
#define	BOT	0050		/* beginning of trailer */
#define	BOTM	0051		/* beginning of trailer, more data follows */
#define	BOTS	0052		/* seq update algorithm on this trailer */
#define	SOU	0053		/* start of unsequenced trailer */
#define	EOU	0054		/* end of unsequenced trailer */
#define	ENQ	0055		/* xmitter requests flow/error status */
#define	CHECK	0056		/* xmitter requests error status */
#define	INITREQ 0057		/* request initialization */
#define	INIT0	0060		/* disable trailer processing */
#define	INIT1	0061		/* enable trailer procesing */
#define	AINIT	0062		/* response to INIT0/INIT1 */
#undef	DELAY
#define	DELAY	0100		/* real-time printing delay */
#define	BREAK	0110		/* Send/receive break (new style) */

#define	REXMITING	0001
#define	REXMIT		0002
#define	INITING 	0004

Urp	urp[Nurp];

/*
 *  predeclared
 */
static void	urpiput(Queue*, Block*, Rendez*);
static void	urpoput(Queue*, Block*, Rendez*);
static void	urpopen(Queue*, Stream*);
static void	urpclose(Queue *);
static void	rcvack(Urp*, int);
static void	flushinput(Urp*);
static void	sendctl(Queue*, int);
static void	queuectl(Urp*, int);
static void	initoutput(Urp*, int);
static void	initinput(Urp*, int);

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

int
urpopen(Queue *q, Stream *s)
{
	Urp *up;
	int i;

	/*
	 *  find a free urp structure
	 */
	for(up = urp; up < &urp[Nurp]; up++){
		qlock(up);
		if(up->state == 0)
			break;
		qunlock(up);
	}
	if(up == &urp[Nurp])
		error(0, Egreg);

	q->ptr = = q->other->ptr = up;
	up->rq = q;
	up->wq = WR(q);
	q->put = urpciput;
	qunlock(up);
	initinput(up, 0);
	initoutput(up, 0);
}

/*
 *  Shut it down.
 */
static int
allacked(void *a)
{
	Urp *up;

	up = (Urp *)a;
	return up->WACK == up->WNX;
}
urpclose(Queue *q)
{
	Block *bp;
	Urp *up;
	int i;

	up = (Urp *)q->ptr;
	up->state |= LCLOSE;

	/*
	 *  wait for output to get acked
	 */
	while(!urpdone(up))
		sleep(&up->r, urpdone, up);
	up->state = 0;
}

/*
 *  upstream control messages
 */
static void
urpctliput(Urp *up, Queue *q, Block *bp)
{
	switch(bp->type){
	case M_HANGUP:
		/*
		 *  ack all outstanding messages
		 */
		lock(up);
		up->state &= ~(INITING);
		up->state |= RCLOSE;
		unlock(up);
		if(up->WS<up->WNX)
			urprack(up, ECHO+((up->WNX-1)&07));
	}
	PUTNEXT(q, bp);
}

/*
 *  character mode input.  the last character in EVERY block is
 *  a control character.
 */
void
urpciput(Queue *q, Block *bp, Rendez *rp)
{
	Urp *up;
	int i, full;
	Block *nbp;

	up = (Urp *)q->ptr;
	if(bp->type != M_DATA){
		urpctliput(up, q, bp);
		return;
	}

	/*
	 *  get the control character
	 */
	if(bp->wptr > bp->rptr)
		ctl = *(--bp->wptr);
	else
		ctl = 0;

	/*
	 *  send the block upstream
	 */
	if(bp->wptr > bp->rptr)
		PUTNEXT(q, bp);
	else
		freeb(bp);

	/*
	 *  handle the control character
	 */
	switch(ctl){
	case 0:
		break;

	case ENQ:
		urpstat.enqsr++;
		queuectl(up, up->lastecho);
		queuectl(up, ACK+up->iseq);
		flushinput(up);
		break;

	case CHECK:
		queuectl(up, ACK+up->iseq);
		break;

	case AINIT:
		up->state &= ~INITING;
		flushinput(up);
		wakeup(&cp->kr);
		break;

	case INIT0:
	case INIT1:
		queuectl(up, AINIT);
		if(*bp->rptr == INIT1)
			q->put = urpbiput;
		initinput(up, 0);
		break;

	case INITREQ:
		initoutput(up, 0);
		break;

	case BREAK:
		break;

	case ACK+0: case ACK+1: case ACK+2: case ACK+3:
	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:
		rcvack(up, ctl);
		break;

	case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3:
	case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7:
		/*
		 *  acknowledge receipt
		 */
		ctl = ctl & 07;
		if(q->next->len < Streamhi){
			queuectl(up, ECHO+ctl);
			up->lastecho = ECHO+ctl;
			wakeup(&cp->kr);
		}
		up->iseq = ctl;
		break;
	}
}

/*
 *  block mode input.  the last character in EVERY block is a control character.
 */
void
urpbiput(Queue *q, Block *bp, Rendez *rp)
{
	Urp *up;
	int i, full;
	Block *nbp;

	up = (Urp *)q->ptr;
	if(bp->type != M_DATA){
		urpctliput(up, q, bp);
		return;
	}

	/*
	 *  get the control character
	 */
	if(bp->wptr > bp->rptr)
		ctl = *(--bp->wptr);
	else
		ctl = 0;

	/*
	 *  take care of any block count(trx)
	 */
	while(bp->wptr > bp->rptr && up->trx){
		switch (up->trx) {
		case 1:
		case 2:
			up->trbuf[up->trx++] = *bp->rptr++;
			continue;
		default:
			up->trx = 0;
		case 0:
			break;
		}
	}

	/*
	 *  queue the block
	 */
	if(bp->wptr > bp->rptr){
		if(q->len > up->iwindow){
			flushinput(up);
			freeb(bp);
			return;
		}
		putq(q, bp);
	} else
		freeb(bp);

	/*
	 *  handle the control character
	 */
	switch(ctl){
	case 0:
		break;
	case ENQ:
		urpstat.enqsr++;
		queuectl(up, up->lastecho);
		queuectl(up, ACK+up->iseq);
		flushinput(up);
		break;

	case CHECK:
		queuectl(WR(q)->next, ACK+up->iseq);
		break;

	case AINIT:
		up->state &= ~INITING;
		flushinput(up);
		wakeup(&cp->kr);
		break;

	case INIT0:
	case INIT1:
		queuectl(up, AINIT);
		if(*bp->rptr == INIT0)
			q->put = urpciput;
		initinput(up, 0);
		break;

	case INITREQ:
		initoutput(up, 0);
		break;

	case BREAK:
		break;

	case BOT:
	case BOTS:
	case BOTM:
		up->trx = 1;
		up->trbuf[0] = ctl;
		break;

	case REJ+0: case REJ+1: case REJ+2: case REJ+3:
	case REJ+4: case REJ+5: case REJ+6: case REJ+7:
		rcvack(up, ctl);
		break;
	
	case ACK+0: case ACK+1: case ACK+2: case ACK+3:
	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:
		rcvack(up, ctl);
		break;

	/*
	 *  this case is extremely ugliferous
	 */
	case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3:
	case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7:
		i = ctl & 07;
		if(up->trx != 3){
			urpstat.rjtrs++;
			flushinput(up);
			break;
		} else if(q->len != up->trbuf[1] + (up->trbuf[2]<<8)){
			urpstat.rjpks++;
			flushinput(up);
			break;
		} else if(i != ((up->iseq+1)&07))) {
			urpstat.rjseq++;
			flushinput(up);
			break;
		}

		/*
		 *  send data upstream
		 */
		if(q->first) {
			q->first->flags |= S_DELIM;
			while(bp = getq(q))
				PUTNEXT(q, nbp);
		} else {
			bp = allocb(0);
			bp->flag |= S_DELIM;
			PUTNEXT(q, bp);
		{
		up->trx = 0;

		/*
		 *  acknowledge receipt
		 */
		ctl = ctl & 07;
		if(q->next->len < Streamhi){
			queuectl(up, ECHO+ctl);
			up->lastecho = ECHO+ctl;
			wakeup(&cp->kr);
		}
		up->iseq = ctl;
		break;
	}
}

/*
 *  downstream control
 */
static void
urpctloput(Urp *up, Queue *q, Block *bp)
{
	int fields[2];
	int n;
	int inwin=0, outwin=0;

	switch(bp->type){
	case M_CTL:
		if(streamparse("init", bp)){
			switch(getfields(bp->rptr, fields, 2, ' ')){
			case 2:
				inwin = strtoul(fields[1], 0, 0);
			case 1:
				outwin = strtoul(fields[0], 0, 0);
			}
			initinput(up, inwin);
			initoutput(up, outwin);
			freeb(bp);
			return;
		}
	}
	PUTNEXT(q, bp);
}

/*
 * accept data from writer
 */
urpoput(Queue *q, Block *bp)
{
	Urp *up;

	up = (Urp *)q->ptr;

	if(bp->type != M_DATA){
		urpctloput(up, q, bp);
		return;
	}

	urpstat.output + =  bp->wptr - bp->rptr;

	for(;;){
	}
}

/*
 * wait for an AINIT
 */
void
urpopenwait(Urp *up, Queue *q)
{
	while((up->state&ISOPENING) && !(up->state&RCLOSE)) {
		proc->state = Waiting;
		up->proc = proc;
		putctl1(q->next, M_RDATA, INIT1);
		if((up->state&ISOPENING) == 0){
			up->proc = 0;
			if(proc->state == Waiting){
				proc->state = Running;
				return;
			}
		}
		sched();
		up->proc = 0;
	}
}

/*
 *  wait till transmission is complete
 */
void
urpxmitwait(Urp *up, Queue *q)
{
	Block *bp;
	int debug;

	debug = (q->flag&QDEBUG);

	up->timeout = 0;
	while(!EMPTY(q) || up->WS<up->WNX){
		/*
		 *  clean up if the channel closed
		 */
		if (up->state & RCLOSE) {
			while(bp = getq(q))
				freeb(bp);
			up->WACK = up->WS = up->WNX;
		}
		/*
		 * free acked blocks
		 */
		urpfreeacked(up);
		/*
		 * retransmit if requested
		 */
		if(up->state&REXMIT)
			urprexmit(up, q);
		/*
		 * fill up the window
		 */
		if(!EMPTY(q) && WINDOW(up))
			urpfillwindow(up, q);
		/*
		 * ask other end for its status
		 */
		if(up->timeout){
			urpstat.enqsx++;
			putctl1(q->next, M_RDATA, ENQ);
			up->timeout = 0;
		}
		lock(up->olock);
		if((up->state&RCLOSE) == 0 && up->WS! = up->WNX) {
			proc->state = Waiting;
			up->proc = proc;
			unlock(up->olock);
			sched();
		} else
			unlock(up->olock);
	}
	urpfreeacked(up);
	up->WS = up->WACK = up->WF = up->WNX = up->WNX&07;
}

/*
 * fill up the urp output window
 */
void
urpfillwindow(Urp *up, Queue *q)
{
	Block *bp, *xbp;
	int debug;

	debug = (q->flag&QDEBUG);

	/*
	 * now process any thing that fits in the flow control window
	 */
	while (WINDOW(up)) {
		bp = getq(q);
		if (bp  ==  NULL)
			break;
		/* force MAXBLOCK length segments */
		if (bp->rptr+up->maxblock < bp->wptr) {
			xbp = allocb(0);
			if (xbp == NULL) {
				putbq(q, bp);
				break;
			}
			xbp->rptr = bp->rptr;
			bp->rptr + =  up->maxblock;
			xbp->wptr = bp->rptr;
			putbq(q, bp);
			bp = xbp;
		}
		/*
		 *  put new block in the block array.  if something is already
		 *  there, it should be because we haven't gotten around to freeing
		 *  it yet.  If not, complain.
		 */
		if (up->xb[up->WNX&07]) {
			urpfreeacked(up);
			if (up->xb[up->WNX&07]) {
				uprint(up, "urpfillwindow: overlap");
				freeb(up->xb[up->WNX&07]);
			}
		}
		up->xb[up->WNX&07] = bp;
		up->WNX++;
		urpxmit(q, bp, up->WNX-1);
	}
}

/*
 *  Send out a message, with trailer.
 */
void
urpxmit(Queue *q, Block *bp, int seqno)
{
	Urp *up = (Urp *)q->ptr;
	int size;
	Block *xbp;
	int debug;

	if (bp == NULL) {
		print("null bp in urpxmit\n");
		return;
	}
	debug = (q->flag&QDEBUG);
	size = bp->wptr - bp->rptr;
	seqno & =  07;
	/* send ptr to block, if non-empty */
	if (size) {
		if ((xbp = allocb(0))  ==  NULL){
			print("can't xmit\n");
			return;
		}
		xbp->rptr = bp->rptr;
		xbp->wptr = bp->wptr;
		xbp->type = bp->type;
		PUTNEXT(q, xbp);
	}
	/* send trailer */
	if ((xbp = allocb(3))  ==  NULL){
		print("can't xmit2\n");
		return;
	}
	xbp->type = M_RDATA;
	*xbp->wptr++ = (bp->class&S_DELIM) ? BOT: BOTM;
	*xbp->wptr++ = size;
	*xbp->wptr++ = size >> 8;
	PUTNEXT(q, xbp);
	putctl1(q->next, M_RDATA, SEQ + seqno);
	up->timer = DKPTIME;
}

void
urprexmit(Urp *up, Queue *q)
{
	int i;

	for (i = up->WACK; i<up->WNX; i++) {
		urpxmit(q, up->xb[i&07], i);
		urpstat.rxmit++;
	}
	up->state & =  ~REXMIT;
}

/*
 *  receive an acknowledgement
 */
static void
rcvack(Urp *up, int msg)
{
	int seqno;
	int next;

	seqno = msg&07;
	next = (seqno+1) & 0x7

	lock(up);
	if(BETWEEN(seqno, up->WACK, up->WNX))
		up->WACK = next;

	switch(msg & 0370){
	case ECHO:
		up->timer = MSrexmit;	/* push off ENQ timeout */
		if(BETWEEN(seqno, up->WS, up->WNX)){
			up->WS = next;
			wakeup(&up->r);
		}
		break;
	case REJ:
	case ACK:
		if(up->WACK == next){
			up->state |= REXMIT;
			wakeup(&up->r);
		}
		break;
	}
	unlock(up);
}

/*
 * throw away any partially collected input
 */
static void
flushinput(Urp *up)
{
	Block *bp;

	while (bp = getq(up->rq))
		freeb(bp);
	up->trx = 0;
}

/*
 *  send a control character down stream
 */
static void
sendctl(Queue *q, int x)
{
	Block *bp;

	/*
	 *  send anything queued
	 */
	while(bp = getq(q))
		PUTNEXT(q, bp);

	/*
	 *  send the new byte
	 */
	bp = allocb(1);
	*bp->wptr++ = x;
	PUTNEXT(q, bp);
}

/*
 *  queue a control character to be sent down stream
 */
static void
queuectl(Urp *up, int x)
{
	Block *bp;
	Queue *q;

	q = up->wq;
	bp = allocb(1);
	*bp->wptr++ = x;
	putq(q, bp);
	wakeup(&up->r);
}

/*
 *  initialize output
 */
static void
initoutput(Urp *up, int window)
{
	/*
	 *  ack any outstanding blocks
	 */
	if(up->WS<up->WNX)
		urprack(up, ECHO+((up->WNX-1)&07));

	/*
	 *  set output window
	 */
	up->maxblock = window/4;
	if(up->maxblock < 64)
		up->maxblock = 64;
	if(up->maxblock > Streamhi/4)
		up->maxblock = Streamhi/4;
	up->XW = 4;

	/*
	 *  set sequence varialbles
	 */
	up->WS = 1;
	up->WACK = 1;
	up->WNX = 1;

	/*
	 *  tell the other side we've inited
	 */
	up->state |= ISOPENING;
	up->timer = MSrexmit;
	sendctl(q->next, INIT1);
}

/*
 *  initialize input
 */
static void
initinput(Urp *up, int window)
{
	/*
	 *  restart all sequence parameters
	 */
	up->trx = 0;
	up->iseq = 0;
	up->lastecho = ECHO+0;
	up->WF = 1;
	flushinput(up);
}
.
## diffname port/sturp.c 1990/0312
## diff -e /n/bootesdump/1990/0227/sys/src/9/mips/sturp.c /n/bootesdump/1990/0312/sys/src/9/mips/sturp.c
807a
}

/*
 *  do retransmissions etc
 */
static int
todo(void *arg)
{
	Urp *up;

	up = (Urp *)arg;
	return (WINDOW(up)>0 && up->wq->len>0 && !(up->state&INITING));
}
static void
urpkproc(void *arg)
{
	Urp *up;

	up = (Urp *)arg;

	for(;;){
		if(up->state & (HUNGUP|CLOSING)){
			if(isflushed(up))
				wakeup(&up->r);
			if(up->state & HUNGUP)
				break;
		}
		if((up->lastecho&Nmask)!=up->iseq && up->rq->next->len<Streamhi)
			sendctl(up, up->lastecho = ECHO+up->iseq);
		output(up);
		tsleep(&up->rq->r, todo, up, MSrexmit/2);
	}
	DPRINT("urpkproc exiting %ux\n", up);
	up->kstarted = 0;
	up->state = 0;
.
806d
789,791c
	up->state |= INITING;
	up->timer = NOW + MSrexmit;
	sendctl(up, INIT1);
.
786a
	 *  free any outstanding blocks
	 */
	for(i = 0; i < 8; i++){
		qlock(&up->xl[i]);
		if(up->xb[i])
			freeb(up->xb[i]);
		qunlock(&up->xl[i]);
	}

	/*
.
782,784c
	up->unechoed = 1;
	up->unacked = 1;
	up->next = 1;
	up->nxb = 1;
.
777c
	up->maxblock -= 4;
	up->maxout = 3;
.
763,767c
	int i;
.
720,757d
703c

	wakeup(&up->rq->r);
.
697,699c
		/*
		 *  start a retransmission if we aren't retransmitting
		 *  and this is the start of a window.
		 */
		if(up->unechoed==next && !(up->state & REJECTING)){
			up->state |= REJECTING;
			up->next = next;
.
695a
		if(IN(seqno, up->unechoed, up->next))
			up->unechoed = next;
		/*
		 *  ... FALL THROUGH ...
		 */
.
693a
		/*
		 *  the next reject at the start of a window starts a 
		 *  retransmission.
		 */
		up->state &= ~REJECTING;
.
689,692c
		if(IN(seqno, up->unechoed, up->next)) {
			up->unechoed = next;
.
683,685c
	/*
	 *  release any acknowledged blocks
	 */
	if(IN(seqno, up->unacked, up->next)){
		for(; up->unacked != next; up->unacked = NEXT(up->unacked)){
			qlock(&up->xl[up->unacked]);
			if(up->xb[up->unacked])
				freeb(up->xb[up->unacked]);
			up->xb[up->unacked] = 0;
			qunlock(&up->xl[up->unacked]);
		}
	}
.
680,681c
	seqno = msg&Nmask;
	next = NEXT(seqno);
.
664,668c
	up->timer = NOW + MSrexmit;
	if(up->wq->next->len > Streamhi)
		return;

	/*
	 *  message 1, the BOT and the data
	 */
	bp = up->xb[bn];
	m = allocb(1);
	m->rptr = m->lim - 1;
	m->wptr = m->lim;
	*m->rptr = (bp->flags & S_DELIM) ? BOT : BOTM;
	nbp = m->next = allocb(0);
	nbp->rptr = bp->rptr;
	nbp->wptr = bp->wptr;
	nbp->flags |= S_DELIM;
	PUTNEXT(up->wq, m);

	/*
	 *  message 2, the block length and the SEQ
	 */
	m = allocb(3);
	m->rptr = m->lim - 3;
	m->wptr = m->lim;
	n = BLEN(bp);
	m->rptr[0] = SEQ | bn;
	m->rptr[1] = n;
	m->rptr[2] = n<<8;
	m->flags |= S_DELIM;
	PUTNEXT(up->wq, m);
.
662c
	Block *bp, *m, *nbp;
	int n;
.
659,660c
/*
 *  send a block.
 */
static void
sendblock(Urp *up, int bn)
.
630,656c
	bp = allocb(1);
	bp->wptr = bp->lim;
	bp->rptr = bp->lim-1;
	*bp->rptr = ctl;
	bp->flags |= S_DELIM;
	PUTNEXT(up->wq, bp);
.
627,628c
	if(up->wq->next->len > Streamhi)
.
622,625c
	Block *bp;
.
619,620c
static void
sendctl(Urp *up, int ctl)
.
617c
 *  send a control byte, put the byte at the end of the allocated
 *  space in case a lower layer needs header room.
.
613a
	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
	 */
	if(up->unechoed != up->next && NOW > up->timer){
		print("sENQ\n");
		up->timer = NOW + MSrexmit;
		up->state &= ~REJECTING;
		sendctl(up, ENQ);
		qunlock(&up->xmit);
		poperror();
		return;
	}

	/*
	 *  if there's a window open, push some blocks out
	 */
	while(WINDOW(up)>0 && up->xb[up->next]!=0 && canqlock(&up->xl[up->next])){
		if(up->xb[up->next])
			sendblock(up, up->next);
		qunlock(&up->xl[up->next]);
		up->next = NEXT(up->next);
	}
	qunlock(&up->xmit);
	poperror();
.
598,612d
581,596c
	q = up->wq;
	for(bp = getq(q); bp && up->xb[up->nxb]==0; up->nxb = NEXT(up->nxb)){
		if(BLEN(bp) > up->maxblock){
			nbp = up->xb[up->nxb] = allocb(0);
			nbp->rptr = bp->rptr;
			nbp->wptr = bp->rptr = bp->rptr + up->maxblock;
		} else {
			up->xb[up->nxb] = bp;
			bp = getq(q);
.
579c
	 *  fill the transmit buffers
.
567,577d
563,565d
532,561c
		qunlock(&up->xmit);
		poperror();
		return;
.
522,530c
	/*
	 *  if still initing and it's time to rexmit, send an INIT1
	 */
	now = NOW;
	if(up->state & INITING){
		if(now > up->timer){
			sendctl(up, INIT1);
			up->timer = now + MSrexmit;
.
520c
	if(waserror()){
		print("urp output error\n");
		qunlock(&up->xmit);
		nexterror();
	}
.
511,518c
	if(!canqlock(&up->xmit))
		return;
.
495,509c
	Block *bp, *nbp;
	ulong now;
	Queue *q;
	int n;
.
492,493c
static void
output(Urp *up)
.
490c
 *  start output
.
483,486c
	urpstat.output += BLEN(bp);
	putq(q, bp);
	output(up);
.
471a
static void
.
470c
 *  accept data from a writer
.
460c
/*			initinput(up, inwin); */
			DPRINT("initoutput %d\n", outwin);
.
454c
			switch(getfields((char *)bp->rptr, fields, 2, ' ')){
.
447c
	char *fields[2];
.
436c
		up->iseq = i;
.
432,434c
			sendctl(up, ECHO+i);
			up->lastecho = ECHO+i;
			wakeup(&up->rq->r);
.
430d
424c
		}
.
422c
			bp->flags |= S_DELIM;
.
419c
				PUTNEXT(q, bp);
.
417c
			if(up->trbuf[0] != BOTM)
				q->last->flags |= S_DELIM;
.
409a
			print("sREJ\n");
			sendctl(up, up->lastecho = REJ+up->iseq);
.
407c
		} else if(i != ((up->iseq+1)&Nmask)) {
.
405a
			print("sREJ\n");
			sendctl(up, up->lastecho = REJ+up->iseq);
.
401a
			print("sREJ\n");
			sendctl(up, up->lastecho = REJ+up->iseq);
.
398c
		i = ctl & Nmask;
.
394c
	 *  if the seuence number is the next expected
	 *	and te trailer length == 3
	 *	and the block count matches the bytes received
	 *  then send the bytes upstream.
.
382a
		print("rREJ\n");
.
361,362c
		sendctl(up, AINIT);
		if(ctl == INIT0)
.
356c
		wakeup(&up->rq->r);
.
350c
		sendctl(up, ACK+up->iseq);
.
344,345c
		sendctl(up, up->lastecho);
		sendctl(up, ACK+up->iseq);
.
342a
		print("rENQ\n");
.
332d
329d
326,327c
	if(BLEN(bp) > 0){
		putq(q, bp);
		q->last->flags &= ~S_DELIM;
		if(q->len > 4*1024){
.
324c
	 *  queue the block(s)
.
318d
310c
	while(up->trx){
		if(BLEN(bp)<=0)
			break;
.
302,305c
	ctl = *bp->rptr++;
.
290,291c
	int i;
	int ctl;
.
287c
urpiput(Queue *q, Block *bp)
.
284c
 *  block mode input.
 *
 *  the first byte in every message is a ctl byte (which belongs at the end).
 *
 *  Simplifying assumption:  one put == one message && the control byte
 *	is in the first block.  If this isn't true, strange bytes will be
 *	used as control bytes.
.
269,278c
		i = ctl & Nmask;
		if(q->next->len < Streamhi)
			sendctl(up, up->lastecho = ECHO+i);
		up->iseq = i;
.
259a
	case REJ+0: case REJ+1: case REJ+2: case REJ+3:
	case REJ+4: case REJ+5: case REJ+6: case REJ+7:
		rcvack(up, ctl);
		break;
	
.
247,249c
		sendctl(up, AINIT);
		if(ctl == INIT1)
			q->put = urpiput;
.
242c
		wakeup(&up->rq->r);
.
236c
		sendctl(up, ACK+up->iseq);
.
230,232c
		sendctl(up, up->lastecho);
		sendctl(up, ACK+up->iseq);
.
227d
216c
	if(BLEN(bp)>0 && q->next->len<Streamhi)
.
214c
	 *  take care of any data
.
208,211c
	ctl = *bp->rptr++;
	if(ctl < 0)
		return;
.
196,197c
	int i;
	int ctl;
.
193c
urpciput(Queue *q, Block *bp)
.
189,190c
 *  character mode input.
 *
 *  the first byte in every message is a ctl byte (which belongs at the end).
.
175,183c
		up->state |= HUNGUP;
		wakeup(&up->r);
		wakeup(&up->rq->r);
		break;
.
162,164c
	up->state |= CLOSING;
	sleep(&up->r, isflushed, up);

	/*
	 *  ack all outstanding messages
	 */
	qlock(&up->xmit);
	up->state |= HUNGUP;
	i = up->next - 1;
	if(i < 0)
		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);
.
160c
	 *  wait for all outstanding messages to drain, tell kernel
	 *  process we're closing.
.
157d
149a
static int
isdead(void *a)
{
	Urp *up;

	up = (Urp *)a;
	return up->kstarted == 0;
}
static void
.
148c
	return (up->state&HUNGUP) || (up->unechoed==up->next && up->wq->len==0);
.
143c
isflushed(void *a)
.
140c
 *  Shut down the connection and kill off the kernel process
.
136a

	/*
	 *  start the ack/(re)xmit process
	 */
	if(up->kstarted == 0){
		up->kstarted = 1;
		sprint(name, "**urp%d**", up - urp);
		kproc(name, urpkproc, up);
	}
.
132,133c
	up->wq = q->other;
	up->state = OPEN;
.
130c
	q->ptr = q->other->ptr = up;
.
116a
	char name[128];
.
112c
static void
.
110c
Qinfo urpinfo = { urpciput, urpoput, urpopen, urpclose, "urp" };
.
108a
static void	urpkproc(void *arg);
.
105,106c
static void	sendctl(Urp*, int);
.
102a
static void	output(Urp*);
static void	sendblock(Urp*, int);
.
99,100c
static void	urpciput(Queue*, Block*);
static void	urpiput(Queue*, Block*);
static void	urpoput(Queue*, Block*);
.
90,92c
#define	REJECTING	0x1
#define	INITING 	0x2
#define HUNGUP		0x4
#define	OPEN		0x8
#define CLOSING		0x10
.
63,65c
#define WINDOW(u) ((u->unechoed + u->maxout - u->next)%8)
#define IN(x, f, n) (f<=n ? x>=f && x<n : x<n || x>=f)
#define NEXT(x) (((x)+1)&Nmask)
.
61c
	QLock	xl[8];
	ulong	timer;		/* timeout for xmit */

	int	kstarted;
.
54,59c
	int	next;		/* next block to send */
	int	unechoed;	/* first unechoed block */
	int	unacked;	/* first unacked block */
	int	nxb;		/* next xb to use */
.
50,52c
	QLock	xmit;		/* output lock, only one process at a time */
	Queue	*wq;		/* output queue */
	int	maxout;		/* maximum outstanding unacked blocks */
.
42c
	Queue	*rq;		/* input queue */
.
38a
	Rendez	r;		/* process waiting for close */
.
37c
	QLock;
.
20a
#define NOW (MACHP(0)->ticks*MS2HZ)

.
18a
#define DPRINT if(0)

.
16a
	Nmask=		0x7,
.
1,12c
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"
.
## diffname port/sturp.c 1990/0315
## diff -e /n/bootesdump/1990/0312/sys/src/9/mips/sturp.c /n/bootesdump/1990/0315/sys/src/9/mips/sturp.c
825a
	DPRINT("urpkproc started\n");
.
782a
		up->xb[i] = 0;
.
458c
			print("sREJ3 %d %d\n", i, up->iseq);
.
452c
			print("sREJ2 %d\n", up->iseq);
.
446c
			print("sREJ1 %d\n", up->iseq);
.
382c
		print("rENQ %uo %uo\n", up->lastecho, ACK+up->iseq);
.
125a
	DPRINT("urpopen\n");

.
## diffname port/sturp.c 1990/0321
## diff -e /n/bootesdump/1990/0315/sys/src/9/mips/sturp.c /n/bootesdump/1990/0321/sys/src/9/mips/sturp.c
843d
838,839c
		sendack(up);
.
829d
805a
	up->blocks = 0;
.
640a
 *  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);
}

/*
.
599c
		DPRINT("sENQ\n");
.
513d
488a
		if(q->next->len < Streamhi)
			sendctl(up, up->lastecho = ECHO|i);
		qunlock(&up->ack);
.
483,487c
		qlock(&up->ack);
.
459,461c
			sendrej(up);
.
453,455c
			sendrej(up);
.
447,449c
			sendrej(up);
.
425c
		DPRINT("rREJ\n");
.
384c
		DPRINT("rENQ %d %uo %uo\n", up->blocks, up->lastecho, ACK+up->iseq);
		up->blocks = 0;
.
315a
		qunlock(&up->ack);
.
311a
		qlock(&up->ack);
.
209d
203d
126,127d
112a
static void	sendack(Urp*);
static void	sendrej(Urp*);
.
47a
	int	blocks;
.
42c
	QLock	ack;		/* ack lock */
.
## diffname port/sturp.c 1990/0331
## diff -e /n/bootesdump/1990/0321/sys/src/9/mips/sturp.c /n/bootesdump/1990/0331/sys/src/9/mips/sturp.c
66c
#define WINDOW(u) ((u)->unechoed>(u)->next ? (u)->unechoed+(u)->maxout-(u)->next-8 :\
			(u)->unechoed+(u)->maxout-(u)->next)
.
## diffname port/sturp.c 1990/0403
## diff -e /n/bootesdump/1990/0331/sys/src/9/mips/sturp.c /n/bootesdump/1990/0403/sys/src/9/mips/sturp.c
885a
	up->kstarted = 0;
.
884d
872a
	if(waserror()){
		up->state = 0;
		up->kstarted = 0;
		wakeup(&up->r);
		return;
	}
.
807,808d
692c
	if(QFULL(up->wq->next))
.
670c
	if(QFULL(up->rq->next) || (up->lastecho&Nmask)==up->iseq){
.
661c
	if(QFULL(up->rq->next) || (up->lastecho&Nmask)==up->iseq)
.
625c
	if(QFULL(up->wq->next))
.
582c
			bp = 0;
.
575c
	for(bp = getq(q); q->first && up->xb[up->nxb]==0; up->nxb = NEXT(up->nxb)){
		if(bp == 0)
			bp = getq(q);
.
482c
		if(!QFULL(q->next))
.
314c
		if(!QFULL(q->next))
.
256c
	if(BLEN(bp)>0 && !QFULL(q->next))
.
209a

	if(up->kstarted == 0)
		up->state = 0;
.
## diffname port/sturp.c 1990/0406
## diff -e /n/bootesdump/1990/0403/sys/src/9/mips/sturp.c /n/bootesdump/1990/0406/sys/src/9/mips/sturp.c
590,591d
588a
		if(bp)
			putbq(q, bp);
.
578,587c
	if(up->xb[up->nxb]==0) {
		for(bp=getq(q); bp && up->xb[up->nxb]==0; up->nxb=NEXT(up->nxb)){
			if(BLEN(bp) > up->maxblock){
				nbp = up->xb[up->nxb] = allocb(0);
				nbp->rptr = bp->rptr;
				nbp->wptr = bp->rptr = bp->rptr + up->maxblock;
			} else {
				up->xb[up->nxb] = bp;
				bp = getq(q);
			}
.
## diffname port/sturp.c 1990/0424
## diff -e /n/bootesdump/1990/0406/sys/src/9/mips/sturp.c /n/bootesdump/1990/0424/sys/src/9/mips/sturp.c
475c
			if(up->trbuf[0] != BOTM)
				bp->flags |= S_DELIM;
.
374d
372a
		bp->flags &= ~S_DELIM;
.
## diffname port/sturp.c 1990/0505
## diff -e /n/bootesdump/1990/0424/sys/src/9/mips/sturp.c /n/bootesdump/1990/0505/sys/src/9/mips/sturp.c
193c
	tsleep(&up->r, isflushed, up, 60*1000);
.
## diffname port/sturp.c 1990/0509
## diff -e /n/bootesdump/1990/0505/sys/src/9/mips/sturp.c /n/bootesdump/1990/0509/sys/src/9/mips/sturp.c
209c
	for(i = 0; i < 7; i++)
		if(up->xb[i]){
			freeb(up->xb[i]);
			up->xb[i] = 0;
		}
	qunlock(&up->xmit);
.
207c
	 *  free all staged but unsent messages
.
204d
199a
	wakeup(&up->rq->r);

	qlock(&up->xmit);
	/*
	 *  ack all outstanding messages
	 */
.
198d
196c
	 *  kill off the kernel process
.
193c
	tsleep(&up->r, isflushed, up, 2*60*1000);
.
190a
	 *
	 *  if 2 minutes elapse, give it up
.
169c
	return (up->state&HUNGUP) || (up->unechoed==up->nxb && up->wq->len==0);
.
## diffname port/sturp.c 1990/0511
## diff -e /n/bootesdump/1990/0509/sys/src/9/mips/sturp.c /n/bootesdump/1990/0511/sys/src/9/mips/sturp.c
906a
	DPRINT("urpkproc %ux\n", up);
.
901c
		if(up->state == 0){
			DPRINT("urpkproc: %ux->state == 0\n", up);
			break;
		}
		if(!QFULL(up->rq->next))
			sendack(up);
.
888a
		print("urpkproc error %ux\n", up);
.
833a
	up->rexmit = 0;
.
789c
			up->rexmit = 1;
.
757,761c
			i = up->unacked;
			qlock(&up->xl[i]);
			if(up->xb[i])
				freeb(up->xb[i]);
			up->xb[i] = 0;
			qunlock(&up->xl[i]);
.
747a
	int i;
.
627a
		poperror();
.
623,626c
	if(up->rexmit){
		up->rexmit = 0;
		up->next = up->unechoed;
	}
	while(WINDOW(up)>0 && up->xb[up->next]!=0){
		i = up->next;
		qlock(&up->xl[i]);
		if(waserror()){
			qunlock(&up->xl[i]);
			nexterror();
		}
		sendblock(up, i);
		qunlock(&up->xl[i]);
.
610,611c
	if(up->unechoed!=up->next && NOW>up->timer){
.
561a
	int i;
.
473a
		} else if(q->next->len > (3*Streamhi)/2
			|| q->next->nb > (3*Streambhi)/2) {
			flushinput(up);
			break;
.
223a
	}
.
222c
	if(up->kstarted == 0){
		DPRINT("urpclose %ux\n", up);
.
171,178d
62a
	int	rexmit;
.
51d
## diffname port/sturp.c 1990/0601
## diff -e /n/bootesdump/1990/0511/sys/src/9/mips/sturp.c /n/bootesdump/1990/0601/sys/src/9/mips/sturp.c
266c
	} else
.
264c
	if(BLEN(bp)>0  && q->next->len<2*Streamhi && q->next->nb<2*Streambhi){
		bp->flags |= S_DELIM;
.
## diffname port/sturp.c 1990/0629
## diff -e /n/bootesdump/1990/0601/sys/src/9/mips/sturp.c /n/bootesdump/1990/0629/sys/src/9/mips/sturp.c
925a
}

/*
 *  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);
.
770a
			else
				urpvomit("rcvack", up);
.
724a
	if(bp == 0){
		urpvomit("sendblock", up);
		return;
	}
.
622,626c
	while(WINDOW(up)>0 && up->next!=up->nxb){
.
620a
	 *
	 *  the lock is to synchronize with acknowledges that free
	 *  blocks.
.
610c
	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
		 */
.
608c
	 *  retransmit cruft
.
604,606c

.
599a
			up->nxb = i;
.
590,591c
	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);
.
587c
	 *  fill the transmit buffers, `nxb' can never overtake `unechoed'
.
119a
static void	urpvomit(char*, Urp*);
.
68c
#define IN(x, f, n) (f<=n ? (x>=f && x<n) : (x<n || x>=f))
.
## diffname port/sturp.c 1990/0702
## diff -e /n/bootesdump/1990/0629/sys/src/9/mips/sturp.c /n/bootesdump/1990/0702/sys/src/9/mips/sturp.c
962a
	lock(up->rq->next);
	for(bp = up->rq->next->first; bp; bp = bp->next){
		print("%d%c:\t", bp->wptr - bp->rptr, (bp->flags&S_DELIM)?'D':' ');
		
		for(cp = bp->rptr; cp<bp->wptr && cp<bp->rptr+10; cp++)
			print(" %uo", *cp);
		print("\n");
	}
	unlock(up->rq->next);
.
961c
	print("\tupq: %ux %d %d\n", &up->rq->next->r,  up->rq->next->nb,
.
952a
	Block *bp;
	uchar *cp;

.
## diffname port/sturp.c 1990/0707
## diff -e /n/bootesdump/1990/0702/sys/src/9/mips/sturp.c /n/bootesdump/1990/0707/sys/src/9/mips/sturp.c
966,974d
953,955d
## diffname port/sturp.c 1990/0717
## diff -e /n/bootesdump/1990/0707/sys/src/9/mips/sturp.c /n/bootesdump/1990/0717/sys/src/9/mips/sturp.c
970c
	for(up = urp; up < &urp[conf.nurp]; up++)
.
179a
	if(up == 0)
		return;
.
141a
	}
.
140c
	if(up == &urp[conf.nurp]){
		q->ptr = 0;
		WR(q)->ptr = 0;
.
134c
	for(up = urp; up < &urp[conf.nurp]; up++){
.
123a
void
urpreset(void)
{
	newqinfo(&urpinfo);
	urp = (Urp *)ialloc(conf.nurp*sizeof(Urp), 0);
}

.
100c
Urp	*urp;
.
10d
## diffname port/sturp.c 1990/0721
## diff -e /n/bootesdump/1990/0717/sys/src/9/mips/sturp.c /n/bootesdump/1990/0721/sys/src/9/mips/sturp.c
928a
	q = up->wq;
.
926c
	Urp *up; Queue *q;
.
690a
	Queue *q = up->wq;
.
538a
		if(streamparse("debug", bp)){
			switch(getfields((char *)bp->rptr, fields, 2, ' ')){
			case 1:
				if (strcmp(fields[0], "on") == 0) {
					q->flag |= QDEBUG;
					q->other->flag |= QDEBUG;
				}
				if (strcmp(fields[0], "off") == 0) {
					q->flag &= ~QDEBUG;
					q->other->flag &= ~QDEBUG;
				}
			}
			freeb(bp);
			return;
		}
.
485a
		DPRINT("rSEQ%d accept %d\n", i, q->len);
.
461,462c
	 *  if the sequence number is the next expected
	 *	and the trailer length == 3
.
442a
	case BOTS:
		DPRINT("rBOT%d...", ctl-BOT);
.
441d
14c
#define DPRINT /*if(q->flag&QDEBUG)kprint*/
.
## diffname port/sturp.c 1990/0722
## diff -e /n/bootesdump/1990/0721/sys/src/9/mips/sturp.c /n/bootesdump/1990/0722/sys/src/9/mips/sturp.c
165c
		sprint(name, "urp%d", up - urp);
.
## diffname port/sturp.c 1990/0725
## diff -e /n/bootesdump/1990/0722/sys/src/9/mips/sturp.c /n/bootesdump/1990/0725/sys/src/9/mips/sturp.c
974a
}

/*
 *  timer to wakeup urpkproc's for retransmissions
 */
static void
urptimer(Alarm *a)
{
	Urp *up;
	Urp *last;
	Queue *q;

	urptiming = 0;
	for(up = urp, last = &urp[conf.nurp]; up < last; up++){
		if(up->state==0)
			continue;
		if(up->unacked!=up->next && NOW>up->timer){
			q = up->rq;
			if(q)
				wakeup(&q->r);
		}
	}
.
970c
		sleep(&up->rq->r, todo, up);
.
591a
	/*
	 *  start the urptimer if it isn't already
	 */
	if(urptiming==0){
		if(canlock(&urptlock)){
			if(urptiming == 0)
				urptiming = alarm(500, urptimer, 0);
			unlock(&urptlock);
		}
	}

.
167a

	/*
	 *  start the urptimer if it isn't already
	 */
	if(urptiming==0){
		if(canlock(&urptlock)){
			if(urptiming == 0)
				urptiming = alarm(500, urptimer, 0);
			unlock(&urptlock);
		}
	}
.
118a
static void	urptimer(Alarm*);
.
70a
 *  Alarm for urptiming
 */
Alarm	*urptiming;
Lock	urptlock;

/*
.
## diffname port/sturp.c 1990/0726
## diff -e /n/bootesdump/1990/0725/sys/src/9/mips/sturp.c /n/bootesdump/1990/0726/sys/src/9/mips/sturp.c
1015a
	cancel(a);
.
## diffname port/sturp.c 1990/0728
## diff -e /n/bootesdump/1990/0726/sys/src/9/mips/sturp.c /n/bootesdump/1990/0728/sys/src/9/mips/sturp.c
1017c
	alarm(500, urptimer, 0);
.
1002a
	wakeup(&up->r);
	poperror();
.
1001d
995d
986,993c
		if(up->state & HUNGUP)
.
980d
976c
	up->kstarted = 1;
.
973c
	Urp *up;
.
707a
out:
.
685,687c
		goto out;
.
639,641c
		goto out;
.
610,620d
244,247c
	/*
	 *  wait for kernel process to die
	 */
	while(up->kstarted)
		sleep(&up->r, isdead, up);

	up->state = 0;
.
220c
	 *  tell kernel process to die
.
191a
isdead(void *a)
{
	Urp *up;

	up = (Urp *)a;
	return up->kstarted==0;
}
static int
.
170,185c
	sprint(name, "urp%d", up - urp);
	kproc(name, urpkproc, up);
.
134a
	alarm(500, urptimer, 0);
.
71,76d
## diffname port/sturp.c 1990/0731
## diff -e /n/bootesdump/1990/0728/sys/src/9/mips/sturp.c /n/bootesdump/1990/0731/sys/src/9/mips/sturp.c
991c
		if((up->unacked!=up->next || (up->state&INITING)) && NOW>up->timer){
.
## diffname port/sturp.c 1990/0804
## diff -e /n/bootesdump/1990/0731/sys/src/9/mips/sturp.c /n/bootesdump/1990/0804/sys/src/9/mips/sturp.c
991,995c
		if(up->rq && todo(up))
			wakeup(&up->rq->r);
.
973d
946c

	return (up->state&INITING)
	? NOW>up->timer					/* time to INIT1 */
	: ((up->unacked!=up->next && NOW>up->timer)	/* time to ENQ */
	  || (!QFULL(up->rq->next) && up->iseq!=(up->lastecho&7))); /* time to ECHO */
.
## diffname port/sturp.c 1990/0814
## diff -e /n/bootesdump/1990/0804/sys/src/9/mips/sturp.c /n/bootesdump/1990/0814/sys/src/9/mips/sturp.c
949a
	  || WINDOW(up)>0 && up->next!=up->nxb
.
777d
774,775c
	if(bp == 0)
.
## diffname port/sturp.c 1990/0911
## diff -e /n/bootesdump/1990/0814/sys/src/9/mips/sturp.c /n/bootesdump/1990/0911/sys/src/9/mips/sturp.c
127d
124c
static void
.
122c
Qinfo urpinfo = { urpciput, urpoput, urpopen, urpclose, "urp", urpreset };
.
103a
static void	urpreset(void);
.
14c
#define DPRINT if(q->flag&QDEBUG)print
.
## diffname port/sturp.c 1990/0930
## diff -e /n/bootesdump/1990/0911/sys/src/9/mips/sturp.c /n/bootesdump/1990/0930/sys/src/9/mips/sturp.c
947c
	: ((up->unechoed!=up->next && NOW>up->timer)	/* time to ENQ */
.
656c
	} else if(up->unechoed!=up->next && NOW>up->timer){
.
## diffname port/sturp.c 1990/1004
## diff -e /n/bootesdump/1990/0930/sys/src/9/mips/sturp.c /n/bootesdump/1990/1004/sys/src/9/mips/sturp.c
993,994c
		if(up->rq && canlock(up)){
			if(up->rq && NOW>up->timer
			   && ((up->state&INITING) || up->unechoed!=up->next))
				wakeup(&up->rq->r);
			unlock(up);
		}
.
986d
948,949c
	  || (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 */
.
797c
	PUTNEXT(q, m);
	DPRINT("sb %d\n", bn);
.
784c
	PUTNEXT(q, m);
.
767c
	if(QFULL(q->next))
.
765a
	q = up->wq;
.
764a
	Queue *q;
.
706c
	PUTNEXT(q, bp);
	DPRINT("sCTL %ulx\n", ctl);
.
699c
	q = up->wq;
	if(QFULL(q->next))
.
697a
	Queue *q;
.
467a
		DPRINT("rACK %ux\n", ctl);
.
239a
	up->rq = 0;
	unlock(up);
.
238a
	lock(up);
.
158c
	unlock(up);
.
146c
		unlock(up);
.
143c
		lock(up);
.
36c
	Lock;
.
## diffname port/sturp.c 1990/11151
## diff -e /n/bootesdump/1990/1004/sys/src/9/mips/sturp.c /n/bootesdump/1990/11151/sys/src/9/mips/sturp.c
123c
Qinfo urpinfo =
{
	urpciput,
	urpoput,
	urpopen,
	urpclose,
	"urp",
	urpreset
};
.
## diffname port/sturp.c 1990/11211
## diff -e /n/bootesdump/1990/11151/sys/src/9/mips/sturp.c /n/bootesdump/1990/11211/sys/src/9/mips/sturp.c
159c
		error(Egreg);
.
## diffname port/sturp.c 1990/1206
## diff -e /n/bootesdump/1990/11211/sys/src/9/mips/sturp.c /n/bootesdump/1990/1206/sys/src/9/mips/sturp.c
1015a
		tsleep(&urpkr, return0, 0, 1000);
.
984,1014c
		for(up = urp; up < eup; up++){
			if(up->state==0 || (up->state&HUNGUP))
				break;
			if(!canqlock(up))
				continue;
			if(up->state==0 || (up->state&HUNGUP))
				break;
			if(up->iseq!=(up->lastecho&7) && !QFULL(up->rq->next))
				sendack(up);
			output(up);
			qunlock(up);
.
977,982c
	eup = urp + conf.nurp;
.
974,975c
	if(waserror())
		;
.
972c
	Urp *up, *eup;
.
953,968d
876c
	wakeup(&urpkr);
.
443c
		wakeup(&urpkr);
.
322c
		wakeup(&urpkr);
.
263d
249,250c
	qunlock(up);
.
241,247c
	qlock(up);
.
220d
215,218d
181,188d
169,174d
166c
	qunlock(up);
.
154c
		qunlock(up);
.
151c
		qlock(up);
.
146a
	if(!urpkstarted){
		qlock(&urpkl);
		if(!urpkstarted){
			urpkstarted = 1;
			kproc("urpkproc", urpkproc, 0);
		}
		qunlock(&urpkl);
	}

.
137d
120d
99,100d
64a
Urp	*urp;

Rendez	urpkr;
QLock	urpkl;
int	urpkstarted;

.
62,63d
38c
	Rendez	r;		/* process waiting for output to finish */
.
36c
	QLock;
.
## diffname port/sturp.c 1990/1210
## diff -e /n/bootesdump/1990/1210/sys/src/9/mips/sturp.c /n/bootesdump/1990/1210/sys/src/9/port/sturp.c
955a
			poperror();
.
950,951c
			if(waserror()){
				qunlock(up);
				continue;
			}
			if(up->state==0 || (up->state&HUNGUP)){
				qunlock(up);
				poperror();
				continue;
			}
.
947c
				continue;
.
209c
	if(!waserror()){
		tsleep(&up->r, isflushed, up, 2*60*1000);
		poperror();
	}
.
## diffname port/sturp.c 1990/1212
## diff -e /n/bootesdump/1990/1210/sys/src/9/port/sturp.c /n/bootesdump/1990/1212/sys/src/9/port/sturp.c
171a
	q->rp = &urpkr;
.
## diffname port/sturp.c 1990/1214
## diff -e /n/bootesdump/1990/1212/sys/src/9/port/sturp.c /n/bootesdump/1990/1214/sys/src/9/port/sturp.c
543a
			USED(inwin);
.
## diffname port/sturp.c 1991/0426
## diff -e /n/bootesdump/1990/1214/sys/src/9/port/sturp.c /n/bootesdump/1991/0426/sys/src/9/port/sturp.c
863a
	wakeup(&up->r);
.
## diffname port/sturp.c 1991/0605
## diff -e /n/bootesdump/1991/0426/sys/src/9/port/sturp.c /n/bootesdump/1991/0605/sys/src/9/port/sturp.c
366a
	if(up == 0)
		return;
.
267a
	if(up == 0)
		return;
.
160,163c
		if(up->state == 0){
			qlock(up);
			if(up->state == 0)
				break;
			qunlock(up);
		}
.
## diffname port/sturp.c 1991/0626
## diff -e /n/bootesdump/1991/0605/sys/src/9/port/sturp.c /n/bootesdump/1991/0626/sys/src/9/port/sturp.c
14c
#define DPRINT if(q->flag&QDEBUG)kprint
.
## diffname port/sturp.c 1991/0705
## diff -e /n/bootesdump/1991/0626/sys/src/9/port/sturp.c /n/bootesdump/1991/0705/sys/src/9/port/sturp.c
14c
#define DPRINT if(q->flag&QDEBUG)print
.
## diffname port/sturp.c 1991/1115
## diff -e /n/bootesdump/1991/0705/sys/src/9/port/sturp.c /n/bootesdump/1991/1115/sys/src/9/port/sturp.c
170c
		errors("out of urp structures");
.
## diffname port/sturp.c 1991/1122
## diff -e /n/bootesdump/1991/1115/sys/src/9/port/sturp.c /n/bootesdump/1991/1122/sys/src/9/port/sturp.c
1006a
}

void
urpfillstats(Chan *c, char *buf, int len)
{
	char b[256];

	USED(c);
	sprint(b, "in: %d\nout: %d\nrexmit: %d\nrjtrs: %d\nrjpks: %d\nrjseq: %d\nenqsx: %d\nenqsr: %d\n",
		urpstat.input, urpstat.output, urpstat.rexmit, urpstat.rjtrs,
		urpstat.rjpks, urpstat.rjseq, urpstat.enqsr, urpstat.enqsr);
	strncpy(buf, b, len);
.
667a
		urpstat.enqsx++;
.
658a
		urpstat.rexmit++;
.
510a
			}
.
509c
			while(bp = getq(q)){
				urpstat.input += BLEN(bp);
.
288a
		urpstat.input += BLEN(bp);
.
26c
	ulong	rexmit;		/* retransmit rejected urp msg */
.
## diffname port/sturp.c 1991/1216
## diff -e /n/bootesdump/1991/1122/sys/src/9/port/sturp.c /n/bootesdump/1991/1216/sys/src/9/port/sturp.c
956a
	USED(arg);

.
## diffname port/sturp.c 1992/0111
## diff -e /n/bootesdump/1991/1216/sys/src/9/port/sturp.c /n/bootesdump/1992/0111/sys/src/9/port/sturp.c
7c
#include	"../port/error.h"
.
## diffname port/sturp.c 1992/0114
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/sturp.c /n/bootesdump/1992/0114/sys/src/9/port/sturp.c
170c
		exhausted("urp structures");
.
## diffname port/sturp.c 1992/0205
## diff -e /n/bootesdump/1992/0114/sys/src/9/port/sturp.c /n/bootesdump/1992/0205/sys/src/9/port/sturp.c
1024c
		urpstat.rjpks, urpstat.rjseq, urpstat.enqsx, urpstat.enqsr);
.
932a
	{ Queue *q = up->wq; DPRINT("initoutput (%d): ", up->timer); }
.
813c
	DPRINT("sb %d (%d)\n", bn, up->timer);
.
765a
	{ Queue *q = up->wq; DPRINT("sendack: "); }
.
719a
	PUTNEXT(q, bp);
.
718d
669a
		DPRINT("OUTPUT timer (%d, %d): ", NOW, up->timer);
.
624a
			q = up->wq;
			DPRINT("INITING timer (%d, %d): ", now, up->timer);
.
502c
		DPRINT("accept %d\n", q->len);
.
483a
		DPRINT("rSEQ%d...", ctl-SEQ);
.
472c
		DPRINT("%s%d\n", (ctl&ECHO)?"rECHO":"rACK", ctl&7);
.
464c
		DPRINT("rREJ%d\n", ctl-REJ);
.
457c
		DPRINT("rBOT%c...", " MS"[ctl-BOT]);
.
447a
		DPRINT("rINITREQ\n");
.
440a
		DPRINT("rINIT%d\n", ctl-INIT0);
.
433a
		DPRINT("rAINIT\n");
.
429a
		DPRINT("rCHECK\n");
.
344a
		DPRINT("rSEQ%d(c)\n", ctl-SEQ);
.
339a
		DPRINT("%s%d(c)\n", (ctl&ECHO)?"rECHO":"rACK", ctl&7);
.
332a
		DPRINT("rREJ%d(c)\n", ctl-REJ);
.
324a
		DPRINT("rINITREQ(c)\n");
.
317a
		DPRINT("rINIT%d(c)\n", ctl-INIT0);
.
310a
		DPRINT("rAINIT(c)\n");
.
306a
		DPRINT("rCHECK(c)\n");
.
300a
		DPRINT("rENQ(c)\n");
.
172c
/*
	q->flag |= QDEBUG;
	q->other->flag |= QDEBUG;
*/
.
## diffname port/sturp.c 1992/0206
## diff -e /n/bootesdump/1992/0205/sys/src/9/port/sturp.c /n/bootesdump/1992/0206/sys/src/9/port/sturp.c
505a
			DPRINT("rej %d rcvd %d xpctd\n", q->len,
				up->trbuf[1] + (up->trbuf[2]<<8));
.
## diffname port/sturp.c 1992/0208
## diff -e /n/bootesdump/1992/0206/sys/src/9/port/sturp.c /n/bootesdump/1992/0208/sys/src/9/port/sturp.c
515,516c
		}else if(q->next->len > (3*Streamhi)/2
			|| q->next->nb > (3*Streambhi)/2){
			DPRINT("next->len=%d, next->nb=%d\n",
				q->next->len, q->next->nb);
.
511c
		}else if(i != ((up->iseq+1)&Nmask)){
.
505,507c
		}else if(q->len != len){
.
499c
		len = up->trbuf[1] + (up->trbuf[2]<<8);
		DPRINT("rSEQ%d(%d,%d,%d)...", ctl-SEQ, up->trx, len, q->len);
.
379c
	int i, len;
.
14c
#define DPRINT if(q->flag&QDEBUG)kprint
.
## diffname port/sturp.c 1992/0321
## diff -e /n/bootesdump/1992/0208/sys/src/9/port/sturp.c /n/bootesdump/1992/0321/sys/src/9/port/sturp.c
2c
#include	"../port/lib.h"
.
## diffname port/sturp.c 1992/0408
## diff -e /n/bootesdump/1992/0321/sys/src/9/port/sturp.c /n/bootesdump/1992/0408/sys/src/9/port/sturp.c
1008c
		tsleep(&urpkr, return0, 0, 500);
.
897,898c
	tryoutput(up);
	if(up->state & CLOSING)
		wakeup(&up->r);
.
722a
 *  try output, this is called by an input process
 */
void
tryoutput(Urp *up)
{
	if(!waserror()){
		output(up);
		poperror();
	}
}

/*
.
449c
		tryoutput(up);
.
373a
 *
 *	There's no input lock.  The channel could be closed while we're
 *	processing a message.
.
319c
		tryoutput(up);
.
122a
static void	tryoutput(Urp*);
.
## diffname port/sturp.c 1992/0409
## diff -e /n/bootesdump/1992/0408/sys/src/9/port/sturp.c /n/bootesdump/1992/0409/sys/src/9/port/sturp.c
946c
	up->maxout = 4;
.
## diffname port/sturp.c 1992/0520
## diff -e /n/bootesdump/1992/0409/sys/src/9/port/sturp.c /n/bootesdump/1992/0520/sys/src/9/port/sturp.c
1054a
	return 0;
.
## diffname port/sturp.c 1992/0622
## diff -e /n/bootesdump/1992/0520/sys/src/9/port/sturp.c /n/bootesdump/1992/0622/sys/src/9/port/sturp.c
138c
	urp = (Urp *)xalloc(conf.nurp*sizeof(Urp));
.
## diffname port/sturp.c 1992/0623
## diff -e /n/bootesdump/1992/0622/sys/src/9/port/sturp.c /n/bootesdump/1992/0623/sys/src/9/port/sturp.c
1045,1055d
1005c
		for(up = urpalloc.urp; up; up = up->list){
.
1003d
996c
	Urp *up;
.
173,176d
168,171c
	if(up == 0){
		/*
		 *  none available, create a new one, they are never freed
		 */
		up = smalloc(sizeof(Urp));
		qlock(up);
		lock(&urpalloc);
		up->list = urpalloc.urp;
		urpalloc.urp = up;
		unlock(&urpalloc);
.
160c
	for(up = urpalloc.urp; up; up = up->list){
.
158c
	 *  find an unused urp structure
.
138d
64a
/* list of allocated urp structures (never freed) */
struct
{
	Lock;
	Urp	*urp;
} urpalloc;

.
63d
36a
	Urp	*list;		/* list of all urp structures */
.
## diffname port/sturp.c 1992/0711
## diff -e /n/bootesdump/1992/0623/sys/src/9/port/sturp.c /n/bootesdump/1992/0711/sys/src/9/port/sturp.c
989c
initinput(Urp *up)
.
790,791d
638d
578,585c
			outwin = strtoul((char*)bp->rptr, 0, 0);
.
572,573c
	int outwin;
.
470c
		initinput(up);
.
337c
		initinput(up);
.
209d
191c
	initinput(up);
.
153a
	USED(s);
.
151,152d
127c
static void	initinput(Urp*);
.
## diffname port/sturp.c 1992/1026
## diff -e /n/bootesdump/1992/0711/sys/src/9/port/sturp.c /n/bootesdump/1992/1026/sys/src/9/port/sturp.c
573a
		if(streamparse("break", bp)){
			sendctl(up, BREAK);
			freeb(bp);
			return;
		}
.
## diffname port/sturp.c 1992/1027
## diff -e /n/bootesdump/1992/1026/sys/src/9/port/sturp.c /n/bootesdump/1992/1027/sys/src/9/port/sturp.c
838c
	if(bp->type == M_CTL){
		PUTNEXT(q, nbp);
		m->flags |= S_DELIM;
		PUTNEXT(q, m);
	} else {
		m->next = nbp;
		PUTNEXT(q, m);
	}
.
836a
	nbp->base = bp->base;
	nbp->lim = bp->lim;
.
834c
	nbp = allocb(0);
.
575,576c
			/*
			 *  send a break as part of the data stream
			 */
			urpstat.output++;
			bp->wptr = bp->lim;
			bp->rptr = bp->wptr - 1;
			*bp->rptr = BREAK;
			putq(q, bp);
			output(up);
.
## diffname port/sturp.c 1993/0116
## diff -e /n/bootesdump/1992/1027/sys/src/9/port/sturp.c /n/bootesdump/1993/0116/sys/src/9/port/sturp.c
893,894d
244a
		qunlock(&up->xl[i]);
	}
.
240c
	for(i = 0; i < 7; i++){
		qlock(&up->xl[i]);
.
## diffname port/sturp.c 1993/0418
## diff -e /n/bootesdump/1993/0116/sys/src/9/port/sturp.c /n/bootesdump/1993/0418/sys/src/9/port/sturp.c
868c
	m->rptr[2] = n>>8;
.
## diffname port/sturp.c 1993/0501
## diff -e /n/bootesdump/1993/0418/sys/src/9/port/sturp.c /n/fornaxdump/1993/0501/sys/src/brazil/port/sturp.c
1057,1060c
		urp->iseq, urp->lastecho, urp->trx, urp->trbuf[0], urp->trbuf[1],
		urp->trbuf[2]);
	print("\tupq: %ux %d %d\n", &urp->rq->next->r,  urp->rq->next->nb,
		urp->rq->next->len);
.
1054,1055c
		urp->xb[0], urp->xb[1], urp->xb[2], urp->xb[3], urp->xb[4], 
		urp->xb[5], urp->xb[6], urp->xb[7]);
.
1052c
		msg, urp, urp->next, urp->unechoed, urp->unacked, urp->nxb);
.
1049c
urpvomit(char *msg, Urp* urp)
.
1035,1038c
			if(urp->iseq!=(urp->lastecho&7) && !QFULL(urp->rq->next))
				sendack(urp);
			output(urp);
			qunlock(urp);
.
1030,1031c
			if(urp->state==0 || (urp->state&HUNGUP)){
				qunlock(urp);
.
1027c
				qunlock(urp);
.
1024c
			if(!canqlock(urp))
.
1021,1022c
		for(urp = urpalloc.urp; urp; urp = urp->list){
			if(urp->state==0 || (urp->state&HUNGUP))
.
1013c
	Urp *urp;
.
1003,1007c
	urp->blocks = 0;
	urp->trx = 0;
	urp->iseq = 0;
	urp->lastecho = ECHO+0;
	flushinput(urp);
.
998c
initinput(Urp *urp)
.
988,991c
	urp->state |= INITING;
	urp->timer = NOW + MSrexmit;
	{ Queue *q = urp->wq; DPRINT("initoutput (%d): ", urp->timer); }
	sendctl(urp, INIT1);
.
978,982c
		qlock(&urp->xl[i]);
		if(urp->xb[i])
			freeb(urp->xb[i]);
		urp->xb[i] = 0;
		qunlock(&urp->xl[i]);
.
968,972c
	urp->unechoed = 1;
	urp->unacked = 1;
	urp->next = 1;
	urp->nxb = 1;
	urp->rexmit = 0;
.
959,963c
	urp->maxblock = window/4;
	if(urp->maxblock < 64)
		urp->maxblock = 64;
	urp->maxblock -= 4;
	urp->maxout = 4;
.
952c
initoutput(Urp *urp, int window)
.
945c
	urp->trx = 0;
.
943c
	while (bp = getq(urp->rq))
.
939c
flushinput(Urp *urp)
.
930,932c
	tryoutput(urp);
	if(urp->state & CLOSING)
		wakeup(&urp->r);
.
923,925c
		if(urp->unechoed==next && !(urp->state & REJECTING)){
			urp->state |= REJECTING;
			urp->rexmit = 1;
.
913,914c
		if(IN(seqno, urp->unechoed, urp->next))
			urp->unechoed = next;
.
910c
		urp->state &= ~REJECTING;
.
903,904c
		if(IN(seqno, urp->unechoed, urp->next)) {
			urp->unechoed = next;
.
890,897c
	if(IN(seqno, urp->unacked, urp->next)){
		for(; urp->unacked != next; urp->unacked = NEXT(urp->unacked)){
			i = urp->unacked;
			qlock(&urp->xl[i]);
			if(urp->xb[i])
				freeb(urp->xb[i]);
			else
				urpvomit("rcvack", urp);
			urp->xb[i] = 0;
			qunlock(&urp->xl[i]);
.
878c
rcvack(Urp *urp, int msg)
.
871c
	DPRINT("sb %d (%d)\n", bn, urp->timer);
.
868c
	m->rptr[2] = n<<8;
.
837c
	bp = urp->xb[bn];
.
829,830c
	q = urp->wq;
	urp->timer = NOW + MSrexmit;
.
827a
	Block *bp, *m, *nbp;
.
825d
823c
sendblock(Urp *urp, int bn)
.
814,816c
	{ Queue *q = urp->wq; DPRINT("sendack: "); }
	sendctl(urp, urp->lastecho = ECHO|urp->iseq);
	qunlock(&urp->ack);
.
806,807c
	if(QFULL(urp->rq->next) || (urp->lastecho&Nmask)==urp->iseq){
		qunlock(&urp->ack);
.
800c
	if(!canqlock(&urp->ack))
.
797c
	if(QFULL(urp->rq->next) || (urp->lastecho&Nmask)==urp->iseq)
.
792c
sendack(Urp *urp)
.
785c
	qunlock(&urp->ack);
.
778,783c
	Queue *q = urp->wq;
	flushinput(urp);
	qlock(&urp->ack);
	if((urp->lastecho&~Nmask) == ECHO){
		DPRINT("REJ %d\n", urp->iseq);
		sendctl(urp, urp->lastecho = REJ|urp->iseq);
.
776c
sendrej(Urp *urp)
.
760c
	q = urp->wq;
.
755c
sendctl(Urp *urp, int ctl)
.
745c
		output(urp);
.
742c
tryoutput(Urp *urp)
.
734c
	qunlock(&urp->xmit);
.
728,730c
		sendblock(urp, i);
		qunlock(&urp->xl[i]);
		urp->next = NEXT(urp->next);
.
725c
			qunlock(&urp->xl[i]);
.
721,723c
	while(WINDOW(urp)>0 && urp->next!=urp->nxb){
		i = urp->next;
		qlock(&urp->xl[i]);
.
711c
		sendctl(urp, ENQ);
.
707,709c
		DPRINT("OUTPUT timer (%d, %d): ", NOW, urp->timer);
		urp->timer = NOW + MSrexmit;
		urp->state &= ~REJECTING;
.
700,702c
		urp->rexmit = 0;
		urp->next = urp->unacked;
	} else if(urp->unechoed!=urp->next && NOW>urp->timer){
.
694c
	if(urp->rexmit){
.
685c
			urp->nxb = i;
.
682c
				urp->xb[urp->nxb] = bp;
.
680c
				nbp->wptr = bp->rptr = bp->rptr + urp->maxblock;
.
671,678c
	q = urp->wq;
	i = NEXT(urp->nxb);
	if(i != urp->unechoed) {
		for(bp = getq(q); bp && i!=urp->unechoed; i = NEXT(i)){
			if(urp->xb[urp->nxb] != 0)
				urpvomit("output", urp);
			if(BLEN(bp) > urp->maxblock){
				nbp = urp->xb[urp->nxb] = allocb(0);
.
658,663c
	if(urp->state & INITING){
		if(now > urp->timer){
			q = urp->wq;
			DPRINT("INITING timer (%d, %d): ", now, urp->timer);
			sendctl(urp, INIT1);
			urp->timer = now + MSrexmit;
.
650c
		qunlock(&urp->xmit);
.
645c
	if(!canqlock(&urp->xmit))
.
638c
output(Urp *urp)
.
631c
	output(urp);
.
625c
		urpctloput(urp, q, bp);
.
622c
	urp = (Urp *)q->ptr;
.
620c
	Urp *urp;
.
591c
			initoutput(urp, outwin);
.
586c
			output(urp);
.
570c
urpctloput(Urp *urp, Queue *q, Block *bp)
.
560,561c
			sendctl(urp, urp->lastecho = ECHO|i);
		qunlock(&urp->ack);
.
557,558c
		qlock(&urp->ack);
		urp->iseq = i;
.
552c
		urp->trx = 0;
.
548c
			if(urp->trbuf[0] != BOTM)
.
540c
			if(urp->trbuf[0] != BOTM)
.
531c
			flushinput(urp);
.
525c
			sendrej(urp);
.
523c
		}else if(i != ((urp->iseq+1)&Nmask)){
.
521c
			sendrej(urp);
.
517c
			sendrej(urp);
.
515c
		if(urp->trx != 3){
.
512,513c
		len = urp->trbuf[1] + (urp->trbuf[2]<<8);
		DPRINT("rSEQ%d(%d,%d,%d)...", ctl-SEQ, urp->trx, len, q->len);
.
501c
		rcvack(urp, ctl);
.
493c
		rcvack(urp, ctl);
.
486,487c
		urp->trx = 1;
		urp->trbuf[0] = ctl;
.
476c
		initoutput(urp, 0);
.
471c
		initinput(urp);
.
468c
		sendctl(urp, AINIT);
.
460,462c
		urp->state &= ~INITING;
		flushinput(urp);
		tryoutput(urp);
.
455c
		sendctl(urp, ACK+urp->iseq);
.
448,450c
		sendctl(urp, urp->lastecho);
		sendctl(urp, ACK+urp->iseq);
		flushinput(urp);
.
445,446c
		DPRINT("rENQ %d %uo %uo\n", urp->blocks, urp->lastecho, ACK+urp->iseq);
		urp->blocks = 0;
.
432c
			flushinput(urp);
.
420c
			urp->trx = 0;
.
417c
			urp->trbuf[urp->trx++] = *bp->rptr++;
.
414c
		switch (urp->trx) {
.
411c
	while(urp->trx){
.
399c
		urpctliput(urp, q, bp);
.
395,396c
	urp = (Urp *)q->ptr;
	if(urp == 0)
.
391c
	Urp *urp;
.
369,371c
			sendctl(urp, urp->lastecho = ECHO+i);
		urp->iseq = i;
		qunlock(&urp->ack);
.
366c
		qlock(&urp->ack);
.
360c
		rcvack(urp, ctl);
.
352c
		rcvack(urp, ctl);
.
343c
		initoutput(urp, 0);
.
338c
		initinput(urp);
.
335c
		sendctl(urp, AINIT);
.
327,329c
		urp->state &= ~INITING;
		flushinput(urp);
		tryoutput(urp);
.
322c
		sendctl(urp, ACK+urp->iseq);
.
316,317c
		sendctl(urp, urp->lastecho);
		sendctl(urp, ACK+urp->iseq);
.
286c
		urpctliput(urp, q, bp);
.
282,283c
	urp = (Urp *)q->ptr;
	if(urp == 0)
.
278c
	Urp *urp;
.
263,264c
		urp->state |= HUNGUP;
		wakeup(&urp->r);
.
259c
urpctliput(Urp *urp, Queue *q, Block *bp)
.
250,252c
	qlock(urp);
	urp->state = 0;
	qunlock(urp);
.
246,248c
	qunlock(&urp->xmit);
.
240,244c
	for(i = 0; i < 7; i++)
		if(urp->xb[i]){
			freeb(urp->xb[i]);
			urp->xb[i] = 0;
.
235c
	rcvack(urp, ECHO+i);
.
232c
	i = urp->next - 1;
.
228c
	qlock(&urp->xmit);
.
226c
	urp->state |= HUNGUP;
.
223c
		tsleep(&urp->r, isflushed, urp, 2*60*1000);
.
221c
	urp->state |= CLOSING;
.
211,212c
	urp = (Urp *)q->ptr;
	if(urp == 0)
.
208c
	Urp *urp;
.
202,203c
	urp = (Urp *)a;
	return (urp->state&HUNGUP) || (urp->unechoed==urp->nxb && urp->wq->len==0);
.
200c
	Urp *urp;
.
186,191c
	urp->rq = q;
	urp->wq = q->other;
	urp->state = OPEN;
	qunlock(urp);
	initinput(urp);
	initoutput(urp, 0);
.
184c
	q->ptr = q->other->ptr = urp;
.
180,181c
		urp->list = urpalloc.urp;
		urpalloc.urp = urp;
.
177,178c
		urp = smalloc(sizeof(Urp));
		qlock(urp);
.
173c
	if(urp == 0){
.
170c
			qunlock(urp);
.
165,168c
	for(urp = urpalloc.urp; urp; urp = urp->list){
		if(urp->state == 0){
			qlock(urp);
			if(urp->state == 0)
.
150c
	Urp *urp;
.
## diffname port/sturp.c 1993/0804 # deleted
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/sturp.c /n/fornaxdump/1993/0804/sys/src/brazil/port/sturp.c
1,1072d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.