V9/sys/dev/stream.c

Compare this file to the similar file:
Show the results in this format:

#include "../h/param.h"
#include "../h/stream.h"
/*#include "../h/mtpr.h"*/
#include "../h/conf.h"
#include "sparam.h"

#define	M_HIPRI	127			/* for use of putbq */

#ifndef	NBLKBIG
#define	NBLKBIG	0
#endif
#define	NBLOCK (NBLKBIG+NBLK64+NBLK16+NBLK4)
struct	block cblock[NBLOCK]; 		/* allocation of blocks */
u_char	blkdata[1024*NBLKBIG+64*NBLK64+NBLK16*16+NBLK4*4];
long	blkubad;			/* unibus address of blocks */
struct	queue queue[NQUEUE];		/* allocation of queues */
struct	queue *qhead;			/* head of queues to run */
struct	queue *qtail;			/* last queue */
struct	block *qfreelist[4];		/* allocation of freelist heads */
int	cblockC[] = { NBLK4, NBLK16, NBLK64, NBLKBIG };
int	cblockM[] = { 1000, 1000, 1000, 1000 };

int	rbsize[] = { 4, 16, 64, 1024 };	/* real block sizes */
int	bsize[] = { 4, 16, 64, 250 };	/* size for q limits */

int	nballoc;
int	queuerun();

struct block *
allocb(size)
register size;
{
	register struct block *bp;
	register s = spl6();
	register class;

	if (size <= 4)
		class = 0;
	else if (size <= 16)
		class = 1;
	else if (size <= 64)
		class = 2;
	else {
		class = 3;
		nballoc++;
	}
	if (bp = qfreelist[class])
		qfreelist[class] = bp->next;
	else {
		if (qfreelist[2])
			return(allocb(64));
		panic("allocb out of blocks\n");
	}
	splx(s);
	if (--cblockC[class] < cblockM[class])
		cblockM[class] = cblockC[class];
	bp->rptr = bp->base;
	bp->wptr = bp->base;
	bp->lim = bp->base+rbsize[class];
	bp->class = class;
	bp->type = M_DATA;
	bp->next = NULL;
	return(bp);
}

freeb(bp)
register struct block *bp;
{
	register s = spl6();
#ifdef CAREFUL
	register struct block *bp1;
#endif
	register class = bp->class;

#ifdef CAREFUL
	if (bp < &cblock[0] || bp >= &cblock[NBLOCK])
		printf("freeing %x\n", bp);
	bp1 = qfreelist[class];
	while (bp1) {
		if (bp1 == bp)
			panic("Free of free block");
		bp1 = bp1->next;
	}
#endif
	bp->next = qfreelist[class];
	qfreelist[class] = bp;
	cblockC[class]++;
	splx(s);
}

struct block *
getq(q)
register struct queue *q;
{
	register struct block *bp;
	register s = spl6();

	if ((bp = q->first) == NULL) {
		if ((q->flag&QENAB) == 0)
			q->flag |= QWANTR;
	} else {
if (bp < &cblock[0] || bp >= &cblock[NBLOCK]) panic("getting bad block\n");
		if ((q->first = bp->next) == NULL)
			q->last = NULL;
		q->count -= bsize[bp->class];
		if (q->count < q->qinfo->limit)
			q->flag &= ~QFULL;
		q->flag &= ~QWANTR;
	}
	if (q->count<=q->qinfo->lolimit && q->flag&QWANTW && OTHERQ(q)->next) {
		register struct queue *bq = backq(q);
		if (bq->qinfo->srvp) {
			qenable(bq);
		}
		q->flag &= ~QWANTW;
	}
	splx(s);
	return(bp);
}

putq(q, bp)
register struct queue *q;
register struct block *bp;
{
	int s;

	if (bp->type==M_FLUSH)
		flushq(q, 0);
	s = spl6();
	if (q->first==NULL) {			/* empty, just tack on */
		q->first = bp;
		q->last = bp;
		bp->next = NULL;
	} else if (bp->type<QPCTL || q->last->type>=QPCTL) {	/* put at end */
		register struct block *lastp = q->last;
		register n = bp->wptr - bp->rptr;
		if (bp->type==M_DATA && lastp->type==M_DATA
		 && n <= lastp->lim-lastp->wptr && lastp->wptr>=lastp->base){
			bcopy(bp->rptr, lastp->wptr, n);
			lastp->wptr += n;
			freeb(bp);
			bp = NULL;
		} else {
			lastp->next = bp;
			q->last = bp;
			bp->next = NULL;
		}
	} else {				/* pri, put after any others */
		register struct block *nbp = q->first;
		if (nbp->type < QPCTL) {
			bp->next = q->first;
			q->first = bp;
		} else {
			while (nbp->next->type>=QPCTL)
				nbp = nbp->next;
			bp->next = nbp->next;
			nbp->next = bp;
		}
	}
	if (bp) {
		q->count += bsize[bp->class];
		if (bp->type >= QPCTL && bp->type!= M_HIPRI)
			q->flag |= QWANTR;
	}
	if (q->count >= q->qinfo->limit)
		q->flag |= QFULL|QWANTW;
	if ((q->flag & (QWANTR|QENAB|QNOENB)) == QWANTR && q->qinfo->srvp)
		qenable(q);
	splx(s);
}

/*
 * Put stuff back at beginning of Q
 * (but after any priority msgs)
 */
putbq(q, bp)
register struct queue *q;
register struct block *bp;
{
	register savetype = bp->type;
	register s = spl6();

	bp->type = M_HIPRI;		/* fake priority, to force to start */
	putq(q, bp);
	bp->type = savetype;
	splx(s);
}

/*
 * empty a queue.  Leave any non-data messages, unless flag is 1.
 */
flushq(q, flag)
register struct queue *q;
{
	register struct block *bp, *nbp;
	register s = spl6();

	bp = q->first;
	q->first = NULL;
	if (q->last)
		q->last->next = NULL;
	q->last = NULL;
	q->count = 0;
	q->flag &= ~QFULL;
	while (bp) {
		nbp = bp->next;
		if (bp->type != M_DATA && bp->type != M_DELIM
		 && bp->type != M_CTL && bp->type != M_DELAY
		 && bp->type != M_FLUSH && !flag)
			putq(q, bp);
		else {
			if (bp->type == M_PASS)
				printf("flushing PASS %x\n",*(int *)(bp->rptr));
			freeb(bp);
		}
		bp = nbp;
	}
	if (q->flag&QWANTW && OTHERQ(q)->next) {
		q->flag &= ~QWANTW;
		qenable(backq(q));
	}
	splx(s);
}

qinit()
{
	register struct block *bp;
	register i, j;
	register u_char *base;

	base = blkdata;
	/* blocks are allocated on unibus for DMA.  Assumes unibus 0 */
#ifdef vax
	blkubad = uballoc(0, (caddr_t)blkdata, sizeof(blkdata), 0);
	if (blkubad == 0)
		panic("Cannot map blocks on unibus in qinit");
#endif
	i = 0;
	for (j=0; j<NBLK4; i++, j++) {
		bp = &cblock[i];
		bp->class = 0;
		bp->base = base;
		base += 4;
		bp->next = qfreelist[0];
		qfreelist[0] = bp;
	}
	for (j=0; j<NBLK16; i++, j++) {
		bp = &cblock[i];
		bp->class = 1;
		bp->base = base;
		base += 16;
		bp->next = qfreelist[1];
		qfreelist[1] = bp;
	}
	for (j=0; j<NBLK64; i++, j++) {
		bp = &cblock[i];
		bp->class = 2;
		bp->base = base;
		base += 64;
		bp->next = qfreelist[2];
		qfreelist[2] = bp;
	}
	for (j=0; j<NBLKBIG; i++, j++) {
		bp = &cblock[i];
		bp->class = 3;
		bp->base = base;
		base += 1024;
		bp->next = qfreelist[3];
		qfreelist[3] = bp;
	}
}

/*
 * allocate a pair of queues
 */
struct queue *
allocq()
{
	register struct queue *qp;
	static struct queue zeroR =
	  { NULL,NULL,NULL,NULL,NULL,NULL,0,QUSE|QREADR};
	static struct queue zeroW =
	  { NULL,NULL,NULL,NULL,NULL,NULL,0,QUSE};

	for (qp = queue; qp < &queue[NQUEUE]; qp += 2) {
		if ((qp->flag & QUSE) == 0) {
			*qp = zeroR;
			*WR(qp) = zeroW;
			return(qp);
		}
	}
	return(NULL);
}

/*
 * Put one data char on a queue, using f
 */
putd(f, q, c)
int (*f)();
register struct queue *q;
{
	register struct block *bp;
	register s = spl6();

	if (f==putq && (bp = q->last) && bp->type==M_DATA && bp->wptr<bp->lim) {
		*bp->wptr++ = c;
		splx(s);
	 } else {
		splx(s);
		if ((bp = allocb(16)) == NULL)
			return(0);
		bp->type = M_DATA;
		*bp->wptr++ = c;
		(*f)(q, bp);
	}
	return(1);
}

/*
 * Put a single-byte control record on queue (>=0100 implies QPCTL)
 */
putctl(q, c)
struct queue *q;
{
	register struct block *bp;

	if ((bp = allocb(1)) == NULL)
		return(0);
	bp->type = c;
	(*q->qinfo->putp)(q, bp);
	return(1);
}

/*
 * Control record with a single-byte parameter
 */
putctl1(q, c, p)
struct queue *q;
{
	register struct block *bp;

	if ((bp = allocb(1)) == NULL)
		return(0);
	bp->type = c;
	*bp->wptr++ = p;
	(*q->qinfo->putp)(q, bp);
	return(1);
}

/*
 * put control record, using putq instead of queue's putp
 */
qpctl(q, d)
register struct queue *q;
{
	register struct block *bp = allocb(1);

	if (bp) {
		bp->type = d;
		putq(q, bp);
	}
}

qpctl1(q, c, d)
register struct queue *q;
{
	register struct block *bp = allocb(1);

	if (bp) {
		bp->type = c;
		*bp->wptr++ = d;
		putq(q, bp);
	}
}

/*
 * Copy a literal record onto queue
 */
putcpy(q, cp, n)
register struct queue *q;
register char *cp;
{
	register struct block *bp;
	register nm;

	while (n) {
		if ((bp = allocb(n)) == NULL)	/* sorry */
			return;
		bp->type = M_DATA;
		nm = bp->lim - bp->wptr;
		if (nm > n)
			nm = n;
		bcopy(cp, bp->wptr, nm);
		cp += nm;
		bp->wptr += nm;
		n -= nm;
		(*q->qinfo->putp)(q, bp);
	}
}

/*
 * return the queue upstream from this one
 */
struct queue *
backq(q)
register struct queue *q;
{
	q = OTHERQ(q);
	if (q->next) {
		q = q->next;
		return(OTHERQ(q));
	}
	q = OTHERQ(q);
	printf("backq called with no back (Q %x)\n", q);
	panic("backq");
	return(NULL);
}

/*
 * Send a block back up the queue in reverse from this
 * one (e.g. to respond to ioctls)
 */
qreply(q, bp)
register struct queue *q;
struct block *bp;
{
	q = OTHERQ(q);
	(*q->next->qinfo->putp)(q->next, bp);
}

/*
 * Enable a queue: put it on list of those whose srvp's are
 * ready to run.
 */
qenable(q)
register struct queue *q;
{
	register s;

	s = spl6();
	if (q->flag & QENAB) {
		splx(s);
		return;
	}
	if (q->qinfo->srvp==NULL) {
		splx(s);
		return;
	}
	q->flag |= QENAB;
	q->link = NULL;
	if (qhead==NULL)
		qhead = q;
	else
		qtail->link = q;
	qtail = q;
	setqsched();
	splx(s);
}

/*
 * Run the srvp's of each enabled queue
 *	-- Should not be reentered
 */
queuerun()
{
	register struct queue *q;
	register s;
	extern int queueflag;
	extern char *panicstr;

	if (panicstr)
		return;		/* to minimize destruction */
	s = spl6();
	queueflag++;
	while (q = qhead) {
		if ((qhead = q->link) == NULL)
			qtail = NULL;
		q->flag &= ~QENAB;
		splx(s);
		if (q->qinfo->srvp != NULL)
			(*q->qinfo->srvp)(q);
		else
			printf("Q %x run with no srvp\n", q);
		spl6();
	}
	queueflag--;
	splx(s);
}