## 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<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<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<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<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<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<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<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<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; } .