aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2012-01-18 16:24:06 -0800
committerBrad Fitzpatrick <bradfitz@golang.org>2012-01-18 16:24:06 -0800
commitb71883e9b0eff7e89081d20204bf33f369cdf735 (patch)
treebf3ded01d2aae9f06a8e24759eb8fa0635377b2e
parent5e77b009d0e9dc8c92fe91d0a2d3182e9fff10ae (diff)
downloadgo-b71883e9b0eff7e89081d20204bf33f369cdf735.tar.gz
go-b71883e9b0eff7e89081d20204bf33f369cdf735.zip
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
-rw-r--r--doc/go1.html15
-rw-r--r--doc/go1.tmpl15
-rw-r--r--src/pkg/crypto/tls/conn.go26
-rw-r--r--src/pkg/exp/ssh/tcpip.go31
-rw-r--r--src/pkg/log/syslog/syslog_test.go3
-rw-r--r--src/pkg/net/dnsclient_unix.go6
-rw-r--r--src/pkg/net/fd.go45
-rw-r--r--src/pkg/net/fd_windows.go36
-rw-r--r--src/pkg/net/http/httputil/dump.go13
-rw-r--r--src/pkg/net/http/serve_test.go6
-rw-r--r--src/pkg/net/http/server.go8
-rw-r--r--src/pkg/net/ipraw_test.go3
-rw-r--r--src/pkg/net/iprawsock_posix.go25
-rw-r--r--src/pkg/net/net.go61
-rw-r--r--src/pkg/net/pipe.go13
-rw-r--r--src/pkg/net/sendfile_linux.go9
-rw-r--r--src/pkg/net/server_test.go5
-rw-r--r--src/pkg/net/sockopt.go15
-rw-r--r--src/pkg/net/tcpsock_posix.go26
-rw-r--r--src/pkg/net/timeout_test.go48
-rw-r--r--src/pkg/net/udpsock_posix.go23
-rw-r--r--src/pkg/net/unixsock_posix.go30
-rw-r--r--src/pkg/websocket/websocket.go27
23 files changed, 254 insertions, 235 deletions
diff --git a/doc/go1.html b/doc/go1.html
index 2018b1aca2..4b985071ef 100644
--- a/doc/go1.html
+++ b/doc/go1.html
@@ -750,6 +750,17 @@ Gofix will update the few programs that are affected except for
uses of <code>RawURL</code>, which must be fixed by hand.
</p>
+<h3 id="net">The net package</h3>
+
+<p>In Go 1, the various <code>SetTimeout</code>,
+<code>SetReadTimeout</code>, and <code>SetWriteTimeout</code> methods
+have been replaced with <code>SetDeadline</code>,
+<code>SetReadDeadline</code>, and <code>SetWriteDeadline</code>,
+respectively. Rather than taking a timeout value in nanoseconds that
+apply to any activity on the connection, the new methods set an
+absolute deadline (as a <code>time.Time</code> value) after which
+reads and writes will time out and no longer block.</p>
+
<h3 id="strconv">The strconv package</h3>
<p>
@@ -957,8 +968,8 @@ documentation for a package is created with:
</pre>
<p>
-where the new <code>mode</mode> parameter specifies the operation mode:
-if set to <a href="go/doc/#AllDecls"><code>AllDecls</a>, all declarations
+where the new <code>mode</code> parameter specifies the operation mode:
+if set to <a href="go/doc/#AllDecls"><code>AllDecls</code></a>, all declarations
(not just exported ones) are considered.
The function <code>NewFileDoc</code> was removed, and the function
<code>CommentText</code> has become the method
diff --git a/doc/go1.tmpl b/doc/go1.tmpl
index d8419f8459..8d295d6e45 100644
--- a/doc/go1.tmpl
+++ b/doc/go1.tmpl
@@ -654,6 +654,17 @@ Gofix will update the few programs that are affected except for
uses of <code>RawURL</code>, which must be fixed by hand.
</p>
+<h3 id="net">The net package</h3>
+
+<p>In Go 1, the various <code>SetTimeout</code>,
+<code>SetReadTimeout</code>, and <code>SetWriteTimeout</code> methods
+have been replaced with <code>SetDeadline</code>,
+<code>SetReadDeadline</code>, and <code>SetWriteDeadline</code>,
+respectively. Rather than taking a timeout value in nanoseconds that
+apply to any activity on the connection, the new methods set an
+absolute deadline (as a <code>time.Time</code> value) after which
+reads and writes will time out and no longer block.</p>
+
<h3 id="strconv">The strconv package</h3>
<p>
@@ -861,8 +872,8 @@ documentation for a package is created with:
</pre>
<p>
-where the new <code>mode</mode> parameter specifies the operation mode:
-if set to <a href="go/doc/#AllDecls"><code>AllDecls</a>, all declarations
+where the new <code>mode</code> parameter specifies the operation mode:
+if set to <a href="go/doc/#AllDecls"><code>AllDecls</code></a>, all declarations
(not just exported ones) are considered.
The function <code>NewFileDoc</code> was removed, and the function
<code>CommentText</code> has become the method
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 6a03fa8042..e6cee1278c 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -15,6 +15,7 @@ import (
"io"
"net"
"sync"
+ "time"
)
// A Conn represents a secured connection.
@@ -86,24 +87,23 @@ func (c *Conn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
-// SetTimeout sets the read deadline associated with the connection.
+// SetDeadline sets the read deadline associated with the connection.
// There is no write deadline.
-func (c *Conn) SetTimeout(nsec int64) error {
- return c.conn.SetTimeout(nsec)
+// A zero value for t means Read will not time out.
+func (c *Conn) SetDeadline(t time.Time) error {
+ return c.conn.SetDeadline(t)
}
-// SetReadTimeout sets the time (in nanoseconds) that
-// Read will wait for data before returning a net.Error
-// with Timeout() == true.
-// Setting nsec == 0 (the default) disables the deadline.
-func (c *Conn) SetReadTimeout(nsec int64) error {
- return c.conn.SetReadTimeout(nsec)
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means Read will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ return c.conn.SetReadDeadline(t)
}
-// SetWriteTimeout exists to satisfy the net.Conn interface
+// SetWriteDeadline exists to satisfy the net.Conn interface
// but is not implemented by TLS. It always returns an error.
-func (c *Conn) SetWriteTimeout(nsec int64) error {
- return errors.New("TLS does not support SetWriteTimeout")
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ return errors.New("TLS does not support SetWriteDeadline")
}
// A halfConn represents one direction of the record layer
@@ -744,7 +744,7 @@ func (c *Conn) Write(b []byte) (n int, err error) {
}
// Read can be made to time out and return a net.Error with Timeout() == true
-// after a fixed time limit; see SetTimeout and SetReadTimeout.
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *Conn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
diff --git a/src/pkg/exp/ssh/tcpip.go b/src/pkg/exp/ssh/tcpip.go
index bee41eeb0d..e0c47bca1f 100644
--- a/src/pkg/exp/ssh/tcpip.go
+++ b/src/pkg/exp/ssh/tcpip.go
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"net"
+ "time"
)
// Dial initiates a connection to the addr from the remote host.
@@ -107,27 +108,25 @@ func (t *tcpchanconn) RemoteAddr() net.Addr {
return t.raddr
}
-// SetTimeout sets the read and write deadlines associated
+// SetDeadline sets the read and write deadlines associated
// with the connection.
-func (t *tcpchanconn) SetTimeout(nsec int64) error {
- if err := t.SetReadTimeout(nsec); err != nil {
+func (t *tcpchanconn) SetDeadline(deadline time.Time) error {
+ if err := t.SetReadDeadline(deadline); err != nil {
return err
}
- return t.SetWriteTimeout(nsec)
+ return t.SetWriteDeadline(deadline)
}
-// SetReadTimeout sets the time (in nanoseconds) that
-// Read will wait for data before returning an error with Timeout() == true.
-// Setting nsec == 0 (the default) disables the deadline.
-func (t *tcpchanconn) SetReadTimeout(nsec int64) error {
- return errors.New("ssh: tcpchan: timeout not supported")
+// SetReadDeadline sets the read deadline.
+// A zero value for t means Read will not time out.
+// After the deadline, the error from Read will implement net.Error
+// with Timeout() == true.
+func (t *tcpchanconn) SetReadDeadline(deadline time.Time) error {
+ return errors.New("ssh: tcpchan: deadline not supported")
}
-// SetWriteTimeout sets the time (in nanoseconds) that
-// Write will wait to send its data before returning an error with Timeout() == true.
-// Setting nsec == 0 (the default) disables the deadline.
-// Even if write times out, it may return n > 0, indicating that
-// some of the data was successfully written.
-func (t *tcpchanconn) SetWriteTimeout(nsec int64) error {
- return errors.New("ssh: tcpchan: timeout not supported")
+// SetWriteDeadline exists to satisfy the net.Conn interface
+// but is not implemented by this type. It always returns an error.
+func (t *tcpchanconn) SetWriteDeadline(deadline time.Time) error {
+ return errors.New("ssh: tcpchan: deadline not supported")
}
diff --git a/src/pkg/log/syslog/syslog_test.go b/src/pkg/log/syslog/syslog_test.go
index 5c0b3e0c4e..b9793e91ab 100644
--- a/src/pkg/log/syslog/syslog_test.go
+++ b/src/pkg/log/syslog/syslog_test.go
@@ -8,6 +8,7 @@ import (
"log"
"net"
"testing"
+ "time"
)
var serverAddr string
@@ -31,7 +32,7 @@ func startServer(done chan<- string) {
log.Fatalf("net.ListenPacket failed udp :0 %v", e)
}
serverAddr = c.LocalAddr().String()
- c.SetReadTimeout(100e6) // 100ms
+ c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
go runSyslog(c, done)
}
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
index 07e72ccb86..18c39360e4 100644
--- a/src/pkg/net/dnsclient_unix.go
+++ b/src/pkg/net/dnsclient_unix.go
@@ -45,7 +45,11 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error
return nil, err
}
- c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
+ if cfg.timeout == 0 {
+ c.SetReadDeadline(time.Time{})
+ } else {
+ c.SetReadDeadline(time.Now().Add(time.Duration(cfg.timeout) * time.Second))
+ }
buf := make([]byte, 2000) // More than enough.
n, err = c.Read(buf)
diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go
index 3dec9f4beb..1b39cd7c4b 100644
--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -33,12 +33,10 @@ type netFD struct {
raddr Addr
// owned by client
- rdeadline_delta int64
- rdeadline int64
- rio sync.Mutex
- wdeadline_delta int64
- wdeadline int64
- wio sync.Mutex
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline int64
+ wio sync.Mutex
// owned by fd wait server
ncr, ncw int
@@ -388,11 +386,6 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
if fd.sysfile == nil {
return 0, os.EINVAL
}
- if fd.rdeadline_delta > 0 {
- fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
- } else {
- fd.rdeadline = 0
- }
for {
n, err = syscall.Read(fd.sysfile.Fd(), p)
if err == syscall.EAGAIN {
@@ -423,11 +416,6 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
defer fd.rio.Unlock()
fd.incref()
defer fd.decref()
- if fd.rdeadline_delta > 0 {
- fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
- } else {
- fd.rdeadline = 0
- }
for {
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
if err == syscall.EAGAIN {
@@ -456,11 +444,6 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
defer fd.rio.Unlock()
fd.incref()
defer fd.decref()
- if fd.rdeadline_delta > 0 {
- fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
- } else {
- fd.rdeadline = 0
- }
for {
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
if err == syscall.EAGAIN {
@@ -493,11 +476,6 @@ func (fd *netFD) Write(p []byte) (n int, err error) {
if fd.sysfile == nil {
return 0, os.EINVAL
}
- if fd.wdeadline_delta > 0 {
- fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
- } else {
- fd.wdeadline = 0
- }
nn := 0
for {
@@ -539,11 +517,6 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
defer fd.wio.Unlock()
fd.incref()
defer fd.decref()
- if fd.wdeadline_delta > 0 {
- fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
- } else {
- fd.wdeadline = 0
- }
for {
err = syscall.Sendto(fd.sysfd, p, 0, sa)
if err == syscall.EAGAIN {
@@ -571,11 +544,6 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
defer fd.wio.Unlock()
fd.incref()
defer fd.decref()
- if fd.wdeadline_delta > 0 {
- fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
- } else {
- fd.wdeadline = 0
- }
for {
err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
@@ -603,11 +571,6 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
fd.incref()
defer fd.decref()
- if fd.rdeadline_delta > 0 {
- fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
- } else {
- fd.rdeadline = 0
- }
// See ../syscall/exec.go for description of ForkLock.
// It is okay to hold the lock across syscall.Accept
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 7bffd1ca2f..9e799bde9f 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -150,12 +150,13 @@ func (s *ioSrv) ProcessRemoteIO() {
}
// ExecIO executes a single io operation. It either executes it
-// inline, or, if timeouts are employed, passes the request onto
+// inline, or, if a deadline is employed, passes the request onto
// a special goroutine and waits for completion or cancels request.
-func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) {
+// deadline is unix nanos.
+func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (n int, err error) {
var e error
o := oi.Op()
- if deadline_delta > 0 {
+ if deadline != 0 {
// Send request to a special dedicated thread,
// so it can stop the io with CancelIO later.
s.submchan <- oi
@@ -172,12 +173,17 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) {
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e}
}
// Wait for our request to complete.
- // TODO(rsc): This should stop the timer.
var r ioResult
- if deadline_delta > 0 {
+ if deadline != 0 {
+ dt := deadline - time.Now().UnixNano()
+ if dt < 1 {
+ dt = 1
+ }
+ ticker := time.NewTicker(time.Duration(dt) * time.Nanosecond)
+ defer ticker.Stop()
select {
case r = <-o.resultc:
- case <-time.After(time.Duration(deadline_delta) * time.Nanosecond):
+ case <-ticker.C:
s.canchan <- oi
<-o.errnoc
r = <-o.resultc
@@ -232,12 +238,10 @@ type netFD struct {
errnoc [2]chan error // read/write submit or cancel operation errors
// owned by client
- rdeadline_delta int64
- rdeadline int64
- rio sync.Mutex
- wdeadline_delta int64
- wdeadline int64
- wio sync.Mutex
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline int64
+ wio sync.Mutex
}
func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) {
@@ -357,7 +361,7 @@ func (fd *netFD) Read(buf []byte) (n int, err error) {
}
var o readOp
o.Init(fd, buf, 'r')
- n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ n, err = iosrv.ExecIO(&o, fd.rdeadline)
if err == nil && n == 0 {
err = io.EOF
}
@@ -398,7 +402,7 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
var o readFromOp
o.Init(fd, buf, 'r')
o.rsan = int32(unsafe.Sizeof(o.rsa))
- n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ n, err = iosrv.ExecIO(&o, fd.rdeadline)
if err != nil {
return 0, nil, err
}
@@ -434,7 +438,7 @@ func (fd *netFD) Write(buf []byte) (n int, err error) {
}
var o writeOp
o.Init(fd, buf, 'w')
- return iosrv.ExecIO(&o, fd.wdeadline_delta)
+ return iosrv.ExecIO(&o, fd.wdeadline)
}
// WriteTo to network.
@@ -470,7 +474,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err error) {
var o writeToOp
o.Init(fd, buf, 'w')
o.sa = sa
- return iosrv.ExecIO(&o, fd.wdeadline_delta)
+ return iosrv.ExecIO(&o, fd.wdeadline)
}
// Accept new network connections.
diff --git a/src/pkg/net/http/httputil/dump.go b/src/pkg/net/http/httputil/dump.go
index 61b18ffb1c..b8a98ee429 100644
--- a/src/pkg/net/http/httputil/dump.go
+++ b/src/pkg/net/http/httputil/dump.go
@@ -13,6 +13,7 @@ import (
"net"
"net/http"
"strings"
+ "time"
)
// One of the copies, say from b to r2, could be avoided by using a more
@@ -36,12 +37,12 @@ type dumpConn struct {
io.Reader
}
-func (c *dumpConn) Close() error { return nil }
-func (c *dumpConn) LocalAddr() net.Addr { return nil }
-func (c *dumpConn) RemoteAddr() net.Addr { return nil }
-func (c *dumpConn) SetTimeout(nsec int64) error { return nil }
-func (c *dumpConn) SetReadTimeout(nsec int64) error { return nil }
-func (c *dumpConn) SetWriteTimeout(nsec int64) error { return nil }
+func (c *dumpConn) Close() error { return nil }
+func (c *dumpConn) LocalAddr() net.Addr { return nil }
+func (c *dumpConn) RemoteAddr() net.Addr { return nil }
+func (c *dumpConn) SetDeadline(t time.Time) error { return nil }
+func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil }
+func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
// DumpRequestOut is like DumpRequest but includes
// headers that the standard http.Transport adds,
diff --git a/src/pkg/net/http/serve_test.go b/src/pkg/net/http/serve_test.go
index 265cb2761a..9aff467eed 100644
--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -84,15 +84,15 @@ func (c *testConn) RemoteAddr() net.Addr {
return dummyAddr("remote-addr")
}
-func (c *testConn) SetTimeout(nsec int64) error {
+func (c *testConn) SetDeadline(t time.Time) error {
return nil
}
-func (c *testConn) SetReadTimeout(nsec int64) error {
+func (c *testConn) SetReadDeadline(t time.Time) error {
return nil
}
-func (c *testConn) SetWriteTimeout(nsec int64) error {
+func (c *testConn) SetWriteDeadline(t time.Time) error {
return nil
}
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index fa9009517d..22ea8e3172 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -954,8 +954,8 @@ func Serve(l net.Listener, handler Handler) error {
type Server struct {
Addr string // TCP address to listen on, ":http" if empty
Handler Handler // handler to invoke, http.DefaultServeMux if nil
- ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections
- WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections
+ ReadTimeout time.Duration // maximum duration before timing out read of the request
+ WriteTimeout time.Duration // maximum duration before timing out write of the response
MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0
}
@@ -989,10 +989,10 @@ func (srv *Server) Serve(l net.Listener) error {
return e
}
if srv.ReadTimeout != 0 {
- rw.SetReadTimeout(srv.ReadTimeout.Nanoseconds())
+ rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
}
if srv.WriteTimeout != 0 {
- rw.SetWriteTimeout(srv.WriteTimeout.Nanoseconds())
+ rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
}
c, err := srv.newConn(rw)
if err != nil {
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index 67a4049d5d..c74bfcd6c7 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -12,6 +12,7 @@ import (
"flag"
"os"
"testing"
+ "time"
)
const ICMP_ECHO_REQUEST = 8
@@ -101,7 +102,7 @@ func TestICMP(t *testing.T) {
t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
}
- c.SetTimeout(100e6)
+ c.SetDeadline(time.Now().Add(100 * time.Millisecond))
resp := make([]byte, 1024)
for {
n, from, err := c.ReadFrom(resp)
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 103c4f6a92..e4f755bc78 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -12,6 +12,7 @@ import (
"errors"
"os"
"syscall"
+ "time"
)
func sockaddrToIP(sa syscall.Sockaddr) Addr {
@@ -97,28 +98,28 @@ func (c *IPConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *IPConn) SetTimeout(nsec int64) error {
+// SetDeadline implements the net.Conn SetDeadline method.
+func (c *IPConn) SetDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *IPConn) SetReadTimeout(nsec int64) error {
+// SetReadDeadline implements the net.Conn SetReadDeadline method.
+func (c *IPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *IPConn) SetWriteTimeout(nsec int64) error {
+// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+func (c *IPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
@@ -146,8 +147,8 @@ func (c *IPConn) SetWriteBuffer(bytes int) error {
// that was on the packet.
//
// ReadFromIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetTimeout and
-// SetReadTimeout.
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetReadDeadline.
func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err error) {
if !c.ok() {
return 0, nil, os.EINVAL
@@ -182,7 +183,7 @@ func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
//
// WriteToIP can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
+// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err error) {
if !c.ok() {
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index b236dfdb1d..7db7dfd134 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -9,7 +9,10 @@ package net
// TODO(rsc):
// support for raw ethernet sockets
-import "errors"
+import (
+ "errors"
+ "time"
+)
// Addr represents a network end point address.
type Addr interface {
@@ -38,21 +41,23 @@ type Conn interface {
// RemoteAddr returns the remote network address.
RemoteAddr() Addr
- // SetTimeout sets the read and write deadlines associated
+ // SetDeadline sets the read and write deadlines associated
// with the connection.
- SetTimeout(nsec int64) error
-
- // SetReadTimeout sets the time (in nanoseconds) that
- // Read will wait for data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
- SetReadTimeout(nsec int64) error
-
- // SetWriteTimeout sets the time (in nanoseconds) that
- // Write will wait to send its data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
+ SetDeadline(t time.Time) error
+
+ // SetReadDeadline sets the deadline for all Read calls to return.
+ // If the deadline is reached, Read will fail with a timeout
+ // (see type Error) instead of blocking.
+ // A zero value for t means Read will not time out.
+ SetReadDeadline(t time.Time) error
+
+ // SetWriteDeadline sets the deadline for all Write calls to return.
+ // If the deadline is reached, Write will fail with a timeout
+ // (see type Error) instead of blocking.
+ // A zero value for t means Write will not time out.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
- SetWriteTimeout(nsec int64) error
+ SetWriteDeadline(t time.Time) error
}
// An Error represents a network error.
@@ -70,13 +75,13 @@ type PacketConn interface {
// was on the packet.
// ReadFrom can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
- // see SetTimeout and SetReadTimeout.
+ // see SetDeadline and SetReadDeadline.
ReadFrom(b []byte) (n int, addr Addr, err error)
// WriteTo writes a packet with payload b to addr.
// WriteTo can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
- // see SetTimeout and SetWriteTimeout.
+ // see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
WriteTo(b []byte, addr Addr) (n int, err error)
@@ -86,21 +91,23 @@ type PacketConn interface {
// LocalAddr returns the local network address.
LocalAddr() Addr
- // SetTimeout sets the read and write deadlines associated
+ // SetDeadline sets the read and write deadlines associated
// with the connection.
- SetTimeout(nsec int64) error
-
- // SetReadTimeout sets the time (in nanoseconds) that
- // Read will wait for data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
- SetReadTimeout(nsec int64) error
-
- // SetWriteTimeout sets the time (in nanoseconds) that
- // Write will wait to send its data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
+ SetDeadline(t time.Time) error
+
+ // SetReadDeadline sets the deadline for all Read calls to return.
+ // If the deadline is reached, Read will fail with a timeout
+ // (see type Error) instead of blocking.
+ // A zero value for t means Read will not time out.
+ SetReadDeadline(t time.Time) error
+
+ // SetWriteDeadline sets the deadline for all Write calls to return.
+ // If the deadline is reached, Write will fail with a timeout
+ // (see type Error) instead of blocking.
+ // A zero value for t means Write will not time out.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
- SetWriteTimeout(nsec int64) error
+ SetWriteDeadline(t time.Time) error
}
// A Listener is a generic network listener for stream-oriented protocols.
diff --git a/src/pkg/net/pipe.go b/src/pkg/net/pipe.go
index 0ce7ccb9d7..f1a2eca4e8 100644
--- a/src/pkg/net/pipe.go
+++ b/src/pkg/net/pipe.go
@@ -7,6 +7,7 @@ package net
import (
"errors"
"io"
+ "time"
)
// Pipe creates a synchronous, in-memory, full duplex
@@ -53,14 +54,14 @@ func (p *pipe) RemoteAddr() Addr {
return pipeAddr(0)
}
-func (p *pipe) SetTimeout(nsec int64) error {
- return errors.New("net.Pipe does not support timeouts")
+func (p *pipe) SetDeadline(t time.Time) error {
+ return errors.New("net.Pipe does not support deadlines")
}
-func (p *pipe) SetReadTimeout(nsec int64) error {
- return errors.New("net.Pipe does not support timeouts")
+func (p *pipe) SetReadDeadline(t time.Time) error {
+ return errors.New("net.Pipe does not support deadlines")
}
-func (p *pipe) SetWriteTimeout(nsec int64) error {
- return errors.New("net.Pipe does not support timeouts")
+func (p *pipe) SetWriteDeadline(t time.Time) error {
+ return errors.New("net.Pipe does not support deadlines")
}
diff --git a/src/pkg/net/sendfile_linux.go b/src/pkg/net/sendfile_linux.go
index 350abe451f..e9ab066663 100644
--- a/src/pkg/net/sendfile_linux.go
+++ b/src/pkg/net/sendfile_linux.go
@@ -40,15 +40,6 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
defer c.wio.Unlock()
c.incref()
defer c.decref()
- if c.wdeadline_delta > 0 {
- // This is a little odd that we're setting the timeout
- // for the entire file but Write has the same issue
- // (if one slurps the whole file into memory and
- // do one large Write). At least they're consistent.
- c.wdeadline = pollserver.Now() + c.wdeadline_delta
- } else {
- c.wdeadline = 0
- }
dst := c.sysfd
src := f.Fd()
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index 29d2532a1e..b0b546be32 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -11,6 +11,7 @@ import (
"runtime"
"strings"
"testing"
+ "time"
)
// Do not test empty datagrams by default.
@@ -63,7 +64,7 @@ func connect(t *testing.T, network, addr string, isEmpty bool) {
if err != nil {
t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
}
- fd.SetReadTimeout(1e9) // 1s
+ fd.SetReadDeadline(time.Now().Add(1 * time.Second))
var b []byte
if !isEmpty {
@@ -169,10 +170,10 @@ func runPacket(t *testing.T, network, addr string, listening chan<- string, done
t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
}
listening <- c.LocalAddr().String()
- c.SetReadTimeout(10e6) // 10ms
var buf [1000]byte
Run:
for {
+ c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
n, addr, err := c.ReadFrom(buf[0:])
if e, ok := err.(Error); ok && e.Timeout() {
select {
diff --git a/src/pkg/net/sockopt.go b/src/pkg/net/sockopt.go
index 7fa1052b12..59f9af5f30 100644
--- a/src/pkg/net/sockopt.go
+++ b/src/pkg/net/sockopt.go
@@ -12,6 +12,7 @@ import (
"bytes"
"os"
"syscall"
+ "time"
)
// Boolean to int.
@@ -115,21 +116,21 @@ func setWriteBuffer(fd *netFD, bytes int) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
}
-func setReadTimeout(fd *netFD, nsec int64) error {
- fd.rdeadline_delta = nsec
+func setReadDeadline(fd *netFD, t time.Time) error {
+ fd.rdeadline = t.UnixNano()
return nil
}
-func setWriteTimeout(fd *netFD, nsec int64) error {
- fd.wdeadline_delta = nsec
+func setWriteDeadline(fd *netFD, t time.Time) error {
+ fd.wdeadline = t.UnixNano()
return nil
}
-func setTimeout(fd *netFD, nsec int64) error {
- if e := setReadTimeout(fd, nsec); e != nil {
+func setDeadline(fd *netFD, t time.Time) error {
+ if e := setReadDeadline(fd, t); e != nil {
return e
}
- return setWriteTimeout(fd, nsec)
+ return setWriteDeadline(fd, t)
}
func setReuseAddr(fd *netFD, reuse bool) error {
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index a492e614e3..91816fa9d4 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -12,6 +12,7 @@ import (
"io"
"os"
"syscall"
+ "time"
)
// BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for
@@ -134,28 +135,28 @@ func (c *TCPConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *TCPConn) SetTimeout(nsec int64) error {
+// SetDeadline implements the net.Conn SetDeadline method.
+func (c *TCPConn) SetDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *TCPConn) SetReadTimeout(nsec int64) error {
+// SetReadDeadline implements the net.Conn SetReadDeadline method.
+func (c *TCPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *TCPConn) SetWriteTimeout(nsec int64) error {
+// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+func (c *TCPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
@@ -294,12 +295,13 @@ func (l *TCPListener) Close() error {
// Addr returns the listener's network address, a *TCPAddr.
func (l *TCPListener) Addr() Addr { return l.fd.laddr }
-// SetTimeout sets the deadline associated with the listener
-func (l *TCPListener) SetTimeout(nsec int64) error {
+// SetDeadline sets the deadline associated with the listener.
+// A zero time value disables the deadline.
+func (l *TCPListener) SetDeadline(t time.Time) error {
if l == nil || l.fd == nil {
return os.EINVAL
}
- return setTimeout(l.fd, nsec)
+ return setDeadline(l.fd, t)
}
// File returns a copy of the underlying os.File, set to blocking mode.
diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index f6e5238c1b..11db012ff5 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -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)
}
}
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index d0bdb14755..0b5bc16f82 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -11,6 +11,7 @@ package net
import (
"os"
"syscall"
+ "time"
)
func sockaddrToUDP(sa syscall.Sockaddr) Addr {
@@ -98,28 +99,28 @@ func (c *UDPConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *UDPConn) SetTimeout(nsec int64) error {
+// SetDeadline implements the net.Conn SetDeadline method.
+func (c *UDPConn) SetDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *UDPConn) SetReadTimeout(nsec int64) error {
+// SetReadDeadline implements the net.Conn SetReadDeadline method.
+func (c *UDPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *UDPConn) SetWriteTimeout(nsec int64) error {
+// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+func (c *UDPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
@@ -147,7 +148,7 @@ func (c *UDPConn) SetWriteBuffer(bytes int) error {
// that was on the packet.
//
// ReadFromUDP can be made to time out and return an error with Timeout() == true
-// after a fixed time limit; see SetTimeout and SetReadTimeout.
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
if !c.ok() {
return 0, nil, os.EINVAL
@@ -175,7 +176,7 @@ func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
//
// WriteToUDP can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
+// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) {
if !c.ok() {
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index 00ee0164f2..2f8ff19e7f 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -11,6 +11,7 @@ package net
import (
"os"
"syscall"
+ "time"
)
func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err error) {
@@ -164,28 +165,28 @@ func (c *UnixConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *UnixConn) SetTimeout(nsec int64) error {
+// SetDeadline implements the net.Conn SetDeadline method.
+func (c *UnixConn) SetDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *UnixConn) SetReadTimeout(nsec int64) error {
+// SetReadDeadline implements the net.Conn SetReadDeadline method.
+func (c *UnixConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *UnixConn) SetWriteTimeout(nsec int64) error {
+// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+func (c *UnixConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
return os.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
@@ -212,7 +213,7 @@ func (c *UnixConn) SetWriteBuffer(bytes int) error {
//
// ReadFromUnix can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetReadTimeout.
+// see SetDeadline and SetReadDeadline.
func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
if !c.ok() {
return 0, nil, os.EINVAL
@@ -238,7 +239,7 @@ func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
//
// WriteToUnix can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
+// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
if !c.ok() {
@@ -386,12 +387,13 @@ func (l *UnixListener) Close() error {
// Addr returns the listener's network address.
func (l *UnixListener) Addr() Addr { return l.fd.laddr }
-// SetTimeout sets the deadline associated wuth the listener
-func (l *UnixListener) SetTimeout(nsec int64) (err error) {
+// SetTimeout sets the deadline associated with the listener.
+// A zero time value disables the deadline.
+func (l *UnixListener) SetDeadline(t time.Time) (err error) {
if l == nil || l.fd == nil {
return os.EINVAL
}
- return setTimeout(l.fd, nsec)
+ return setDeadline(l.fd, t)
}
// File returns a copy of the underlying os.File, set to blocking mode.
diff --git a/src/pkg/websocket/websocket.go b/src/pkg/websocket/websocket.go
index df4416e22e..f7aabc94b3 100644
--- a/src/pkg/websocket/websocket.go
+++ b/src/pkg/websocket/websocket.go
@@ -17,6 +17,7 @@ import (
"net/http"
"net/url"
"sync"
+ "time"
)
const (
@@ -243,30 +244,30 @@ func (ws *Conn) RemoteAddr() net.Addr {
return &Addr{ws.config.Origin}
}
-var errSetTimeout = errors.New("websocket: cannot set timeout: not using a net.Conn")
+var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
-// SetTimeout sets the connection's network timeout in nanoseconds.
-func (ws *Conn) SetTimeout(nsec int64) error {
+// SetDeadline sets the connection's network read & write deadlines.
+func (ws *Conn) SetDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetTimeout(nsec)
+ return conn.SetDeadline(t)
}
- return errSetTimeout
+ return errSetDeadline
}
-// SetReadTimeout sets the connection's network read timeout in nanoseconds.
-func (ws *Conn) SetReadTimeout(nsec int64) error {
+// SetReadDeadline sets the connection's network read deadline.
+func (ws *Conn) SetReadDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetReadTimeout(nsec)
+ return conn.SetReadDeadline(t)
}
- return errSetTimeout
+ return errSetDeadline
}
-// SetWriteTimeout sets the connection's network write timeout in nanoseconds.
-func (ws *Conn) SetWriteTimeout(nsec int64) error {
+// SetWriteDeadline sets the connection's network write deadline.
+func (ws *Conn) SetWriteDeadline(t time.Time) error {
if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetWriteTimeout(nsec)
+ return conn.SetWriteDeadline(t)
}
- return errSetTimeout
+ return errSetDeadline
}
// Config returns the WebSocket config.