/* * For any block B_i in the queue, we know that the bsize for * that block is at least (f->length - B_i->col). * * If (f->length - B_0->col > f->max_width) then we can set B_0's * bsize to infinity (PP_MAX_BSIZE), update the csize of the head * token, and remove B_0 from the queue. The head token is ready to be * printed at this point (since its csize, bsize and fsize fields are * known). */ static void flush_wide_blocks(formatter_t *f) { pp_block_t *b; pp_open_token_t *tk, *head; while (!block_queue_is_empty(&f->block_queue)) { b = first_block(&f->block_queue); assert(b->col <= f->length); if (f->length - b->col <= f->max_width) break; /* * b has bsize > max_width: set its bsize to MAX * then remove it from the block queue */ tk = b->token; tk->bsize = PP_MAX_BSIZE; head = f->head_token; if (head != NULL) { // update csize and fsize of the head token head->csize = PP_MAX_BSIZE; if (head->fsize == 0) { head->fsize = PP_MAX_BSIZE; } } // print all queued tokens, until tk flush_tokens(f, tag_open(tk)); // tk becomes the head token assert(ptr_queue_first(&f->token_queue) == tag_open(tk)); f->head_token = tk; if (f->nclosed == f->queue_size) { f->nclosed --; } pop_first_block(&f->block_queue); f->queue_size --; } }
/* Helper and back-end for __qbread: extracts and returns a list of blocks * containing up to len bytes. It may contain less than len even if q has more * data. * * Returns a code interpreted by __qbread, and the returned blist in ret. */ static int __try_qbread(struct queue *q, size_t len, int qio_flags, struct block **real_ret, struct block *spare) { struct block *ret, *ret_last, *first; size_t blen; if (qio_flags & QIO_CAN_ERR_SLEEP) { if (!qwait_and_ilock(q, qio_flags)) { spin_unlock_irqsave(&q->lock); return QBR_FAIL; } /* we qwaited and still hold the lock, so the q is not empty */ first = q->bfirst; } else { spin_lock_irqsave(&q->lock); first = q->bfirst; if (!first) { spin_unlock_irqsave(&q->lock); return QBR_FAIL; } } blen = BLEN(first); if ((q->state & Qcoalesce) && (blen == 0)) { freeb(pop_first_block(q)); spin_unlock_irqsave(&q->lock); /* Need to retry to make sure we have a first block */ return QBR_AGAIN; } /* Qmsg is a bit weird. The old 9ns code seemed to yank the entire block, * regardless of len. We'll do the same, and just return the minimum: the * first block. I'd be happy to remove this. */ if (q->state & Qmsg) { ret = pop_first_block(q); goto out_ok; } /* Let's get at least something first - makes the code easier. This way, * we'll only ever split the block once. */ if (blen <= len) { ret = pop_first_block(q); len -= blen; } else { /* need to split the block. we won't actually take the first block out * of the queue - we're just extracting a little bit. */ if (!spare) { /* We have nothing and need a spare block. Retry! */ spin_unlock_irqsave(&q->lock); return QBR_SPARE; } copy_from_first_block(q, spare, len); ret = spare; goto out_ok; } /* At this point, we just grabbed the first block. We can try to grab some * more, up to len (if they want). */ if (qio_flags & QIO_JUST_ONE_BLOCK) goto out_ok; ret_last = ret; while (q->bfirst && (len > 0)) { blen = BLEN(q->bfirst); if ((q->state & Qcoalesce) && (blen == 0)) { /* remove the intermediate 0 blocks */ freeb(pop_first_block(q)); continue; } if (blen > len) { /* We could try to split the block, but that's a huge pain. For * instance, we might need to move the main body of b into an * extra_data of ret_last. lots of ways for that to fail, and lots * of cases to consider. Easier to just bail out. This is why I * did the first block above: we don't need to worry about this. */ break; } ret_last->next = pop_first_block(q); ret_last = ret_last->next; len -= blen; } out_ok: qwakeup_iunlock(q); *real_ret = ret; return QBR_OK; }