diff --git a/doc/go1.html b/doc/go1.html index 2018b1aca2d..4b985071ef6 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 RawURL, which must be fixed by hand.

+

The net package

+ +

In Go 1, the various SetTimeout, +SetReadTimeout, and SetWriteTimeout methods +have been replaced with SetDeadline, +SetReadDeadline, and SetWriteDeadline, +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 time.Time value) after which +reads and writes will time out and no longer block.

+

The strconv package

@@ -957,8 +968,8 @@ documentation for a package is created with:

-where the new mode parameter specifies the operation mode: -if set to AllDecls, all declarations +where the new mode parameter specifies the operation mode: +if set to AllDecls, all declarations (not just exported ones) are considered. The function NewFileDoc was removed, and the function CommentText has become the method diff --git a/doc/go1.tmpl b/doc/go1.tmpl index d8419f8459e..8d295d6e454 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 RawURL, which must be fixed by hand.

+

The net package

+ +

In Go 1, the various SetTimeout, +SetReadTimeout, and SetWriteTimeout methods +have been replaced with SetDeadline, +SetReadDeadline, and SetWriteDeadline, +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 time.Time value) after which +reads and writes will time out and no longer block.

+

The strconv package

@@ -861,8 +872,8 @@ documentation for a package is created with:

-where the new mode parameter specifies the operation mode: -if set to AllDecls, all declarations +where the new mode parameter specifies the operation mode: +if set to AllDecls, all declarations (not just exported ones) are considered. The function NewFileDoc was removed, and the function CommentText has become the method diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go index 6a03fa8042a..e6cee1278c3 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 bee41eeb0db..e0c47bca1fc 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 5c0b3e0c4e2..b9793e91abd 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 07e72ccb862..18c39360e40 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 3dec9f4beb8..1b39cd7c4ba 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 7bffd1ca2fb..9e799bde9ff 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 61b18ffb1c6..b8a98ee4292 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 265cb2761a3..9aff467eedb 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 fa9009517db..22ea8e31720 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 67a4049d5d3..c74bfcd6c79 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 103c4f6a925..e4f755bc785 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 b236dfdb1dd..7db7dfd1343 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 + SetDeadline(t time.Time) 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 + // 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 - // 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. + // 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 + SetDeadline(t time.Time) 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 + // 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 - // 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. + // 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 0ce7ccb9d7b..f1a2eca4e88 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 350abe451f3..e9ab066663e 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 29d2532a1ed..b0b546be32b 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 7fa1052b120..59f9af5f30a 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 a492e614e35..91816fa9d46 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 f6e5238c1b1..11db012ff57 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 d0bdb14755e..0b5bc16f822 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 00ee0164f2e..2f8ff19e7ff 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 df4416e22ed..f7aabc94b35 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.