Skip to content

Commit 331a10c

Browse files
author
Chao Xu
committed
User time.AfterFunc to remove the need of explicitly managing goroutines
The race in golang/go#11513 does not affect time.AfterFunc, because the timer returned by time.AfterFunc() does not have the buffered channel at all.
1 parent b2e6f87 commit 331a10c

File tree

1 file changed

+15
-30
lines changed

1 file changed

+15
-30
lines changed

http2/transport.go

+15-30
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,12 @@ type Transport struct {
113113
// if response is not received within PingTimeout.
114114
// 0 means no periodic pings. Defaults to 0.
115115
PingPeriod time.Duration
116+
116117
// PingTimeout is the timeout after which the connection will be closed
117118
// if a response to Ping is not received.
118119
// 0 means no periodic pings. Defaults to 0.
119120
PingTimeout time.Duration
121+
120122
// ReadIdleTimeout is the timeout after which the periodic ping for
121123
// connection health check will begin if no frame is received on the
122124
// connection.
@@ -148,6 +150,14 @@ func (t *Transport) disableCompression() bool {
148150
return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
149151
}
150152

153+
func (t *Transport) readIdleTimeout() time.Duration {
154+
to := t.ReadIdleTimeout
155+
if to == 0 {
156+
to = 60 * time.Second
157+
}
158+
return to
159+
}
160+
151161
// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
152162
// It returns an error if t1 has already been HTTP/2-enabled.
153163
func ConfigureTransport(t1 *http.Transport) error {
@@ -1775,42 +1785,17 @@ func (rl *clientConnReadLoop) cleanup() {
17751785
cc.mu.Unlock()
17761786
}
17771787

1778-
type frameAndError struct {
1779-
f Frame
1780-
err error
1781-
}
1782-
1783-
func nonBlockingReadFrame(fr *Framer) chan frameAndError {
1784-
feCh := make(chan frameAndError)
1785-
go func() {
1786-
f, err := fr.ReadFrame()
1787-
feCh <- frameAndError{f: f, err: err}
1788-
}()
1789-
return feCh
1790-
}
1791-
17921788
func (rl *clientConnReadLoop) run() error {
17931789
cc := rl.cc
17941790
rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
17951791
gotReply := false // ever saw a HEADERS reply
17961792
gotSettings := false
1793+
to := cc.t.readIdleTimeout()
1794+
t := time.AfterFunc(to, cc.startHealthCheck)
17971795
for {
1798-
var fe frameAndError
1799-
feCh := nonBlockingReadFrame(cc.fr)
1800-
to := cc.t.ReadIdleTimeout
1801-
if to == 0 {
1802-
to = 60 * time.Second
1803-
}
1804-
readIdleTimer := time.NewTimer(to)
1805-
select {
1806-
case fe = <-feCh:
1807-
cc.stopHealthCheck()
1808-
readIdleTimer.Stop()
1809-
case <-readIdleTimer.C:
1810-
cc.startHealthCheck()
1811-
fe = <-feCh
1812-
}
1813-
f, err := fe.f, fe.err
1796+
f, err := cc.fr.ReadFrame()
1797+
t.Reset(to)
1798+
cc.stopHealthCheck()
18141799
if err != nil {
18151800
cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
18161801
}

0 commit comments

Comments
 (0)