/* * copy 'count' bytes into a new block */ struct block *copyblock(struct block *bp, int count) { int l; struct block *nbp; QDEBUG checkb(bp, "copyblock 0"); nbp = block_alloc(count, MEM_WAIT); if (bp->flag & BCKSUM_FLAGS) { nbp->flag |= (bp->flag & BCKSUM_FLAGS); nbp->checksum_start = bp->checksum_start; nbp->checksum_offset = bp->checksum_offset; nbp->mss = bp->mss; } PANIC_EXTRA(bp); 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++; QDEBUG checkb(nbp, "copyblock 1"); return nbp; }
/* * copy 'count' bytes into a new block */ Block* copyblock(Block *bp, int count) { int l; Block *nbp; QDEBUG checkb(bp, "copyblock 0"); 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++; QDEBUG checkb(nbp, "copyblock 1"); return nbp; }
Block* adjustblock(Block* bp, int len) { int n; Block *nbp; if(len < 0){ freeb(bp); return nil; } if(bp->rp+len > bp->lim){ nbp = copyblock(bp, len); freeblist(bp); QDEBUG checkb(nbp, "adjustblock 1"); return nbp; } n = BLEN(bp); if(len > n) memset(bp->wp, 0, len-n); bp->wp = bp->rp+len; QDEBUG checkb(bp, "adjustblock 2"); return bp; }
/* * 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++; bp->wp += n; nbp->rp += n; QDEBUG checkb(bp, "pullupblock 1"); return bp; } else { /* shouldn't happen but why crash if it does */ if(i < 0){ print("pullup negative length packet, called from %#p\n", getcallerpc(&bp)); i = 0; } memmove(bp->wp, nbp->rp, i); pullupblockcnt++; bp->wp += i; bp->next = nbp->next; nbp->next = 0; freeb(nbp); n -= i; if(n == 0){ QDEBUG checkb(bp, "pullupblock 2"); return bp; } } } freeb(bp); return 0; }
/* * pad a block to the front (or the back if size is negative) */ struct block *padblock(struct block *bp, int size) { int n; struct block *nbp; uint8_t bcksum = bp->flag & BCKSUM_FLAGS; uint16_t checksum_start = bp->checksum_start; uint16_t checksum_offset = bp->checksum_offset; uint16_t mss = bp->mss; QDEBUG checkb(bp, "padblock 1"); if (size >= 0) { if (bp->rp - bp->base >= size) { bp->checksum_start += size; bp->rp -= size; return bp; } PANIC_EXTRA(bp); if (bp->next) panic("padblock %p", getcallerpc(&bp)); n = BLEN(bp); padblockcnt++; nbp = block_alloc(size + n, MEM_WAIT); nbp->rp += size; nbp->wp = nbp->rp; memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); nbp->rp -= size; } else { size = -size; PANIC_EXTRA(bp); if (bp->next) panic("padblock %p", getcallerpc(&bp)); if (bp->lim - bp->wp >= size) return bp; n = BLEN(bp); padblockcnt++; nbp = block_alloc(size + n, MEM_WAIT); memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); } if (bcksum) { nbp->flag |= bcksum; nbp->checksum_start = checksum_start; nbp->checksum_offset = checksum_offset; nbp->mss = mss; } QDEBUG checkb(nbp, "padblock 1"); return nbp; }
int qpass(struct queue *q, struct block *b) { int dlen, len, dowakeup; /* sync with qread */ dowakeup = 0; spin_lock_irqsave(&q->lock); if (q->len >= q->limit) { freeblist(b); spin_unlock_irqsave(&q->lock); return -1; } if (q->state & Qclosed) { len = blocklen(b); freeblist(b); spin_unlock_irqsave(&q->lock); return len; } /* add buffer to queue */ if (q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); QDEBUG checkb(b, "qpass"); while (b->next) { 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) q->state |= Qflow; if (q->state & Qstarve) { q->state &= ~Qstarve; dowakeup = 1; } spin_unlock_irqsave(&q->lock); if (dowakeup) { rendez_wakeup(&q->rr); qwake_cb(q, FDTAP_FILT_READABLE); } return len; }
int qpass(Queue *q, Block *b) { int dlen, len, dowakeup; /* sync with qread */ dowakeup = 0; ilock(q); if(q->len >= q->limit){ freeblist(b); iunlock(q); return -1; } if(q->state & Qclosed){ len = BALLOC(b); freeblist(b); iunlock(q); return len; } /* add buffer to queue */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); QDEBUG checkb(b, "qpass"); while(b->next){ 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) q->state |= Qflow; if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } iunlock(q); if(dowakeup) wakeup(&q->rr); return len; }
long qibwrite(struct queue *q, struct block *b) { int n, dowakeup; dowakeup = 0; n = BLEN(b); spin_lock_irqsave(&q->lock); QDEBUG checkb(b, "qibwrite"); if (q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; q->len += BALLOC(b); q->dlen += n; if (q->state & Qstarve) { q->state &= ~Qstarve; dowakeup = 1; } spin_unlock_irqsave(&q->lock); if (dowakeup) { if (q->kick) q->kick(q->arg); rendez_wakeup(&q->rr); qwake_cb(q, FDTAP_FILT_READABLE); } return n; }
/* * trim to len bytes starting at offset */ struct block *trimblock(struct block *bp, int offset, int len) { uint32_t l, trim; int olen = len; QDEBUG checkb(bp, "trimblock 1"); if (blocklen(bp) < offset + len) { freeblist(bp); return NULL; } l =_pullblock(&bp, offset, 0); if (bp == NULL) return NULL; if (l != offset) { freeblist(bp); return NULL; } while ((l = BLEN(bp)) < len) { len -= l; bp = bp->next; } trim = BLEN(bp) - len; trim -= dropext(bp, trim); bp->wp -= trim; if (bp->next) { freeblist(bp->next); bp->next = NULL; } return bp; }
/* * 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; QDEBUG checkb(bp, "pullblock "); if(BLEN(bp) == 0) { *bph = bp->next; bp->next = nil; freeb(bp); } } return bytes; }
/* * throw away up to count bytes from a * list of blocks. Return count of bytes * thrown away. */ static int _pullblock(struct block **bph, int count, int free) { struct block *bp; int n, bytes; bytes = 0; if (bph == NULL) return 0; while (*bph != NULL && count != 0) { bp = *bph; n = MIN(BHLEN(bp), count); bytes += n; count -= n; bp->rp += n; n = pullext(bp, count); bytes += n; count -= n; QDEBUG checkb(bp, "pullblock "); if (BLEN(bp) == 0 && (free || count)) { *bph = bp->next; bp->next = NULL; freeb(bp); } } return bytes; }
/* * get next block from a queue, return null if nothing there */ Block* qget(Queue *q) { int dowakeup; Block *b; /* sync with qwrite */ ilock(q); b = q->bfirst; if(b == nil){ q->state |= Qstarve; iunlock(q); return nil; } q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); QDEBUG checkb(b, "qget"); /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit/2){ q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; iunlock(q); if(dowakeup) wakeup(&q->wr); return b; }
/* * used by print() to write to a queue. Since we may be splhi or not in * a process, don't qlock. * * this routine merges adjacent blocks if block n+1 will fit into * the free space of block n. */ 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 > Maxatomic) n = Maxatomic; b = iallocb(n); if(b == nil) break; memmove(b->wp, p+sofar, n); b->wp += n; ilock(q); /* we use an artificially high limit for kernel prints since anything * over the limit gets dropped */ if(q->dlen >= 16*1024){ iunlock(q); freeb(b); break; } QDEBUG checkb(b, "qiwrite"); if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; q->len += BALLOC(b); q->dlen += 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 sofar; }
int qproduce(Queue *q, void *vp, int len) { Block *b; int dowakeup; uchar *p = vp; /* sync with qread */ dowakeup = 0; lock(&q->l); if(q->state & Qclosed){ unlock(&q->l); return -1; } /* no waiting receivers, room in buffer? */ if(q->len >= q->limit){ q->state |= Qflow; unlock(&q->l); return -1; } /* save in buffer */ b = iallocb(len); if(b == 0){ unlock(&q->l); print("qproduce: iallocb failed\n"); return -1; } memmove(b->wp, p, len); b->wp += len; if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; /* b->next = 0; done by allocb() */ q->len += BALLOC(b); q->dlen += BLEN(b); QDEBUG checkb(b, "qproduce"); if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } if(q->len >= q->limit) q->state |= Qflow; unlock(&q->l); if(dowakeup) Wakeup(&q->rr); return len; }
/* * pad a block to the front (or the back if size is negative) */ Block* padblock(Block *bp, int size) { int n; Block *nbp; QDEBUG checkb(bp, "padblock 1"); if(size >= 0){ if(bp->rp - bp->base >= size){ bp->rp -= size; return bp; } if(bp->next) panic("padblock %#p", getcallerpc(&bp)); n = BLEN(bp); padblockcnt++; 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->next) panic("padblock %#p", getcallerpc(&bp)); if(bp->lim - bp->wp >= size) return bp; n = BLEN(bp); padblockcnt++; nbp = allocb(size+n); memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); } QDEBUG checkb(nbp, "padblock 1"); return nbp; }
/* * used by print() to write to a queue. Since we may be splhi or not in * a process, don't qlock. */ 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 > Maxatomic) n = Maxatomic; b = iallocb(n); if (b == 0) { print("qiwrite: iallocb failed\n"); break; } memmove(b->wp, p+sofar, n); b->wp += n; lock(&q->l); QDEBUG checkb(b, "qiwrite"); if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; q->len += BALLOC(b); q->dlen += n; if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } unlock(&q->l); if(dowakeup){ if(q->kick) q->kick(q->arg); Wakeup(&q->rr); } sofar += n; } while(sofar < len && (q->state & Qmsg) == 0); return sofar; }
/* * called with q ilocked */ struct block *qremove(struct queue *q) { struct block *b; b = q->bfirst; if (b == NULL) return NULL; q->bfirst = b->next; b->next = NULL; q->dlen -= BLEN(b); q->len -= BALLOC(b); QDEBUG checkb(b, "qremove"); return b; }
/* * throw away the next 'len' bytes in the queue */ int qdiscard(Queue *q, int len) { Block *b; int dowakeup, n, sofar; ilock(q); for(sofar = 0; sofar < len; sofar += n){ b = q->bfirst; if(b == nil) break; QDEBUG checkb(b, "qdiscard"); n = BLEN(b); if(n <= len - sofar){ q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); freeb(b); } else { n = len - sofar; b->rp += n; q->dlen -= n; } } /* * 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){ q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; iunlock(q); if(dowakeup) wakeup(&q->wr); return sofar; }
/* * called with q ilocked */ Block* qremove(Queue *q) { Block *b; b = q->bfirst; if(b == nil) return nil; q->bfirst = b->next; b->next = nil; q->dlen -= BLEN(b); q->len -= BALLOC(b); QDEBUG checkb(b, "qremove"); return b; }
/* * copy from offset in the queue */ struct block *qcopy_old(struct queue *q, int len, uint32_t offset) { int sofar; int n; struct block *b, *nb; uint8_t *p; nb = block_alloc(len, MEM_WAIT); spin_lock_irqsave(&q->lock); /* go to offset */ b = q->bfirst; for (sofar = 0;; sofar += n) { if (b == NULL) { spin_unlock_irqsave(&q->lock); 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; PANIC_EXTRA(b); memmove(nb->wp, p, n); qcopycnt += n; sofar += n; nb->wp += n; b = b->next; if (b == NULL) break; n = BLEN(b); p = b->rp; } spin_unlock_irqsave(&q->lock); return nb; }
/* * 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); ilock(q); /* 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); return nb; }
/* * 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); QDEBUG checkb(nb, "concatblock 1"); return nb; }
/* * copy the string of blocks into * a single block and free the string */ struct block *concatblock(struct block *bp) { int len; struct block *nb, *f; if (bp->next == 0) return bp; /* probably use parts of qclone */ PANIC_EXTRA(bp); nb = block_alloc(blocklen(bp), MEM_WAIT); for (f = bp; f; f = f->next) { len = BLEN(f); memmove(nb->wp, f->rp, len); nb->wp += len; } concatblockcnt += BLEN(nb); freeblist(bp); QDEBUG checkb(nb, "concatblock 1"); return nb; }
/* * throw away the next 'len' bytes in the queue */ int qdiscard(Queue *q, int len) { Block *b; int dowakeup, n, sofar; lock(&q->l); for(sofar = 0; sofar < len; sofar += n){ b = q->bfirst; if(b == nil) break; QDEBUG checkb(b, "qdiscard"); n = BLEN(b); if(n <= len - sofar){ q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); freeb(b); } else { n = len - sofar; b->rp += n; q->dlen -= n; } } /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit){ q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; unlock(&q->l); if(dowakeup) Wakeup(&q->wr); return sofar; }
/* * trim to len bytes starting at offset */ Block * trimblock(Block *bp, int offset, int len) { ulong l; Block *nb, *startb; QDEBUG checkb(bp, "trimblock 1"); 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; }
/* * get next block from a queue, return null if nothing there */ struct block *qget(struct queue *q) { int dowakeup; struct block *b; /* sync with qwrite */ spin_lock_irqsave(&q->lock); b = q->bfirst; if (b == NULL) { q->state |= Qstarve; spin_unlock_irqsave(&q->lock); return NULL; } q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); QDEBUG checkb(b, "qget"); /* if writer flow controlled, restart */ if ((q->state & Qflow) && q->len < q->limit / 2) { q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; spin_unlock_irqsave(&q->lock); if (dowakeup) { rendez_wakeup(&q->wr); /* We only send the writable event on wakeup, which is edge triggered */ qwake_cb(q, FDTAP_FILT_WRITABLE); } return b; }
main(){ int np, nts; int nrun; int seed; int k; int bd[NMAX]; int v; int sum = 0; double result; //input np, nts printf("To simulate the birthday problem\n"); printf("----------------------------------------\n"); printf("Enter the number of persons in a group:\t"); scanf("%d", &np); if (np > NMAX){ printf("np > NMAX = %d\n", NMAX); exit(1); } printf("Enter the number of trials:\t"); scanf("%d", &nts); //To get the seed for the random number seed = time(NULL); srand(seed); //main loop for (nrun = 1; nrun <= nts; nrun++){ for (k = 0; k < np; k++){ bd[k] = 365*(double)rand()/(double)RAND_MAX + 1; } checkb(np, bd, &v); sum += v; } result = (double)sum / (double)nts; printf("\nFor np = %d \t the probability = %f\n", np, result); system("pause"); }
/* Adds block (which can be a list of blocks) to the queue, subject to * qio_flags. Returns the length written on success or -1 on non-throwable * error. Adjust qio_flags to control the value-added features!. */ static ssize_t __qbwrite(struct queue *q, struct block *b, int qio_flags) { ssize_t ret; bool dowakeup = FALSE; bool was_empty; if (q->bypass) { ret = blocklen(b); (*q->bypass) (q->arg, b); return ret; } spin_lock_irqsave(&q->lock); was_empty = q->len == 0; if (q->state & Qclosed) { spin_unlock_irqsave(&q->lock); freeblist(b); if (!(qio_flags & QIO_CAN_ERR_SLEEP)) return -1; if (q->err[0]) error(EFAIL, q->err); else error(EFAIL, "connection closed"); } if ((qio_flags & QIO_LIMIT) && (q->len >= q->limit)) { /* drop overflow takes priority over regular non-blocking */ if ((qio_flags & QIO_DROP_OVERFLOW) || (q->state & Qdropoverflow)) { spin_unlock_irqsave(&q->lock); freeb(b); return -1; } /* People shouldn't set NON_BLOCK without CAN_ERR, but we can be nice * and catch it. */ if ((qio_flags & QIO_CAN_ERR_SLEEP) && (qio_flags & QIO_NON_BLOCK)) { spin_unlock_irqsave(&q->lock); freeb(b); error(EAGAIN, "queue full"); } } ret = enqueue_blist(q, b); QDEBUG checkb(b, "__qbwrite"); /* make sure other end gets awakened */ if (q->state & Qstarve) { q->state &= ~Qstarve; dowakeup = TRUE; } spin_unlock_irqsave(&q->lock); /* TODO: not sure if the usage of a kick is mutually exclusive with a * wakeup, meaning that actual users either want a kick or have qreaders. */ if (q->kick && (dowakeup || (q->state & Qkick))) q->kick(q->arg); if (dowakeup) rendez_wakeup(&q->rr); if (was_empty) qwake_cb(q, FDTAP_FILT_READABLE); /* * 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 queued. 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. */ if ((qio_flags & QIO_CAN_ERR_SLEEP) && !(q->state & Qdropoverflow) && !(qio_flags & QIO_NON_BLOCK)) { /* This is a racy peek at the q status. If we accidentally block, we * set Qflow, so someone should wake us. If we accidentally don't * block, we just returned to the user and let them slip a block past * flow control. */ while (!qnotfull(q)) { spin_lock_irqsave(&q->lock); q->state |= Qflow; spin_unlock_irqsave(&q->lock); rendez_sleep(&q->wr, qnotfull, q); } } return ret; }
/* Adjust block @bp so that its size is exactly @len. * If the size is increased, fill in the new contents with zeros. * If the size is decreased, discard some of the old contents at the tail. */ struct block *adjustblock(struct block *bp, int len) { struct extra_bdata *ebd; void *buf; int i; if (len < 0) { freeb(bp); return NULL; } if (len == BLEN(bp)) return bp; /* Shrink within block main body. */ if (len <= BHLEN(bp)) { free_block_extra(bp); bp->wp = bp->rp + len; QDEBUG checkb(bp, "adjustblock 1"); return bp; } /* Need to grow. */ if (len > BLEN(bp)) { /* Grow within block main body. */ if (bp->extra_len == 0 && bp->rp + len <= bp->lim) { memset(bp->wp, 0, len - BLEN(bp)); bp->wp = bp->rp + len; QDEBUG checkb(bp, "adjustblock 2"); return bp; } /* Grow with extra data buffers. */ buf = kzmalloc(len - BLEN(bp), MEM_WAIT); block_append_extra(bp, (uintptr_t)buf, 0, len - BLEN(bp), MEM_WAIT); QDEBUG checkb(bp, "adjustblock 3"); return bp; } /* Shrink extra data buffers. * len is how much of ebd we need to keep. * extra_len is re-accumulated. */ assert(bp->extra_len > 0); len -= BHLEN(bp); bp->extra_len = 0; for (i = 0; i < bp->nr_extra_bufs; i++) { ebd = &bp->extra_data[i]; if (len <= ebd->len) break; len -= ebd->len; bp->extra_len += ebd->len; } /* If len becomes zero, extra_data[i] should be freed. */ if (len > 0) { ebd = &bp->extra_data[i]; ebd->len = len; bp->extra_len += ebd->len; i++; } for (; i < bp->nr_extra_bufs; i++) { ebd = &bp->extra_data[i]; if (ebd->base) kfree((void*)ebd->base); ebd->base = ebd->off = ebd->len = 0; } QDEBUG checkb(bp, "adjustblock 4"); return bp; }
/* * make sure the first block has at least n bytes in its main body */ struct block *pullupblock(struct block *bp, int n) { int i, len, seglen; struct block *nbp; struct extra_bdata *ebd; /* * this should almost always be true, it's * just to avoid every caller checking. */ if (BHLEN(bp) >= n) return bp; /* a start at explicit main-body / header management */ if (bp->extra_len) { if (n > bp->lim - bp->rp) { /* would need to realloc a new block and copy everything over. */ panic("can't pullup %d bytes, no place to put it: bp->lim %p, bp->rp %p, bp->lim-bp->rp %d\n", n, bp->lim, bp->rp, bp->lim-bp->rp); } len = n - BHLEN(bp); if (len > bp->extra_len) panic("pullup more than extra (%d, %d, %d)\n", n, BHLEN(bp), bp->extra_len); QDEBUG checkb(bp, "before pullup"); for (int i = 0; (i < bp->nr_extra_bufs) && len; i++) { ebd = &bp->extra_data[i]; if (!ebd->base || !ebd->len) continue; seglen = MIN(ebd->len, len); memcpy(bp->wp, (void*)(ebd->base + ebd->off), seglen); bp->wp += seglen; len -= seglen; ebd->len -= seglen; ebd->off += seglen; bp->extra_len -= seglen; if (ebd->len == 0) { kfree((void *)ebd->base); ebd->off = 0; ebd->base = 0; } } /* maybe just call pullupblock recursively here */ if (len) panic("pullup %d bytes overdrawn\n", len); QDEBUG checkb(bp, "after pullup"); 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 = block_alloc(n, MEM_WAIT); 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++; bp->wp += n; nbp->rp += n; QDEBUG checkb(bp, "pullupblock 1"); return bp; } else { memmove(bp->wp, nbp->rp, i); pullupblockcnt++; bp->wp += i; bp->next = nbp->next; nbp->next = 0; freeb(nbp); n -= i; if (n == 0) { QDEBUG checkb(bp, "pullupblock 2"); return bp; } } } freeb(bp); return 0; }