+++ /dev/null
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin freebsd linux netbsd openbsd windows
-
-package net
-
-import (
- "testing"
- "time"
-)
-
-var deadlineSetTimeTests = []struct {
- input time.Time
- expected int64
-}{
- {time.Time{}, 0},
- {time.Date(2009, 11, 10, 23, 00, 00, 00, time.UTC), 1257894000000000000}, // 2009-11-10 23:00:00 +0000 UTC
-}
-
-func TestDeadlineSetTime(t *testing.T) {
- for _, tt := range deadlineSetTimeTests {
- var d deadline
- d.setTime(tt.input)
- actual := d.value()
- expected := int64(0)
- if !tt.input.IsZero() {
- expected = tt.input.UnixNano()
- }
- if actual != expected {
- t.Errorf("set/value failed: expected %v, actual %v", expected, actual)
- }
- }
-}
-
-var deadlineExpiredTests = []struct {
- deadline time.Time
- expired bool
-}{
- // note, times are relative to the start of the test run, not
- // the start of TestDeadlineExpired
- {time.Now().Add(5 * time.Minute), false},
- {time.Now().Add(-5 * time.Minute), true},
- {time.Time{}, false}, // no deadline set
-}
-
-func TestDeadlineExpired(t *testing.T) {
- for _, tt := range deadlineExpiredTests {
- var d deadline
- d.set(tt.deadline.UnixNano())
- expired := d.expired()
- if expired != tt.expired {
- t.Errorf("expire failed: expected %v, actual %v", tt.expired, expired)
- }
- }
-}
"os"
"runtime"
"sync"
- "sync/atomic"
"syscall"
"time"
)
laddr Addr
raddr Addr
- // serialize access to Read and Write methods
- rio, wio sync.Mutex
-
- // read and write deadlines
- rdeadline, wdeadline deadline
+ // owned by client
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline int64
+ wio sync.Mutex
// owned by fd wait server
ncr, ncw int
pollServer *pollServer
}
-// deadline is an atomically-accessed number of nanoseconds since 1970
-// or 0, if no deadline is set.
-type deadline int64
-
-func (d *deadline) expired() bool {
- t := d.value()
- return t > 0 && time.Now().UnixNano() >= t
-}
-
-func (d *deadline) value() int64 {
- return atomic.LoadInt64((*int64)(d))
-}
-
-func (d *deadline) set(v int64) {
- atomic.StoreInt64((*int64)(d), v)
-}
-
-func (d *deadline) setTime(t time.Time) {
- if t.IsZero() {
- d.set(0)
- } else {
- d.set(t.UnixNano())
- }
-}
-
// A pollServer helps FDs determine when to retry a non-blocking
// read or write after they get EAGAIN. When an FD needs to wait,
// call s.WaitRead() or s.WaitWrite() to pass the request to the poll server.
key := intfd << 1
if mode == 'r' {
fd.ncr++
- t = fd.rdeadline.value()
+ t = fd.rdeadline
} else {
fd.ncw++
key++
- t = fd.wdeadline.value()
+ t = fd.wdeadline
}
s.pending[key] = fd
doWakeup := false
}
}
+func (s *pollServer) Now() int64 {
+ return time.Now().UnixNano()
+}
+
func (s *pollServer) CheckDeadlines() {
- now := time.Now().UnixNano()
+ now := s.Now()
// TODO(rsc): This will need to be handled more efficiently,
// probably with a heap indexed by wakeup time.
mode = 'w'
}
if mode == 'r' {
- t = fd.rdeadline.value()
+ t = fd.rdeadline
} else {
- t = fd.wdeadline.value()
+ t = fd.wdeadline
}
if t > 0 {
if t <= now {
s.Lock()
defer s.Unlock()
for {
- var timeout int64 // nsec to wait for or 0 for none
- if s.deadline > 0 {
- timeout = s.deadline - time.Now().UnixNano()
- if timeout <= 0 {
+ var t = s.deadline
+ if t > 0 {
+ t = t - s.Now()
+ if t <= 0 {
s.CheckDeadlines()
continue
}
}
- fd, mode, err := s.poll.WaitFD(s, timeout)
+ fd, mode, err := s.poll.WaitFD(s, t)
if err != nil {
print("pollServer WaitFD: ", err.Error(), "\n")
return
}
defer fd.decref()
for {
- if fd.rdeadline.expired() {
- err = errTimeout
- break
+ if fd.rdeadline > 0 {
+ if time.Now().UnixNano() >= fd.rdeadline {
+ err = errTimeout
+ break
+ }
}
n, err = syscall.Read(int(fd.sysfd), p)
if err != nil {
}
defer fd.decref()
for {
- if fd.rdeadline.expired() {
- err = errTimeout
- break
+ if fd.rdeadline > 0 {
+ if time.Now().UnixNano() >= fd.rdeadline {
+ err = errTimeout
+ break
+ }
}
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
if err != nil {
}
defer fd.decref()
for {
- if fd.rdeadline.expired() {
- err = errTimeout
- break
+ if fd.rdeadline > 0 {
+ if time.Now().UnixNano() >= fd.rdeadline {
+ err = errTimeout
+ break
+ }
}
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
if err != nil {
- // TODO(dfc) should n and oobn be set to 0
+ // TODO(dfc) should n and oobn be set to nil
if err == syscall.EAGAIN {
if err = fd.pollServer.WaitRead(fd); err == nil {
continue
return err
}
-func (fd *netFD) Write(p []byte) (nn int, err error) {
+func (fd *netFD) Write(p []byte) (int, error) {
fd.wio.Lock()
defer fd.wio.Unlock()
if err := fd.incref(false); err != nil {
return 0, err
}
defer fd.decref()
+ var err error
+ nn := 0
for {
- if fd.wdeadline.expired() {
- err = errTimeout
- break
+ if fd.wdeadline > 0 {
+ if time.Now().UnixNano() >= fd.wdeadline {
+ err = errTimeout
+ break
+ }
}
var n int
n, err = syscall.Write(int(fd.sysfd), p[nn:])
}
defer fd.decref()
for {
- if fd.wdeadline.expired() {
- err = errTimeout
- break
+ if fd.wdeadline > 0 {
+ if time.Now().UnixNano() >= fd.wdeadline {
+ err = errTimeout
+ break
+ }
}
err = syscall.Sendto(fd.sysfd, p, 0, sa)
if err == syscall.EAGAIN {
}
defer fd.decref()
for {
- if fd.wdeadline.expired() {
- err = errTimeout
- break
+ if fd.wdeadline > 0 {
+ if time.Now().UnixNano() >= fd.wdeadline {
+ err = errTimeout
+ break
+ }
}
err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
errnoc [2]chan error // read/write submit or cancel operation errors
closec chan bool // used by Close to cancel pending IO
- // serialize access to Read and Write methods
- rio, wio sync.Mutex
-
- // read and write deadlines
- rdeadline, wdeadline deadline
-}
-
-// deadline is a number of nanoseconds since 1970 or 0, if no deadline is set.
-// For compatability, deadline has the same method set as fd_unix.go, but
-// does not use atomic operations as it is not known if data races exist on
-// these values.
-// TODO(dfc,brainman) when we get a windows race builder, revisit this.
-type deadline int64
-
-func (d *deadline) expired() bool {
- t := d.value()
- return t > 0 && time.Now().UnixNano() >= t
-}
-
-func (d *deadline) value() int64 {
- return int64(*d)
-}
-
-func (d *deadline) set(v int64) {
- *d = deadline(v)
-}
-
-func (d *deadline) setTime(t time.Time) {
- if t.IsZero() {
- d.set(0)
- } else {
- d.set(t.UnixNano())
- }
+ // owned by client
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline int64
+ wio sync.Mutex
}
func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
defer fd.rio.Unlock()
var o readOp
o.Init(fd, buf, 'r')
- n, err := iosrv.ExecIO(&o, fd.rdeadline.value())
+ n, err := iosrv.ExecIO(&o, fd.rdeadline)
if err == nil && n == 0 {
err = io.EOF
}
var o readFromOp
o.Init(fd, buf, 'r')
o.rsan = int32(unsafe.Sizeof(o.rsa))
- n, err = iosrv.ExecIO(&o, fd.rdeadline.value())
+ n, err = iosrv.ExecIO(&o, fd.rdeadline)
if err != nil {
return 0, nil, err
}
defer fd.wio.Unlock()
var o writeOp
o.Init(fd, buf, 'w')
- return iosrv.ExecIO(&o, fd.wdeadline.value())
+ return iosrv.ExecIO(&o, fd.wdeadline)
}
// WriteTo to network.
var o writeToOp
o.Init(fd, buf, 'w')
o.sa = sa
- return iosrv.ExecIO(&o, fd.wdeadline.value())
+ return iosrv.ExecIO(&o, fd.wdeadline)
}
// Accept new network connections.
var o acceptOp
o.Init(fd, 'r')
o.newsock = s
- _, err = iosrv.ExecIO(&o, fd.rdeadline.value())
+ _, err = iosrv.ExecIO(&o, fd.rdeadline)
if err != nil {
closesocket(s)
return nil, err
if n == 0 && err1 == nil {
break
}
- if err1 == syscall.EAGAIN {
+ if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
if err1 = c.pollServer.WaitWrite(c); err1 == nil {
continue
}
if n == 0 && err1 == nil {
break
}
- if err1 == syscall.EAGAIN {
+ if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
if err1 = c.pollServer.WaitWrite(c); err1 == nil {
continue
}
}
if ursa != nil {
- fd.wdeadline.setTime(deadline)
+ if !deadline.IsZero() {
+ fd.wdeadline = deadline.UnixNano()
+ }
if err = fd.connect(ursa); err != nil {
closesocket(s)
fd.Close()
return nil, err
}
fd.isConnected = true
- fd.wdeadline.set(0)
+ fd.wdeadline = 0
}
lsa, _ := syscall.Getsockname(s)
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
}
-// TODO(dfc) these unused error returns could be removed
-
func setReadDeadline(fd *netFD, t time.Time) error {
- fd.rdeadline.setTime(t)
+ if t.IsZero() {
+ fd.rdeadline = 0
+ } else {
+ fd.rdeadline = t.UnixNano()
+ }
return nil
}
func setWriteDeadline(fd *netFD, t time.Time) error {
- fd.wdeadline.setTime(t)
+ if t.IsZero() {
+ fd.wdeadline = 0
+ } else {
+ fd.wdeadline = t.UnixNano()
+ }
return nil
}
func setDeadline(fd *netFD, t time.Time) error {
- setReadDeadline(fd, t)
- setWriteDeadline(fd, t)
- return nil
+ if err := setReadDeadline(fd, t); err != nil {
+ return err
+ }
+ return setWriteDeadline(fd, t)
}
func setKeepAlive(fd *netFD, keepalive bool) error {