net: change SetTimeout to SetDeadline

Previously, a timeout (in int64 nanoseconds) applied to a granularity
even smaller than one operation:  a 100 byte read with a 1 second timeout
could take 100 seconds, if the bytes all arrived on the network 1 second
apart.  This was confusing.

Rather than making the timeout granularity be per-Read/Write,
this CL makes callers set an absolute deadline (in time.Time)
after which operations will fail.  This makes it possible to
set deadlines at higher levels, without knowing exactly how
many read/write operations will happen in e.g. reading an HTTP
request.

Fixes #2723

R=r, rsc, dave
CC=golang-dev
https://golang.org/cl/5555048
This commit is contained in:
Brad Fitzpatrick 2012-01-18 16:24:06 -08:00
parent 5e77b009d0
commit b71883e9b0
23 changed files with 250 additions and 231 deletions

View file

@ -5,6 +5,7 @@
package net
import (
"fmt"
"runtime"
"testing"
"time"
@ -17,26 +18,41 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
return
}
defer fd.Close()
t0 := time.Now()
fd.SetReadTimeout(1e8) // 100ms
var b [100]byte
var n int
var err1 error
if readFrom {
n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
} else {
n, err1 = fd.Read(b[0:])
}
t1 := time.Now()
what := "Read"
if readFrom {
what = "ReadFrom"
}
if n != 0 || err1 == nil || !err1.(Error).Timeout() {
t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
}
if dt := t1.Sub(t0); dt < 50*time.Millisecond || dt > 150*time.Millisecond {
t.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt)
errc := make(chan error, 1)
go func() {
t0 := time.Now()
fd.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
var b [100]byte
var n int
var err1 error
if readFrom {
n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
} else {
n, err1 = fd.Read(b[0:])
}
t1 := time.Now()
if n != 0 || err1 == nil || !err1.(Error).Timeout() {
errc <- fmt.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
return
}
if dt := t1.Sub(t0); dt < 50*time.Millisecond || dt > 250*time.Millisecond {
errc <- fmt.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt)
return
}
errc <- nil
}()
select {
case err := <-errc:
if err != nil {
t.Error(err)
}
case <-time.After(1 * time.Second):
t.Errorf("%s on %s %s took over 1 second, expected 0.1s", what, network, addr)
}
}