kernel/qio: big cleanup of qio functions
remove bl2mem(), it is broken. a fault while copying to memory yields a partially freed block list. it can be simply replaced by readblist() and freeblist(), which we also use for qcopy() now. remove mem2bl(), and handle putting back remainer from a short read internally (splitblock()) avoiding the releasing and re- acquiering of the ilock. always attempt to free blocks outside of the ilock. have qaddlist() return the number of bytes enqueued, which avoids walking the block list twice.
This commit is contained in:
parent
23d217afb4
commit
a54d1cd95e
3 changed files with 135 additions and 259 deletions
|
@ -729,7 +729,7 @@ mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
|
||||||
if(nr > nreq)
|
if(nr > nreq)
|
||||||
nr = nreq;
|
nr = nreq;
|
||||||
if(type == Tread)
|
if(type == Tread)
|
||||||
r->b = bl2mem((uchar*)uba, r->b, nr);
|
nr = readblist(r->b, (uchar*)uba, nr, 0);
|
||||||
mntfree(r);
|
mntfree(r);
|
||||||
poperror();
|
poperror();
|
||||||
|
|
||||||
|
@ -1076,13 +1076,8 @@ doread(Mnt *m, int len)
|
||||||
|
|
||||||
while(qlen(m->q) < len){
|
while(qlen(m->q) < len){
|
||||||
b = devtab[m->c->type]->bread(m->c, m->msize, 0);
|
b = devtab[m->c->type]->bread(m->c, m->msize, 0);
|
||||||
if(b == nil)
|
if(b == nil || qaddlist(m->q, b) == 0)
|
||||||
return -1;
|
return -1;
|
||||||
if(blocklen(b) == 0){
|
|
||||||
freeblist(b);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
qaddlist(m->q, b);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ Block* allocb(int);
|
||||||
int anyhigher(void);
|
int anyhigher(void);
|
||||||
int anyready(void);
|
int anyready(void);
|
||||||
Image* attachimage(int, Chan*, uintptr, ulong);
|
Image* attachimage(int, Chan*, uintptr, ulong);
|
||||||
Block* bl2mem(uchar*, Block*, int);
|
|
||||||
int blocklen(Block*);
|
int blocklen(Block*);
|
||||||
void bootlinks(void);
|
void bootlinks(void);
|
||||||
void cachedel(Image*, uintptr);
|
void cachedel(Image*, uintptr);
|
||||||
|
@ -250,7 +249,7 @@ void putseg(Segment*);
|
||||||
void putstrn(char*, int);
|
void putstrn(char*, int);
|
||||||
void putswap(Page*);
|
void putswap(Page*);
|
||||||
ulong pwait(Waitmsg*);
|
ulong pwait(Waitmsg*);
|
||||||
void qaddlist(Queue*, Block*);
|
int qaddlist(Queue*, Block*);
|
||||||
Block* qbread(Queue*, int);
|
Block* qbread(Queue*, int);
|
||||||
long qbwrite(Queue*, Block*);
|
long qbwrite(Queue*, Block*);
|
||||||
Queue* qbypass(void (*)(void*, Block*), void*);
|
Queue* qbypass(void (*)(void*, Block*), void*);
|
||||||
|
|
|
@ -78,6 +78,9 @@ padblock(Block *bp, int size)
|
||||||
int n;
|
int n;
|
||||||
Block *nbp;
|
Block *nbp;
|
||||||
|
|
||||||
|
if(bp->next != nil)
|
||||||
|
panic("padblock %#p", getcallerpc(&bp));
|
||||||
|
|
||||||
QDEBUG checkb(bp, "padblock 1");
|
QDEBUG checkb(bp, "padblock 1");
|
||||||
if(size >= 0){
|
if(size >= 0){
|
||||||
if(bp->rp - bp->base >= size){
|
if(bp->rp - bp->base >= size){
|
||||||
|
@ -85,33 +88,25 @@ padblock(Block *bp, int size)
|
||||||
return bp;
|
return bp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bp->next != nil)
|
|
||||||
panic("padblock %#p", getcallerpc(&bp));
|
|
||||||
n = BLEN(bp);
|
n = BLEN(bp);
|
||||||
padblockcnt++;
|
|
||||||
nbp = allocb(size+n);
|
nbp = allocb(size+n);
|
||||||
nbp->rp += size;
|
nbp->rp += size;
|
||||||
nbp->wp = nbp->rp;
|
nbp->wp = nbp->rp;
|
||||||
memmove(nbp->wp, bp->rp, n);
|
memmove(nbp->wp, bp->rp, n);
|
||||||
nbp->wp += n;
|
nbp->wp += n;
|
||||||
freeb(bp);
|
|
||||||
nbp->rp -= size;
|
nbp->rp -= size;
|
||||||
} else {
|
} else {
|
||||||
size = -size;
|
size = -size;
|
||||||
|
|
||||||
if(bp->next != nil)
|
|
||||||
panic("padblock %#p", getcallerpc(&bp));
|
|
||||||
|
|
||||||
if(bp->lim - bp->wp >= size)
|
if(bp->lim - bp->wp >= size)
|
||||||
return bp;
|
return bp;
|
||||||
|
|
||||||
n = BLEN(bp);
|
n = BLEN(bp);
|
||||||
padblockcnt++;
|
|
||||||
nbp = allocb(size+n);
|
nbp = allocb(size+n);
|
||||||
memmove(nbp->wp, bp->rp, n);
|
memmove(nbp->wp, bp->rp, n);
|
||||||
nbp->wp += n;
|
nbp->wp += n;
|
||||||
freeb(bp);
|
|
||||||
}
|
}
|
||||||
|
freeb(bp);
|
||||||
|
padblockcnt++;
|
||||||
QDEBUG checkb(nbp, "padblock 1");
|
QDEBUG checkb(nbp, "padblock 1");
|
||||||
return nbp;
|
return nbp;
|
||||||
}
|
}
|
||||||
|
@ -155,20 +150,21 @@ blockalloclen(Block *bp)
|
||||||
Block*
|
Block*
|
||||||
concatblock(Block *bp)
|
concatblock(Block *bp)
|
||||||
{
|
{
|
||||||
|
Block *nb, *next;
|
||||||
int len;
|
int len;
|
||||||
Block *nb, *f;
|
|
||||||
|
|
||||||
if(bp->next == nil)
|
if(bp->next == nil)
|
||||||
return bp;
|
return bp;
|
||||||
|
|
||||||
nb = allocb(blocklen(bp));
|
nb = allocb(blocklen(bp));
|
||||||
for(f = bp; f != nil; f = f->next) {
|
for(; bp != nil; bp = next) {
|
||||||
len = BLEN(f);
|
next = bp->next;
|
||||||
memmove(nb->wp, f->rp, len);
|
len = BLEN(bp);
|
||||||
|
memmove(nb->wp, bp->rp, len);
|
||||||
nb->wp += len;
|
nb->wp += len;
|
||||||
|
freeb(bp);
|
||||||
}
|
}
|
||||||
concatblockcnt += BLEN(nb);
|
concatblockcnt += BLEN(nb);
|
||||||
freeblist(bp);
|
|
||||||
QDEBUG checkb(nb, "concatblock 1");
|
QDEBUG checkb(nb, "concatblock 1");
|
||||||
return nb;
|
return nb;
|
||||||
}
|
}
|
||||||
|
@ -179,8 +175,8 @@ concatblock(Block *bp)
|
||||||
Block*
|
Block*
|
||||||
pullupblock(Block *bp, int n)
|
pullupblock(Block *bp, int n)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Block *nbp;
|
Block *nbp;
|
||||||
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this should almost always be true, it's
|
* this should almost always be true, it's
|
||||||
|
@ -204,10 +200,10 @@ pullupblock(Block *bp, int n)
|
||||||
*/
|
*/
|
||||||
n -= BLEN(bp);
|
n -= BLEN(bp);
|
||||||
while((nbp = bp->next) != nil){
|
while((nbp = bp->next) != nil){
|
||||||
|
pullupblockcnt++;
|
||||||
i = BLEN(nbp);
|
i = BLEN(nbp);
|
||||||
if(i > n) {
|
if(i > n) {
|
||||||
memmove(bp->wp, nbp->rp, n);
|
memmove(bp->wp, nbp->rp, n);
|
||||||
pullupblockcnt++;
|
|
||||||
bp->wp += n;
|
bp->wp += n;
|
||||||
nbp->rp += n;
|
nbp->rp += n;
|
||||||
QDEBUG checkb(bp, "pullupblock 1");
|
QDEBUG checkb(bp, "pullupblock 1");
|
||||||
|
@ -220,7 +216,6 @@ pullupblock(Block *bp, int n)
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
memmove(bp->wp, nbp->rp, i);
|
memmove(bp->wp, nbp->rp, i);
|
||||||
pullupblockcnt++;
|
|
||||||
bp->wp += i;
|
bp->wp += i;
|
||||||
bp->next = nbp->next;
|
bp->next = nbp->next;
|
||||||
nbp->next = nil;
|
nbp->next = nil;
|
||||||
|
@ -403,11 +398,11 @@ qget(Queue *q)
|
||||||
iunlock(q);
|
iunlock(q);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
QDEBUG checkb(b, "qget");
|
||||||
q->bfirst = b->next;
|
q->bfirst = b->next;
|
||||||
b->next = nil;
|
b->next = nil;
|
||||||
q->len -= BALLOC(b);
|
q->len -= BALLOC(b);
|
||||||
q->dlen -= BLEN(b);
|
q->dlen -= BLEN(b);
|
||||||
QDEBUG checkb(b, "qget");
|
|
||||||
|
|
||||||
/* if writer flow controlled, restart */
|
/* if writer flow controlled, restart */
|
||||||
if((q->state & Qflow) && q->len < q->limit/2){
|
if((q->state & Qflow) && q->len < q->limit/2){
|
||||||
|
@ -430,7 +425,7 @@ qget(Queue *q)
|
||||||
int
|
int
|
||||||
qdiscard(Queue *q, int len)
|
qdiscard(Queue *q, int len)
|
||||||
{
|
{
|
||||||
Block *b;
|
Block *b, *tofree = nil;
|
||||||
int dowakeup, n, sofar;
|
int dowakeup, n, sofar;
|
||||||
|
|
||||||
ilock(q);
|
ilock(q);
|
||||||
|
@ -442,10 +437,12 @@ qdiscard(Queue *q, int len)
|
||||||
n = BLEN(b);
|
n = BLEN(b);
|
||||||
if(n <= len - sofar){
|
if(n <= len - sofar){
|
||||||
q->bfirst = b->next;
|
q->bfirst = b->next;
|
||||||
b->next = nil;
|
|
||||||
q->len -= BALLOC(b);
|
q->len -= BALLOC(b);
|
||||||
q->dlen -= BLEN(b);
|
q->dlen -= BLEN(b);
|
||||||
freeb(b);
|
|
||||||
|
/* remember to free this */
|
||||||
|
b->next = tofree;
|
||||||
|
tofree = b;
|
||||||
} else {
|
} else {
|
||||||
n = len - sofar;
|
n = len - sofar;
|
||||||
b->rp += n;
|
b->rp += n;
|
||||||
|
@ -474,6 +471,9 @@ qdiscard(Queue *q, int len)
|
||||||
if(dowakeup)
|
if(dowakeup)
|
||||||
wakeup(&q->wr);
|
wakeup(&q->wr);
|
||||||
|
|
||||||
|
if(tofree != nil)
|
||||||
|
freeblist(tofree);
|
||||||
|
|
||||||
return sofar;
|
return sofar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,10 +483,9 @@ qdiscard(Queue *q, int len)
|
||||||
int
|
int
|
||||||
qconsume(Queue *q, void *vp, int len)
|
qconsume(Queue *q, void *vp, int len)
|
||||||
{
|
{
|
||||||
Block *b;
|
Block *b, *tofree = nil;
|
||||||
int n, dowakeup;
|
int n, dowakeup;
|
||||||
uchar *p = vp;
|
uchar *p = vp;
|
||||||
Block *tofree = nil;
|
|
||||||
|
|
||||||
/* sync with qwrite */
|
/* sync with qwrite */
|
||||||
ilock(q);
|
ilock(q);
|
||||||
|
@ -495,8 +494,8 @@ qconsume(Queue *q, void *vp, int len)
|
||||||
b = q->bfirst;
|
b = q->bfirst;
|
||||||
if(b == nil){
|
if(b == nil){
|
||||||
q->state |= Qstarve;
|
q->state |= Qstarve;
|
||||||
iunlock(q);
|
len = -1;
|
||||||
return -1;
|
goto out;
|
||||||
}
|
}
|
||||||
QDEBUG checkb(b, "qconsume 1");
|
QDEBUG checkb(b, "qconsume 1");
|
||||||
|
|
||||||
|
@ -511,17 +510,16 @@ qconsume(Queue *q, void *vp, int len)
|
||||||
tofree = b;
|
tofree = b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
consumecnt += n;
|
||||||
if(n < len)
|
if(n < len)
|
||||||
len = n;
|
len = n;
|
||||||
memmove(p, b->rp, len);
|
memmove(p, b->rp, len);
|
||||||
consumecnt += n;
|
|
||||||
b->rp += len;
|
b->rp += len;
|
||||||
q->dlen -= len;
|
q->dlen -= len;
|
||||||
|
|
||||||
/* discard the block if we're done with it */
|
/* discard the block if we're done with it */
|
||||||
if((q->state & Qmsg) || len == n){
|
if((q->state & Qmsg) || len == n){
|
||||||
q->bfirst = b->next;
|
q->bfirst = b->next;
|
||||||
b->next = nil;
|
|
||||||
q->len -= BALLOC(b);
|
q->len -= BALLOC(b);
|
||||||
q->dlen -= BLEN(b);
|
q->dlen -= BLEN(b);
|
||||||
|
|
||||||
|
@ -530,6 +528,7 @@ qconsume(Queue *q, void *vp, int len)
|
||||||
tofree = b;
|
tofree = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
/* if writer flow controlled, restart */
|
/* if writer flow controlled, restart */
|
||||||
if((q->state & Qflow) && q->len < q->limit/2){
|
if((q->state & Qflow) && q->len < q->limit/2){
|
||||||
q->state &= ~Qflow;
|
q->state &= ~Qflow;
|
||||||
|
@ -551,40 +550,23 @@ qconsume(Queue *q, void *vp, int len)
|
||||||
int
|
int
|
||||||
qpass(Queue *q, Block *b)
|
qpass(Queue *q, Block *b)
|
||||||
{
|
{
|
||||||
int dlen, len, dowakeup;
|
int len, dowakeup;
|
||||||
|
|
||||||
/* sync with qread */
|
/* sync with qread */
|
||||||
dowakeup = 0;
|
dowakeup = 0;
|
||||||
ilock(q);
|
ilock(q);
|
||||||
if(q->len >= q->limit){
|
if(q->len >= q->limit){
|
||||||
freeblist(b);
|
|
||||||
iunlock(q);
|
iunlock(q);
|
||||||
|
freeblist(b);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(q->state & Qclosed){
|
if(q->state & Qclosed){
|
||||||
len = BALLOC(b);
|
|
||||||
freeblist(b);
|
|
||||||
iunlock(q);
|
iunlock(q);
|
||||||
return len;
|
freeblist(b);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add buffer to queue */
|
len = qaddlist(q, b);
|
||||||
if(q->bfirst != nil)
|
|
||||||
q->blast->next = b;
|
|
||||||
else
|
|
||||||
q->bfirst = b;
|
|
||||||
len = BALLOC(b);
|
|
||||||
dlen = BLEN(b);
|
|
||||||
QDEBUG checkb(b, "qpass");
|
|
||||||
while(b->next != nil){
|
|
||||||
b = b->next;
|
|
||||||
QDEBUG checkb(b, "qpass");
|
|
||||||
len += BALLOC(b);
|
|
||||||
dlen += BLEN(b);
|
|
||||||
}
|
|
||||||
q->blast = b;
|
|
||||||
q->len += len;
|
|
||||||
q->dlen += dlen;
|
|
||||||
|
|
||||||
if(q->len >= q->limit/2)
|
if(q->len >= q->limit/2)
|
||||||
q->state |= Qflow;
|
q->state |= Qflow;
|
||||||
|
@ -604,35 +586,19 @@ qpass(Queue *q, Block *b)
|
||||||
int
|
int
|
||||||
qpassnolim(Queue *q, Block *b)
|
qpassnolim(Queue *q, Block *b)
|
||||||
{
|
{
|
||||||
int dlen, len, dowakeup;
|
int len, dowakeup;
|
||||||
|
|
||||||
/* sync with qread */
|
/* sync with qread */
|
||||||
dowakeup = 0;
|
dowakeup = 0;
|
||||||
ilock(q);
|
ilock(q);
|
||||||
|
|
||||||
if(q->state & Qclosed){
|
if(q->state & Qclosed){
|
||||||
freeblist(b);
|
|
||||||
iunlock(q);
|
iunlock(q);
|
||||||
return BALLOC(b);
|
freeblist(b);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add buffer to queue */
|
len = qaddlist(q, b);
|
||||||
if(q->bfirst != nil)
|
|
||||||
q->blast->next = b;
|
|
||||||
else
|
|
||||||
q->bfirst = b;
|
|
||||||
len = BALLOC(b);
|
|
||||||
dlen = BLEN(b);
|
|
||||||
QDEBUG checkb(b, "qpass");
|
|
||||||
while(b->next != nil){
|
|
||||||
b = b->next;
|
|
||||||
QDEBUG checkb(b, "qpass");
|
|
||||||
len += BALLOC(b);
|
|
||||||
dlen += BLEN(b);
|
|
||||||
}
|
|
||||||
q->blast = b;
|
|
||||||
q->len += len;
|
|
||||||
q->dlen += dlen;
|
|
||||||
|
|
||||||
if(q->len >= q->limit/2)
|
if(q->len >= q->limit/2)
|
||||||
q->state |= Qflow;
|
q->state |= Qflow;
|
||||||
|
@ -680,6 +646,10 @@ qproduce(Queue *q, void *vp, int len)
|
||||||
int dowakeup;
|
int dowakeup;
|
||||||
uchar *p = vp;
|
uchar *p = vp;
|
||||||
|
|
||||||
|
b = iallocb(len);
|
||||||
|
if(b == nil)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* sync with qread */
|
/* sync with qread */
|
||||||
dowakeup = 0;
|
dowakeup = 0;
|
||||||
ilock(q);
|
ilock(q);
|
||||||
|
@ -690,25 +660,12 @@ qproduce(Queue *q, void *vp, int len)
|
||||||
iunlock(q);
|
iunlock(q);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
producecnt += len;
|
||||||
|
|
||||||
/* save in buffer */
|
/* save in buffer */
|
||||||
b = iallocb(len);
|
|
||||||
if(b == nil){
|
|
||||||
iunlock(q);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memmove(b->wp, p, len);
|
memmove(b->wp, p, len);
|
||||||
producecnt += len;
|
|
||||||
b->wp += len;
|
b->wp += len;
|
||||||
if(q->bfirst != nil)
|
qaddlist(q, b);
|
||||||
q->blast->next = b;
|
|
||||||
else
|
|
||||||
q->bfirst = b;
|
|
||||||
q->blast = b;
|
|
||||||
/* b->next = 0; done by iallocb() */
|
|
||||||
q->len += BALLOC(b);
|
|
||||||
q->dlen += BLEN(b);
|
|
||||||
QDEBUG checkb(b, "qproduce");
|
|
||||||
|
|
||||||
if(q->state & Qstarve){
|
if(q->state & Qstarve){
|
||||||
q->state &= ~Qstarve;
|
q->state &= ~Qstarve;
|
||||||
|
@ -731,49 +688,13 @@ qproduce(Queue *q, void *vp, int len)
|
||||||
Block*
|
Block*
|
||||||
qcopy(Queue *q, int len, ulong offset)
|
qcopy(Queue *q, int len, ulong offset)
|
||||||
{
|
{
|
||||||
int sofar;
|
Block *b;
|
||||||
int n;
|
|
||||||
Block *b, *nb;
|
|
||||||
uchar *p;
|
|
||||||
|
|
||||||
nb = allocb(len);
|
|
||||||
|
|
||||||
|
b = allocb(len);
|
||||||
ilock(q);
|
ilock(q);
|
||||||
|
b->wp += readblist(q->bfirst, b->wp, len, offset);
|
||||||
/* go to offset */
|
|
||||||
b = q->bfirst;
|
|
||||||
for(sofar = 0; ; sofar += n){
|
|
||||||
if(b == nil){
|
|
||||||
iunlock(q);
|
|
||||||
return nb;
|
|
||||||
}
|
|
||||||
n = BLEN(b);
|
|
||||||
if(sofar + n > offset){
|
|
||||||
p = b->rp + offset - sofar;
|
|
||||||
n -= offset - sofar;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
QDEBUG checkb(b, "qcopy");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
iunlock(q);
|
iunlock(q);
|
||||||
|
return b;
|
||||||
return nb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -855,21 +776,34 @@ qwait(Queue *q)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add a block list to a queue
|
* add a block list to a queue, return bytes added
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
qaddlist(Queue *q, Block *b)
|
qaddlist(Queue *q, Block *b)
|
||||||
{
|
{
|
||||||
|
int len, dlen;
|
||||||
|
|
||||||
|
QDEBUG checkb(b, "qaddlist 1");
|
||||||
|
|
||||||
/* queue the block */
|
/* queue the block */
|
||||||
if(q->bfirst != nil)
|
if(q->bfirst != nil)
|
||||||
q->blast->next = b;
|
q->blast->next = b;
|
||||||
else
|
else
|
||||||
q->bfirst = b;
|
q->bfirst = b;
|
||||||
q->len += blockalloclen(b);
|
|
||||||
q->dlen += blocklen(b);
|
len = BALLOC(b);
|
||||||
while(b->next != nil)
|
dlen = BLEN(b);
|
||||||
|
while(b->next != nil){
|
||||||
b = b->next;
|
b = b->next;
|
||||||
|
QDEBUG checkb(b, "qaddlist 2");
|
||||||
|
|
||||||
|
len += BALLOC(b);
|
||||||
|
dlen += BLEN(b);
|
||||||
|
}
|
||||||
q->blast = b;
|
q->blast = b;
|
||||||
|
q->len += len;
|
||||||
|
q->dlen += dlen;
|
||||||
|
return dlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -883,11 +817,11 @@ qremove(Queue *q)
|
||||||
b = q->bfirst;
|
b = q->bfirst;
|
||||||
if(b == nil)
|
if(b == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
QDEBUG checkb(b, "qremove");
|
||||||
q->bfirst = b->next;
|
q->bfirst = b->next;
|
||||||
b->next = nil;
|
b->next = nil;
|
||||||
q->dlen -= BLEN(b);
|
q->dlen -= BLEN(b);
|
||||||
q->len -= BALLOC(b);
|
q->len -= BALLOC(b);
|
||||||
QDEBUG checkb(b, "qremove");
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,68 +855,6 @@ readblist(Block *b, uchar *p, long n, long o)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* put a block back to the front of the queue
|
* put a block back to the front of the queue
|
||||||
* called with q ilocked
|
* called with q ilocked
|
||||||
|
@ -998,6 +870,35 @@ qputback(Queue *q, Block *b)
|
||||||
q->dlen += BLEN(b);
|
q->dlen += BLEN(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cut off n bytes from the end of *h. return a new
|
||||||
|
* block with the tail and change *h to refer to the
|
||||||
|
* head.
|
||||||
|
*/
|
||||||
|
static Block*
|
||||||
|
splitblock(Block **h, int n)
|
||||||
|
{
|
||||||
|
Block *a, *b;
|
||||||
|
int m;
|
||||||
|
|
||||||
|
a = *h;
|
||||||
|
m = BLEN(a) - n;
|
||||||
|
if(m < n){
|
||||||
|
b = allocb(m);
|
||||||
|
memmove(b->wp, a->rp, m);
|
||||||
|
b->wp += m;
|
||||||
|
a->rp += m;
|
||||||
|
*h = b;
|
||||||
|
return a;
|
||||||
|
} else {
|
||||||
|
b = allocb(n);
|
||||||
|
a->wp -= n;
|
||||||
|
memmove(b->wp, a->wp, n);
|
||||||
|
b->wp += n;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* flow control, get producer going again
|
* flow control, get producer going again
|
||||||
* called with q ilocked
|
* called with q ilocked
|
||||||
|
@ -1029,7 +930,7 @@ qwakeup_iunlock(Queue *q)
|
||||||
Block*
|
Block*
|
||||||
qbread(Queue *q, int len)
|
qbread(Queue *q, int len)
|
||||||
{
|
{
|
||||||
Block *b, *nb;
|
Block *b;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
eqlock(&q->rlock);
|
eqlock(&q->rlock);
|
||||||
|
@ -1057,24 +958,21 @@ qbread(Queue *q, int len)
|
||||||
n = BLEN(b);
|
n = BLEN(b);
|
||||||
|
|
||||||
/* split block if it's too big and this is not a message queue */
|
/* split block if it's too big and this is not a message queue */
|
||||||
nb = b;
|
|
||||||
if(n > len){
|
if(n > len){
|
||||||
if((q->state&Qmsg) == 0){
|
n -= len;
|
||||||
n -= len;
|
if((q->state & Qmsg) == 0)
|
||||||
b = allocb(n);
|
qputback(q, splitblock(&b, n));
|
||||||
memmove(b->wp, nb->rp+len, n);
|
else
|
||||||
b->wp += n;
|
b->wp -= n;
|
||||||
qputback(q, b);
|
|
||||||
}
|
|
||||||
nb->wp = nb->rp + len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restart producer */
|
/* restart producer */
|
||||||
qwakeup_iunlock(q);
|
qwakeup_iunlock(q);
|
||||||
|
|
||||||
poperror();
|
|
||||||
qunlock(&q->rlock);
|
qunlock(&q->rlock);
|
||||||
return nb;
|
poperror();
|
||||||
|
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1084,7 +982,7 @@ qbread(Queue *q, int len)
|
||||||
long
|
long
|
||||||
qread(Queue *q, void *vp, int len)
|
qread(Queue *q, void *vp, int len)
|
||||||
{
|
{
|
||||||
Block *b, *first, **l;
|
Block *b, *first, **last;
|
||||||
int m, n;
|
int m, n;
|
||||||
|
|
||||||
eqlock(&q->rlock);
|
eqlock(&q->rlock);
|
||||||
|
@ -1109,6 +1007,7 @@ again:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we get here, there's at least one block in the queue */
|
/* if we get here, there's at least one block in the queue */
|
||||||
|
last = &first;
|
||||||
if(q->state & Qcoalesce){
|
if(q->state & Qcoalesce){
|
||||||
/* when coalescing, 0 length blocks just go away */
|
/* when coalescing, 0 length blocks just go away */
|
||||||
b = q->bfirst;
|
b = q->bfirst;
|
||||||
|
@ -1123,13 +1022,13 @@ again:
|
||||||
* fit in the read.
|
* fit in the read.
|
||||||
*/
|
*/
|
||||||
n = 0;
|
n = 0;
|
||||||
l = &first;
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
*l = qremove(q);
|
*last = qremove(q);
|
||||||
l = &b->next;
|
|
||||||
n += m;
|
n += m;
|
||||||
if(n >= len || (b = q->bfirst) == nil)
|
if(n >= len || q->bfirst == nil)
|
||||||
break;
|
break;
|
||||||
|
last = &b->next;
|
||||||
|
b = q->bfirst;
|
||||||
m = BLEN(b);
|
m = BLEN(b);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1137,25 +1036,24 @@ again:
|
||||||
n = BLEN(first);
|
n = BLEN(first);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy to user space outside of the ilock */
|
/* split last block if it's too big and this is not a message queue */
|
||||||
iunlock(q);
|
if(n > len && (q->state & Qmsg) == 0)
|
||||||
b = bl2mem(vp, first, len);
|
qputback(q, splitblock(last, n - len));
|
||||||
ilock(q);
|
|
||||||
|
|
||||||
/* take care of any left over partial block */
|
|
||||||
if(b != nil){
|
|
||||||
n -= BLEN(b);
|
|
||||||
if(q->state & Qmsg)
|
|
||||||
freeb(b);
|
|
||||||
else
|
|
||||||
qputback(q, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restart producer */
|
/* restart producer */
|
||||||
qwakeup_iunlock(q);
|
qwakeup_iunlock(q);
|
||||||
|
|
||||||
poperror();
|
|
||||||
qunlock(&q->rlock);
|
qunlock(&q->rlock);
|
||||||
|
poperror();
|
||||||
|
|
||||||
|
if(waserror()){
|
||||||
|
freeblist(first);
|
||||||
|
nexterror();
|
||||||
|
}
|
||||||
|
n = readblist(first, vp, len, 0);
|
||||||
|
freeblist(first);
|
||||||
|
poperror();
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,19 +1096,18 @@ qflow(Queue *q)
|
||||||
long
|
long
|
||||||
qbwrite(Queue *q, Block *b)
|
qbwrite(Queue *q, Block *b)
|
||||||
{
|
{
|
||||||
int n, dowakeup;
|
int len, dowakeup;
|
||||||
Proc *p;
|
Proc *p;
|
||||||
|
|
||||||
n = BLEN(b);
|
|
||||||
|
|
||||||
if(q->bypass != nil){
|
if(q->bypass != nil){
|
||||||
|
len = blocklen(b);
|
||||||
(*q->bypass)(q->arg, b);
|
(*q->bypass)(q->arg, b);
|
||||||
return n;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
dowakeup = 0;
|
dowakeup = 0;
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
freeb(b);
|
freeblist(b);
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
ilock(q);
|
ilock(q);
|
||||||
|
@ -1224,21 +1121,13 @@ qbwrite(Queue *q, Block *b)
|
||||||
/* don't queue over the limit */
|
/* don't queue over the limit */
|
||||||
if(q->len >= q->limit && q->noblock){
|
if(q->len >= q->limit && q->noblock){
|
||||||
iunlock(q);
|
iunlock(q);
|
||||||
freeb(b);
|
|
||||||
poperror();
|
poperror();
|
||||||
return n;
|
len = blocklen(b);
|
||||||
|
freeblist(b);
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* queue the block */
|
len = qaddlist(q, b);
|
||||||
if(q->bfirst != nil)
|
|
||||||
q->blast->next = b;
|
|
||||||
else
|
|
||||||
q->bfirst = b;
|
|
||||||
q->blast = b;
|
|
||||||
b->next = nil;
|
|
||||||
q->len += BALLOC(b);
|
|
||||||
q->dlen += n;
|
|
||||||
QDEBUG checkb(b, "qbwrite");
|
|
||||||
|
|
||||||
/* make sure other end gets awakened */
|
/* make sure other end gets awakened */
|
||||||
if(q->state & Qstarve){
|
if(q->state & Qstarve){
|
||||||
|
@ -1270,7 +1159,7 @@ qbwrite(Queue *q, Block *b)
|
||||||
*/
|
*/
|
||||||
qflow(q);
|
qflow(q);
|
||||||
|
|
||||||
return n;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1359,14 +1248,7 @@ qiwrite(Queue *q, void *vp, int len)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDEBUG checkb(b, "qiwrite");
|
qaddlist(q, b);
|
||||||
if(q->bfirst != nil)
|
|
||||||
q->blast->next = b;
|
|
||||||
else
|
|
||||||
q->bfirst = b;
|
|
||||||
q->blast = b;
|
|
||||||
q->len += BALLOC(b);
|
|
||||||
q->dlen += n;
|
|
||||||
|
|
||||||
if(q->state & Qstarve){
|
if(q->state & Qstarve){
|
||||||
q->state &= ~Qstarve;
|
q->state &= ~Qstarve;
|
||||||
|
|
Loading…
Reference in a new issue