## diffname port/qio.c 1993/0526
## diff -e /dev/null /n/fornaxdump/1993/0526/sys/src/brazil/port/qio.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
typedef struct Chunk Chunk;
typedef struct Chunkl Chunkl;
typedef struct Arena Arena;
enum
{
Minpow= 7,
Maxpow= 12,
};
struct Chunk
{
Chunk *next;
};
struct Chunkl
{
Lock;
Chunk *first;
int have;
int goal;
int hist;
};
struct Arena
{
Chunkl alloc[Maxpow+1];
Chunkl freed;
Rendez r;
};
static Arena arena;
/*
* Manage interrupt level memory allocation.
*/
static void
iallockproc(void *arg)
{
Chunk *p, *first, **l;
Chunkl *cl;
int pow, x, i;
USED(arg);
for(;;){
tsleep(&arena.r, return0, 0, 500);
/* 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);
for(; first; first = p){
p = first->next;
free(first);
}
}
/* 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){
cl->hist = ((cl->hist<<1) | 1) & 0xff;
if(cl->hist == 0xff && cl->goal > 8)
cl->goal--;
continue;
} else
cl->hist <<= 1;
/*
* increase goal if we've been drained, decrease
* goal if we've had lots of blocks twice in a row.
*/
if(cl->have == 0)
cl->goal += cl->goal>>2;
first = 0;
l = &first;
for(i = x = cl->goal - cl->have; x > 0; x--){
p = malloc(1<<pow);
if(p == 0)
break;
*l = p;
l = &p->next;
}
if(first){
x = splhi();
lock(cl);
*l = cl->first;
cl->first = first;
cl->have += i;
unlock(cl);
splx(x);
}
}
}
}
void
iallocinit(void)
{
int pow;
Chunkl *cl;
for(pow = Minpow; pow <= Maxpow; pow++){
cl = &arena.alloc[pow];
cl->goal = Maxpow-pow + 4;
}
/* start garbage collector */
kproc("iallockproc", iallockproc, 0);
}
Block*
iallocb(int size)
{
int pow;
Chunkl *cl;
Chunk *p;
Block *b;
size += sizeof(Block);
for(pow = Minpow; pow <= Maxpow; pow++)
if(size <= (1<<pow)){
cl = &arena.alloc[pow];
lock(cl);
p = cl->first;
if(p){
cl->have--;
cl->first = p->next;
}
unlock(cl);
b = (Block *)p;
b->base = (uchar*)(b+1);
b->wp = b->rp = b->base;
b->lim = b->base + (1<<pow) - sizeof(Block);
return b;
}
panic("iallocb %d\n", size);
return 0; /* not reached */
}
void
ifree(void *a)
{
Chunk *p;
Chunkl *cl;
cl = &arena.freed;
p = a;
lock(cl);
p->next = cl->first;
cl->first = p;
unlock(cl);
}
/*
* allocate queues and blocks
*/
Block*
allocb(int size)
{
Block *b;
b = malloc(sizeof(Block) + size);
if(b == 0)
exhausted("Blocks");
b->base = (uchar*)(b+1);
b->rp = b->wp = b->base;
b->lim = b->base + size;
return b;
}
/*
* Interrupt level copy out of a queue, return # bytes copied. If drop is
* set, any bytes left in a block afer a consume are discarded.
*/
int
qconsume(Queue *q, uchar *p, int len)
{
Block *b;
int n;
lock(q);
b = q->bfirst;
if(b == 0){
q->state |= Qstarve;
unlock(q);
return -1;
}
n = BLEN(b);
if(n < len)
len = n;
memmove(p, b->rp, len);
if((q->state&Qmsg) || len == n)
q->bfirst = b->next;
else
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);
unlock(q);
if((q->state&Qmsg) || len == n)
ifree(b);
return len;
}
static int
qproduce0(Queue *q, uchar *p, int len)
{
Block *b;
int n;
lock(q);
b = q->rfirst;
if(b){
/* hand to waiting receiver */
n = b->lim - b->wp;
if(n < len)
len = n;
memmove(b->wp, p, len);
b->wp += len;
q->rfirst = b->next;
wakeup(&b->r);
unlock(q);
return len;
}
/* no waiting receivers, room in buffer? */
if(q->len >= q->limit){
unlock(q);
return -1;
}
/* save in buffer */
b = q->bfirst;
if((q->state&Qmsg)==0 && b && b->lim-b->wp <= len){
memmove(b->wp, p, len);
b->wp += len;
} else {
b = iallocb(len);
if(b == 0){
unlock(q);
return -1;
}
b->wp += len;
memmove(b->rp, p, len);
if(q->bfirst)
q->blast->next = b;
else
q->bfirst = b;
q->blast = b;
}
q->len += len;
unlock(q);
return len;
}
int
qproduce(Queue *q, uchar *p, int len)
{
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);
if(n < 0)
break;
}
return sofar;
}
/*
* called by non-interrupt code
*/
Queue*
qopen(int limit, void (*kick)(void*), void *arg)
{
Queue *q;
q = malloc(sizeof(Queue));
if(q == 0)
exhausted("Queues");
q->limit = limit;
q->kick = kick;
q->arg = arg;
q->state = Qmsg;
return q;
}
static int
bfilled(void *a)
{
Block *b = a;
return b->wp - b->rp;
}
long
qread(Queue *q, char *p, int len)
{
Block *b, *bb;
int x, n;
qlock(&q->rlock);
/* ... to be replaced by a kmapping if need be */
b = allocb(len);
x = splhi();
lock(q);
bb = q->bfirst;
if(bb == 0){
/* wait for our block to be filled */
if(q->rfirst)
q->rlast->next = b;
else
q->rfirst = b;
q->rlast = b;
unlock(q);
splx(x);
qunlock(&q->rlock);
sleep(&b->r, bfilled, b);
n = BLEN(b);
memmove(p, b->rp, n);
free(b);
return n;
}
/* copy from a buffered block */
q->bfirst = bb->next;
n = BLEN(bb);
if(n > len)
n = len;
q->len -= n;
unlock(q);
splx(x);
memmove(p, bb->rp, n);
bb->rp += n;
/* free it or put it back */
if(drop || bb->rp == bb->wp)
free(bb);
else {
x = splhi();
lock(q);
bb->next = q->bfirst;
q->bfirst = bb;
unlock(q);
splx(x);
}
qunlock(&q->rlock);
free(b);
return n;
}
static int
qnotfull(void *a)
{
Queue *q = a;
return q->len < q->limit;
}
static long
qwrite0(Queue *q, char *p, int len)
{
Block *b, *bb;
int x, n;
b = allocb(len);
x = splhi();
lock(q);
bb = q->rfirst;
if(bb){
/* 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;
wakeup(&bb->r);
free(b);
return len;
}
memmove(b->rp, p, len);
b->wp += len;
/* flow control */
if(!qnotfull(q))
sleep(&q->r, qnotfull, q);
x = splhi();
lock(q);
if(q->bfirst)
q->blast->next = b;
else
q->bfirst = b;
q->blast = b;
q->len += len;
if((q->state & Qstarve) && q->kick){
q->state &= ~Qstarve;
(*q->kick)(q->arg);
}
unlock(q);
splx(x);
return len;
}
long
qwrite(Queue *q, char *p, int len)
{
int n, sofar;
qlock(&q->wlock);
if(waserror()){
qunlock(&q->wlock);
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;
}
}
poperror();
qunlock(&q->wlock);
return sofar;
}
.
## diffname port/qio.c 1993/0527
## diff -e /n/fornaxdump/1993/0526/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0527/sys/src/brazil/port/qio.c
468c
poperror();
return n;
.
466d
456,463c
/* 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);
.
449a
/*
* 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 */
.
448c
int n, i;
Block *b;
.
444a
static int
qnotfull(void *a)
{
Queue *q = a;
return q->len < q->limit;
}
.
423,425c
/* 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;
.
419,421d
416,417c
sofar += n;
if(sofar == len){
if(b){
free(b); /* we were wrong to allocate */
qwtoomany++;
}
return len;
}
.
410,413c
n = bb->lim - bb->wp;
if(n > len-sofar)
n = len - sofar;
memmove(bb->wp, p+sofar, n);
bb->wp += n;
bb->flag |= Bfilled;
.
405d
402,403c
sofar = 0;
while(bb = q->rfirst){
.
398,399c
/* sync with qconsume/qread */
.
395,396c
Block *bb;
int x, n, sofar;
.
393c
qwrite0(Queue *q, char *p, int len, Block *b)
.
389,391d
384,387c
ulong qwtoomany;
ulong qwtoofew;
.
380c
if(b){
qrtoomany++;
free(b);
}
.
378a
poperror();
.
368,369c
/* free it or put it back on the queue */
if(bb->rp >= bb->wp || (q->state&Qmsg))
.
364a
/* do this outside of the lock(q)! */
.
353a
.
352a
poperror();
.
349a
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 */
.
341c
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 */
.
338a
.
336a
/* sync with qwrite/qproduce */
.
334,335c
/*
* 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);
.
332a
b = 0;
if(waserror()){
qunlock(&q->rlock);
if(b)
free(b);
nexterror();
}
.
329c
Block *b, *bb, **l;
.
323c
return b->flag & Bfilled;
.
317a
ulong qrtoomany;
ulong qrtoofew;
.
295c
sofar += n;
} while(sofar < len && (q->state & Qmsg) == 0);
.
288,292c
sofar = 0;
do {
n = qproduce0(q, p + sofar, len - sofar);
.
279a
.
271c
b->flag |= Bfilled;
.
269a
memmove(b->wp, p, len);
.
263a
b->flag |= Bfilled;
.
261c
if((q->state & Qmsg) == 0 && b && b->lim - b->wp <= len){
.
249d
247c
b->flag |= Bfilled;
.
241a
q->rfirst = b->next;
unlock(q);
.
238a
.
237a
/* sync with qread */
.
226c
if((q->state & Qmsg) || len == n)
.
214c
if((q->state & Qmsg) || len == n)
.
203a
.
202a
/* sync with qwrite */
.
188a
b->flag = 0;
.
153a
b->flag = 0;
.
148a
cl->have--;
cl->first = p->next;
.
145,147c
if(p == 0){
unlock(cl);
return 0;
.
## diffname port/qio.c 1993/0528
## diff -e /n/fornaxdump/1993/0527/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0528/sys/src/brazil/port/qio.c
572c
/* 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;
.
569,570c
/* mark it */
x = splhi();
lock(q);
q->state |= Qclosed;
unlock(q);
splx(x);
.
559,567c
/*
* Mark a queue as closed. Wakeup any readers. Don't remove queued
* blocks.
*/
void
qhangup(Queue *q)
{
int x;
.
556,557c
/* wake up readers/writers */
wakeup(&q->rr);
wakeup(&q->wr);
}
.
529,553c
/* free queued blocks */
while(b = bfirst){
bfirst = b->next;
free(b);
.
526,527c
/* mark it */
x = splhi();
lock(q);
q->state |= Qclosed;
bfirst = q->bfirst;
q->bfirst = 0;
unlock(q);
splx(x);
.
524c
int x;
Block *b, *bfirst;
.
521,522c
/*
* Mark a queue as closed. No further IO is permitted.
* All blocks are released.
*/
void
qclose(Queue *q)
.
517a
if(dowakeup)
wakeup(&q->rr);
.
513,514c
dowakeup = 1;
} else
dowakeup = 0;
.
511c
if(q->state & Qstarve){
.
503,509c
b->next = q->bfirst;
q->bfirst = b;
.
501d
498,499c
error(Ehungup);
.
493,495c
x = splhi();
lock(q);
if(q->state & Qclosed){
.
483,490c
/* flow control */
while(!qnotfull(q)){
qlock(&q->wlock);
q->state |= Qflow;
sleep(&q->wr, qnotfull, q);
qunlock(&q->wlock);
.
475,481c
b = allocb(len);
memmove(b->wp, p, len);
b->wp += len;
.
468,473c
/*
* 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;
.
464,466c
return q->len < q->limit;
}
.
461,462c
Queue *q = a;
.
455,459c
static int
qnotfull(void *a)
.
448,451d
445a
/* wakeup flow controlled writers (with a bit of histeresis) */
if(dowakeup)
wakeup(&q->wr);
.
440,441c
b->next = q->bfirst;
q->bfirst = b;
q->len += BLEN(b);
.
434,436c
/* free it or put it what's left on the queue */
if(b->rp >= b->wp || (q->state&Qmsg))
free(b);
.
431,432c
if(n > len)
n = len;
memmove(p, b->rp, n);
b->rp += n;
.
426a
/* if writer flow controlled, restart */
if((q->state & Qflow) && q->len < q->limit/2){
q->state &= ~Qflow;
dowakeup = 1;
} else
dowakeup = 0;
.
421,425c
/* remove a buffered block */
q->bfirst = b->next;
n = BLEN(b);
.
390,418c
sleep(&q->rr, notempty, q);
.
382,387c
b = q->bfirst;
if(b)
break;
q->state |= Qstarve;
.
378,379c
return 0;
.
368,375c
if(q->state & Qclosed){
.
355,366c
/* wait for data */
for(;;){
/* sync with qwrite/qproduce */
x = splhi();
lock(q);
.
350,351d
347d
343,344c
Block *b;
int x, n, dowakeup;
.
339a
/*
* read a queue. if no data is queued, post a Block
* and wait on its Rendez.
*/
.
337c
return q->bfirst != 0;
.
335c
Queue *q = a;
.
333c
notempty(void *a)
.
329,331d
320c
return 0;
memset(q, 0, sizeof(Queue));
.
295,309d
291a
if(dowakeup)
wakeup(&q->rr);
.
289a
if(q->state & Qstarve){
q->state &= ~Qstarve;
dowakeup = 1;
} else
dowakeup = 0;
.
282d
247,261d
242c
int dowakeup;
.
238,239c
int
qproduce(Queue *q, uchar *p, int len)
.
231a
if(dowakeup)
wakeup(&q->wr);
/* discard the block if we're done with it */
.
226,228c
/* if writer flow controlled, restart */
if((q->state & Qflow) && q->len < q->limit/2){
q->state &= ~Qflow;
dowakeup = 1;
} else
dowakeup = 0;
.
215a
.
205c
int n, dowakeup;
.
188a
memset(b, 0, sizeof(Block));
.
156d
152a
memset(b, 0, sizeof(Block));
.
## diffname port/qio.c 1993/0530
## diff -e /n/fornaxdump/1993/0528/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0530/sys/src/brazil/port/qio.c
519a
}
/*
* return bytes queued
*/
int
qlen(Queue *q)
{
return q->len;
.
312c
q->state = msg ? Qmsg : 0;
.
300c
qopen(int limit, int msg, void (*kick)(void*), void *arg)
.
41a
* 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),
};
/*
.
7a
/*
* interrupt level memory allocation
*/
.
## diffname port/qio.c 1993/0601
## diff -e /n/fornaxdump/1993/0530/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0601/sys/src/brazil/port/qio.c
581a
}
/*
* return true if we can read without blocking
*/
int
qcanread(Queue *q)
{
return q->bfirst!=0;
.
572a
q->state |= Qstarve;
.
510a
}
.
509c
if(dowakeup){
if(q->kick)
(*q->kick)(q->arg);
.
496,497c
if(q->bfirst)
q->blast->next = b;
else
q->bfirst = b;
q->blast = b;
.
480a
if(nowait)
return len;
.
473a
uchar *p = vp;
.
470c
qwrite(Queue *q, void *vp, int len, int nowait)
.
386a
uchar *p = vp;
.
383c
qread(Queue *q, void *vp, int len)
.
365a
q->state |= Qstarve;
.
344a
}
.
343c
if(dowakeup){
if(q->kick)
(*q->kick)(q->arg);
.
304a
uchar *p = vp;
.
301c
qproduce(Queue *q, void *vp, int len)
.
259a
uchar *p = vp;
.
256c
qconsume(Queue *q, void *vp, int len)
.
## diffname port/qio.c 1993/0725
## diff -e /n/fornaxdump/1993/0601/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0725/sys/src/brazil/port/qio.c
442c
/* free it or put what's left on the queue */
.
409a
print("Qclosed %lux\n", q);
.
181c
kproc("ialloc", iallockproc, 0);
.
## diffname port/qio.c 1993/0727
## diff -e /n/fornaxdump/1993/0725/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0727/sys/src/brazil/port/qio.c
410d
## diffname port/qio.c 1993/0728
## diff -e /n/fornaxdump/1993/0727/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0728/sys/src/brazil/port/qio.c
413,415d
406a
b = q->bfirst;
if(b)
break;
.
## diffname port/qio.c 1993/0804
## diff -e /n/fornaxdump/1993/0728/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0804/sys/src/brazil/port/qio.c
552,554c
while(bfirst){
b = bfirst->next;
free(bfirst);
bfirst = b;
.
244c
b->rp = b->base;
b->wp = b->base;
.
242d
211a
}
.
208c
b->wp = b->base;
b->rp = b->base;
.
193c
for(pow = Minpow; pow <= Maxpow; pow++){
.
152a
.
149c
i = cl->goal - cl->have;
for(x = i; x > 0; x--){
.
120a
first = p;
.
118c
while(first != 0) {
.
## diffname port/qio.c 1993/0811
## diff -e /n/fornaxdump/1993/0804/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0811/sys/src/brazil/port/qio.c
559a
poison(bfirst);
.
451a
}
.
450c
if(b->rp >= b->wp || (q->state&Qmsg)) {
poison(b);
.
303c
}
.
301c
if((q->state & Qmsg) || len == n) {
poison(b);
.
93a
void
poison(Block *b)
{
b->next = (void*)0xdeadbabe;
b->rp = (void*)0xdeadbabe;
b->wp = (void*)0xdeadbabe;
b->lim = (void*)0xdeadbabe;
b->base = (void*)0xdeadbabe;
}
.
## diffname port/qio.c 1993/0819
## diff -e /n/fornaxdump/1993/0811/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0819/sys/src/brazil/port/qio.c
212a
wakeup(&arena.r);
.
211a
cl->wanted++;
.
196a
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");
}
.
168a
i -= x;
.
155,156c
if(cl->have == 0){
i = cl->goal>>2;
if(cl->wanted > i)
cl->goal += cl->wanted;
else
cl->goal += i;
cl->wanted = 0;
}
.
152,153c
* increase goal if we've been drained.
.
144,145c
cl->hist = ((cl->hist<<1) | 1) & 0xffff;
if(cl->hist == 0xffff && cl->goal > 32)
.
32a
int wanted;
.
## diffname port/qio.c 1993/0908
## diff -e /n/fornaxdump/1993/0819/sys/src/brazil/port/qio.c /n/fornaxdump/1993/0908/sys/src/brazil/port/qio.c
634a
q->eof = 0;
.
453a
poperror();
qunlock(&q->rlock);
if(++q->eof > 3)
error(Ehungup);
.
411a
q->eof = 0;
.
72a
int eof; /* number of eofs read by user */
.
## diffname port/qio.c 1993/1102
## diff -e /n/fornaxdump/1993/0908/sys/src/brazil/port/qio.c /n/fornaxdump/1993/1102/sys/src/brazil/port/qio.c
198c
cl->goal = Maxpow-pow + 16;
.
159c
cl->goal += 2*cl->wanted;
.
157c
i = cl->goal>>1;
.
## diffname port/qio.c 1993/1103
## diff -e /n/fornaxdump/1993/1102/sys/src/brazil/port/qio.c /n/fornaxdump/1993/1103/sys/src/brazil/port/qio.c
368c
return -2;
.
## diffname port/qio.c 1993/1227
## diff -e /n/fornaxdump/1993/1103/sys/src/brazil/port/qio.c /n/fornaxdump/1993/1227/sys/src/brazil/port/qio.c
543a
poperror();
.
540a
if(waserror()) {
qunlock(&q->wlock);
nexterror();
}
.
## diffname port/qio.c 1994/0208
## diff -e /n/fornaxdump/1993/1227/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0208/sys/src/brazil/port/qio.c
573,581c
qunlock(&q->wlock);
poperror();
.
567,571c
sofar += n;
} while(sofar < len && (q->state & Qmsg) == 0);
.
560,565c
if(dowakeup){
if(q->kick)
(*q->kick)(q->arg);
wakeup(&q->rr);
}
.
557,558d
554c
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;
}
}
.
551,552c
do {
n = len-sofar;
if(n > 128*1024)
n = 128*1024;
.
545,548d
543c
poperror();
return len;
.
536,541c
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)){
.
532,534c
dowakeup = 0;
.
528c
int n, sofar, x, dowakeup;
.
523a
*
* all copies should be outside of spl since they can fault.
.
493,494c
} else {
.
463,466c
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);
}
.
438a
/* 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);
}
.
418a
filled(void *a)
{
Queue *q = a;
return q->syncbuf == 0;
}
static int
.
382,383c
}
.
351a
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;
}
.
349a
dowakeup = 0;
.
346c
int i, dowakeup;
.
285c
b->lim = ((uchar*)b) + size;
.
282c
addr = (ulong)b;
addr = (addr + sizeof(Block) + 7) & ~7;
b->base = (uchar*)addr;
.
278c
size += sizeof(Block) + 7;
b = malloc(size);
.
276a
ulong addr;
.
271c
* allocate queues and blocks (round data base address to 64 bit boundary)
.
247c
b->lim = ((uchar*)b) + (1<<pow);
.
244c
addr = (ulong)b;
addr = (addr + sizeof(Block) + 7) & ~7;
b->base = (uchar*)addr;
.
241a
.
227c
size += sizeof(Block) + 7;
.
222a
ulong addr;
.
218a
/*
* interrupt time allocation (round data base address to 64 bit boundary)
*/
.
201c
}
void
iallocinit(void)
{
/* start garbage collector/creator */
.
198c
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;
}
.
195a
/* start with a bunch of initial blocks */
.
194a
Chunk *p;
.
191c
qinit(void)
.
81a
uchar *syncbuf; /* synchronous IO buffer */
int synclen; /* syncbuf length */
.
## diffname port/qio.c 1994/0215
## diff -e /n/fornaxdump/1994/0208/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0215/sys/src/brazil/port/qio.c
594c
return q->len < q->limit || (q->state & Qclosed);
.
## diffname port/qio.c 1994/0219
## diff -e /n/fornaxdump/1994/0215/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0219/sys/src/brazil/port/qio.c
723a
q->len = 0;
.
## diffname port/qio.c 1994/0222
## diff -e /n/fornaxdump/1994/0219/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0222/sys/src/brazil/port/qio.c
666c
checkb(b, "qwrite");
.
565a
checkb(b, "qread 2");
.
544a
checkb(b, "qread 1");
.
425a
checkb(b, "qproduce");
.
424a
memmove(b->wp, p, len);
b->wp += len;
if(q->bfirst)
q->blast->next = b;
else
q->bfirst = b;
q->blast = b;
.
406,423c
b = iallocb(len);
if(b == 0){
unlock(q);
return -2;
.
360a
checkb(b, "qconsume 2");
.
345,346c
b->rp += len;
.
337a
checkb(b, "qconsume 1");
.
313d
99a
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
.
## diffname port/qio.c 1994/0306
## diff -e /n/fornaxdump/1994/0222/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0306/sys/src/brazil/port/qio.c
50,60d
48d
## diffname port/qio.c 1994/0309
## diff -e /n/fornaxdump/1994/0306/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0309/sys/src/brazil/port/qio.c
49d
## diffname port/qio.c 1994/0311
## diff -e /n/fornaxdump/1994/0309/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0311/sys/src/brazil/port/qio.c
371a
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
.
## diffname port/qio.c 1994/0312
## diff -e /n/fornaxdump/1994/0311/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0312/sys/src/brazil/port/qio.c
420c
checkb(b, "qpass");
.
374,375c
int s, i, len, dowakeup;
.
## diffname port/qio.c 1994/0319
## diff -e /n/fornaxdump/1994/0312/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0319/sys/src/brazil/port/qio.c
208a
if(p == 0)
panic("qinit");
.
205c
cl->goal = 0;
if(pow < 12)
cl->goal = Maxpow-pow + 32;
.
200a
Chunkl *cl;
.
199d
18c
Maxpow= 16,
.
## diffname port/qio.c 1994/0320
## diff -e /n/fornaxdump/1994/0319/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0320/sys/src/brazil/port/qio.c
400c
free(b);
.
208d
205c
cl->goal = 4;
.
167a
if(cl->goal > 5000)
cl->goal = 5000;
.
## diffname port/qio.c 1994/0321
## diff -e /n/fornaxdump/1994/0320/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0321/sys/src/brazil/port/qio.c
293,298c
p = &pool[bp->size];
lock(p);
bp->next = p->list;
p->list = bp;
p->have++;
unlock(p);
.
290,291c
Pool *p;
.
288c
ifreeb(Block *bp)
.
282,284c
p->have--;
p->list = bp->next;
unlock(p);
bp->wp = b->base;
bp->rp = b->base;
bp->list = 0;
bp->next = 0;
return bp;
.
280a
return 0;
.
271,279c
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);
.
255,269c
for(pow = Minpow; pow < Maxpow; pow++)
if(size >= (1<<pow))
break;
.
250,253c
Block *bp;
.
244c
* interrupt time allocation
.
237,238c
cl = &pool[pow];
print("%d %d/%d\n", 1<<pow, p->have, p->goal);
.
233c
Pool *p;
.
223,229d
200,219d
193a
p->had = p->have;
p->want = 0;
.
183,192c
spllo();
lock(p);
unlock(p);
splhi();
.
179,181c
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++;
.
171,177c
splhi();
}
else {
spllo();
n = 0;
s = sizeof(Block)+(1<<pow)+(BY2V-1);
while(delta--) {
b = malloc(s);
if(b == 0)
.
142,169c
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;
.
125,140c
/* Low pass filter */
delta = 3 * (p->had - p->have);
delta = (delta/2) + p->want;
.
121,123c
attention = 0;
spllo();
for(pow = Minpow; pow <= Maxpow; pow++) {
p = &pool[pow];
.
117,119c
int pow;
.
115c
iallocmgr(void)
.
70c
uchar* syncbuf; /* synchronous IO buffer */
.
63c
void* arg; /* argument to kick */
.
54,55c
Block* bfirst; /* buffer */
Block* blast;
.
36,44d
34a
Pool pool[Maxpow];
.
32,33d
30a
int want;
.
29c
Block* list;
int had;
.
23,27d
21c
struct Pool
.
17,18c
Minpow = 7,
Maxpow = 16,
.
8,13d
## diffname port/qio.c 1994/0322
## diff -e /n/fornaxdump/1994/0321/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0322/sys/src/brazil/port/qio.c
723,724c
freeb(bfirst);
.
667c
freeb(b);
.
640c
freeb(b);
.
559,560c
freeb(b);
.
531c
while(q->bfirst == 0)
sleep(&q->rr, notempty, q);
.
522c
while(q->syncbuf != 0)
sleep(&q->rr, filled, q);
.
331,337d
325d
321c
freeb(b);
.
305d
303d
290,293c
if((q->state & Qmsg) || len == n)
freeb(b);
.
246,247c
* Interrupt level copy out of a queue, return # bytes copied.
.
236c
addr = ROUND(addr + sizeof(Block), BY2V);
.
233a
memset(b, 0, sizeof(Block));
.
230,231c
size = sizeof(Block) + size + (BY2V-1);
b = mallocz(size, 0);
.
211,218c
print("ialloc %d/%d\n", ialloc.bytes, conf.ialloc);
.
209c
ixsummary(void)
.
179,205c
free(b);
.
170,177c
/* poison the block in case someone is still holding onto it */
b->next = (void*)0xdeadbabe;
b->rp = (void*)0xdeadbabe;
b->wp = (void*)0xdeadbabe;
b->lim = (void*)0xdeadbabe;
b->base = (void*)0xdeadbabe;
.
167,168d
159,165c
if(b->intr){
ilock(&ialloc);
ialloc.bytes -= b->lim - b->base;
iunlock(&ialloc);
.
157c
freeb(Block *b)
.
151,153c
return b;
.
109,149c
lock(&ialloc);
ialloc.bytes += b->lim - b->base;
unlock(&ialloc);
.
105,107c
addr = (ulong)b;
addr = ROUND(addr + sizeof(Block), BY2V);
b->base = (uchar*)addr;
b->rp = b->base;
b->wp = b->base;
b->lim = ((uchar*)b) + size;
b->intr = 1;
.
100,103c
size = sizeof(Block) + size + (BY2V-1);
if(ialloc.bytes > conf.ialloc){
iprint("whoops %d/%d\n", ialloc.bytes, conf.ialloc);
return 0;
}
b = mallocz(size, 0);
if(b == 0){
iprint("malloc %d/%d\n", ialloc.bytes, conf.ialloc);
return 0;
}
memset(b, 0, sizeof(Block));
.
98c
Block *b;
ulong addr;
.
95,96c
Block*
iallocb(int size)
.
93c
* interrupt time allocation
.
82,91d
18,24c
ulong bytes;
} ialloc;
.
11,16d
8,9c
struct
.
## diffname port/qio.c 1994/0323
## diff -e /n/fornaxdump/1994/0322/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0323/sys/src/brazil/port/qio.c
644,645c
iunlock(q);
.
641,642c
ilock(q);
.
638,639d
616,617c
iunlock(q);
.
610,611c
ilock(q);
.
606d
582,583c
iunlock(q);
.
552,553c
iunlock(q);
.
548,549c
ilock(q);
.
496c
int n, sofar, dowakeup;
.
491c
* all copies should be outside of ilock since they can fault.
.
466,467c
iunlock(q);
.
461,462c
ilock(q);
.
447,448c
iunlock(q);
.
428,431c
iunlock(q);
sleep(&q->rr, notempty, q);
.
418,419c
iunlock(q);
.
405,406c
iunlock(q);
.
397,398c
ilock(q);
.
386,387c
iunlock(q);
.
383,384c
ilock(q);
.
375c
int n, dowakeup;
.
364c
return (q->state & Qclosed) || q->bfirst != 0;
.
267a
if(debuging) print("qproduce %d\n", len);
.
256d
249c
iunlock(q);
.
228d
225c
iunlock(q);
.
214c
ilock(q);
.
210d
208c
int i, len, dowakeup;
.
128c
debuging ^= 1;
print("ialloc %d/%d %d\n", ialloc.bytes, conf.ialloc, debuging);
.
13a
static int debuging;
.
## diffname port/qio.c 1994/0324
## diff -e /n/fornaxdump/1994/0323/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0324/sys/src/brazil/port/qio.c
463a
}
.
462c
if(dowakeup){
if(q->kick)
(*q->kick)(q->arg);
.
436c
if((q->state & Qflow) && q->len < q->limit){
.
268d
245a
if(q->len >= q->limit)
q->state |= Qflow;
.
233a
/* queue anything that's left */
.
232d
226c
if(len <= 0 || (q->state & Qmsg)) {
.
## diffname port/qio.c 1994/0327
## diff -e /n/fornaxdump/1994/0324/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0327/sys/src/brazil/port/qio.c
658a
* return space remaining before flow control
*/
int
qwindow(Queue *q)
{
int l;
l = q->limit - q->len;
if(l < 0)
l = 0;
return l;
}
/*
.
## diffname port/qio.c 1994/0328
## diff -e /n/fornaxdump/1994/0327/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0328/sys/src/brazil/port/qio.c
438c
if((q->state & Qflow) && q->len < q->limit/2){
.
## diffname port/qio.c 1994/0331
## diff -e /n/fornaxdump/1994/0328/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0331/sys/src/brazil/port/qio.c
418,419c
sleep(&q->rr, filled, q);
.
## diffname port/qio.c 1994/0418
## diff -e /n/fornaxdump/1994/0331/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0418/sys/src/brazil/port/qio.c
246c
if(q->len >= q->limit/2)
.
## diffname port/qio.c 1994/0505
## diff -e /n/fornaxdump/1994/0418/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0505/sys/src/brazil/port/qio.c
111c
if(b->intr) {
.
88c
iprint("iallocb: no memory %d/%d\n", ialloc.bytes, conf.ialloc);
.
83c
iprint("ialloc limit exceeded %d/%d\n", ialloc.bytes, conf.ialloc);
.
## diffname port/qio.c 1994/0507
## diff -e /n/fornaxdump/1994/0505/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0507/sys/src/brazil/port/qio.c
111c
if(b->flag & BINTR) {
.
103c
iunlock(&ialloc);
.
101c
ilock(&ialloc);
.
99c
b->flag = BINTR;
.
83c
iprint("ialloc limit %d/%d\n", ialloc.bytes, conf.ialloc);
.
51,54c
Qstarve = (1<<0), /* consumer starved */
Qmsg = (1<<1), /* message stream */
Qclosed = (1<<2),
Qflow = (1<<3),
.
47,49d
## diffname port/qio.c 1994/0804
## diff -e /n/fornaxdump/1994/0507/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0804/sys/src/brazil/port/qio.c
545a
poperror();
.
533a
poperror();
.
524a
if(waserror()){
freeb(b);
nexterror();
}
.
497c
}
.
340d
## diffname port/qio.c 1994/0902
## diff -e /n/fornaxdump/1994/0804/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0902/sys/src/brazil/port/qio.c
679a
}
/*
* change queue limit
*/
void
qsetlimit(Queue *q, int limit)
{
q->limit = limit;
}
/*
* set blocking/nonblocking
*/
void
qnoblock(Queue *q, int onoff)
{
q->noblock = onoff;
.
647a
q->noblock = 0;
q->limit = q->inilim;
.
552c
QDEBUG checkb(b, "qwrite");
.
533c
if(q->noblock){
.
485c
qwrite(Queue *q, void *vp, int len)
.
446c
QDEBUG checkb(b, "qread 2");
.
425c
QDEBUG checkb(b, "qread 1");
.
340c
q->limit = q->inilim = limit;
.
311c
QDEBUG checkb(b, "qproduce");
.
241c
QDEBUG checkb(b, "qpass");
.
198c
QDEBUG checkb(b, "qconsume 2");
.
175c
QDEBUG checkb(b, "qconsume 1");
.
30a
int noblock; /* true if writes return immediately when q full */
.
29a
int inilim; /* initial limit */
.
15a
#define QDEBUG if(0)
.
## diffname port/qio.c 1994/0927
## diff -e /n/fornaxdump/1994/0902/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0927/sys/src/brazil/port/qio.c
703a
}
/*
* flush the output queue
*/
void
qflush(Queue *q)
{
Block *b, *bfirst;
/* mark it */
ilock(q);
bfirst = q->bfirst;
q->bfirst = 0;
q->len = 0;
iunlock(q);
/* free queued blocks */
while(bfirst){
b = bfirst->next;
freeb(bfirst);
bfirst = b;
}
/* wake up readers/writers */
wakeup(&q->wr);
.
652d
611a
q->noblock = 0;
.
## diffname port/qio.c 1994/0929
## diff -e /n/fornaxdump/1994/0927/sys/src/brazil/port/qio.c /n/fornaxdump/1994/0929/sys/src/brazil/port/qio.c
574c
.
549c
.
547c
.
534c
.
## diffname port/qio.c 1994/1026
## diff -e /n/fornaxdump/1994/0929/sys/src/brazil/port/qio.c /n/fornaxdump/1994/1026/sys/src/brazil/port/qio.c
421a
poperror();
.
420d
417a
syncwait = 1; USED(syncwait);
.
386a
if(q->syncbuf == 0){
/* we got some data before the interrupt, queue it */
b = allocb(q->synclen);
memmove(b->wp, vp, q->synclen);
b->wp += q->synclen;
if(q->bfirst == 0)
q->blast = b;
q->bfirst = b;
q->len += q->synclen;
}
.
384c
if(syncwait){
.
381a
syncwait = 0;
.
378c
int n, dowakeup, syncwait;
.
## diffname port/qio.c 1994/1103
## diff -e /n/fornaxdump/1994/1026/sys/src/brazil/port/qio.c /n/fornaxdump/1994/1103/sys/src/brazil/port/qio.c
392a
b->next = q->bfirst;
.
## diffname port/qio.c 1994/1116
## diff -e /n/fornaxdump/1994/1103/sys/src/brazil/port/qio.c /n/fornaxdump/1994/1116/sys/src/brazil/port/qio.c
469a
if(q->bfirst == 0)
q->blast = b;
.
463a
.
431a
poperror();
.
430c
if(waserror()){
/* sync with qwrite() & qproduce() */
qlock(&q->wlock);
ilock(q);
if(q->syncbuf == 0){
/* we got some data before the interrupt */
b = allocb(q->synclen);
memmove(b->wp, vp, q->synclen);
b->wp += q->synclen;
b->next = q->bfirst;
if(q->bfirst == 0)
q->blast = b;
q->bfirst = b;
q->len += q->synclen;
}
q->syncbuf = 0;
iunlock(q);
qunlock(&q->wlock);
nexterror();
}
.
384,402d
382d
378c
int n, dowakeup;
.
303a
q->state |= Qflow;
.
296a
q->state |= Qflow;
.
## diffname port/qio.c 1994/1117
## diff -e /n/fornaxdump/1994/1116/sys/src/brazil/port/qio.c /n/fornaxdump/1994/1117/sys/src/brazil/port/qio.c
329d
325,327c
if(dowakeup)
.
307c
return 0;
.
305d
260d
256,258c
if(dowakeup)
.
## diffname port/qio.c 1994/1124
## diff -e /n/fornaxdump/1994/1117/sys/src/brazil/port/qio.c /n/fornaxdump/1994/1124/sys/src/brazil/port/qio.c
740a
}
int
qstate(Queue *q)
{
return q->state;
.
608a
* used by print() to write to a queue
*/
int
qiwrite(Queue *q, void *vp, int len)
{
int n, sofar, dowakeup;
Block *b;
uchar *p = vp;
dowakeup = 0;
sofar = 0;
do {
n = len-sofar;
if(n > 128*1024)
n = 128*1024;
b = allocb(n);
memmove(b->wp, p+sofar, n);
b->wp += n;
ilock(q);
QDEBUG checkb(b, "qiwrite");
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;
freeb(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;
}
}
iunlock(q);
if(dowakeup){
if(q->kick)
(*q->kick)(q->arg);
wakeup(&q->rr);
}
sofar += n;
} while(sofar < len && (q->state & Qmsg) == 0);
return len;
}
/*
.
181c
n = BLEN(b);
if(n > 0)
break;
q->bfirst = b->next;
freeb(b);
};
.
173,179c
for(;;) {
b = q->bfirst;
if(b == 0){
q->state |= Qstarve;
unlock(q);
return -1;
}
QDEBUG checkb(b, "qconsume 1");
.
## diffname port/qio.c 1995/0101
## diff -e /n/fornaxdump/1994/1124/sys/src/brazil/port/qio.c /n/fornaxdump/1995/0101/sys/src/brazil/port/qio.c
111a
/*
* drivers which perform non cache coherent DMA manage their
* own buffer pools, so they provide their own free routines.
*/
if(b->free) {
b->free(b);
return;
}
.
## diffname port/qio.c 1995/0104
## diff -e /n/fornaxdump/1995/0101/sys/src/brazil/port/qio.c /n/fornaxdump/1995/0104/sys/src/brazil/port/qio.c
522a
if((getstatus()&IE) == 0)
print("qwrite hi %lux\n", getcallerpc(q));
.
## diffname port/qio.c 1995/0108
## diff -e /n/fornaxdump/1995/0104/sys/src/brazil/port/qio.c /n/fornaxdump/1995/0108/sys/src/brazil/port/qio.c
523,524c
if((getstatus()&IE) == 0)
print("qwrite hi %lux\n", getcallerpc(q));
.
114c
* own buffer pool and provide their own free routine.
.
## diffname port/qio.c 1995/0125
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/port/qio.c /n/fornaxdump/1995/0125/sys/src/brazil/port/qio.c
488c
/* wakeup flow controlled writers (with a bit of histeria) */
.
113,114c
* drivers which perform non cache coherent DMA manage their own buffer
* pool of uncached buffers and provide their own free routine.
.
84c
iprint("iallocb: limited %d/%d\n", ialloc.bytes, conf.ialloc);
.
27c
Block* bfirst; /* buffer */
.
## diffname port/qio.c 1995/0714
## diff -e /n/fornaxdump/1995/0125/sys/src/brazil/port/qio.c /n/fornaxdump/1995/0714/sys/src/brazil/port/qio.c
669,672c
if(q->state & Qstarve){
q->state &= ~Qstarve;
dowakeup = 1;
.
651,667c
if(q->bfirst)
q->blast->next = b;
else
q->bfirst = b;
q->blast = b;
q->len += n;
.
627c
* used by print() to write to a queue. Since we may be splhi or not in
* a process, don't qlock.
.
621,622d
577,617d
564,575c
qbwrite(q, b);
.
561a
poperror();
.
550a
ilock(q);
if(q->state & Qclosed){
iunlock(q);
error(Ehungup);
}
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;
}
iunlock(q);
if(dowakeup){
if(q->kick)
(*q->kick)(q->arg);
wakeup(&q->rr);
}
qunlock(&q->wlock);
poperror();
return n;
}
/*
* write to a queue. only 128k at a time is atomic.
*/
long
qwrite(Queue *q, void *vp, int len)
{
int n, sofar;
Block *b;
uchar *p = vp;
QDEBUG if((getstatus()&IE) == 0)
print("qwrite hi %lux\n", getcallerpc(q));
sofar = 0;
.
548a
q->state |= Qflow;
sleep(&q->wr, qnotfull, q);
.
547c
return n;
.
532,544c
/* flow control */
while(!qnotfull(q)){
if(q->noblock){
freeb(b);
.
523,525d
521a
n = BLEN(b);
.
517,519c
int n, dowakeup;
.
515c
qbwrite(Queue *q, Block *b)
.
509,512c
* add a block to a queue obeying flow control
.
499a
/*
* read a queue. if no data is queued, post a Block
* and wait on its Rendez.
*/
long
qread(Queue *q, void *vp, int len)
{
Block *b;
b = qbread(q, len);
if(b == 0)
return 0;
len = BLEN(b);
memmove(vp, b->rp, len);
freeb(b);
return len;
}
.
497c
return nb;
.
488c
iunlock(q);
/* wakeup flow controlled writers */
.
473,485c
b->next = q->bfirst;
if(q->bfirst == 0)
q->blast = b;
q->bfirst = b;
q->len += n;
}
nb->wp = nb->rp + len;
.
467,471c
/* split block if its too big and this is not a message oriented queue */
nb = b;
if(n > len){
if((q->state&Qmsg) == 0){
n -= len;
b = allocb(n);
memmove(b->wp, nb->rp+len, n);
b->wp += n;
.
465d
452d
415,450c
q->state |= Qstarve; /* flag requesting producer to wake me */
iunlock(q);
sleep(&q->rr, notempty, q);
.
389d
387c
Block *b, *nb;
.
384,385c
Block*
qbread(Queue *q, int len)
.
381,382c
* get next block from a queue (up to a limit)
.
365,372d
288,306d
281c
int dowakeup;
.
234,252d
227c
int len, dowakeup;
.
44,46d
## diffname port/qio.c 1995/0902
## diff -e /n/fornaxdump/1995/0714/sys/src/brazil/port/qio.c /n/fornaxdump/1995/0902/sys/src/brazil/port/qio.c
162a
}
ulong bpadoverhead;
/*
* pad a block to the front
*/
Block*
bpad(Block *bp, int size)
{
int n;
Block *nbp;
if(bp->rp - bp->base > size)
return bp;
n = bp->wp - bp->rp;
bpadoverhead += n;
nbp = allocb(size+n);
nbp->rp += size;
nbp->wp = nbp->rp;
memmove(nbp->wp, bp->rp, n);
nbp->wp += n;
freeb(bp);
return nbp;
.
159,160c
n = b->lim - b->base - size;
b->rp += n & ~(BY2V-1);
b->wp = b->rp;
.
157a
b->lim = ((uchar*)b) + msize(b);
.
149,150c
n = sizeof(Block) + size + (BY2V-1);
b = mallocz(n, 0);
.
147a
int n;
.
141c
* allocate blocks (round data base address to 64 bit boundary).
* if mallocz gives us more than we asked for, leave room at the front
* for header.
.
## diffname port/qio.c 1995/0917
## diff -e /n/fornaxdump/1995/0902/sys/src/brazil/port/qio.c /n/fornaxdump/1995/0917/sys/src/brazil/port/qio.c
419a
ilock(q);
.
414a
iunlock(q);
.
## diffname port/qio.c 1995/1121
## diff -e /n/fornaxdump/1995/0917/sys/src/brazil/port/qio.c /n/fornaxdump/1995/1121/sys/src/brazil/port/qio.c
184,191c
n = bp->wp - bp->rp;
bpadoverhead += n;
nbp = allocb(size+n);
nbp->rp += size;
nbp->wp = nbp->rp;
memmove(nbp->wp, bp->rp, n);
nbp->wp += n;
freeb(bp);
} else {
size = -size;
if(bp->lim - bp->wp >= size)
return bp;
n = bp->wp - bp->rp;
bpadoverhead += n;
nbp = allocb(size+n);
memmove(nbp->wp, bp->rp, n);
nbp->wp += n;
freeb(bp);
}
.
181,182c
if(size >= 0){
if(bp->rp - bp->base >= size)
return bp;
.
176c
padblock(Block *bp, int size)
.
173c
* pad a block to the front (or the back if size is negative)
.
## diffname port/qio.c 1995/1217
## diff -e /n/fornaxdump/1995/1121/sys/src/brazil/port/qio.c /n/fornaxdump/1995/1217/sys/src/brazil/port/qio.c
775a
/*
* make sure the first block has at least n bytes
*/
Block*
pullupblock(Block *bp, int n)
{
int i;
Block *nbp;
/*
* this should almost always be true, the rest it
* just to avoid every caller checking.
*/
if(BLEN(bp) >= n)
return bp;
/*
* if not enough room in the first block,
* add another to the front of the list.
*/
if(bp->lim - bp->rp < n){
nbp = allocb(n);
nbp->next = bp;
bp = nbp;
}
/*
* copy bytes from the trailing blocks into the first
*/
n -= BLEN(bp);
while(nbp = bp->next){
i = BLEN(nbp);
if(i >= n) {
memmove(bp->wp, nbp->rp, n);
bp->wp += n;
nbp->rp += n;
return bp;
}
else {
memmove(bp->wp, nbp->rp, i);
bp->wp += i;
bp->next = nbp->next;
nbp->next = 0;
freeb(nbp);
n -= i;
}
}
freeb(bp);
return 0;
}
.
## diffname port/qio.c 1996/0305
## diff -e /n/fornaxdump/1995/1217/sys/src/brazil/port/qio.c /n/fornaxdump/1996/0305/sys/src/brazil/port/qio.c
519a
freeb(b);
.
## diffname port/qio.c 1996/0611
## diff -e /n/fornaxdump/1996/0305/sys/src/brazil/port/qio.c /n/fornaxdump/1996/0611/sys/src/brazil/port/qio.c
822a
if(n == 0)
return bp;
.
810c
if(i > n) {
.
## diffname port/qio.c 1996/0731
## diff -e /n/fornaxdump/1996/0611/sys/src/brazil/port/qio.c /n/fornaxdump/1996/0731/sys/src/brazil/port/qio.c
200c
padblockoverhead += n;
.
192a
nbp->rp -= size;
.
186c
padblockoverhead += n;
.
183a
}
.
182c
if(bp->rp - bp->base >= size){
bp->rp -= size;
.
170c
ulong padblockoverhead;
.
## diffname port/qio.c 1996/1225
## diff -e /n/fornaxdump/1996/0731/sys/src/brazil/port/qio.c /n/fornaxdump/1996/1225/sys/src/brazil/port/qio.c
592c
long
.
## diffname port/qio.c 1997/0327
## diff -e /n/fornaxdump/1996/1225/sys/src/brazil/port/qio.c /n/emeliedump/1997/0327/sys/src/brazil/port/qio.c
787,831c
return q->state;
.
781,785c
int
qstate(Queue *q)
.
778c
return q->state & Qflow;
.
776c
qfull(Queue *q)
.
765,769c
freeblist(bfirst);
.
755c
Block *bfirst;
.
679a
if(msg == 0 || *msg == 0)
strcpy(q->err, Ehungup);
else
strncpy(q->err, msg, ERRLEN-1);
.
675c
qhangup(Queue *q, char *msg)
.
659,663c
freeblist(bfirst);
.
651a
strcpy(q->err, Ehungup);
.
648a
if(q == nil)
return;
.
647c
Block *bfirst;
.
640a
* be extremely careful when calling this,
* as there is no reference accounting
*/
void
qfree(Queue *q)
{
qclose(q);
free(q);
}
/*
.
630c
q->kick(q->arg);
.
592c
int
.
562c
QDEBUG if(islo() == 0)
.
555c
int
.
543c
q->kick(q->arg);
.
531a
b->next = 0;
.
524c
error(q->err);
.
454c
q->kick(q->arg);
.
419a
QDEBUG checkb(b, "qbread 1");
.
417a
b->next = 0;
.
407c
error(q->err);
.
400a
}
.
399c
if(b){
QDEBUG checkb(b, "qbread 0");
.
348a
* copy from offset in the queue
*/
Block*
qcopy(Queue *q, int len, ulong offset)
{
int sofar;
int n;
Block *b, *nb;
uchar *p;
nb = allocb(len);
lock(q);
/* go to offset */
b = q->bfirst;
for(sofar = 0; ; sofar += n){
if(b == nil){
unlock(q);
return nb;
}
n = BLEN(b);
if(sofar + n > offset){
p = b->rp + offset - sofar;
n -= offset - sofar;
break;
}
b = b->next;
}
/* copy bytes from there */
for(sofar = 0; sofar < len;){
if(n > len - sofar)
n = len - sofar;
memmove(nb->wp, p, n);
qcopycnt += n;
sofar += n;
nb->wp += n;
b = b->next;
if(b == nil)
break;
n = BLEN(b);
p = b->rp;
}
unlock(q);
return nb;
}
/*
.
332a
/* b->next = 0; done by iallocb() */
.
326a
producecnt += len;
.
285d
282a
len = BLEN(b);
QDEBUG checkb(b, "qpass");
while(b->next){
b = b->next;
QDEBUG checkb(b, "qpass");
len += BLEN(b);
}
.
278c
/* add buffer to queue */
.
273d
264a
}
.
263c
if((q->state & Qmsg) || len == n){
b->next = 0;
.
243a
consumecnt += n;
.
209c
/* if writer flow controlled, restart */
if((q->state & Qflow) && q->len < q->limit/2){
q->state &= ~Qflow;
dowakeup = 1;
} else
dowakeup = 0;
unlock(q);
if(dowakeup)
wakeup(&q->wr);
.
202,207c
iunlock(q);
if(dowakeup)
wakeup(&q->wr);
return b;
}
/*
* throw away the next 'len' bytes in the queue
*/
void
qdiscard(Queue *q, int len)
{
Block *b;
int dowakeup, n, sofar;
lock(q);
for(sofar = 0; sofar < len; sofar += n){
b = q->bfirst;
if(b == nil)
break;
n = BLEN(b);
if(n <= len - sofar){
q->bfirst = b->next;
b->next = 0;
freeb(b);
} else {
n = len - sofar;
b->rp += n;
}
q->len -= n;
.
199,200c
/* if writer flow controlled, restart */
if((q->state & Qflow) && q->len < q->limit/2){
q->state &= ~Qflow;
dowakeup = 1;
} else
dowakeup = 0;
.
187,197c
b = q->bfirst;
if(b == 0){
q->state |= Qstarve;
iunlock(q);
return 0;
}
q->bfirst = b->next;
b->next = 0;
q->len -= BLEN(b);
.
181,185c
/* sync with qwrite */
ilock(q);
.
178,179c
int dowakeup;
Block *b;
.
176c
qget(Queue *q)
.
173c
* get next block from a queue, return null if nothing there
.
170,171d
137a
print("pad %lud, concat %lud, pullup %lud, copy %lud\n",
padblockcnt, concatblockcnt, pullupblockcnt, copyblockcnt);
print("consume %lud, produce %lud, qcopy %lud\n",
consumecnt, producecnt, qcopycnt);
.
133a
freeblist(Block *b)
{
Block *next;
for(; b != 0; b = next){
next = b->next;
b->next = 0;
freeb(b);
}
}
/*
* pad a block to the front (or the back if size is negative)
*/
Block*
padblock(Block *bp, int size)
{
int n;
Block *nbp;
if(size >= 0){
if(bp->rp - bp->base >= size){
bp->rp -= size;
return bp;
}
n = BLEN(bp);
padblockcnt += n;
nbp = allocb(size+n);
nbp->rp += size;
nbp->wp = nbp->rp;
memmove(nbp->wp, bp->rp, n);
nbp->wp += n;
freeb(bp);
nbp->rp -= size;
} else {
size = -size;
if(bp->lim - bp->wp >= size)
return bp;
n = BLEN(bp);
padblockcnt += n;
nbp = allocb(size+n);
memmove(nbp->wp, bp->rp, n);
nbp->wp += n;
freeb(bp);
}
return nbp;
}
/*
* return count of bytes in a string of blocks
*/
int
blocklen(Block *bp)
{
int len;
len = 0;
while(bp) {
len += BLEN(bp);
bp = bp->next;
}
return len;
}
/*
* copy the string of blocks into
* a single block and free the string
*/
Block*
concatblock(Block *bp)
{
int len;
Block *nb, *f;
if(bp->next == 0)
return bp;
nb = allocb(blocklen(bp));
for(f = bp; f; f = f->next) {
len = BLEN(f);
memmove(nb->wp, f->rp, len);
nb->wp += len;
}
concatblockcnt += BLEN(nb);
freeblist(bp);
return nb;
}
/*
* make sure the first block has at least n bytes
*/
Block*
pullupblock(Block *bp, int n)
{
int i;
Block *nbp;
/*
* this should almost always be true, it's
* just to avoid every caller checking.
*/
if(BLEN(bp) >= n)
return bp;
/*
* if not enough room in the first block,
* add another to the front of the list.
*/
if(bp->lim - bp->rp < n){
nbp = allocb(n);
nbp->next = bp;
bp = nbp;
}
/*
* copy bytes from the trailing blocks into the first
*/
n -= BLEN(bp);
while(nbp = bp->next){
i = BLEN(nbp);
if(i > n) {
memmove(bp->wp, nbp->rp, n);
pullupblockcnt += n;
bp->wp += n;
nbp->rp += n;
return bp;
}
else {
memmove(bp->wp, nbp->rp, i);
pullupblockcnt += i;
bp->wp += i;
bp->next = nbp->next;
nbp->next = 0;
freeb(nbp);
n -= i;
if(n == 0)
return bp;
}
}
freeb(bp);
return 0;
}
/*
* trim to len bytes starting at offset
*/
Block *
trimblock(Block *bp, int offset, int len)
{
ulong l;
Block *nb, *startb;
if(blocklen(bp) < offset+len) {
freeblist(bp);
return nil;
}
while((l = BLEN(bp)) < offset) {
offset -= l;
nb = bp->next;
bp->next = nil;
freeb(bp);
bp = nb;
}
startb = bp;
bp->rp += offset;
while((l = BLEN(bp)) < len) {
len -= l;
bp = bp->next;
}
bp->wp -= (BLEN(bp) - len);
if(bp->next) {
freeblist(bp->next);
bp->next = nil;
}
return startb;
}
/*
* copy 'count' bytes into a new block
*/
Block*
copyblock(Block *bp, int count)
{
int l;
Block *nbp;
nbp = allocb(count);
for(; count > 0 && bp != 0; bp = bp->next){
l = BLEN(bp);
if(l > count)
l = count;
memmove(nbp->wp, bp->rp, l);
nbp->wp += l;
count -= l;
}
if(count > 0){
memset(nbp->wp, 0, count);
nbp->wp += count;
}
copyblockcnt += count;
return nbp;
}
/*
* throw away up to count bytes from a
* list of blocks. Return count of bytes
* thrown away.
*/
int
pullblock(Block **bph, int count)
{
Block *bp;
int n, bytes;
bytes = 0;
if(bph == nil)
return 0;
while(*bph != nil && count != 0) {
bp = *bph;
n = BLEN(bp);
if(count < n)
n = count;
bytes += n;
count -= n;
bp->rp += n;
if(BLEN(bp) == 0) {
*bph = bp->next;
bp->next = nil;
freeb(bp);
}
}
return bytes;
}
void
.
132a
/*
* free a list of blocks
*/
.
110c
* drivers which perform non cache coherent DMA manage their own buffer
.
67a
if(b->base == dead || b->lim == dead || b->next == dead
|| b->rp == dead || b->wp == dead){
print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
b->base, b->lim, b->next);
print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
panic("checkb dead: %s\n", msg);
}
.
57a
void *dead = (void*)0xDEADBABE;
if(b == dead)
panic("checkb b %s %lux", msg, b);
.
48c
/* Queue.state */
.
43a
char err[ERRLEN];
.
16c
#define QDEBUG if(0)
.
13a
static ulong padblockcnt;
static ulong concatblockcnt;
static ulong pullupblockcnt;
static ulong copyblockcnt;
static ulong consumecnt;
static ulong producecnt;
static ulong qcopycnt;
.
## diffname port/qio.c 1997/0404
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/port/qio.c /n/emeliedump/1997/0404/sys/src/brazil/port/qio.c
588a
if(q->len >= q->limit){
freeb(b);
iunlock(q);
return -1;
}
.
## diffname port/qio.c 1997/0410
## diff -e /n/emeliedump/1997/0404/sys/src/brazil/port/qio.c /n/emeliedump/1997/0410/sys/src/brazil/port/qio.c
718c
iunlock(q);
.
692c
iunlock(q);
.
686c
ilock(q);
.
665c
iunlock(q);
.
646c
iunlock(q);
.
639c
iunlock(q);
.
634c
ilock(q);
.
567c
iunlock(q);
.
539c
iunlock(q);
.
533c
ilock(q);
.
516c
iunlock(q);
.
492c
ilock(q);
.
## diffname port/qio.c 1997/0806
## diff -e /n/emeliedump/1997/0410/sys/src/brazil/port/qio.c /n/emeliedump/1997/0806/sys/src/brazil/port/qio.c
1045a
q->state &= ~(Qflow|Qstarve);
.
## diffname port/qio.c 1997/0925
## diff -e /n/emeliedump/1997/0806/sys/src/brazil/port/qio.c /n/emeliedump/1997/0925/sys/src/brazil/port/qio.c
403,443d
372a
Block*
adjustblock(Block* bp, int len)
{
int n;
if(len < 0){
freeb(bp);
return nil;
}
if(bp->rp+len > bp->lim)
return copyblock(bp, len);
n = BLEN(bp);
if(len > n)
memset(bp->wp, 0, len-n);
bp->wp = bp->rp+len;
return bp;
}
.
368c
copyblockcnt++;
.
292c
pullupblockcnt++;
.
285c
pullupblockcnt++;
.
202c
padblockcnt++;
.
187c
padblockcnt++;
.
118,119c
n = b->lim - b->base - size;
b->rp += n & ~(BY2V-1);
b->wp = b->rp;
.
116a
b->lim = ((uchar*)b) + msize(b);
.
110c
return nil;
.
107,108c
n = sizeof(Block) + size + (BY2V-1);
b = mallocz(n, 0);
if(b == nil){
.
102d
100a
int n;
.
93a
* allocate blocks (round data base address to 64 bit boundary).
* if mallocz gives us more than we asked for, leave room at the front
* for header.
*/
Block*
allocb(int size)
{
Block *b;
ulong addr;
int n;
n = sizeof(Block) + size + (BY2V-1);
b = mallocz(n+Hdrspc, 0);
if(b == 0)
exhausted("Blocks");
memset(b, 0, sizeof(Block));
addr = (ulong)b;
addr = ROUND(addr + sizeof(Block), BY2V);
b->base = (uchar*)addr;
b->lim = ((uchar*)b) + msize(b);
b->rp = b->base;
n = b->lim - b->base - size;
b->rp += n & ~(BY2V-1);
b->wp = b->rp;
return b;
}
/*
.
92a
void
ixsummary(void)
{
debuging ^= 1;
print("ialloc %d/%d %d\n", ialloc.bytes, conf.ialloc, debuging);
print("pad %lud, concat %lud, pullup %lud, copy %lud\n",
padblockcnt, concatblockcnt, pullupblockcnt, copyblockcnt);
print("consume %lud, produce %lud, qcopy %lud\n",
consumecnt, producecnt, qcopycnt);
}
.
62a
Hdrspc = 64, /* leave room for high-level headers */
.
## diffname port/qio.c 1997/0926
## diff -e /n/emeliedump/1997/0925/sys/src/brazil/port/qio.c /n/emeliedump/1997/0926/sys/src/brazil/port/qio.c
152c
b = mallocz(n+Hdrspc, 0);
.
## diffname port/qio.c 1997/1007
## diff -e /n/emeliedump/1997/0926/sys/src/brazil/port/qio.c /n/emeliedump/1997/1007/sys/src/brazil/port/qio.c
431,432c
if(bp->rp+len > bp->lim){
nbp = copyblock(bp, len);
freeblist(bp);
return nbp;
}
.
424a
Block *nbp;
.
## diffname port/qio.c 1997/1102
## diff -e /n/emeliedump/1997/1007/sys/src/brazil/port/qio.c /n/emeliedump/1997/1102/sys/src/brazil/port/qio.c
841c
/* split block if it's too big and this is not a message-oriented queue */
.
## diffname port/qio.c 1997/1104
## diff -e /n/emeliedump/1997/1102/sys/src/brazil/port/qio.c /n/emeliedump/1997/1104/sys/src/brazil/port/qio.c
891a
poot("Q 4", 0);
.
890a
poot("Q 3", 0);
.
885a
poot("Q 2", 0);
.
884a
poot("Q 1", 0);
.
872a
poot("QB end", nb);
.
842a
poot("QB 2", len);
.
826a
poot("QB 1", len);
.
824a
poot("QB after sleep", len);
.
823a
poot("QB before sleep", len);
.
795a
poot("QB start", len);
.
150a
if(size < 0)
panic("iallocb < 0");
.
117a
if(size < 0)
panic("allocb < 0");
.
24c
#define QDEBUG if(1)
.
## diffname port/qio.c 1997/1105
## diff -e /n/emeliedump/1997/1104/sys/src/brazil/port/qio.c /n/emeliedump/1997/1105/sys/src/brazil/port/qio.c
905d
903d
897d
895d
882d
851d
834d
831d
829d
800d
153,154d
118,119d
24c
#define QDEBUG if(0)
.
## diffname port/qio.c 1998/0328
## diff -e /n/emeliedump/1997/1105/sys/src/brazil/port/qio.c /n/emeliedump/1998/0328/sys/src/brazil/port/qio.c
1126a
iunlock(q);
.
1122a
ilock(q);
.
932,939d
928a
iunlock(q);
.
927a
.
922a
iunlock(q);
.
921c
for(;;){
ilock(q);
if(q->state & Qclosed){
iunlock(q);
freeb(b);
error(q->err);
}
if(q->len < q->limit)
break;
.
918d
913a
qlock(&q->wlock);
.
774a
iunlock(q);
.
768a
ilock(q);
.
## diffname port/qio.c 1998/0605
## diff -e /n/emeliedump/1998/0328/sys/src/brazil/port/qio.c /n/emeliedump/1998/0605/sys/src/brazil/port/qio.c
954a
QDEBUG checkb(b, "qbwrite");
.
734a
QDEBUG checkb(b, "qcopy");
.
530a
QDEBUG checkb(b, "qdiscard");
.
500a
QDEBUG checkb(b, "qget");
.
470a
QDEBUG checkb(bp, "pullblock ");
.
442a
QDEBUG checkb(bp, "adjustblock 2");
.
434a
QDEBUG checkb(nbp, "adjustblock 1");
.
416a
QDEBUG checkb(nbp, "copyblock 1");
.
402a
QDEBUG checkb(bp, "copyblock 0");
.
362a
QDEBUG checkb(bp, "trimblock 1");
.
347a
}
.
346c
if(n == 0){
QDEBUG checkb(bp, "pullupblock 2");
.
335a
QDEBUG checkb(bp, "pullupblock 1");
.
295a
QDEBUG checkb(nb, "concatblock 1");
.
255a
QDEBUG checkb(nbp, "padblock 1");
.
248a
if(bp->next)
panic("padblock 0x%uX", getcallerpc(bp));
.
233a
if(bp->next)
panic("padblock 0x%uX", getcallerpc(bp));
.
227a
QDEBUG checkb(bp, "padblock 1");
.
195,199c
b->next = dead;
b->rp = dead;
b->wp = dead;
b->lim = dead;
b->base = dead;
.
179a
void *dead = (void*)Bdead;
.
98,99c
debugging ^= 1;
print("ialloc %d/%d %d\n", ialloc.bytes, conf.ialloc, debugging);
.
86,92d
73a
if(b->base == dead || b->lim == dead || b->next == dead
|| b->rp == dead || b->wp == dead){
print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
b->base, b->lim, b->next);
print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
panic("checkb dead: %s\n", msg);
}
.
70c
void *dead = (void*)Bdead;
.
64a
Bdead = 0x51494F42, /* "QIOB" */
.
22c
static int debugging;
.
## diffname port/qio.c 1998/0703
## diff -e /n/emeliedump/1998/0605/sys/src/brazil/port/qio.c /n/emeliedump/1998/0703/sys/src/brazil/port/qio.c
798a
q->noblock = 0;
.
## diffname port/qio.c 1998/0825
## diff -e /n/emeliedump/1998/0703/sys/src/brazil/port/qio.c /n/emeliedump/1998/0825/sys/src/brazil/port/qio.c
101c
print("ialloc %lud/%lud %d\n", ialloc.bytes, conf.ialloc, debugging);
.
## diffname port/qio.c 1998/0918
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/port/qio.c /n/emeliedump/1998/0918/sys/src/brazil/port/qio.c
1170c
int len;
Block *b;
len = 0;
for(b = q->bfirst; b; b= b->next)
len += BLEN(b);
return len;
.
1072a
checkqlen(q);
.
1066c
q->len += BALLOC(b);
.
985a
checkqlen(q);
.
978c
q->len += BALLOC(b);
.
887a
checkqlen(q);
.
883c
q->len += BALLOC(b);
.
857c
q->len -= BALLOC(b);
.
720a
checkqlen(q);
.
714c
q->len += BALLOC(b);
.
681a
qpassnolim(Queue *q, Block *b)
{
int len, dowakeup;
/* sync with qread */
dowakeup = 0;
ilock(q);
/* add buffer to queue */
if(q->bfirst)
q->blast->next = b;
else
q->bfirst = b;
len = BALLOC(b);
QDEBUG checkb(b, "qpass");
while(b->next){
b = b->next;
QDEBUG checkb(b, "qpass");
len += BALLOC(b);
}
q->blast = b;
q->len += len;
if(q->len >= q->limit/2)
q->state |= Qflow;
if(q->state & Qstarve){
q->state &= ~Qstarve;
dowakeup = 1;
}
checkqlen(q);
iunlock(q);
if(dowakeup)
wakeup(&q->rr);
return len;
}
/*
* if the allocated space is way out of line with the used
* space, reallocate to a smaller block
*/
Block*
packblock(Block *bp)
{
int len, alen;
Block *nbp;
len = alen = 0;
for(nbp = bp; nbp; nbp = bp->next){
len += BLEN(bp);
alen += BALLOC(bp);
}
if(alen >= (len<<2)){
nbp = allocb(len);
nbp->next = bp;
return pullupblock(nbp, len);
}
return bp;
}
int
.
672a
checkqlen(q);
.
661c
len += BALLOC(b);
.
656c
len = BALLOC(b);
.
646c
freeblist(b);
.
631a
q->len -= BALLOC(b);
.
614d
603a
q->len -= BALLOC(b);
.
562d
556a
q->len -= BALLOC(b);
.
520c
q->len -= BALLOC(b);
.
97a
checkqlen(Queue *q)
{
int len;
Block *b;
len = 0;
for(b = q->bfirst; b; b = b->next)
len += BALLOC(b);
if(len != q->len)
panic("checkqlen");
}
void
.
## diffname port/qio.c 1998/0922
## diff -e /n/emeliedump/1998/0918/sys/src/brazil/port/qio.c /n/emeliedump/1998/0922/sys/src/brazil/port/qio.c
1316a
q->dlen = 0;
.
1254,1260c
return q->dlen;
.
1149a
q->dlen += n;
.
1060a
q->dlen += n;
.
1021d
964a
q->dlen += n;
.
937a
q->dlen -= n;
.
794a
q->dlen += BLEN(b);
.
718a
q->dlen += dlen;
.
715a
dlen += BLEN(b);
.
710a
dlen = BLEN(b);
.
699c
int dlen, len, dowakeup;
.
678a
q->dlen += dlen;
.
675a
dlen += BLEN(b);
.
670a
dlen = BLEN(b);
.
654c
int dlen, len, dowakeup;
.
645a
q->dlen -= BLEN(b);
.
627a
q->dlen -= len;
.
574a
q->dlen -= n;
.
570a
q->dlen -= BLEN(b);
.
533a
q->dlen -= BLEN(b);
.
38c
int len; /* bytes allocated to queue */
int dlen; /* data bytes in queue */
.
## diffname port/qio.c 1998/0923
## diff -e /n/emeliedump/1998/0922/sys/src/brazil/port/qio.c /n/emeliedump/1998/0923/sys/src/brazil/port/qio.c
1172d
1083d
984d
814d
764,769d
758,761c
for(l = &bp; *l; l = &(*l)->next){
nbp = *l;
n = BLEN(nbp);
if((n<<2) < BALLOC(nbp)){
*l = allocb(n);
memmove((*l)->wp, nbp->rp, n);
(*l)->wp += n;
(*l)->next = nbp->next;
freeb(nbp);
}
.
755,756c
Block **l, *nbp;
int n;
.
739d
696d
99,111d
## diffname port/qio.c 1998/0929
## diff -e /n/emeliedump/1998/0923/sys/src/brazil/port/qio.c /n/emeliedump/1998/0929/sys/src/brazil/port/qio.c
1198a
q->dlen = 0;
.
## diffname port/qio.c 1998/1127
## diff -e /n/emeliedump/1998/0929/sys/src/brazil/port/qio.c /n/emeliedump/1998/1127/sys/src/brazil/port/qio.c
1229a
}
/*
* return non-zero if the q is hungup
*/
int
qisclosed(Queue *q)
{
return q->state & Qclosed;
.
157c
print("iallocb: no memory %d/%d\n",
ialloc.bytes, conf.ialloc);
.
150c
print("iallocb: limited %d/%d\n",
ialloc.bytes, conf.ialloc);
.
## diffname port/qio.c 1998/1128
## diff -e /n/emeliedump/1998/1127/sys/src/brazil/port/qio.c /n/emeliedump/1998/1128/sys/src/brazil/port/qio.c
158c
print("iallocb: no memory %lud/%lud\n",
.
150c
print("iallocb: limited %lud/%lud\n",
.
## diffname port/qio.c 1999/0115
## diff -e /n/emeliedump/1998/1128/sys/src/brazil/port/qio.c /n/emeliedump/1999/0115/sys/src/brazil/port/qio.c
968a
/* if writer flow controlled, restart */
if((q->state & Qflow) && q->len < q->limit/2){
q->state &= ~Qflow;
dowakeup = 1;
} else
dowakeup = 0;
.
941,947d
800a
if(q->len >= q->limit)
q->state |= Qflow;
.
635,642c
if(tofree != nil)
freeblist(tofree);
.
622a
/* discard the block if we're done with it */
if((q->state & Qmsg) || len == n){
b->next = 0;
q->len -= BALLOC(b);
q->dlen -= BLEN(b);
/* remember to free this */
b->next = tofree;
tofree = b;
}
.
611c
/* remember to free this */
b->next = tofree;
tofree = b;
.
592a
Block *tofree = nil;
.
## diffname port/qio.c 1999/0219
## diff -e /n/emeliedump/1999/0115/sys/src/brazil/port/qio.c /n/emeliedump/1999/0219/sys/src/brazil/port/qio.c
1146,1147c
if(n > Maxatomic)
n = Maxatomic;
.
1110,1111c
if(n > Maxatomic)
n = Maxatomic;
.
1095c
* write to a queue. only Maxatomic bytes at a time is atomic.
.
67a
Maxatomic = 32*1024,
.
## diffname port/qio.c 1999/0311
## diff -e /n/emeliedump/1999/0219/sys/src/brazil/port/qio.c /n/emeliedump/1999/0311/sys/src/brazil/port/qio.c
261,262d
257a
if(bp->next)
panic("padblock 0x%uX", getcallerpc(bp));
.
## diffname port/qio.c 1999/0501
## diff -e /n/emeliedump/1999/0311/sys/src/brazil/port/qio.c /n/emeliedump/1999/0501/sys/src/brazil/port/qio.c
1108c
print("qwrite hi %lux\n", getcallerpc(&q));
.
259c
panic("padblock 0x%uX", getcallerpc(&bp));
.
245c
panic("padblock 0x%uX", getcallerpc(&bp));
.
## diffname port/qio.c 1999/0522
## diff -e /n/emeliedump/1999/0501/sys/src/brazil/port/qio.c /n/emeliedump/1999/0522/sys/src/brazil/port/qio.c
133,135c
addr = (ulong)(b->lim);
addr = addr & ~(BLOCKALIGN-1);
b->lim = (uchar*)addr;
/* leave sluff at beginning for added headers */
b->rp = b->lim - ROUND(size, BLOCKALIGN);
if(b->rp < b->base)
panic("allocb");
.
131a
/* align end of data portion by rounding down */
.
130c
addr = ROUND(addr + sizeof(Block), BLOCKALIGN);
.
128a
/* align start of data portion by rounding up */
.
123c
n = sizeof(Block) + size;
.
## diffname port/qio.c 1999/0527
## diff -e /n/emeliedump/1999/0522/sys/src/brazil/port/qio.c /n/emeliedump/1999/0527/sys/src/brazil/port/qio.c
109,218d
104c
iallocsummary();
.
73,100d
65,68d
8,13d
## diffname port/qio.c 1999/0603
## diff -e /n/emeliedump/1999/0527/sys/src/brazil/port/qio.c /n/emeliedump/1999/0603/sys/src/brazil/port/qio.c
976a
tagwithpc(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]);
.
## diffname port/qio.c 1999/0714
## diff -e /n/emeliedump/1999/0603/sys/src/brazil/port/qio.c /n/emeliedump/1999/0714/sys/src/brazil/port/qio.c
977c
setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]);
.
## diffname port/qio.c 2000/0913
## diff -e /n/emeliedump/1999/0714/sys/src/brazil/port/qio.c /n/emeliedump/2000/0913/sys/src/9/port/qio.c
937a
b = nil;
.
909d
898a
if(b != nil)
freeb(b);
.
## diffname port/qio.c 2000/0914
## diff -e /n/emeliedump/2000/0913/sys/src/9/port/qio.c /n/emeliedump/2000/0914/sys/src/9/port/qio.c
952a
/*
* flow control, wait for queue to get below the limit
* before allowing the process to continue and queue
* more. We do this here so that postnote can only
* interrupt us after the data has been quued. This
* means that things like 9p flushes and ssl messages
* will not be disrupted by software interrupts.
*
* Note - this is moderately dangerous since a process
* that keeps getting interrupted and rewriting will
* queue infinite crud.
*/
for(;;){
if(q->noblock || qnotfull(q))
break;
ilock(q);
q->state |= Qflow;
iunlock(q);
sleep(&q->wr, qnotfull, q);
}
USED(b);
.
945d
940a
/* make sure other end gets awakened */
.
929a
/* queue the block */
.
924,927d
914,916c
/* if nonblocking, don't queue over the limit */
if(q->len >= q->limit){
.
909,912c
/* give up if the queue is closed */
if(q->state & Qclosed){
iunlock(q);
error(q->err);
}
.
905,907c
ilock(q);
.
## diffname port/qio.c 2001/0127
## diff -e /n/emeliedump/2000/0914/sys/src/9/port/qio.c /n/emeliedump/2001/0127/sys/src/9/port/qio.c
873,876c
if((q->state & Qcoalesce) == 0){
b = qbread(q, len);
if(b == 0)
return 0;
m = BLEN(b);
memmove(p, b->rp, m);
freeb(b);
return m;
}
for(e = p + len; p < e; p += m){
b = qbread(q, e-p);
if(b == 0)
return 0;
m = BLEN(b);
memmove(p, b->rp, m);
freeb(b);
}
return p-(uchar*)vp;
.
869,871c
p = vp;
.
867a
int m;
uchar *p;
uchar *e;
.
752c
q->state = 0;
if(msg > 0)
q->state |= Qmsg;
else if(msg < 0)
q->state |= Qcoalesce;
.
57a
Qcoalesce = (1<<4), /* coallesce packets on read */
.
## diffname port/qio.c 2001/0128
## diff -e /n/emeliedump/2001/0127/sys/src/9/port/qio.c /n/emeliedump/2001/0128/sys/src/9/port/qio.c
901c
/* take care of any left over partial block */
if(b != nil){
if(q->state & Qmsg)
freeb(b);
else
qputback(q, b);
}
/* restart producer */
qwakeup_iunlock(q);
poperror();
qunlock(&q->rlock);
return n;
.
899a
ilock(q);
.
897a
p += m;
n += m;
next = b->next;
b->next = nil;
.
896a
if(m > len-n){
m = len - n;
n = len;
memmove(p, b->rp, m);
b->rp += m;
break;
}
.
891,895c
/* copy to user space outside of the ilock */
iunlock(q);
n = 0;
for(b = first; b != nil; b = next){
.
886,888c
n = 0;
for(;;) {
*l = qremove(q);
l = &b->next;
n += m;
b = q->bfirst;
if(b == nil)
break;
m = BLEN(b);
if(n+m > len)
break;
}
} else {
first = qremove(q);
.
884a
/* if we get here, there's at least one block in the queue */
if(q->state & Qcoalesce){
/* when coalescing, 0 length blocks just go away */
if(q->dlen <= 0){
freeb(qremove(q));
goto again;
}
/* grab the first block plus as many
* following blocks as will completely
* fit in the read.
*/
l = &first;
b = q->bfirst;
.
880,883c
ilock(q);
again:
switch(qwait(q)){
case 0:
/* queue closed */
iunlock(q);
qunlock(&q->rlock);
poperror();
return 0;
case -1:
/* multiple reads on a closed queue */
iunlock(q);
error(q->err);
}
.
878c
qlock(&q->rlock);
if(waserror()){
qunlock(&q->rlock);
nexterror();
}
.
873,876c
Block *b, *first, *next, **l;
int m, n;
uchar *p = vp;
.
860a
/*
* get next block from a queue (up to a limit)
*/
Block*
qbread(Queue *q, int len)
{
Block *b, *nb;
int n;
qlock(&q->rlock);
if(waserror()){
qunlock(&q->rlock);
nexterror();
}
ilock(q);
switch(qwait(q)){
case 0:
/* queue closed */
iunlock(q);
qunlock(&q->rlock);
poperror();
return nil;
case -1:
/* multiple reads on a closed queue */
iunlock(q);
error(q->err);
}
/* if we get here, there's at least one block in the queue */
b = qremove(q);
n = BLEN(b);
/* split block if it's too big and this is not a message queue */
nb = b;
if(n > len){
if((q->state&Qmsg) == 0){
n -= len;
b = allocb(n);
memmove(b->wp, nb->rp+len, n);
b->wp += n;
qputback(q, b);
}
nb->wp = nb->rp + len;
}
/* restart producer */
qwakeup_iunlock(q);
.
859a
}
.
849,850c
}
.
844a
/*
* flow control, get producer going again
* called with q ilocked
*/
static void
qwakeup_iunlock(Queue *q)
{
int dowakeup = 0;
.
843a
b->next = q->bfirst;
if(q->bfirst == nil)
q->blast = b;
q->bfirst = b;
q->len += BALLOC(b);
q->dlen += BLEN(b);
}
.
823,842c
/*
* put a block back to the front of the queue
* called with q ilocked
*/
static void
qputback(Queue *q, Block *b)
{
if(q->state & (Qclosed|Qmsg)){
freeb(b);
return;
.
821c
QDEBUG checkb(b, "qremove");
return b;
}
.
817,819c
b->next = nil;
q->dlen -= BLEN(b);
.
815c
/*
* called with q ilocked
*/
static Block*
qremove(Queue *q)
{
Block *b;
b = q->bfirst;
if(b == nil)
return nil;
.
813a
return 1;
}
.
812a
ilock(q);
.
806c
return -1;
.
802,804d
792,794d
784,789d
781,782c
Block *b;
.
778,779c
static int
qwait(Queue *q)
.
776c
* wait for the queue to be non-empty or closed.
* called with q ilocked.
.
## diffname port/qio.c 2001/0203
## diff -e /n/emeliedump/2001/0128/sys/src/9/port/qio.c /n/emeliedump/2001/0203/sys/src/9/port/qio.c
1020c
return p-s;
.
1000d
994a
p += m;
.
991,993c
if(m > e - p){
m = e - p;
.
988c
p = s;
.
979c
if(p+m > e)
.
974c
p += m;
.
970d
968d
958c
b = q->bfirst;
if(BLEN(b) <= 0){
.
933a
s = p = vp;
e = s+len;
.
931,932c
int m;
uchar *s, *e, *p;
.
832,835d
790d
786,788c
if(q->bfirst != nil)
.
782,783d
## diffname port/qio.c 2001/0207
## diff -e /n/emeliedump/2001/0203/sys/src/9/port/qio.c /n/emeliedump/2001/0207/sys/src/9/port/qio.c
1083c
p = wakeup(&q->rr);
/* if we just wokeup a higher priority process, let it run */
if(p != nil && p->priority > up->priority)
sched();
.
1030a
Proc *p;
.
## diffname port/qio.c 2001/0306
## diff -e /n/emeliedump/2001/0207/sys/src/9/port/qio.c /n/emeliedump/2001/0306/sys/src/9/port/qio.c
445a
return sofar;
.
409c
int
.
## diffname port/qio.c 2001/0317
## diff -e /n/emeliedump/2001/0306/sys/src/9/port/qio.c /n/emeliedump/2001/0317/sys/src/9/port/qio.c
576a
if(q->state & Qclosed){
freeblist(b);
iunlock(q);
return BALLOC(b);
}
.
534a
if(q->state & Qclosed){
freeblist(b);
iunlock(q);
return BALLOC(b);
}
.
## diffname port/qio.c 2001/0504
## diff -e /n/emeliedump/2001/0317/sys/src/9/port/qio.c /n/emeliedump/2001/0504/sys/src/9/port/qio.c
1219c
return sofar;
.
1188c
b = iallocb(n);
if(b == nil)
break;
.
## diffname port/qio.c 2001/0527
## diff -e /n/emeliedump/2001/0504/sys/src/9/port/qio.c /n/emeliedump/2001/0527/sys/src/9/port/qio.c
1280c
strncpy(q->err, msg, ERRMAX-1);
.
48c
char err[ERRMAX];
.
## diffname port/qio.c 2001/0602
## diff -e /n/emeliedump/2001/0527/sys/src/9/port/qio.c /n/emeliedump/2001/0602/sys/src/9/port/qio.c
837c
void
.
817c
Block*
.
814a
* add a block to a queue
*/
void
qadd(Queue *q, Block *b)
{
/* queue the block */
if(q->bfirst)
q->blast->next = b;
else
q->bfirst = b;
q->blast = b;
b->next = 0;
q->len += BALLOC(b);
q->dlen += BLEN(b);
}
/*
.
235a
* make sure the first block has at least n bytes
*/
Block*
pullupqueue(Queue *q, int n)
{
Block *b;
if(BLEN(q->bfirst) >= n)
return q->bfirst;
q->bfirst = pullupblock(q->bfirst, n);
for(b = q->bfirst; b != nil && b->next != nil; b = b->next)
;
q->blast = b;
return q->bfirst;
}
/*
.
## diffname port/qio.c 2001/0619
## diff -e /n/emeliedump/2001/0602/sys/src/9/port/qio.c /n/emeliedump/2001/0619/sys/src/9/port/qio.c
1196,1198c
}
poperror();
.
1179,1194c
b = mem2bl(vp, len);
if(waserror()){
freeblist(b);
nexterror();
}
for(; b != nil; b = next){
next = b->next;
b->next = nil;
.
1176c
QDEBUG if(!islo())
.
1172,1174c
Block *b, *next;
.
1060c
return n;
.
1048a
n -= BLEN(b);
.
1029,1044c
b = bl2mem(vp, first, len);
.
1024a
n = BLEN(first);
.
1020c
if(n+m > len)
.
1014c
n += m;
.
1008a
n = 0;
.
972,974d
968,970c
Block *b, *first, **l;
int m, n;
.
867a
* copy the contents of a string of blocks into
* memory. emptied blocks are freed. return
* pointer to first unconsumed block.
*/
Block*
bl2mem(uchar *p, Block *b, int n)
{
int i;
Block *next;
for(; b != nil; b = next){
i = BLEN(b);
if(i > n){
memmove(p, b->rp, n);
b->rp += n;
return b;
}
memmove(p, b->rp, i);
n -= i;
p += i;
b->rp += i;
next = b->next;
freeb(b);
}
return nil;
}
/*
* copy the contents of memory into a string of blocks.
* return nil on error.
*/
Block*
mem2bl(uchar *p, int len)
{
int n;
Block *b, *first, **l;
first = nil;
l = &first;
if(waserror()){
freeblist(first);
nexterror();
}
do {
n = len;
if(n > Maxatomic)
n = Maxatomic;
*l = b = allocb(n);
setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]);
memmove(b->wp, p, n);
b->wp += n;
p += n;
len -= n;
l = &b->next;
} while(len > 0);
poperror();
return first;
}
/*
.
## diffname port/qio.c 2001/0624
## diff -e /n/emeliedump/2001/0619/sys/src/9/port/qio.c /n/emeliedump/2001/0624/sys/src/9/port/qio.c
1225c
freeblist(next);
.
1222a
next = nil;
.
## diffname port/qio.c 2001/0728
## diff -e /n/emeliedump/2001/0624/sys/src/9/port/qio.c /n/emeliedump/2001/0728/sys/src/9/port/qio.c
819a
if(*q->err && strcmp(q->err, Ehungup) != 0)
return -1;
.
## diffname port/qio.c 2001/0804
## diff -e /n/emeliedump/2001/0728/sys/src/9/port/qio.c /n/emeliedump/2001/0804/sys/src/9/port/qio.c
1190c
* interrupt us after the data has been queued. This
.
## diffname port/qio.c 2001/0805
## diff -e /n/emeliedump/2001/0804/sys/src/9/port/qio.c /n/emeliedump/2001/0805/sys/src/9/port/qio.c
1235,1236c
sofar += n;
} while(sofar < len && (q->state & Qmsg) == 0);
.
1225,1233c
sofar = 0;
do {
n = len-sofar;
if(n > Maxatomic)
n = Maxatomic;
b = allocb(n);
setmalloctag(b, (up->text[0]<<24)|(up->text[1]<<16)|(up->text[2]<<8)|up->text[3]);
if(waserror()){
freeb(b);
nexterror();
}
memmove(b->wp, p+sofar, n);
poperror();
b->wp += n;
.
1220c
int n, sofar;
Block *b;
uchar *p = vp;
.
## diffname port/qio.c 2001/0825
## diff -e /n/emeliedump/2001/0805/sys/src/9/port/qio.c /n/emeliedump/2001/0825/sys/src/9/port/qio.c
845,847d
843a
q->len += blockalloclen(b);
q->dlen += blocklen(b);
while(b->next)
b = b->next;
.
837c
qaddlist(Queue *q, Block *b)
.
834c
* add a block list to a queue
.
152a
* return count of space in blocks
*/
int
blockalloclen(Block *bp)
{
int len;
len = 0;
while(bp) {
len += BALLOC(bp);
bp = bp->next;
}
return len;
}
/*
.
## diffname port/qio.c 2001/0904
## diff -e /n/emeliedump/2001/0825/sys/src/9/port/qio.c /n/emeliedump/2001/0904/sys/src/9/port/qio.c
62a
uint qiomaxatomic = Maxatomic;
.
## diffname port/qio.c 2002/0114
## diff -e /n/emeliedump/2001/0904/sys/src/9/port/qio.c /n/emeliedump/2002/0114/sys/src/9/port/qio.c
122c
panic("padblock 0x%luX", getcallerpc(&bp));
.
108c
panic("padblock 0x%luX", getcallerpc(&bp));
.
## diffname port/qio.c 2002/0613
## diff -e /n/emeliedump/2002/0114/sys/src/9/port/qio.c /n/emeliedump/2002/0613/sys/src/9/port/qio.c
60c
Maxatomic = 64*1024,
.
## diffname port/qio.c 2002/0711
## diff -e /n/emeliedump/2002/0613/sys/src/9/port/qio.c /n/emeliedump/2002/0711/sys/src/9/port/qio.c
1196,1197d
1194a
/* get output going again */
if(q->kick && (dowakeup || (q->state&Qkick)))
q->kick(q->arg);
/* wakeup anyone consuming at the other end */
.
801,805c
q->state = msg;
.
53,59d
## diffname port/qio.c 2002/0712
## diff -e /n/emeliedump/2002/0711/sys/src/9/port/qio.c /n/emeliedump/2002/0712/sys/src/9/port/qio.c
1450a
print("nonblocking %d\n", onoff);
.
## diffname port/qio.c 2002/0713
## diff -e /n/emeliedump/2002/0712/sys/src/9/port/qio.c /n/emeliedump/2002/0713/sys/src/9/port/qio.c
1451d
1158a
noblockcnt += n;
.
1126a
ulong noblockcnt;
.
## diffname port/qio.c 2002/0714
## diff -e /n/emeliedump/2002/0713/sys/src/9/port/qio.c /n/emeliedump/2002/0714/sys/src/9/port/qio.c
463,464c
/*
* if writer flow controlled, restart
*
* This used to be
* q->len < q->limit/2
* but it slows down tcp too much for certain write sizes.
* I really don't understand it completely. It may be
* due to the queue draining so fast that the transmission
* stalls waiting for the app to produce more data. - presotto
*/
if((q->state & Qflow) && q->len < q->limit){
.
## diffname port/qio.c 2002/1011
## diff -e /n/emeliedump/2002/0714/sys/src/9/port/qio.c /n/emeliedump/2002/1011/sys/src/9/port/qio.c
531a
q->bfirst = b->next;
.
525,526d
486a
long
qblen(Queue *q)
{
Block *b;
int n;
Block *tofree = nil;
ilock(q);
for(;;) {
b = q->bfirst;
if(b == 0){
q->state |= Qstarve;
iunlock(q);
return -1;
}
QDEBUG checkb(b, "qblen 1");
n = BLEN(b);
if(n > 0)
break;
q->bfirst = b->next;
q->len -= BALLOC(b);
/* remember to free this */
b->next = tofree;
tofree = b;
};
iunlock(q);
if(tofree != nil)
freeblist(tofree);
return len;
}
.
411c
return nil;
.
408c
if(b == nil){
.
## diffname port/qio.c 2002/1012
## diff -e /n/emeliedump/2002/1011/sys/src/9/port/qio.c /n/emeliedump/2002/1012/sys/src/9/port/qio.c
486a
/*
* Return length that next qconsume will return
*/
.
## diffname port/qio.c 2002/1014
## diff -e /n/emeliedump/2002/1012/sys/src/9/port/qio.c /n/emeliedump/2002/1014/sys/src/9/port/qio.c
524a
#endif sape
.
486a
#ifdef sape
.
## diffname port/qio.c 2002/1015
## diff -e /n/emeliedump/2002/1014/sys/src/9/port/qio.c /n/emeliedump/2002/1015/sys/src/9/port/qio.c
526d
524c
return n;
.
487d
## diffname port/qio.c 2002/1113
## diff -e /n/emeliedump/2002/1015/sys/src/9/port/qio.c /n/emeliedump/2002/1113/sys/src/9/port/qio.c
488,526d
## diffname port/qio.c 2003/0220
## diff -e /n/emeliedump/2002/1113/sys/src/9/port/qio.c /n/emeliedump/2003/0220/sys/src/9/port/qio.c
1147a
if(q->bypass){
(*q->bypass)(q->arg, b);
return n;
}
dowakeup = 0;
.
1146d
811a
/* open a queue to be bypassed */
Queue*
qbypass(void (*bypass)(void*, Block*), void *arg)
{
Queue *q;
q = malloc(sizeof(Queue));
if(q == 0)
return 0;
q->limit = 0;
q->arg = arg;
q->bypass = bypass;
q->state = 0;
return q;
}
.
807d
798d
40a
void (*bypass)(void*, Block*); /* bypass queue altogether */
.
## diffname port/qio.c 2003/0304
## diff -e /n/emeliedump/2003/0220/sys/src/9/port/qio.c /n/emeliedump/2003/0304/sys/src/9/port/qio.c
228,229c
} else {
/* shouldn't happen but why crash if it does */
if(i < 0){
print("pullup negative length packet\n");
i = 0;
}
.
|