run should be run in a separate goroutine. It reads control frames from controlBuf and processes them by: 1. Updating loopy's internal state, or/and 2. Writing out HTTP2 frames on the wire. Loopy keeps all active streams with data to send in a linked-list. All streams in the activeStreams linked-li
()
| 584 | // flushes the underlying connection. The connection is always left open to |
| 585 | // allow different closing behavior on the client and server. |
| 586 | func (l *loopyWriter) run() (err error) { |
| 587 | defer func() { |
| 588 | if l.logger.V(logLevel) { |
| 589 | l.logger.Infof("loopyWriter exiting with error: %v", err) |
| 590 | } |
| 591 | if !isIOError(err) { |
| 592 | l.framer.writer.Flush() |
| 593 | } |
| 594 | l.cbuf.finish() |
| 595 | }() |
| 596 | for { |
| 597 | it, err := l.cbuf.get(true) |
| 598 | if err != nil { |
| 599 | return err |
| 600 | } |
| 601 | if err = l.handle(it); err != nil { |
| 602 | return err |
| 603 | } |
| 604 | if _, err = l.processData(); err != nil { |
| 605 | return err |
| 606 | } |
| 607 | gosched := true |
| 608 | hasdata: |
| 609 | for { |
| 610 | it, err := l.cbuf.get(false) |
| 611 | if err != nil { |
| 612 | return err |
| 613 | } |
| 614 | if it != nil { |
| 615 | if err = l.handle(it); err != nil { |
| 616 | return err |
| 617 | } |
| 618 | if _, err = l.processData(); err != nil { |
| 619 | return err |
| 620 | } |
| 621 | continue hasdata |
| 622 | } |
| 623 | isEmpty, err := l.processData() |
| 624 | if err != nil { |
| 625 | return err |
| 626 | } |
| 627 | if !isEmpty { |
| 628 | continue hasdata |
| 629 | } |
| 630 | if gosched { |
| 631 | gosched = false |
| 632 | if l.framer.writer.offset < minBatchSize { |
| 633 | runtime.Gosched() |
| 634 | continue hasdata |
| 635 | } |
| 636 | } |
| 637 | l.framer.writer.Flush() |
| 638 | break hasdata |
| 639 | } |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | func (l *loopyWriter) outgoingWindowUpdateHandler(w *outgoingWindowUpdate) error { |