]> Cypherpunks repositories - gostls13.git/commitdiff
net: change SetTimeout to SetDeadline
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 19 Jan 2012 00:24:06 +0000 (16:24 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 19 Jan 2012 00:24:06 +0000 (16:24 -0800)
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

23 files changed:
doc/go1.html
doc/go1.tmpl
src/pkg/crypto/tls/conn.go
src/pkg/exp/ssh/tcpip.go
src/pkg/log/syslog/syslog_test.go
src/pkg/net/dnsclient_unix.go
src/pkg/net/fd.go
src/pkg/net/fd_windows.go
src/pkg/net/http/httputil/dump.go
src/pkg/net/http/serve_test.go
src/pkg/net/http/server.go
src/pkg/net/ipraw_test.go
src/pkg/net/iprawsock_posix.go
src/pkg/net/net.go
src/pkg/net/pipe.go
src/pkg/net/sendfile_linux.go
src/pkg/net/server_test.go
src/pkg/net/sockopt.go
src/pkg/net/tcpsock_posix.go
src/pkg/net/timeout_test.go
src/pkg/net/udpsock_posix.go
src/pkg/net/unixsock_posix.go
src/pkg/websocket/websocket.go

index 2018b1aca2daea4b64aa3dd575b54b6cdcdbf01b..4b985071ef638257dbe76867030cf019fb3ef88e 100644 (file)
@@ -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
index d8419f8459e8c4f93ae82602e909bf1a2c16e0ee..8d295d6e4548d87cfe2aab382ceb65cca2252f07 100644 (file)
@@ -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
index 6a03fa8042ae964979af5f8393ca69e635a2a98d..e6cee1278c3102154b5e4cceedd63b6d539437f3 100644 (file)
@@ -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
index bee41eeb0dbc64a2c13fdd7b0d594951aa482223..e0c47bca1fcd4180dc89b56f73e3091443fdcbc8 100644 (file)
@@ -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")
 }
index 5c0b3e0c4e2b5d947173750def484d80439a9171..b9793e91abd712e729773474b26e8bfdc956046d 100644 (file)
@@ -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)
 }
 
index 07e72ccb862cff6ac1f2d461ed3674edd04a829f..18c39360e40454ad6302adf57f65e6cd0ab2c580 100644 (file)
@@ -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)
index 3dec9f4beb8b87ba6046ff148c48dac2e0ab7ce1..1b39cd7c4ba0c0674cb1e658fe6d204cee3061a0 100644 (file)
@@ -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
index 7bffd1ca2fb9751061d54c81cc15fce38362ecc3..9e799bde9ff770b9eb3a22fe7e22228cd8815212 100644 (file)
@@ -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.
index 61b18ffb1c6d94d4a88583b7d9e695ddd4598bab..b8a98ee42929b033497f74acb19719304ddf9298 100644 (file)
@@ -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,
index 265cb2761a3f5e09ce34ee3dbe9ff977350440d1..9aff467eedb8e91d0640f03b487ad65393299dee 100644 (file)
@@ -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
 }
 
index fa9009517dbabe5659b737c906a031e35a090a30..22ea8e31720026f3e2d21e9e8690a82c9cc078ab 100644 (file)
@@ -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 {
index 67a4049d5d3ff885ccf1dff89467e0bd4ce295dc..c74bfcd6c79c81b817c07d11745c6687b28a6fcc 100644 (file)
@@ -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)
index 103c4f6a92555de9a45caeac69e7feb8f673476a..e4f755bc785f049204dc97d9e17a416874b8a226 100644 (file)
@@ -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() {
index b236dfdb1dd81ae5daa50537485a521da4cf6702..7db7dfd13433eef08a67c2724c03b0dbc223b332 100644 (file)
@@ -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.
index 0ce7ccb9d7b1af1144adf5d8d33cfbfe5a86578e..f1a2eca4e8847b4321af226e7c43a493d0cdeb81 100644 (file)
@@ -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")
 }
index 350abe451f37854b1d26889ca5a243010e51f251..e9ab066663ea8619993dbdde5ac288a8c2707952 100644 (file)
@@ -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()
index 29d2532a1ed36d022127d9d47bc9c76300cbe6ba..b0b546be32b7047d2dfd19023f3e6d818813fdaa 100644 (file)
@@ -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 {
index 7fa1052b120f59cc555010a69bea00c1d631dd06..59f9af5f30adb334cec6a304476b4f22cf437fa2 100644 (file)
@@ -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 {
index a492e614e35419ba95aca0e1cec32e2f8b876481..91816fa9d46c8ae302d2b8ef682e291a000e510a 100644 (file)
@@ -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.
index f6e5238c1b1d481873be8886fb258f58f491ca27..11db012ff576393fbfeb8c27d2e4ffd7e15e2026 100644 (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)
        }
 }
 
index d0bdb14755e4348772444095a8a3b6f079a7155c..0b5bc16f822f8fc95d7ba13d0bc589558f0c5c22 100644 (file)
@@ -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() {
index 00ee0164f2e64ad14511b258fcddd124f226db2b..2f8ff19e7ffe15d5de6a94a03a5a8af82d9c787b 100644 (file)
@@ -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.
index df4416e22ed9e999ffe5c4a3bca6bc2bc2f2ca91..f7aabc94b35d1d48dd9c63fa9705a9e3512785be 100644 (file)
@@ -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.