/* * 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); poperror(); qunlock(&q->rlock); return nb; }
/* * get next block from a queue (up to a limit) */ struct block *qbread(struct queue *q, int len) { ERRSTACK(1); struct block *b, *nb; int n; qlock(&q->rlock); if (waserror()) { qunlock(&q->rlock); nexterror(); } spin_lock_irqsave(&q->lock); if (!qwait(q)) { /* queue closed */ spin_unlock_irqsave(&q->lock); qunlock(&q->rlock); poperror(); return NULL; } /* 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) { PANIC_EXTRA(b); 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); poperror(); qunlock(&q->rlock); return nb; }
/* * 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, *first, **l; int m, n; qlock(&q->rlock); if(waserror()){ qunlock(&q->rlock); nexterror(); } 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); } /* 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 */ b = q->bfirst; if(BLEN(b) <= 0){ freeb(qremove(q)); goto again; } /* grab the first block plus as many * following blocks as will completely * fit in the read. */ n = 0; l = &first; m = BLEN(b); 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); n = BLEN(first); } /* copy to user space outside of the ilock */ iunlock(q); b = bl2mem(vp, first, 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 */ qwakeup_iunlock(q); poperror(); qunlock(&q->rlock); return n; }
/* * read a queue. if no data is queued, post a struct block * and wait on its Rendez. */ long qread(struct queue *q, void *vp, int len) { ERRSTACK(1); struct block *b, *first, **l; int m, n; qlock(&q->rlock); if (waserror()) { qunlock(&q->rlock); nexterror(); } spin_lock_irqsave(&q->lock); again: if (!qwait(q)) { /* queue closed */ spin_unlock_irqsave(&q->lock); qunlock(&q->rlock); poperror(); return 0; } /* if we get here, there's at least one block in the queue */ // TODO: Consider removing the Qcoalesce flag and force a coalescing // strategy by default. if (q->state & Qcoalesce) { /* when coalescing, 0 length blocks just go away */ b = q->bfirst; if (BLEN(b) <= 0) { freeb(qremove(q)); goto again; } /* grab the first block plus as many * following blocks as will completely * fit in the read. */ n = 0; l = &first; m = BLEN(b); for (;;) { *l = qremove(q); l = &b->next; n += m; b = q->bfirst; if (b == NULL) break; m = BLEN(b); if (n + m > len) break; } } else { first = qremove(q); n = BLEN(first); } /* copy to user space outside of the ilock */ spin_unlock_irqsave(&q->lock); b = bl2mem(vp, first, len); spin_lock_irqsave(&q->lock); /* take care of any left over partial block */ if (b != NULL) { n -= BLEN(b); if (q->state & Qmsg) freeb(b); else qputback(q, b); } /* restart producer */ qwakeup_iunlock(q); poperror(); qunlock(&q->rlock); return n; }