plan 9 kernel history: overview | file list | diff list

2001/0203/port/qio.c (diff list | history)

1993/0526/sys/src/9/port/qio.c:142,1561993/0527/sys/src/9/port/qio.c:142,159 (short | long)
1993/0526    
			cl = &arena.alloc[pow]; 
			lock(cl); 
			p = cl->first; 
			if(p){ 
				cl->have--; 
				cl->first = p->next; 
1993/0527    
			if(p == 0){ 
				unlock(cl); 
				return 0; 
1993/0526    
			} 
1993/0527    
			cl->have--; 
			cl->first = p->next; 
1993/0526    
			unlock(cl); 
			b = (Block *)p; 
			b->base = (uchar*)(b+1); 
			b->wp = b->rp = b->base; 
			b->lim = b->base + (1<<pow) - sizeof(Block); 
1993/0527    
			b->flag = 0; 
1993/0526    
			return b; 
		} 
	panic("iallocb %d\n", size); 
1993/0526/sys/src/9/port/qio.c:186,1911993/0527/sys/src/9/port/qio.c:189,195
1993/0526    
	b->base = (uchar*)(b+1); 
	b->rp = b->wp = b->base; 
	b->lim = b->base + size; 
1993/0527    
	b->flag = 0; 
1993/0526    
 
	return b; 
} 
1993/0526/sys/src/9/port/qio.c:200,2061993/0527/sys/src/9/port/qio.c:204,212
1993/0526    
	Block *b; 
	int n; 
 
1993/0527    
	/* sync with qwrite */ 
1993/0526    
	lock(q); 
1993/0527    
 
1993/0526    
	b = q->bfirst; 
	if(b == 0){ 
		q->state |= Qstarve; 
1993/0526/sys/src/9/port/qio.c:211,2171993/0527/sys/src/9/port/qio.c:217,223
1993/0526    
	if(n < len) 
		len = n; 
	memmove(p, b->rp, len); 
	if((q->state&Qmsg) || len == n) 
1993/0527    
	if((q->state & Qmsg) || len == n) 
1993/0526    
		q->bfirst = b->next; 
	else 
		b->rp += len; 
1993/0526/sys/src/9/port/qio.c:223,2291993/0527/sys/src/9/port/qio.c:229,235
1993/0526    
 
	unlock(q); 
 
	if((q->state&Qmsg) || len == n) 
1993/0527    
	if((q->state & Qmsg) || len == n) 
1993/0526    
		ifree(b); 
 
	return len; 
1993/0526/sys/src/9/port/qio.c:235,2521993/0527/sys/src/9/port/qio.c:241,261
1993/0526    
	Block *b; 
	int n; 
 
1993/0527    
	/* sync with qread */ 
1993/0526    
	lock(q); 
1993/0527    
 
1993/0526    
	b = q->rfirst; 
	if(b){ 
		/* hand to waiting receiver */ 
1993/0527    
		q->rfirst = b->next; 
		unlock(q); 
1993/0526    
		n = b->lim - b->wp; 
		if(n < len) 
			len = n; 
		memmove(b->wp, p, len); 
		b->wp += len; 
		q->rfirst = b->next; 
1993/0527    
		b->flag |= Bfilled; 
1993/0526    
		wakeup(&b->r); 
		unlock(q); 
		return len; 
	} 
 
1993/0526/sys/src/9/port/qio.c:258,2661993/0527/sys/src/9/port/qio.c:267,276
1993/0526    
 
	/* save in buffer */ 
	b = q->bfirst; 
	if((q->state&Qmsg)==0 && b && b->lim-b->wp <= len){ 
1993/0527    
	if((q->state & Qmsg) == 0 && b && b->lim - b->wp <= len){ 
1993/0526    
		memmove(b->wp, p, len); 
		b->wp += len; 
1993/0527    
		b->flag |= Bfilled; 
1993/0526    
	} else { 
		b = iallocb(len); 
		if(b == 0){ 
1993/0526/sys/src/9/port/qio.c:267,2741993/0527/sys/src/9/port/qio.c:277,285
1993/0526    
			unlock(q); 
			return -1; 
		} 
1993/0527    
		memmove(b->wp, p, len); 
1993/0526    
		b->wp += len; 
		memmove(b->rp, p, len); 
1993/0527    
		b->flag |= Bfilled; 
1993/0526    
		if(q->bfirst) 
			q->blast->next = b; 
		else 
1993/0526/sys/src/9/port/qio.c:277,2821993/0527/sys/src/9/port/qio.c:288,294
1993/0526    
	} 
	q->len += len; 
	unlock(q); 
1993/0527    
 
1993/0526    
	return len; 
} 
 
1993/0526/sys/src/9/port/qio.c:285,2981993/0527/sys/src/9/port/qio.c:297,309
1993/0526    
{ 
	int n, sofar; 
 
	if(q->state&Qmsg) 
		return qproduce0(q, p, len); 
                 
	for(sofar = 0; sofar < len; sofar += n){ 
		n = qproduce0(q, p+sofar, len-sofar); 
1993/0527    
	sofar = 0; 
	do { 
		n = qproduce0(q, p + sofar, len - sofar); 
1993/0526    
		if(n < 0) 
			break; 
	} 
1993/0527    
		sofar += n; 
	} while(sofar < len && (q->state & Qmsg) == 0); 
1993/0526    
	return sofar; 
} 
 
1993/0526/sys/src/9/port/qio.c:315,3441993/0527/sys/src/9/port/qio.c:326,385
1993/0526    
	return q; 
} 
 
1993/0527    
ulong qrtoomany; 
ulong qrtoofew; 
 
1993/0526    
static int 
bfilled(void *a) 
{ 
	Block *b = a; 
 
	return b->wp - b->rp; 
1993/0527    
	return b->flag & Bfilled; 
1993/0526    
} 
 
long 
qread(Queue *q, char *p, int len) 
{ 
	Block *b, *bb; 
1993/0527    
	Block *b, *bb, **l; 
1993/0526    
	int x, n; 
 
	qlock(&q->rlock); 
1993/0527    
	b = 0; 
	if(waserror()){ 
		qunlock(&q->rlock); 
		if(b) 
			free(b); 
		nexterror(); 
	} 
1993/0526    
 
	/* ... to be replaced by a kmapping if need be */ 
	b = allocb(len); 
1993/0527    
	/* 
	 *  If there are no buffered blocks, allocate a block 
	 *  for the qproducer/qwrite to fill.  This is 
	 *  optimistic and and we will 
	 *  sometimes be wrong: after locking we may either 
	 *  have to throw away or allocate one. 
	 * 
	 *  We hope to replace the allocb with a kmap later on. 
	 */ 
retry: 
	if(q->bfirst == 0) 
		b = allocb(len); 
1993/0526    
 
1993/0527    
	/* sync with qwrite/qproduce */ 
1993/0526    
	x = splhi(); 
	lock(q); 
1993/0527    
 
1993/0526    
	bb = q->bfirst; 
	if(bb == 0){ 
		/* wait for our block to be filled */ 
1993/0527    
		if(b == 0){ 
			/* we guessed wrong, drop the locks and try again */ 
			unlock(q); 
			splx(x); 
			qrtoofew++; 
			goto retry; 
		} 
 
		/* add ourselves to the list of readers */ 
1993/0526    
		if(q->rfirst) 
			q->rlast->next = b; 
		else 
1993/0526/sys/src/9/port/qio.c:347,3561993/0527/sys/src/9/port/qio.c:388,420
1993/0526    
		unlock(q); 
		splx(x); 
		qunlock(&q->rlock); 
1993/0527    
		poperror(); 
 
		if(waserror()){ 
			/* on error, unlink us from the chain */ 
			x = splhi(); 
			lock(q); 
			l = &q->rfirst; 
			for(bb = q->rfirst; bb; bb = bb->next){ 
				if(b == bb){ 
					*l = bb->next; 
					break; 
				} else 
					l = &bb->next; 
			} 
			unlock(q); 
			splx(x); 
			free(b); 
			nexterror(); 
		} 
 
		/* wait for the producer */ 
1993/0526    
		sleep(&b->r, bfilled, b); 
		n = BLEN(b); 
		memmove(p, b->rp, n); 
1993/0527    
		poperror(); 
1993/0526    
		free(b); 
1993/0527    
 
1993/0526    
		return n; 
	} 
 
1993/0526/sys/src/9/port/qio.c:362,3721993/0527/sys/src/9/port/qio.c:426,438
1993/0526    
	q->len -= n; 
	unlock(q); 
	splx(x); 
1993/0527    
 
	/* do this outside of the lock(q)! */ 
1993/0526    
	memmove(p, bb->rp, n); 
	bb->rp += n; 
 
	/* free it or put it back */ 
	if(drop || bb->rp == bb->wp) 
1993/0527    
	/* free it or put it back on the queue */ 
	if(bb->rp >= bb->wp || (q->state&Qmsg)) 
1993/0526    
		free(bb); 
	else { 
		x = splhi(); 
1993/0526/sys/src/9/port/qio.c:376,4281993/0527/sys/src/9/port/qio.c:442,504
1993/0526    
		unlock(q); 
		splx(x); 
	} 
1993/0527    
 
	poperror(); 
1993/0526    
	qunlock(&q->rlock); 
	free(b); 
1993/0527    
	if(b){ 
		qrtoomany++; 
		free(b); 
	} 
1993/0526    
	return n; 
} 
 
static int 
qnotfull(void *a) 
{ 
	Queue *q = a; 
1993/0527    
ulong qwtoomany; 
ulong qwtoofew; 
1993/0526    
 
	return q->len < q->limit; 
} 
                 
static long 
qwrite0(Queue *q, char *p, int len) 
1993/0527    
qwrite0(Queue *q, char *p, int len, Block *b) 
1993/0526    
{ 
	Block *b, *bb; 
	int x, n; 
1993/0527    
	Block *bb; 
	int x, n, sofar; 
1993/0526    
 
	b = allocb(len); 
                 
1993/0527    
	/* sync with qconsume/qread */ 
1993/0526    
	x = splhi(); 
	lock(q); 
	bb = q->rfirst; 
	if(bb){ 
1993/0527    
 
	sofar = 0; 
	while(bb = q->rfirst){ 
1993/0526    
		/* hand to waiting receiver */ 
		n = bb->lim - bb->wp; 
		q->rfirst = bb->next; 
		unlock(q); 
		splx(x); 
 
		if(n < len) 
			len = n; 
		memmove(bb->wp, p, len); 
		bb->wp += len; 
1993/0527    
		n = bb->lim - bb->wp; 
		if(n > len-sofar) 
			n = len - sofar; 
		memmove(bb->wp, p+sofar, n); 
		bb->wp += n; 
		bb->flag |= Bfilled; 
1993/0526    
		wakeup(&bb->r); 
 
		free(b); 
		return len; 
1993/0527    
		sofar += n; 
		if(sofar == len){ 
			if(b){ 
				free(b);	/* we were wrong to allocate */ 
				qwtoomany++; 
			} 
			return len; 
		} 
1993/0526    
	} 
		                 
	memmove(b->rp, p, len); 
	b->wp += len; 
 
	/* flow control */ 
	if(!qnotfull(q)) 
		sleep(&q->r, qnotfull, q); 
1993/0527    
	/* buffer what ever is left */ 
	if(b == 0){ 
		/* we should have alloc'd, return to qwrite and have it do it */ 
		unlock(q); 
		splx(x); 
		qwtoofew++; 
		return sofar; 
	} 
	b->rp += sofar; 
1993/0526    
 
	x = splhi(); 
	lock(q); 
1993/0526/sys/src/9/port/qio.c:442,4521993/0527/sys/src/9/port/qio.c:518,552
1993/0526    
	return len; 
} 
 
1993/0527    
static int 
qnotfull(void *a) 
{ 
	Queue *q = a; 
 
	return q->len < q->limit; 
} 
 
1993/0526    
long 
qwrite(Queue *q, char *p, int len) 
{ 
	int n, sofar; 
1993/0527    
	int n, i; 
	Block *b; 
1993/0526    
 
1993/0527    
	/* 
	 *  If there are no readers, grab a buffer and copy 
	 *  into it before locking anything down.  This 
	 *  provides the highest concurrency but we will 
	 *  sometimes be wrong: after locking we may either 
	 *  have to throw away or allocate one. 
	 */ 
	if(q->rfirst == 0){ 
		b = allocb(len); 
		memmove(b->wp, p, len); 
		b->wp += len; 
	} else 
		b = 0; 
 
	/* ensure atomic writes */ 
1993/0526    
	qlock(&q->wlock); 
	if(waserror()){ 
		qunlock(&q->wlock); 
1993/0526/sys/src/9/port/qio.c:453,4691993/0527/sys/src/9/port/qio.c:553,573
1993/0526    
		nexterror(); 
	} 
 
	if(q->state&Qmsg){ 
		sofar = qwrite0(q, p, len); 
	} else { 
		for(sofar = 0; sofar < len; sofar += n){ 
			n = qwrite0(q, p+sofar, len-sofar); 
			if(n < 0) 
				break; 
		} 
1993/0527    
	/* flow control */ 
	sleep(&q->r, qnotfull, q); 
 
	n = qwrite0(q, p, len, b); 
	if(n != len){ 
		/* no readers and we need a buffer */ 
		i = len - n; 
		b = allocb(i); 
		memmove(b->wp, p + n, i); 
		b->wp += n; 
		n += qwrite0(q, p + n, i, b); 
1993/0526    
	} 
 
	poperror(); 
	qunlock(&q->wlock); 
	return sofar; 
1993/0527    
	poperror(); 
 
	return n; 
1993/0526    
} 
1993/0527/sys/src/9/port/qio.c:150,1591993/0528/sys/src/9/port/qio.c:150,159 (short | long)
1993/0527    
			cl->first = p->next; 
1993/0526    
			unlock(cl); 
			b = (Block *)p; 
1993/0528    
			memset(b, 0, sizeof(Block)); 
1993/0526    
			b->base = (uchar*)(b+1); 
			b->wp = b->rp = b->base; 
			b->lim = b->base + (1<<pow) - sizeof(Block); 
1993/0527    
			b->flag = 0; 
1993/0526    
			return b; 
		} 
	panic("iallocb %d\n", size); 
1993/0527/sys/src/9/port/qio.c:186,1911993/0528/sys/src/9/port/qio.c:186,192
1993/0526    
	if(b == 0) 
		exhausted("Blocks"); 
 
1993/0528    
	memset(b, 0, sizeof(Block)); 
1993/0526    
	b->base = (uchar*)(b+1); 
	b->rp = b->wp = b->base; 
	b->lim = b->base + size; 
1993/0527/sys/src/9/port/qio.c:202,2081993/0528/sys/src/9/port/qio.c:203,209
1993/0526    
qconsume(Queue *q, uchar *p, int len) 
{ 
	Block *b; 
	int n; 
1993/0528    
	int n, dowakeup; 
1993/0526    
 
1993/0527    
	/* sync with qwrite */ 
1993/0526    
	lock(q); 
1993/0527/sys/src/9/port/qio.c:213,2181993/0528/sys/src/9/port/qio.c:214,220
1993/0526    
		unlock(q); 
		return -1; 
	} 
1993/0528    
 
1993/0526    
	n = BLEN(b); 
	if(n < len) 
		len = n; 
1993/0527/sys/src/9/port/qio.c:223,2341993/0528/sys/src/9/port/qio.c:225,243
1993/0526    
		b->rp += len; 
	q->len -= len; 
 
	/* wakeup flow controlled writers (with a bit of histeresis) */ 
	if(q->len+len >= q->limit && q->len < q->limit/2) 
		wakeup(&q->r); 
1993/0528    
	/* if writer flow controlled, restart */ 
	if((q->state & Qflow) && q->len < q->limit/2){ 
		q->state &= ~Qflow; 
		dowakeup = 1; 
	} else 
		dowakeup = 0; 
1993/0526    
 
	unlock(q); 
 
1993/0528    
	if(dowakeup) 
		wakeup(&q->wr); 
 
	/* discard the block if we're done with it */ 
1993/0527    
	if((q->state & Qmsg) || len == n) 
1993/0526    
		ifree(b); 
 
1993/0527/sys/src/9/port/qio.c:235,2641993/0528/sys/src/9/port/qio.c:244,258
1993/0526    
	return len; 
} 
 
static int 
qproduce0(Queue *q, uchar *p, int len) 
1993/0528    
int 
qproduce(Queue *q, uchar *p, int len) 
1993/0526    
{ 
	Block *b; 
	int n; 
1993/0528    
	int dowakeup; 
1993/0526    
 
1993/0527    
	/* sync with qread */ 
1993/0526    
	lock(q); 
1993/0527    
 
1993/0526    
	b = q->rfirst; 
	if(b){ 
		/* hand to waiting receiver */ 
1993/0527    
		q->rfirst = b->next; 
		unlock(q); 
1993/0526    
		n = b->lim - b->wp; 
		if(n < len) 
			len = n; 
		memmove(b->wp, p, len); 
		b->wp += len; 
1993/0527    
		b->flag |= Bfilled; 
1993/0526    
		wakeup(&b->r); 
		return len; 
	} 
                 
	/* no waiting receivers, room in buffer? */ 
	if(q->len >= q->limit){ 
		unlock(q); 
1993/0527/sys/src/9/port/qio.c:279,2851993/0528/sys/src/9/port/qio.c:273,278
1993/0526    
		} 
1993/0527    
		memmove(b->wp, p, len); 
1993/0526    
		b->wp += len; 
1993/0527    
		b->flag |= Bfilled; 
1993/0526    
		if(q->bfirst) 
			q->blast->next = b; 
		else 
1993/0527/sys/src/9/port/qio.c:287,3121993/0528/sys/src/9/port/qio.c:280,298
1993/0526    
		q->blast = b; 
	} 
	q->len += len; 
1993/0528    
	if(q->state & Qstarve){ 
		q->state &= ~Qstarve; 
		dowakeup = 1; 
	} else 
		dowakeup = 0; 
1993/0526    
	unlock(q); 
1993/0527    
 
1993/0528    
	if(dowakeup) 
		wakeup(&q->rr); 
 
1993/0526    
	return len; 
} 
 
int 
qproduce(Queue *q, uchar *p, int len) 
{ 
	int n, sofar; 
                 
1993/0527    
	sofar = 0; 
	do { 
		n = qproduce0(q, p + sofar, len - sofar); 
1993/0526    
		if(n < 0) 
			break; 
1993/0527    
		sofar += n; 
	} while(sofar < len && (q->state & Qmsg) == 0); 
1993/0526    
	return sofar; 
} 
                 
/* 
 *  called by non-interrupt code 
 */ 
1993/0527/sys/src/9/port/qio.c:317,3231993/0528/sys/src/9/port/qio.c:303,311
1993/0526    
 
	q = malloc(sizeof(Queue)); 
	if(q == 0) 
		exhausted("Queues"); 
1993/0528    
		return 0; 
 
	memset(q, 0, sizeof(Queue)); 
1993/0526    
	q->limit = limit; 
	q->kick = kick; 
	q->arg = arg; 
1993/0527/sys/src/9/port/qio.c:326,5731993/0528/sys/src/9/port/qio.c:314,520
1993/0526    
	return q; 
} 
 
1993/0527    
ulong qrtoomany; 
ulong qrtoofew; 
                 
1993/0526    
static int 
bfilled(void *a) 
1993/0528    
notempty(void *a) 
1993/0526    
{ 
	Block *b = a; 
1993/0528    
	Queue *q = a; 
1993/0526    
 
1993/0527    
	return b->flag & Bfilled; 
1993/0528    
	return q->bfirst != 0; 
1993/0526    
} 
 
1993/0528    
/* 
 *  read a queue.  if no data is queued, post a Block 
 *  and wait on its Rendez. 
 */ 
1993/0526    
long 
qread(Queue *q, char *p, int len) 
{ 
1993/0527    
	Block *b, *bb, **l; 
1993/0526    
	int x, n; 
1993/0528    
	Block *b; 
	int x, n, dowakeup; 
1993/0526    
 
	qlock(&q->rlock); 
1993/0527    
	b = 0; 
	if(waserror()){ 
		qunlock(&q->rlock); 
		if(b) 
			free(b); 
		nexterror(); 
	} 
1993/0526    
 
1993/0527    
	/* 
	 *  If there are no buffered blocks, allocate a block 
	 *  for the qproducer/qwrite to fill.  This is 
	 *  optimistic and and we will 
	 *  sometimes be wrong: after locking we may either 
	 *  have to throw away or allocate one. 
	 * 
	 *  We hope to replace the allocb with a kmap later on. 
	 */ 
retry: 
	if(q->bfirst == 0) 
		b = allocb(len); 
1993/0528    
	/* wait for data */ 
	for(;;){ 
		/* sync with qwrite/qproduce */ 
		x = splhi(); 
		lock(q); 
1993/0526    
 
1993/0527    
	/* sync with qwrite/qproduce */ 
1993/0526    
	x = splhi(); 
	lock(q); 
1993/0527    
                 
1993/0526    
	bb = q->bfirst; 
	if(bb == 0){ 
1993/0527    
		if(b == 0){ 
			/* we guessed wrong, drop the locks and try again */ 
1993/0528    
		if(q->state & Qclosed){ 
1993/0527    
			unlock(q); 
			splx(x); 
			qrtoofew++; 
			goto retry; 
1993/0528    
			return 0; 
1993/0527    
		} 
 
		/* add ourselves to the list of readers */ 
1993/0526    
		if(q->rfirst) 
			q->rlast->next = b; 
		else 
			q->rfirst = b; 
		q->rlast = b; 
1993/0528    
		b = q->bfirst; 
		if(b) 
			break; 
		q->state |= Qstarve; 
1993/0526    
		unlock(q); 
		splx(x); 
		qunlock(&q->rlock); 
1993/0527    
		poperror(); 
                 
		if(waserror()){ 
			/* on error, unlink us from the chain */ 
			x = splhi(); 
			lock(q); 
			l = &q->rfirst; 
			for(bb = q->rfirst; bb; bb = bb->next){ 
				if(b == bb){ 
					*l = bb->next; 
					break; 
				} else 
					l = &bb->next; 
			} 
			unlock(q); 
			splx(x); 
			free(b); 
			nexterror(); 
		} 
                 
		/* wait for the producer */ 
1993/0526    
		sleep(&b->r, bfilled, b); 
		n = BLEN(b); 
		memmove(p, b->rp, n); 
1993/0527    
		poperror(); 
1993/0526    
		free(b); 
1993/0527    
                 
1993/0526    
		return n; 
1993/0528    
		sleep(&q->rr, notempty, q); 
1993/0526    
	} 
 
	/* copy from a buffered block */ 
	q->bfirst = bb->next; 
	n = BLEN(bb); 
	if(n > len) 
		n = len; 
1993/0528    
	/* remove a buffered block */ 
	q->bfirst = b->next; 
	n = BLEN(b); 
1993/0526    
	q->len -= n; 
1993/0528    
 
	/* if writer flow controlled, restart */ 
	if((q->state & Qflow) && q->len < q->limit/2){ 
		q->state &= ~Qflow; 
		dowakeup = 1; 
	} else 
		dowakeup = 0; 
1993/0526    
	unlock(q); 
	splx(x); 
1993/0527    
 
	/* do this outside of the lock(q)! */ 
1993/0526    
	memmove(p, bb->rp, n); 
	bb->rp += n; 
1993/0528    
	if(n > len) 
		n = len; 
	memmove(p, b->rp, n); 
	b->rp += n; 
1993/0526    
 
1993/0527    
	/* free it or put it back on the queue */ 
	if(bb->rp >= bb->wp || (q->state&Qmsg)) 
1993/0526    
		free(bb); 
1993/0528    
	/* free it or put it what's left on the queue */ 
	if(b->rp >= b->wp || (q->state&Qmsg)) 
		free(b); 
1993/0526    
	else { 
		x = splhi(); 
		lock(q); 
		bb->next = q->bfirst; 
		q->bfirst = bb; 
1993/0528    
		b->next = q->bfirst; 
		q->bfirst = b; 
		q->len += BLEN(b); 
1993/0526    
		unlock(q); 
		splx(x); 
	} 
1993/0527    
 
1993/0528    
	/* wakeup flow controlled writers (with a bit of histeresis) */ 
	if(dowakeup) 
		wakeup(&q->wr); 
 
1993/0527    
	poperror(); 
1993/0526    
	qunlock(&q->rlock); 
1993/0527    
	if(b){ 
		qrtoomany++; 
		free(b); 
	} 
1993/0526    
	return n; 
} 
 
1993/0527    
ulong qwtoomany; 
ulong qwtoofew; 
1993/0526    
                 
static long 
1993/0527    
qwrite0(Queue *q, char *p, int len, Block *b) 
1993/0528    
static int 
qnotfull(void *a) 
1993/0526    
{ 
1993/0527    
	Block *bb; 
	int x, n, sofar; 
1993/0528    
	Queue *q = a; 
1993/0526    
 
1993/0527    
	/* sync with qconsume/qread */ 
1993/0526    
	x = splhi(); 
	lock(q); 
1993/0528    
	return q->len < q->limit; 
} 
1993/0527    
 
	sofar = 0; 
	while(bb = q->rfirst){ 
1993/0526    
		/* hand to waiting receiver */ 
		q->rfirst = bb->next; 
		unlock(q); 
		splx(x); 
1993/0528    
/* 
 *  write to a queue.  if no reader blocks are posted 
 *  queue the data. 
 */ 
long 
qwrite(Queue *q, char *p, int len) 
{ 
	int x, dowakeup; 
	Block *b; 
1993/0526    
 
1993/0527    
		n = bb->lim - bb->wp; 
		if(n > len-sofar) 
			n = len - sofar; 
		memmove(bb->wp, p+sofar, n); 
		bb->wp += n; 
		bb->flag |= Bfilled; 
1993/0526    
		wakeup(&bb->r); 
1993/0528    
	b = allocb(len); 
	memmove(b->wp, p, len); 
	b->wp += len; 
1993/0526    
 
1993/0527    
		sofar += n; 
		if(sofar == len){ 
			if(b){ 
				free(b);	/* we were wrong to allocate */ 
				qwtoomany++; 
			} 
			return len; 
		} 
1993/0528    
	/* flow control */ 
	while(!qnotfull(q)){ 
		qlock(&q->wlock); 
		q->state |= Qflow; 
		sleep(&q->wr, qnotfull, q); 
		qunlock(&q->wlock); 
1993/0526    
	} 
 
1993/0527    
	/* buffer what ever is left */ 
	if(b == 0){ 
		/* we should have alloc'd, return to qwrite and have it do it */ 
1993/0528    
	x = splhi(); 
	lock(q); 
 
	if(q->state & Qclosed){ 
1993/0527    
		unlock(q); 
		splx(x); 
		qwtoofew++; 
		return sofar; 
1993/0528    
		error(Ehungup); 
1993/0527    
	} 
	b->rp += sofar; 
1993/0526    
 
	x = splhi(); 
	lock(q); 
	if(q->bfirst) 
		q->blast->next = b; 
	else 
		q->bfirst = b; 
	q->blast = b; 
1993/0528    
	b->next = q->bfirst; 
	q->bfirst = b; 
1993/0526    
	q->len += len; 
	if((q->state & Qstarve) && q->kick){ 
1993/0528    
 
	if(q->state & Qstarve){ 
1993/0526    
		q->state &= ~Qstarve; 
		(*q->kick)(q->arg); 
	} 
1993/0528    
		dowakeup = 1; 
	} else 
		dowakeup = 0; 
 
1993/0526    
	unlock(q); 
	splx(x); 
 
1993/0528    
	if(dowakeup) 
		wakeup(&q->rr); 
 
1993/0526    
	return len; 
} 
 
1993/0527    
static int 
qnotfull(void *a) 
1993/0528    
/* 
 *  Mark a queue as closed.  No further IO is permitted. 
 *  All blocks are released. 
 */ 
void 
qclose(Queue *q) 
1993/0527    
{ 
	Queue *q = a; 
1993/0528    
	int x; 
	Block *b, *bfirst; 
1993/0527    
 
	return q->len < q->limit; 
} 
1993/0528    
	/* mark it */ 
	x = splhi(); 
	lock(q); 
	q->state |= Qclosed; 
	bfirst = q->bfirst; 
	q->bfirst = 0; 
	unlock(q); 
	splx(x); 
1993/0527    
 
1993/0526    
long 
qwrite(Queue *q, char *p, int len) 
{ 
1993/0527    
	int n, i; 
	Block *b; 
1993/0526    
                 
1993/0527    
	/* 
	 *  If there are no readers, grab a buffer and copy 
	 *  into it before locking anything down.  This 
	 *  provides the highest concurrency but we will 
	 *  sometimes be wrong: after locking we may either 
	 *  have to throw away or allocate one. 
	 */ 
	if(q->rfirst == 0){ 
		b = allocb(len); 
		memmove(b->wp, p, len); 
		b->wp += len; 
	} else 
		b = 0; 
                 
	/* ensure atomic writes */ 
1993/0526    
	qlock(&q->wlock); 
	if(waserror()){ 
		qunlock(&q->wlock); 
		nexterror(); 
1993/0528    
	/* free queued blocks */ 
	while(b = bfirst){ 
		bfirst = b->next; 
		free(b); 
1993/0526    
	} 
 
1993/0527    
	/* flow control */ 
	sleep(&q->r, qnotfull, q); 
1993/0528    
	/* wake up readers/writers */ 
	wakeup(&q->rr); 
	wakeup(&q->wr); 
} 
1993/0527    
 
	n = qwrite0(q, p, len, b); 
	if(n != len){ 
		/* no readers and we need a buffer */ 
		i = len - n; 
		b = allocb(i); 
		memmove(b->wp, p + n, i); 
		b->wp += n; 
		n += qwrite0(q, p + n, i, b); 
1993/0526    
	} 
1993/0528    
/* 
 *  Mark a queue as closed.  Wakeup any readers.  Don't remove queued 
 *  blocks. 
 */ 
void 
qhangup(Queue *q) 
{ 
	int x; 
1993/0526    
 
	qunlock(&q->wlock); 
1993/0527    
	poperror(); 
1993/0528    
	/* mark it */ 
	x = splhi(); 
	lock(q); 
	q->state |= Qclosed; 
	unlock(q); 
	splx(x); 
1993/0527    
 
	return n; 
1993/0528    
	/* wake up readers/writers */ 
	wakeup(&q->rr); 
	wakeup(&q->wr); 
} 
 
/* 
 *  mark a queue as no longer hung up 
 */ 
void 
qreopen(Queue *q) 
{ 
	q->state &= ~Qclosed; 
1993/0526    
} 
1993/0528/sys/src/9/port/qio.c:5,101993/0530/sys/src/9/port/qio.c:5,13 (short | long)
1993/0526    
#include	"fns.h" 
#include	"../port/error.h" 
 
1993/0530    
/* 
 *  interrupt level memory allocation 
 */ 
1993/0526    
typedef struct Chunk	Chunk; 
typedef	struct Chunkl	Chunkl; 
typedef	struct Arena	Arena; 
1993/0528/sys/src/9/port/qio.c:39,441993/0530/sys/src/9/port/qio.c:42,97
1993/0526    
static Arena arena; 
 
/* 
1993/0530    
 *  IO queues 
 */ 
typedef struct Block	Block; 
typedef struct Queue	Queue; 
 
struct Block 
{ 
	Block	*next; 
 
	uchar	*rp;			/* first unconsumed byte */ 
	uchar	*wp;			/* first empty byte */ 
	uchar	*lim;			/* 1 past the end of the buffer */ 
	uchar	*base;			/* start of the buffer */ 
	uchar	flag; 
}; 
#define BLEN(b)		((b)->wp - (b)->rp) 
 
struct Queue 
{ 
	Lock; 
 
	Block	*bfirst;	/* buffer */ 
	Block	*blast; 
 
	int	len;		/* bytes in queue */ 
	int	limit;		/* max bytes in queue */ 
	int	state; 
 
	void	(*kick)(void*);	/* restart output */ 
	void	*arg;		/* argument to kick */ 
 
	QLock	rlock;		/* mutex for reading processes */ 
	Rendez	rr;		/* process waiting to read */ 
	QLock	wlock;		/* mutex for writing processes */ 
	Rendez	wr;		/* process waiting to write */ 
}; 
 
enum 
{ 
	/* Block.flag */ 
	Bfilled=1,		/* block filled */ 
 
	/* Queue.state */	 
	Qstarve=	(1<<0),		/* consumer starved */ 
	Qmsg=		(1<<1),		/* message stream */ 
	Qclosed=	(1<<2), 
	Qflow=		(1<<3), 
}; 
 
/* 
1993/0526    
 *  Manage interrupt level memory allocation. 
 */ 
static void 
1993/0528/sys/src/9/port/qio.c:297,3031993/0530/sys/src/9/port/qio.c:350,356
1993/0526    
 *  called by non-interrupt code 
 */ 
Queue* 
qopen(int limit, void (*kick)(void*), void *arg) 
1993/0530    
qopen(int limit, int msg, void (*kick)(void*), void *arg) 
1993/0526    
{ 
	Queue *q; 
 
1993/0528/sys/src/9/port/qio.c:309,3151993/0530/sys/src/9/port/qio.c:362,368
1993/0526    
	q->limit = limit; 
	q->kick = kick; 
	q->arg = arg; 
	q->state = Qmsg; 
1993/0530    
	q->state = msg ? Qmsg : 0; 
1993/0526    
 
	return q; 
} 
1993/0528/sys/src/9/port/qio.c:517,5201993/0530/sys/src/9/port/qio.c:570,582
1993/0528    
qreopen(Queue *q) 
{ 
	q->state &= ~Qclosed; 
1993/0530    
} 
 
/* 
 *  return bytes queued 
 */ 
int 
qlen(Queue *q) 
{ 
	return q->len; 
1993/0526    
} 
1993/0530/sys/src/9/port/qio.c:253,2621993/0601/sys/src/9/port/qio.c:253,263 (short | long)
1993/0526    
 *  set, any bytes left in a block afer a consume are discarded. 
 */ 
int 
qconsume(Queue *q, uchar *p, int len) 
1993/0601    
qconsume(Queue *q, void *vp, int len) 
1993/0526    
{ 
	Block *b; 
1993/0528    
	int n, dowakeup; 
1993/0601    
	uchar *p = vp; 
1993/0526    
 
1993/0527    
	/* sync with qwrite */ 
1993/0526    
	lock(q); 
1993/0530/sys/src/9/port/qio.c:298,3071993/0601/sys/src/9/port/qio.c:299,309
1993/0526    
} 
 
1993/0528    
int 
qproduce(Queue *q, uchar *p, int len) 
1993/0601    
qproduce(Queue *q, void *vp, int len) 
1993/0526    
{ 
	Block *b; 
1993/0528    
	int dowakeup; 
1993/0601    
	uchar *p = vp; 
1993/0526    
 
1993/0527    
	/* sync with qread */ 
1993/0526    
	lock(q); 
1993/0530/sys/src/9/port/qio.c:340,3471993/0601/sys/src/9/port/qio.c:342,352
1993/0528    
		dowakeup = 0; 
1993/0526    
	unlock(q); 
1993/0527    
 
1993/0528    
	if(dowakeup) 
1993/0601    
	if(dowakeup){ 
		if(q->kick) 
			(*q->kick)(q->arg); 
1993/0528    
		wakeup(&q->rr); 
1993/0601    
	} 
1993/0528    
 
1993/0526    
	return len; 
} 
1993/0530/sys/src/9/port/qio.c:363,3681993/0601/sys/src/9/port/qio.c:368,374
1993/0526    
	q->kick = kick; 
	q->arg = arg; 
1993/0530    
	q->state = msg ? Qmsg : 0; 
1993/0601    
	q->state |= Qstarve; 
1993/0526    
 
	return q; 
} 
1993/0530/sys/src/9/port/qio.c:380,3891993/0601/sys/src/9/port/qio.c:386,396
1993/0528    
 *  and wait on its Rendez. 
 */ 
1993/0526    
long 
qread(Queue *q, char *p, int len) 
1993/0601    
qread(Queue *q, void *vp, int len) 
1993/0526    
{ 
1993/0528    
	Block *b; 
	int x, n, dowakeup; 
1993/0601    
	uchar *p = vp; 
1993/0526    
 
	qlock(&q->rlock); 
1993/0527    
	if(waserror()){ 
1993/0530/sys/src/9/port/qio.c:467,4761993/0601/sys/src/9/port/qio.c:474,484
1993/0528    
 *  queue the data. 
 */ 
long 
qwrite(Queue *q, char *p, int len) 
1993/0601    
qwrite(Queue *q, void *vp, int len, int nowait) 
1993/0528    
{ 
	int x, dowakeup; 
	Block *b; 
1993/0601    
	uchar *p = vp; 
1993/0526    
 
1993/0528    
	b = allocb(len); 
	memmove(b->wp, p, len); 
1993/0530/sys/src/9/port/qio.c:478,4831993/0601/sys/src/9/port/qio.c:486,493
1993/0526    
 
1993/0528    
	/* flow control */ 
	while(!qnotfull(q)){ 
1993/0601    
		if(nowait) 
			return len; 
1993/0528    
		qlock(&q->wlock); 
		q->state |= Qflow; 
		sleep(&q->wr, qnotfull, q); 
1993/0530/sys/src/9/port/qio.c:493,5001993/0601/sys/src/9/port/qio.c:503,513
1993/0528    
		error(Ehungup); 
1993/0527    
	} 
1993/0526    
 
1993/0528    
	b->next = q->bfirst; 
	q->bfirst = b; 
1993/0601    
	if(q->bfirst) 
		q->blast->next = b; 
	else 
		q->bfirst = b; 
	q->blast = b; 
1993/0526    
	q->len += len; 
1993/0528    
 
	if(q->state & Qstarve){ 
1993/0530/sys/src/9/port/qio.c:506,5131993/0601/sys/src/9/port/qio.c:519,529
1993/0526    
	unlock(q); 
	splx(x); 
 
1993/0528    
	if(dowakeup) 
1993/0601    
	if(dowakeup){ 
		if(q->kick) 
			(*q->kick)(q->arg); 
1993/0528    
		wakeup(&q->rr); 
1993/0601    
	} 
1993/0528    
 
1993/0526    
	return len; 
} 
1993/0530/sys/src/9/port/qio.c:570,5751993/0601/sys/src/9/port/qio.c:586,592
1993/0528    
qreopen(Queue *q) 
{ 
	q->state &= ~Qclosed; 
1993/0601    
	q->state |= Qstarve; 
1993/0530    
} 
 
/* 
1993/0530/sys/src/9/port/qio.c:579,5821993/0601/sys/src/9/port/qio.c:596,608
1993/0530    
qlen(Queue *q) 
{ 
	return q->len; 
1993/0601    
} 
 
/* 
 *  return true if we can read without blocking 
 */ 
int 
qcanread(Queue *q) 
{ 
	return q->bfirst!=0; 
1993/0526    
} 
1993/0601/sys/src/9/port/qio.c:178,1841993/0725/sys/src/9/port/qio.c:178,184 (short | long)
1993/0526    
	} 
 
	/* start garbage collector */ 
	kproc("iallockproc", iallockproc, 0); 
1993/0725    
	kproc("ialloc", iallockproc, 0); 
1993/0526    
} 
 
Block* 
1993/0601/sys/src/9/port/qio.c:407,4121993/0725/sys/src/9/port/qio.c:407,413
1993/0528    
		if(q->state & Qclosed){ 
1993/0527    
			unlock(q); 
			splx(x); 
1993/0725    
print("Qclosed %lux\n", q); 
1993/0528    
			return 0; 
1993/0527    
		} 
 
1993/0601/sys/src/9/port/qio.c:439,4451993/0725/sys/src/9/port/qio.c:440,446
1993/0528    
	memmove(p, b->rp, n); 
	b->rp += n; 
1993/0526    
 
1993/0528    
	/* free it or put it what's left on the queue */ 
1993/0725    
	/* free it or put what's left on the queue */ 
1993/0528    
	if(b->rp >= b->wp || (q->state&Qmsg)) 
		free(b); 
1993/0526    
	else { 
1993/0725/sys/src/9/port/qio.c:407,4131993/0727/sys/src/9/port/qio.c:407,412 (short | long)
1993/0528    
		if(q->state & Qclosed){ 
1993/0527    
			unlock(q); 
			splx(x); 
1993/0725    
print("Qclosed %lux\n", q); 
1993/0528    
			return 0; 
1993/0527    
		} 
 
1993/0727/sys/src/9/port/qio.c:404,4091993/0728/sys/src/9/port/qio.c:404,413 (short | long)
1993/0528    
		x = splhi(); 
		lock(q); 
1993/0526    
 
1993/0728    
		b = q->bfirst; 
		if(b) 
			break; 
 
1993/0528    
		if(q->state & Qclosed){ 
1993/0527    
			unlock(q); 
			splx(x); 
1993/0727/sys/src/9/port/qio.c:410,4181993/0728/sys/src/9/port/qio.c:414,419
1993/0528    
			return 0; 
1993/0527    
		} 
 
1993/0528    
		b = q->bfirst; 
		if(b) 
			break; 
		q->state |= Qstarve; 
1993/0526    
		unlock(q); 
		splx(x); 
1993/0728/sys/src/9/port/qio.c:115,1231993/0804/sys/src/9/port/qio.c:115,124 (short | long)
1993/0526    
			unlock(cl); 
			splx(x); 
	 
			for(; first; first = p){ 
1993/0804    
			while(first != 0) { 
1993/0526    
				p = first->next; 
				free(first); 
1993/0804    
				first = p; 
1993/0526    
			} 
		} 
 
1993/0728/sys/src/9/port/qio.c:146,1551993/0804/sys/src/9/port/qio.c:147,158
1993/0526    
 
			first = 0; 
			l = &first; 
			for(i = x = cl->goal - cl->have; x > 0; x--){ 
1993/0804    
			i = cl->goal - cl->have; 
			for(x = i; x > 0; x--){ 
1993/0526    
				p = malloc(1<<pow); 
				if(p == 0) 
					break; 
1993/0804    
 
1993/0526    
				*l = p; 
				l = &p->next; 
			} 
1993/0728/sys/src/9/port/qio.c:190,1961993/0804/sys/src/9/port/qio.c:193,199
1993/0526    
	Block *b; 
 
	size += sizeof(Block); 
	for(pow = Minpow; pow <= Maxpow; pow++) 
1993/0804    
	for(pow = Minpow; pow <= Maxpow; pow++){ 
1993/0526    
		if(size <= (1<<pow)){ 
			cl = &arena.alloc[pow]; 
			lock(cl); 
1993/0728/sys/src/9/port/qio.c:205,2141993/0804/sys/src/9/port/qio.c:208,220
1993/0526    
			b = (Block *)p; 
1993/0528    
			memset(b, 0, sizeof(Block)); 
1993/0526    
			b->base = (uchar*)(b+1); 
			b->wp = b->rp = b->base; 
1993/0804    
			b->wp = b->base; 
			b->rp = b->base; 
1993/0526    
			b->lim = b->base + (1<<pow) - sizeof(Block); 
			return b; 
		} 
1993/0804    
	} 
 
1993/0526    
	panic("iallocb %d\n", size); 
	return 0;			/* not reached */ 
} 
1993/0728/sys/src/9/port/qio.c:239,2471993/0804/sys/src/9/port/qio.c:245,253
1993/0526    
	if(b == 0) 
		exhausted("Blocks"); 
 
1993/0528    
	memset(b, 0, sizeof(Block)); 
1993/0526    
	b->base = (uchar*)(b+1); 
	b->rp = b->wp = b->base; 
1993/0804    
	b->rp = b->base; 
	b->wp = b->base; 
1993/0526    
	b->lim = b->base + size; 
1993/0527    
	b->flag = 0; 
1993/0526    
 
1993/0728/sys/src/9/port/qio.c:549,5571993/0804/sys/src/9/port/qio.c:555,564
1993/0528    
	splx(x); 
1993/0527    
 
1993/0528    
	/* free queued blocks */ 
	while(b = bfirst){ 
		bfirst = b->next; 
		free(b); 
1993/0804    
	while(bfirst){ 
		b = bfirst->next; 
		free(bfirst); 
		bfirst = b; 
1993/0526    
	} 
 
1993/0528    
	/* wake up readers/writers */ 
1993/0804/sys/src/9/port/qio.c:91,961993/0811/sys/src/9/port/qio.c:91,106 (short | long)
1993/0530    
	Qflow=		(1<<3), 
}; 
 
1993/0811    
void 
poison(Block *b) 
{ 
	b->next = (void*)0xdeadbabe; 
	b->rp = (void*)0xdeadbabe; 
	b->wp = (void*)0xdeadbabe; 
	b->lim = (void*)0xdeadbabe; 
	b->base = (void*)0xdeadbabe; 
} 
 
1993/0530    
/* 
1993/0526    
 *  Manage interrupt level memory allocation. 
 */ 
1993/0804/sys/src/9/port/qio.c:298,3061993/0811/sys/src/9/port/qio.c:308,317
1993/0528    
		wakeup(&q->wr); 
 
	/* discard the block if we're done with it */ 
1993/0527    
	if((q->state & Qmsg) || len == n) 
1993/0811    
	if((q->state & Qmsg) || len == n) { 
		poison(b); 
1993/0526    
		ifree(b); 
                 
1993/0811    
	} 
1993/0526    
	return len; 
} 
 
1993/0804/sys/src/9/port/qio.c:447,4541993/0811/sys/src/9/port/qio.c:458,467
1993/0528    
	b->rp += n; 
1993/0526    
 
1993/0725    
	/* free it or put what's left on the queue */ 
1993/0528    
	if(b->rp >= b->wp || (q->state&Qmsg)) 
1993/0811    
	if(b->rp >= b->wp || (q->state&Qmsg)) { 
		poison(b); 
1993/0528    
		free(b); 
1993/0811    
	} 
1993/0526    
	else { 
		x = splhi(); 
		lock(q); 
1993/0804/sys/src/9/port/qio.c:557,5621993/0811/sys/src/9/port/qio.c:570,576
1993/0528    
	/* free queued blocks */ 
1993/0804    
	while(bfirst){ 
		b = bfirst->next; 
1993/0811    
		poison(bfirst); 
1993/0804    
		free(bfirst); 
		bfirst = b; 
1993/0526    
	} 
1993/0811/sys/src/9/port/qio.c:30,351993/0819/sys/src/9/port/qio.c:30,36 (short | long)
1993/0526    
	int	have; 
	int	goal; 
	int	hist; 
1993/0819    
	int	wanted; 
1993/0526    
}; 
 
struct Arena 
1993/0811/sys/src/9/port/qio.c:141,1481993/0819/sys/src/9/port/qio.c:142,149
1993/0526    
			 *  start giving blocks back to the general pool 
			 */ 
			if(cl->have >= cl->goal){ 
				cl->hist = ((cl->hist<<1) | 1) & 0xff; 
				if(cl->hist == 0xff && cl->goal > 8) 
1993/0819    
				cl->hist = ((cl->hist<<1) | 1) & 0xffff; 
				if(cl->hist == 0xffff && cl->goal > 32) 
1993/0526    
					cl->goal--; 
				continue; 
			} else 
1993/0811/sys/src/9/port/qio.c:149,1591993/0819/sys/src/9/port/qio.c:150,165
1993/0526    
				cl->hist <<= 1; 
 
			/* 
			 *  increase goal if we've been drained, decrease 
			 *  goal if we've had lots of blocks twice in a row. 
1993/0819    
			 *  increase goal if we've been drained. 
1993/0526    
			 */ 
			if(cl->have == 0) 
				cl->goal += cl->goal>>2; 
1993/0819    
			if(cl->have == 0){ 
				i = cl->goal>>2; 
				if(cl->wanted > i) 
					cl->goal += cl->wanted; 
				else 
					cl->goal += i; 
				cl->wanted = 0; 
			} 
1993/0526    
 
			first = 0; 
			l = &first; 
1993/0811/sys/src/9/port/qio.c:166,1711993/0819/sys/src/9/port/qio.c:172,178
1993/0526    
				*l = p; 
				l = &p->next; 
			} 
1993/0819    
			i -= x; 
1993/0526    
			if(first){ 
				x = splhi(); 
				lock(cl); 
1993/0811/sys/src/9/port/qio.c:194,1991993/0819/sys/src/9/port/qio.c:201,220
1993/0725    
	kproc("ialloc", iallockproc, 0); 
1993/0526    
} 
 
1993/0819    
void 
ixsummary(void) 
{ 
	int pow; 
	Chunkl *cl; 
 
	print("size	have/goal\n"); 
	for(pow = Minpow; pow <= Maxpow; pow++){ 
		cl = &arena.alloc[pow]; 
		print("%d	%d/%d\n", 1<<pow, cl->have, cl->goal); 
	} 
	print("\n"); 
} 
 
1993/0526    
Block* 
iallocb(int size) 
{ 
1993/0811/sys/src/9/port/qio.c:209,2151993/0819/sys/src/9/port/qio.c:230,238
1993/0526    
			lock(cl); 
			p = cl->first; 
1993/0527    
			if(p == 0){ 
1993/0819    
				cl->wanted++; 
1993/0527    
				unlock(cl); 
1993/0819    
				wakeup(&arena.r); 
1993/0527    
				return 0; 
1993/0526    
			} 
1993/0527    
			cl->have--; 
1993/0819/sys/src/9/port/qio.c:70,751993/0908/sys/src/9/port/qio.c:70,76 (short | long)
1993/0530    
	int	len;		/* bytes in queue */ 
	int	limit;		/* max bytes in queue */ 
	int	state; 
1993/0908    
	int	eof;		/* number of eofs read by user */ 
1993/0530    
 
	void	(*kick)(void*);	/* restart output */ 
	void	*arg;		/* argument to kick */ 
1993/0819/sys/src/9/port/qio.c:409,4141993/0908/sys/src/9/port/qio.c:410,416
1993/0526    
	q->arg = arg; 
1993/0530    
	q->state = msg ? Qmsg : 0; 
1993/0601    
	q->state |= Qstarve; 
1993/0908    
	q->eof = 0; 
1993/0526    
 
	return q; 
} 
1993/0819/sys/src/9/port/qio.c:451,4561993/0908/sys/src/9/port/qio.c:453,462
1993/0528    
		if(q->state & Qclosed){ 
1993/0527    
			unlock(q); 
			splx(x); 
1993/0908    
			poperror(); 
			qunlock(&q->rlock); 
			if(++q->eof > 3) 
				error(Ehungup); 
1993/0528    
			return 0; 
1993/0527    
		} 
 
1993/0819/sys/src/9/port/qio.c:632,6371993/0908/sys/src/9/port/qio.c:638,644
1993/0528    
{ 
	q->state &= ~Qclosed; 
1993/0601    
	q->state |= Qstarve; 
1993/0908    
	q->eof = 0; 
1993/0530    
} 
 
/* 
1993/0908/sys/src/9/port/qio.c:154,1621993/1102/sys/src/9/port/qio.c:154,162 (short | long)
1993/0819    
			 *  increase goal if we've been drained. 
1993/0526    
			 */ 
1993/0819    
			if(cl->have == 0){ 
				i = cl->goal>>2; 
1993/1102    
				i = cl->goal>>1; 
1993/0819    
				if(cl->wanted > i) 
					cl->goal += cl->wanted; 
1993/1102    
					cl->goal += 2*cl->wanted; 
1993/0819    
				else 
					cl->goal += i; 
				cl->wanted = 0; 
1993/0908/sys/src/9/port/qio.c:195,2011993/1102/sys/src/9/port/qio.c:195,201
1993/0526    
 
	for(pow = Minpow; pow <= Maxpow; pow++){ 
		cl = &arena.alloc[pow]; 
		cl->goal = Maxpow-pow + 4; 
1993/1102    
		cl->goal = Maxpow-pow + 16; 
1993/0526    
	} 
 
	/* start garbage collector */ 
1993/1102/sys/src/9/port/qio.c:365,3711993/1103/sys/src/9/port/qio.c:365,371 (short | long)
1993/0526    
		b = iallocb(len); 
		if(b == 0){ 
			unlock(q); 
			return -1; 
1993/1103    
			return -2; 
1993/0526    
		} 
1993/0527    
		memmove(b->wp, p, len); 
1993/0526    
		b->wp += len; 
1993/1103/sys/src/9/port/qio.c:538,5461993/1227/sys/src/9/port/qio.c:538,551 (short | long)
1993/0601    
		if(nowait) 
			return len; 
1993/0528    
		qlock(&q->wlock); 
1993/1227    
		if(waserror()) { 
			qunlock(&q->wlock); 
			nexterror(); 
		} 
1993/0528    
		q->state |= Qflow; 
		sleep(&q->wr, qnotfull, q); 
		qunlock(&q->wlock); 
1993/1227    
		poperror(); 
1993/0526    
	} 
 
1993/0528    
	x = splhi(); 
1993/1227/sys/src/9/port/qio.c:79,841994/0208/sys/src/9/port/qio.c:79,87 (short | long)
1993/0530    
	Rendez	rr;		/* process waiting to read */ 
	QLock	wlock;		/* mutex for writing processes */ 
	Rendez	wr;		/* process waiting to write */ 
1994/0208    
 
	uchar	*syncbuf;	/* synchronous IO buffer */ 
	int	synclen;	/* syncbuf length */ 
1993/0530    
}; 
 
enum 
1993/1227/sys/src/9/port/qio.c:188,2041994/0208/sys/src/9/port/qio.c:191,220
1993/0526    
} 
 
void 
iallocinit(void) 
1994/0208    
qinit(void) 
1993/0526    
{ 
	int pow; 
	Chunkl *cl; 
1994/0208    
	Chunk *p; 
1993/0526    
 
1994/0208    
	/* start with a bunch of initial blocks */ 
1993/0526    
	for(pow = Minpow; pow <= Maxpow; pow++){ 
		cl = &arena.alloc[pow]; 
1993/1102    
		cl->goal = Maxpow-pow + 16; 
1994/0208    
		cl->goal = Maxpow-pow + 32; 
		cl->first = 0; 
		for(; cl->have < cl->goal; cl->have++){ 
			p = malloc(1<<pow); 
			p->next = cl->first; 
			cl->first = p; 
		} 
1993/0526    
	} 
 
	/* start garbage collector */ 
1994/0208    
} 
 
void 
iallocinit(void) 
{ 
	/* start garbage collector/creator */ 
1993/0725    
	kproc("ialloc", iallockproc, 0); 
1993/0526    
} 
 
1993/1227/sys/src/9/port/qio.c:216,2301994/0208/sys/src/9/port/qio.c:232,250
1993/0819    
	print("\n"); 
} 
 
1994/0208    
/* 
 *  interrupt time allocation (round data base address to 64 bit boundary) 
 */ 
1993/0526    
Block* 
iallocb(int size) 
{ 
	int pow; 
1994/0208    
	ulong addr; 
1993/0526    
	Chunkl *cl; 
	Chunk *p; 
	Block *b; 
 
	size += sizeof(Block); 
1994/0208    
	size += sizeof(Block) + 7; 
1993/0804    
	for(pow = Minpow; pow <= Maxpow; pow++){ 
1993/0526    
		if(size <= (1<<pow)){ 
			cl = &arena.alloc[pow]; 
1993/1227/sys/src/9/port/qio.c:239,2501994/0208/sys/src/9/port/qio.c:259,273
1993/0527    
			cl->have--; 
			cl->first = p->next; 
1993/0526    
			unlock(cl); 
1994/0208    
 
1993/0526    
			b = (Block *)p; 
1993/0528    
			memset(b, 0, sizeof(Block)); 
1993/0526    
			b->base = (uchar*)(b+1); 
1994/0208    
			addr = (ulong)b; 
			addr = (addr + sizeof(Block) + 7) & ~7; 
			b->base = (uchar*)addr; 
1993/0804    
			b->wp = b->base; 
			b->rp = b->base; 
1993/0526    
			b->lim = b->base + (1<<pow) - sizeof(Block); 
1994/0208    
			b->lim = ((uchar*)b) + (1<<pow); 
1993/0526    
			return b; 
		} 
1993/0804    
	} 
1993/1227/sys/src/9/port/qio.c:268,2881994/0208/sys/src/9/port/qio.c:291,315
1993/0526    
} 
 
/* 
 *  allocate queues and blocks 
1994/0208    
 *  allocate queues and blocks (round data base address to 64 bit boundary) 
1993/0526    
 */ 
Block* 
allocb(int size) 
{ 
	Block *b; 
1994/0208    
	ulong addr; 
1993/0526    
 
	b = malloc(sizeof(Block) + size); 
1994/0208    
	size += sizeof(Block) + 7; 
	b = malloc(size); 
1993/0526    
	if(b == 0) 
		exhausted("Blocks"); 
 
	b->base = (uchar*)(b+1); 
1994/0208    
	addr = (ulong)b; 
	addr = (addr + sizeof(Block) + 7) & ~7; 
	b->base = (uchar*)addr; 
1993/0804    
	b->rp = b->base; 
	b->wp = b->base; 
1993/0526    
	b->lim = b->base + size; 
1994/0208    
	b->lim = ((uchar*)b) + size; 
1993/0527    
	b->flag = 0; 
1993/0526    
 
	return b; 
1993/1227/sys/src/9/port/qio.c:343,3541994/0208/sys/src/9/port/qio.c:370,401
1993/0601    
qproduce(Queue *q, void *vp, int len) 
1993/0526    
{ 
	Block *b; 
1993/0528    
	int dowakeup; 
1994/0208    
	int i, dowakeup; 
1993/0601    
	uchar *p = vp; 
1993/0526    
 
1993/0527    
	/* sync with qread */ 
1994/0208    
	dowakeup = 0; 
1993/0526    
	lock(q); 
1993/0527    
 
1994/0208    
	if(q->syncbuf){ 
		/* synchronous communications, just copy into buffer */ 
		if(len < q->synclen) 
			q->synclen = len; 
		i = q->synclen; 
		memmove(q->syncbuf, p, i); 
		q->syncbuf = 0;		/* tell reader buffer is full */ 
		len -= i; 
		if(len <= 0 || (q->state & Qmsg)){ 
			unlock(q); 
			wakeup(&q->rr); 
			return i; 
		} 
 
		/* queue anything that's left */ 
		dowakeup = 1; 
		p += i; 
	} 
 
1993/0526    
	/* no waiting receivers, room in buffer? */ 
	if(q->len >= q->limit){ 
		unlock(q); 
1993/1227/sys/src/9/port/qio.c:379,3861994/0208/sys/src/9/port/qio.c:426,432
1993/0528    
	if(q->state & Qstarve){ 
		q->state &= ~Qstarve; 
		dowakeup = 1; 
	} else 
		dowakeup = 0; 
1994/0208    
	} 
1993/0526    
	unlock(q); 
1993/0527    
 
1993/0601    
	if(dowakeup){ 
1993/1227/sys/src/9/port/qio.c:416,4211994/0208/sys/src/9/port/qio.c:462,475
1993/0526    
} 
 
static int 
1994/0208    
filled(void *a) 
{ 
	Queue *q = a; 
 
	return q->syncbuf == 0; 
} 
 
static int 
1993/0528    
notempty(void *a) 
1993/0526    
{ 
1993/0528    
	Queue *q = a; 
1993/1227/sys/src/9/port/qio.c:436,4411994/0208/sys/src/9/port/qio.c:490,505
1993/0526    
 
	qlock(&q->rlock); 
1993/0527    
	if(waserror()){ 
1994/0208    
		/* can't let go if the buffer is in use */ 
		if(q->syncbuf){ 
			qlock(&q->wlock); 
			x = splhi(); 
			lock(q); 
			q->syncbuf = 0; 
			unlock(q); 
			splx(x); 
			qunlock(&q->wlock); 
		} 
1993/0527    
		qunlock(&q->rlock); 
		nexterror(); 
	} 
1993/1227/sys/src/9/port/qio.c:460,4691994/0208/sys/src/9/port/qio.c:524,546
1993/0528    
			return 0; 
1993/0527    
		} 
 
1993/0528    
		q->state |= Qstarve; 
1993/0526    
		unlock(q); 
		splx(x); 
1993/0528    
		sleep(&q->rr, notempty, q); 
1994/0208    
		if(globalmem(vp)){ 
			/* just let the writer fill the buffer directly */ 
			q->synclen = len; 
			q->syncbuf = vp; 
			unlock(q); 
			splx(x); 
			sleep(&q->rr, filled, q); 
			len = q->synclen; 
			poperror(); 
			qunlock(&q->rlock); 
			return len; 
		} else { 
			q->state |= Qstarve; 
			unlock(q); 
			splx(x); 
			sleep(&q->rr, notempty, q); 
		} 
1993/0526    
	} 
 
1993/0528    
	/* remove a buffered block */ 
1993/1227/sys/src/9/port/qio.c:490,4971994/0208/sys/src/9/port/qio.c:567,573
1993/0811    
	if(b->rp >= b->wp || (q->state&Qmsg)) { 
		poison(b); 
1993/0528    
		free(b); 
1993/0811    
	} 
1993/0526    
	else { 
1994/0208    
	} else { 
1993/0526    
		x = splhi(); 
		lock(q); 
1993/0528    
		b->next = q->bfirst; 
1993/1227/sys/src/9/port/qio.c:521,5841994/0208/sys/src/9/port/qio.c:597,707
1993/0528    
/* 
 *  write to a queue.  if no reader blocks are posted 
 *  queue the data. 
1994/0208    
 * 
 *  all copies should be outside of spl since they can fault. 
1993/0528    
 */ 
long 
1993/0601    
qwrite(Queue *q, void *vp, int len, int nowait) 
1993/0528    
{ 
	int x, dowakeup; 
1994/0208    
	int n, sofar, x, dowakeup; 
1993/0528    
	Block *b; 
1993/0601    
	uchar *p = vp; 
1993/0526    
 
1993/0528    
	b = allocb(len); 
	memmove(b->wp, p, len); 
	b->wp += len; 
1994/0208    
	dowakeup = 0; 
1993/0526    
 
1993/0528    
	/* flow control */ 
	while(!qnotfull(q)){ 
1993/0601    
		if(nowait) 
			return len; 
1993/0528    
		qlock(&q->wlock); 
1993/1227    
		if(waserror()) { 
1994/0208    
	if(waserror()){ 
		qunlock(&q->wlock); 
		nexterror(); 
	}; 
	qlock(&q->wlock); 
 
	sofar = 0; 
	if(q->syncbuf){ 
		if(len < q->synclen) 
			sofar = len; 
		else 
			sofar = q->synclen; 
 
		memmove(q->syncbuf, p, sofar); 
		q->synclen = sofar; 
		q->syncbuf = 0; 
		wakeup(&q->rr); 
 
		if(len == sofar || (q->state & Qmsg)){ 
1993/1227    
			qunlock(&q->wlock); 
			nexterror(); 
1994/0208    
			poperror(); 
			return len; 
1993/1227    
		} 
1993/0528    
		q->state |= Qflow; 
		sleep(&q->wr, qnotfull, q); 
		qunlock(&q->wlock); 
1993/1227    
		poperror(); 
1993/0526    
	} 
 
1993/0528    
	x = splhi(); 
	lock(q); 
1994/0208    
	do { 
		n = len-sofar; 
		if(n > 128*1024) 
			n = 128*1024; 
1993/0528    
 
	if(q->state & Qclosed){ 
1994/0208    
		b = allocb(n); 
		memmove(b->wp, p+sofar, n); 
		b->wp += n; 
	 
		/* flow control */ 
		while(!qnotfull(q)){ 
			if(nowait){ 
				free(b); 
				qunlock(&q->wlock); 
				poperror(); 
				return len; 
			} 
			q->state |= Qflow; 
			sleep(&q->wr, qnotfull, q); 
		} 
	 
		x = splhi(); 
		lock(q); 
	 
		if(q->state & Qclosed){ 
			unlock(q); 
			splx(x); 
			error(Ehungup); 
		} 
	 
		if(q->syncbuf){ 
			/* we guessed wrong and did an extra copy */ 
			if(n > q->synclen) 
				n = q->synclen; 
			memmove(q->syncbuf, b->rp, n); 
			q->synclen = n; 
			q->syncbuf = 0; 
			dowakeup = 1; 
			free(b); 
		} else { 
			/* we guessed right, queue it */ 
			if(q->bfirst) 
				q->blast->next = b; 
			else 
				q->bfirst = b; 
			q->blast = b; 
			q->len += n; 
	 
			if(q->state & Qstarve){ 
				q->state &= ~Qstarve; 
				dowakeup = 1; 
			} 
		} 
 
1993/0527    
		unlock(q); 
		splx(x); 
1993/0528    
		error(Ehungup); 
1993/0527    
	} 
1993/0526    
 
1993/0601    
	if(q->bfirst) 
		q->blast->next = b; 
	else 
		q->bfirst = b; 
	q->blast = b; 
1993/0526    
	q->len += len; 
1994/0208    
		if(dowakeup){ 
			if(q->kick) 
				(*q->kick)(q->arg); 
			wakeup(&q->rr); 
		} 
1993/0528    
 
	if(q->state & Qstarve){ 
1993/0526    
		q->state &= ~Qstarve; 
1993/0528    
		dowakeup = 1; 
	} else 
		dowakeup = 0; 
1994/0208    
		sofar += n; 
	} while(sofar < len && (q->state & Qmsg) == 0); 
1993/0528    
 
1993/0526    
	unlock(q); 
	splx(x); 
                 
1993/0601    
	if(dowakeup){ 
		if(q->kick) 
			(*q->kick)(q->arg); 
1993/0528    
		wakeup(&q->rr); 
1993/0601    
	} 
1993/0528    
                 
1994/0208    
	qunlock(&q->wlock); 
	poperror(); 
1993/0526    
	return len; 
} 
 
1994/0208/sys/src/9/port/qio.c:591,5971994/0215/sys/src/9/port/qio.c:591,597 (short | long)
1993/0526    
{ 
1993/0528    
	Queue *q = a; 
1993/0526    
 
1993/0528    
	return q->len < q->limit; 
1994/0215    
	return q->len < q->limit || (q->state & Qclosed); 
1993/0528    
} 
1993/0527    
 
1993/0528    
/* 
1994/0215/sys/src/9/port/qio.c:721,7261994/0219/sys/src/9/port/qio.c:721,727 (short | long)
1993/0528    
	q->state |= Qclosed; 
	bfirst = q->bfirst; 
	q->bfirst = 0; 
1994/0219    
	q->len = 0; 
1993/0528    
	unlock(q); 
	splx(x); 
1993/0527    
 
1994/0219/sys/src/9/port/qio.c:97,1021994/0222/sys/src/9/port/qio.c:97,117 (short | long)
1993/0530    
}; 
 
1993/0811    
void 
1994/0222    
checkb(Block *b, char *msg) 
{ 
	if(b->base > b->lim) 
		panic("checkb 0 %s %lux %lux", msg, b->base, b->lim); 
	if(b->rp < b->base) 
		panic("checkb 1 %s %lux %lux", msg, b->base, b->rp); 
	if(b->wp < b->base) 
		panic("checkb 2 %s %lux %lux", msg, b->base, b->wp); 
	if(b->rp > b->lim) 
		panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim); 
	if(b->wp > b->lim) 
		panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim); 
} 
 
void 
1993/0811    
poison(Block *b) 
{ 
	b->next = (void*)0xdeadbabe; 
1994/0219/sys/src/9/port/qio.c:310,3161994/0222/sys/src/9/port/qio.c:325,330
1993/0804    
	b->rp = b->base; 
	b->wp = b->base; 
1994/0208    
	b->lim = ((uchar*)b) + size; 
1993/0527    
	b->flag = 0; 
1993/0526    
 
	return b; 
} 
1994/0219/sys/src/9/port/qio.c:335,3401994/0222/sys/src/9/port/qio.c:349,355
1993/0526    
		unlock(q); 
		return -1; 
	} 
1994/0222    
checkb(b, "qconsume 1"); 
1993/0528    
 
1993/0526    
	n = BLEN(b); 
	if(n < len) 
1994/0219/sys/src/9/port/qio.c:342,3491994/0222/sys/src/9/port/qio.c:357,363
1993/0526    
	memmove(p, b->rp, len); 
1993/0527    
	if((q->state & Qmsg) || len == n) 
1993/0526    
		q->bfirst = b->next; 
	else 
		b->rp += len; 
1994/0222    
	b->rp += len; 
1993/0526    
	q->len -= len; 
 
1993/0528    
	/* if writer flow controlled, restart */ 
1994/0219/sys/src/9/port/qio.c:358,3631994/0222/sys/src/9/port/qio.c:372,378
1993/0528    
	if(dowakeup) 
		wakeup(&q->wr); 
 
1994/0222    
checkb(b, "qconsume 2"); 
1993/0528    
	/* discard the block if we're done with it */ 
1993/0811    
	if((q->state & Qmsg) || len == n) { 
		poison(b); 
1994/0219/sys/src/9/port/qio.c:403,4281994/0222/sys/src/9/port/qio.c:418,438
1993/0526    
	} 
 
	/* save in buffer */ 
	b = q->bfirst; 
1993/0527    
	if((q->state & Qmsg) == 0 && b && b->lim - b->wp <= len){ 
1993/0526    
		memmove(b->wp, p, len); 
		b->wp += len; 
1993/0527    
		b->flag |= Bfilled; 
1993/0526    
	} else { 
		b = iallocb(len); 
		if(b == 0){ 
			unlock(q); 
1993/1103    
			return -2; 
1993/0526    
		} 
1993/0527    
		memmove(b->wp, p, len); 
1993/0526    
		b->wp += len; 
		if(q->bfirst) 
			q->blast->next = b; 
		else 
			q->bfirst = b; 
		q->blast = b; 
1994/0222    
	b = iallocb(len); 
	if(b == 0){ 
		unlock(q); 
		return -2; 
1993/0526    
	} 
1994/0222    
	memmove(b->wp, p, len); 
	b->wp += len; 
	if(q->bfirst) 
		q->blast->next = b; 
	else 
		q->bfirst = b; 
	q->blast = b; 
1993/0526    
	q->len += len; 
1994/0222    
checkb(b, "qproduce"); 
 
1993/0528    
	if(q->state & Qstarve){ 
		q->state &= ~Qstarve; 
		dowakeup = 1; 
1994/0219/sys/src/9/port/qio.c:542,5471994/0222/sys/src/9/port/qio.c:552,558
1994/0208    
			sleep(&q->rr, notempty, q); 
		} 
1993/0526    
	} 
1994/0222    
checkb(b, "qread 1"); 
1993/0526    
 
1993/0528    
	/* remove a buffered block */ 
	q->bfirst = b->next; 
1994/0219/sys/src/9/port/qio.c:563,5681994/0222/sys/src/9/port/qio.c:574,580
1993/0528    
	memmove(p, b->rp, n); 
	b->rp += n; 
1993/0526    
 
1994/0222    
checkb(b, "qread 2"); 
1993/0725    
	/* free it or put what's left on the queue */ 
1993/0811    
	if(b->rp >= b->wp || (q->state&Qmsg)) { 
		poison(b); 
1994/0219/sys/src/9/port/qio.c:663,6691994/0222/sys/src/9/port/qio.c:675,682
1994/0208    
			splx(x); 
			error(Ehungup); 
		} 
	                 
1994/0222    
 
checkb(b, "qwrite"); 
1994/0208    
		if(q->syncbuf){ 
			/* we guessed wrong and did an extra copy */ 
			if(n > q->synclen) 
1994/0222/sys/src/9/port/qio.c:45,631994/0306/sys/src/9/port/qio.c:45,51 (short | long)
1993/0526    
/* 
1993/0530    
 *  IO queues 
 */ 
typedef struct Block	Block; 
typedef struct Queue	Queue; 
                 
struct Block 
{ 
	Block	*next; 
                 
	uchar	*rp;			/* first unconsumed byte */ 
	uchar	*wp;			/* first empty byte */ 
	uchar	*lim;			/* 1 past the end of the buffer */ 
	uchar	*base;			/* start of the buffer */ 
	uchar	flag; 
}; 
#define BLEN(b)		((b)->wp - (b)->rp) 
 
struct Queue 
1994/0306/sys/src/9/port/qio.c:46,521994/0309/sys/src/9/port/qio.c:46,51 (short | long)
1993/0530    
 *  IO queues 
 */ 
typedef struct Queue	Queue; 
#define BLEN(b)		((b)->wp - (b)->rp) 
 
struct Queue 
{ 
1994/0309/sys/src/9/port/qio.c:369,3741994/0311/sys/src/9/port/qio.c:369,441 (short | long)
1993/0526    
} 
 
1993/0528    
int 
1994/0311    
qpass(Queue *q, Block *b) 
{ 
	int s, i, len; 
	int dowakeup; 
 
	s = splhi(); 
 
	len = BLEN(b); 
 
	/* sync with qread */ 
	dowakeup = 0; 
	lock(q); 
 
	if(q->syncbuf){ 
		/* synchronous communications, just copy into buffer */ 
		if(len < q->synclen) 
			q->synclen = len; 
		i = q->synclen; 
		memmove(q->syncbuf, b->rp, i); 
		q->syncbuf = 0;		/* tell reader buffer is full */ 
		len -= i; 
		if(len <= 0 || (q->state & Qmsg)){ 
			unlock(q); 
			wakeup(&q->rr); 
			ifree(b); 
			splx(s); 
			return i; 
		} 
 
		/* queue anything that's left */ 
		dowakeup = 1; 
		b->rp += i; 
	} 
 
	/* no waiting receivers, room in buffer? */ 
	if(q->len >= q->limit){ 
		unlock(q); 
		splx(s); 
		return -1; 
	} 
 
	/* save in buffer */ 
	if(q->bfirst) 
		q->blast->next = b; 
	else 
		q->bfirst = b; 
	q->blast = b; 
	q->len += len; 
checkb(b, "qproduce"); 
 
	if(q->state & Qstarve){ 
		q->state &= ~Qstarve; 
		dowakeup = 1; 
	} 
	unlock(q); 
 
	if(dowakeup){ 
		if(q->kick) 
			(*q->kick)(q->arg); 
		wakeup(&q->rr); 
	} 
	splx(s); 
 
	return len; 
} 
 
int 
1993/0601    
qproduce(Queue *q, void *vp, int len) 
1993/0526    
{ 
	Block *b; 
1994/0311/sys/src/9/port/qio.c:371,3781994/0312/sys/src/9/port/qio.c:371,377 (short | long)
1993/0528    
int 
1994/0311    
qpass(Queue *q, Block *b) 
{ 
	int s, i, len; 
	int dowakeup; 
1994/0312    
	int s, i, len, dowakeup; 
1994/0311    
 
	s = splhi(); 
 
1994/0311/sys/src/9/port/qio.c:417,4231994/0312/sys/src/9/port/qio.c:416,422
1994/0311    
		q->bfirst = b; 
	q->blast = b; 
	q->len += len; 
checkb(b, "qproduce"); 
1994/0312    
checkb(b, "qpass"); 
1994/0311    
 
	if(q->state & Qstarve){ 
		q->state &= ~Qstarve; 
1994/0312/sys/src/9/port/qio.c:15,211994/0319/sys/src/9/port/qio.c:15,21 (short | long)
1993/0526    
enum 
{ 
	Minpow= 7, 
	Maxpow=	12, 
1994/0319    
	Maxpow=	16, 
1993/0526    
}; 
 
struct Chunk 
1994/0312/sys/src/9/port/qio.c:196,2111994/0319/sys/src/9/port/qio.c:196,216
1994/0208    
qinit(void) 
1993/0526    
{ 
	int pow; 
	Chunkl *cl; 
1994/0208    
	Chunk *p; 
1994/0319    
	Chunkl *cl; 
1993/0526    
 
1994/0208    
	/* start with a bunch of initial blocks */ 
1993/0526    
	for(pow = Minpow; pow <= Maxpow; pow++){ 
		cl = &arena.alloc[pow]; 
1994/0208    
		cl->goal = Maxpow-pow + 32; 
1994/0319    
		cl->goal = 0; 
		if(pow < 12) 
			cl->goal = Maxpow-pow + 32; 
 
1994/0208    
		cl->first = 0; 
		for(; cl->have < cl->goal; cl->have++){ 
			p = malloc(1<<pow); 
1994/0319    
			if(p == 0) 
				panic("qinit"); 
1994/0208    
			p->next = cl->first; 
			cl->first = p; 
		} 
1994/0319/sys/src/9/port/qio.c:165,1701994/0320/sys/src/9/port/qio.c:165,172 (short | long)
1993/0819    
				else 
					cl->goal += i; 
				cl->wanted = 0; 
1994/0320    
				if(cl->goal > 5000) 
					cl->goal = 5000; 
1993/0819    
			} 
1993/0526    
 
			first = 0; 
1994/0319/sys/src/9/port/qio.c:202,2111994/0320/sys/src/9/port/qio.c:204,212
1994/0208    
	/* start with a bunch of initial blocks */ 
1993/0526    
	for(pow = Minpow; pow <= Maxpow; pow++){ 
		cl = &arena.alloc[pow]; 
1994/0319    
		cl->goal = 0; 
1994/0320    
		cl->goal = 4; 
1994/0319    
		if(pow < 12) 
			cl->goal = Maxpow-pow + 32; 
                 
1994/0208    
		cl->first = 0; 
		for(; cl->have < cl->goal; cl->have++){ 
			p = malloc(1<<pow); 
1994/0319/sys/src/9/port/qio.c:397,4031994/0320/sys/src/9/port/qio.c:398,404
1994/0311    
		if(len <= 0 || (q->state & Qmsg)){ 
			unlock(q); 
			wakeup(&q->rr); 
			ifree(b); 
1994/0320    
			free(b); 
1994/0311    
			splx(s); 
			return i; 
		} 
1994/0320/sys/src/9/port/qio.c:5,471994/0321/sys/src/9/port/qio.c:5,28 (short | long)
1993/0526    
#include	"fns.h" 
#include	"../port/error.h" 
 
1993/0530    
/* 
 *  interrupt level memory allocation 
 */ 
1993/0526    
typedef struct Chunk	Chunk; 
typedef	struct Chunkl	Chunkl; 
typedef	struct Arena	Arena; 
 
enum 
{ 
	Minpow= 7, 
1994/0319    
	Maxpow=	16, 
1994/0321    
	Minpow	= 7, 
	Maxpow	= 16, 
1993/0526    
}; 
 
struct Chunk 
1994/0321    
struct Pool 
1993/0526    
{ 
	Chunk	*next; 
}; 
                 
struct Chunkl 
{ 
	Lock; 
	Chunk	*first; 
1994/0321    
	Block*	list; 
	int	had; 
1993/0526    
	int	have; 
1994/0321    
	int	want; 
1993/0526    
	int	goal; 
	int	hist; 
1993/0819    
	int	wanted; 
1993/0526    
}; 
1994/0321    
Pool	pool[Maxpow]; 
1993/0526    
 
struct Arena 
{ 
	Chunkl	alloc[Maxpow+1]; 
	Chunkl	freed; 
	Rendez r; 
}; 
                 
static Arena arena; 
                 
/* 
1993/0530    
 *  IO queues 
 */ 
1994/0320/sys/src/9/port/qio.c:51,581994/0321/sys/src/9/port/qio.c:32,39
1993/0530    
{ 
	Lock; 
 
	Block	*bfirst;	/* buffer */ 
	Block	*blast; 
1994/0321    
	Block*	bfirst;	/* buffer */ 
	Block*	blast; 
1993/0530    
 
	int	len;		/* bytes in queue */ 
	int	limit;		/* max bytes in queue */ 
1994/0320/sys/src/9/port/qio.c:60,661994/0321/sys/src/9/port/qio.c:41,47
1993/0908    
	int	eof;		/* number of eofs read by user */ 
1993/0530    
 
	void	(*kick)(void*);	/* restart output */ 
	void	*arg;		/* argument to kick */ 
1994/0321    
	void*	arg;		/* argument to kick */ 
1993/0530    
 
	QLock	rlock;		/* mutex for reading processes */ 
	Rendez	rr;		/* process waiting to read */ 
1994/0320/sys/src/9/port/qio.c:67,731994/0321/sys/src/9/port/qio.c:48,54
1993/0530    
	QLock	wlock;		/* mutex for writing processes */ 
	Rendez	wr;		/* process waiting to write */ 
1994/0208    
 
	uchar	*syncbuf;	/* synchronous IO buffer */ 
1994/0321    
	uchar*	syncbuf;	/* synchronous IO buffer */ 
1994/0208    
	int	synclen;	/* syncbuf length */ 
1993/0530    
}; 
 
1994/0320/sys/src/9/port/qio.c:112,1961994/0321/sys/src/9/port/qio.c:93,150
1993/0526    
 *  Manage interrupt level memory allocation. 
 */ 
static void 
iallockproc(void *arg) 
1994/0321    
iallocmgr(void) 
1993/0526    
{ 
	Chunk *p, *first, **l; 
	Chunkl *cl; 
	int pow, x, i; 
1994/0321    
	int pow; 
1993/0526    
 
	USED(arg); 
	for(;;){ 
		tsleep(&arena.r, return0, 0, 500); 
1994/0321    
	attention = 0; 
	spllo(); 
	for(pow = Minpow; pow <= Maxpow; pow++) { 
		p = &pool[pow]; 
1993/0526    
 
		/* really free what was freed at interrupt level */ 
		cl = &arena.freed; 
		if(cl->first){ 
			x = splhi(); 
			lock(cl); 
			first = cl->first; 
			cl->first = 0; 
			unlock(cl); 
			splx(x); 
	                 
1993/0804    
			while(first != 0) { 
1993/0526    
				p = first->next; 
				free(first); 
1993/0804    
				first = p; 
1993/0526    
			} 
		} 
1994/0321    
		/* Low pass filter */ 
		delta = 3 * (p->had - p->have); 
		delta = (delta/2) + p->want; 
1993/0526    
 
		/* make sure we have blocks available for interrupt level */ 
		for(pow = Minpow; pow <= Maxpow; pow++){ 
			cl = &arena.alloc[pow]; 
                 
			/* 
			 *  if we've been ahead of the game for a while 
			 *  start giving blocks back to the general pool 
			 */ 
			if(cl->have >= cl->goal){ 
1993/0819    
				cl->hist = ((cl->hist<<1) | 1) & 0xffff; 
				if(cl->hist == 0xffff && cl->goal > 32) 
1993/0526    
					cl->goal--; 
				continue; 
			} else 
				cl->hist <<= 1; 
                 
			/* 
1993/0819    
			 *  increase goal if we've been drained. 
1993/0526    
			 */ 
1993/0819    
			if(cl->have == 0){ 
1993/1102    
				i = cl->goal>>1; 
1993/0819    
				if(cl->wanted > i) 
1993/1102    
					cl->goal += 2*cl->wanted; 
1993/0819    
				else 
					cl->goal += i; 
				cl->wanted = 0; 
1994/0320    
				if(cl->goal > 5000) 
					cl->goal = 5000; 
1994/0321    
		if(delta < 0) { 
			lock(p); 
			p->have -= delta; 
			bp = p->list; 
			while(delta--) 
				p->list = p->list->next; 
			unlock(p); 
			spllo(); 
			while(bp) { 
				next = bp->next; 
				free(bp); 
				bp = next; 
1993/0819    
			} 
1993/0526    
                 
			first = 0; 
			l = &first; 
1993/0804    
			i = cl->goal - cl->have; 
			for(x = i; x > 0; x--){ 
1993/0526    
				p = malloc(1<<pow); 
				if(p == 0) 
1994/0321    
			splhi(); 
		} 
		else { 
			spllo(); 
			n = 0; 
			s = sizeof(Block)+(1<<pow)+(BY2V-1); 
			while(delta--) { 
				b = malloc(s); 
				if(b == 0) 
1993/0526    
					break; 
1993/0804    
                 
1993/0526    
				*l = p; 
				l = &p->next; 
1994/0321    
				addr = (ulong)b; 
				addr = (addr+sizeof(Block)+(BY2V-1)) & ~(BY2V-1); 
				b->base = (uchar*)addr; 
				b->rp = b->base; 
				b->wp = b->base; 
				b->lim = ((uchar*)b)+size; 
				b->size = pow; 
				n++; 
1993/0526    
			} 
1993/0819    
			i -= x; 
1993/0526    
			if(first){ 
				x = splhi(); 
				lock(cl); 
				*l = cl->first; 
				cl->first = first; 
				cl->have += i; 
				unlock(cl); 
				splx(x); 
			} 
1994/0321    
			spllo(); 
			lock(p); 
			unlock(p); 
			splhi(); 
1993/0526    
		} 
1994/0321    
		p->had = p->have; 
		p->want = 0;		 
1993/0526    
	} 
} 
 
1994/0320/sys/src/9/port/qio.c:197,3011994/0321/sys/src/9/port/qio.c:151,221
1993/0526    
void 
1994/0208    
qinit(void) 
1993/0526    
{ 
	int pow; 
1994/0208    
	Chunk *p; 
1994/0319    
	Chunkl *cl; 
1993/0526    
                 
1994/0208    
	/* start with a bunch of initial blocks */ 
1993/0526    
	for(pow = Minpow; pow <= Maxpow; pow++){ 
		cl = &arena.alloc[pow]; 
1994/0320    
		cl->goal = 4; 
1994/0319    
		if(pow < 12) 
			cl->goal = Maxpow-pow + 32; 
1994/0208    
		cl->first = 0; 
		for(; cl->have < cl->goal; cl->have++){ 
			p = malloc(1<<pow); 
1994/0319    
			if(p == 0) 
				panic("qinit"); 
1994/0208    
			p->next = cl->first; 
			cl->first = p; 
		} 
1993/0526    
	} 
                 
1994/0208    
} 
 
void 
iallocinit(void) 
{ 
	/* start garbage collector/creator */ 
1993/0725    
	kproc("ialloc", iallockproc, 0); 
1993/0526    
} 
                 
1993/0819    
void 
ixsummary(void) 
{ 
	int pow; 
	Chunkl *cl; 
1994/0321    
	Pool *p; 
1993/0819    
 
	print("size	have/goal\n"); 
	for(pow = Minpow; pow <= Maxpow; pow++){ 
		cl = &arena.alloc[pow]; 
		print("%d	%d/%d\n", 1<<pow, cl->have, cl->goal); 
1994/0321    
		cl = &pool[pow]; 
		print("%d	%d/%d\n", 1<<pow, p->have, p->goal); 
1993/0819    
	} 
	print("\n"); 
} 
 
1994/0208    
/* 
 *  interrupt time allocation (round data base address to 64 bit boundary) 
1994/0321    
 *  interrupt time allocation 
1994/0208    
 */ 
1993/0526    
Block* 
iallocb(int size) 
{ 
	int pow; 
1994/0208    
	ulong addr; 
1993/0526    
	Chunkl *cl; 
	Chunk *p; 
	Block *b; 
1994/0321    
	Block *bp; 
1993/0526    
 
1994/0208    
	size += sizeof(Block) + 7; 
1993/0804    
	for(pow = Minpow; pow <= Maxpow; pow++){ 
1993/0526    
		if(size <= (1<<pow)){ 
			cl = &arena.alloc[pow]; 
			lock(cl); 
			p = cl->first; 
1993/0527    
			if(p == 0){ 
1993/0819    
				cl->wanted++; 
1993/0527    
				unlock(cl); 
1993/0819    
				wakeup(&arena.r); 
1993/0527    
				return 0; 
1993/0526    
			} 
1993/0527    
			cl->have--; 
			cl->first = p->next; 
1993/0526    
			unlock(cl); 
1994/0321    
	for(pow = Minpow; pow < Maxpow; pow++) 
		if(size >= (1<<pow)) 
			break; 
1994/0208    
 
1993/0526    
			b = (Block *)p; 
1993/0528    
			memset(b, 0, sizeof(Block)); 
1994/0208    
			addr = (ulong)b; 
			addr = (addr + sizeof(Block) + 7) & ~7; 
			b->base = (uchar*)addr; 
1993/0804    
			b->wp = b->base; 
			b->rp = b->base; 
1994/0208    
			b->lim = ((uchar*)b) + (1<<pow); 
1993/0526    
			return b; 
1994/0321    
	if(pow == Maxpow) 
		return 0; 
 
	p = &pool[pow]; 
	lock(p); 
	bp = p->list; 
	if(p == 0) { 
		p->want++; 
		unlock(p); 
		if(attention == 0) { 
			attention++; 
			newcallback(iallocmgr); 
1993/0526    
		} 
1994/0321    
		return 0; 
1993/0804    
	} 
                 
1993/0526    
	panic("iallocb %d\n", size); 
	return 0;			/* not reached */ 
1994/0321    
	p->have--; 
	p->list = bp->next; 
	unlock(p); 
	bp->wp = b->base; 
	bp->rp = b->base; 
	bp->list = 0; 
	bp->next = 0; 
	return bp; 
1993/0526    
} 
 
void 
ifree(void *a) 
1994/0321    
ifreeb(Block *bp) 
1993/0526    
{ 
	Chunk *p; 
	Chunkl *cl; 
1994/0321    
	Pool *p; 
1993/0526    
 
	cl = &arena.freed; 
	p = a; 
	lock(cl); 
	p->next = cl->first; 
	cl->first = p; 
	unlock(cl); 
1994/0321    
	p = &pool[bp->size]; 
	lock(p); 
	bp->next = p->list; 
	p->list = bp; 
	p->have++; 
	unlock(p); 
1993/0526    
} 
 
/* 
Too many diffs (26 > 25). Stopping.


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)