Rename frameAndProcessed to frameAndGate, add little helper type.
diff --git a/server.go b/server.go
index a8c4980..b56c64d 100644
--- a/server.go
+++ b/server.go
@@ -78,7 +78,7 @@
handler: h,
framer: NewFramer(c, c), // TODO: write to a (custom?) buffered writer that can alternate when it's in buffered mode.
streams: make(map[uint32]*stream),
- readFrameCh: make(chan frameAndProcessed),
+ readFrameCh: make(chan frameAndGate),
readFrameErrCh: make(chan error, 1), // must be buffered for 1
wantWriteFrameCh: make(chan frameWriteMsg, 8),
writeFrameCh: make(chan frameWriteMsg, 1), // may be 0 or 1, but more is useless. (max 1 in flight)
@@ -94,13 +94,14 @@
sc.serve()
}
-// frameAndProcessed coordinates the readFrames and serve goroutines, since
-// the Framer interface only permits the most recently-read Frame from being
-// accessed. The serve goroutine sends on processed to signal to the readFrames
-// goroutine that another frame may be read.
-type frameAndProcessed struct {
- f Frame
- processed chan struct{}
+// frameAndGates coordinates the readFrames and serve
+// goroutines. Because the Framer interface only permits the most
+// recently-read Frame from being accessed, the readFrames goroutine
+// blocks until it has a frame, passes it to serve, and then waits for
+// serve to be done with it before reading the next one.
+type frameAndGate struct {
+ f Frame
+ g gate
}
type serverConn struct {
@@ -110,8 +111,8 @@
handler http.Handler
framer *Framer
hpackDecoder *hpack.Decoder
- doneServing chan struct{} // closed when serverConn.serve ends
- readFrameCh chan frameAndProcessed // written by serverConn.readFrames
+ doneServing chan struct{} // closed when serverConn.serve ends
+ readFrameCh chan frameAndGate // written by serverConn.readFrames
readFrameErrCh chan error
wantWriteFrameCh chan frameWriteMsg // from handlers -> serve
writeFrameCh chan frameWriteMsg // from serve -> writeFrames
@@ -277,7 +278,7 @@
// readFrames is the loop that reads incoming frames.
// It's run on its own goroutine.
func (sc *serverConn) readFrames() {
- processed := make(chan struct{}, 1)
+ g := make(gate, 1)
for {
f, err := sc.framer.ReadFrame()
if err != nil {
@@ -285,8 +286,8 @@
close(sc.readFrameCh)
return
}
- sc.readFrameCh <- frameAndProcessed{f, processed}
- <-processed
+ sc.readFrameCh <- frameAndGate{f, g}
+ g.Wait()
}
}
@@ -362,7 +363,7 @@
case <-sc.wroteFrameCh:
sc.writingFrame = false
sc.scheduleFrameWrite()
- case fp, ok := <-sc.readFrameCh:
+ case fg, ok := <-sc.readFrameCh:
if !ok {
err := <-sc.readFrameErrCh
if err != io.EOF {
@@ -373,10 +374,10 @@
}
return
}
- f := fp.f
+ f := fg.f
sc.vlogf("got %v: %#v", f.Header(), f)
err := sc.processFrame(f)
- fp.processed <- struct{}{} // let readFrames proceed
+ fg.g.Done() // unblock the readFrames goroutine
switch ev := err.(type) {
case nil:
// nothing.