summaryrefslogtreecommitdiff
path: root/libgo/go/net/fd_unix.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/fd_unix.go')
-rw-r--r--libgo/go/net/fd_unix.go184
1 files changed, 94 insertions, 90 deletions
diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go
index ff498c2bff..9bc5ebc7a0 100644
--- a/libgo/go/net/fd_unix.go
+++ b/libgo/go/net/fd_unix.go
@@ -7,12 +7,12 @@
package net
import (
+ "context"
"io"
"os"
"runtime"
"sync/atomic"
"syscall"
- "time"
)
// Network file descriptor.
@@ -24,11 +24,15 @@ type netFD struct {
sysfd int
family int
sotype int
+ isStream bool
isConnected bool
net string
laddr Addr
raddr Addr
+ // writev cache.
+ iovecs *[]syscall.Iovec
+
// wait server
pd pollDesc
}
@@ -36,16 +40,12 @@ type netFD struct {
func sysInit() {
}
-func dial(network string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
- return dialer(deadline)
-}
-
func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
- return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil
+ return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
}
func (fd *netFD) init() error {
- if err := fd.pd.Init(fd); err != nil {
+ if err := fd.pd.init(fd); err != nil {
return err
}
return nil
@@ -68,15 +68,17 @@ func (fd *netFD) name() string {
return fd.net + ":" + ls + "->" + rs
}
-func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
+func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret error) {
// Do not need to call fd.writeLock here,
// because fd is not yet accessible to user,
// so no concurrent operations are possible.
switch err := connectFunc(fd.sysfd, ra); err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
case nil, syscall.EISCONN:
- if !deadline.IsZero() && deadline.Before(time.Now()) {
- return errTimeout
+ select {
+ case <-ctx.Done():
+ return mapErr(ctx.Err())
+ default:
}
if err := fd.init(); err != nil {
return err
@@ -98,23 +100,50 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
if err := fd.init(); err != nil {
return err
}
- if !deadline.IsZero() {
+ if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
fd.setWriteDeadline(deadline)
defer fd.setWriteDeadline(noDeadline)
}
- if cancel != nil {
- done := make(chan bool)
- defer close(done)
+
+ // Start the "interrupter" goroutine, if this context might be canceled.
+ // (The background context cannot)
+ //
+ // The interrupter goroutine waits for the context to be done and
+ // interrupts the dial (by altering the fd's write deadline, which
+ // wakes up waitWrite).
+ if ctx != context.Background() {
+ // Wait for the interrupter goroutine to exit before returning
+ // from connect.
+ done := make(chan struct{})
+ interruptRes := make(chan error)
+ defer func() {
+ close(done)
+ if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
+ // The interrupter goroutine called setWriteDeadline,
+ // but the connect code below had returned from
+ // waitWrite already and did a successful connect (ret
+ // == nil). Because we've now poisoned the connection
+ // by making it unwritable, don't return a successful
+ // dial. This was issue 16523.
+ ret = ctxErr
+ fd.Close() // prevent a leak
+ }
+ }()
go func() {
select {
- case <-cancel:
- // Force the runtime's poller to immediately give
- // up waiting for writability.
+ case <-ctx.Done():
+ // Force the runtime's poller to immediately give up
+ // waiting for writability, unblocking waitWrite
+ // below.
fd.setWriteDeadline(aLongTimeAgo)
+ testHookCanceledDial()
+ interruptRes <- ctx.Err()
case <-done:
+ interruptRes <- nil
}
}()
}
+
for {
// Performing multiple connect system calls on a
// non-blocking socket under Unix variants does not
@@ -124,10 +153,10 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
// SO_ERROR socket option to see if the connection
// succeeded or failed. See issue 7474 for further
// details.
- if err := fd.pd.WaitWrite(); err != nil {
+ if err := fd.pd.waitWrite(); err != nil {
select {
- case <-cancel:
- return errCanceled
+ case <-ctx.Done():
+ return mapErr(ctx.Err())
default:
}
return err
@@ -139,7 +168,16 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
switch err := syscall.Errno(nerr); err {
case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
case syscall.Errno(0), syscall.EISCONN:
- return nil
+ if runtime.GOOS != "darwin" {
+ return nil
+ }
+ // See golang.org/issue/14548.
+ // On Darwin, multiple connect system calls on
+ // a non-blocking socket never harm SO_ERROR.
+ switch err := connectFunc(fd.sysfd, ra); err {
+ case nil, syscall.EISCONN:
+ return nil
+ }
default:
return os.NewSyscallError("getsockopt", err)
}
@@ -149,71 +187,22 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
func (fd *netFD) destroy() {
// Poller may want to unregister fd in readiness notification mechanism,
// so this must be executed before closeFunc.
- fd.pd.Close()
+ fd.pd.close()
closeFunc(fd.sysfd)
fd.sysfd = -1
runtime.SetFinalizer(fd, nil)
}
-// Add a reference to this fd.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) incref() error {
- if !fd.fdmu.Incref() {
- return errClosing
- }
- return nil
-}
-
-// Remove a reference to this FD and close if we've been asked to do so
-// (and there are no references left).
-func (fd *netFD) decref() {
- if fd.fdmu.Decref() {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for reading.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) readLock() error {
- if !fd.fdmu.RWLock(true) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for reading and remove a reference to this FD.
-func (fd *netFD) readUnlock() {
- if fd.fdmu.RWUnlock(true) {
- fd.destroy()
- }
-}
-
-// Add a reference to this fd and lock for writing.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) writeLock() error {
- if !fd.fdmu.RWLock(false) {
- return errClosing
- }
- return nil
-}
-
-// Unlock for writing and remove a reference to this FD.
-func (fd *netFD) writeUnlock() {
- if fd.fdmu.RWUnlock(false) {
- fd.destroy()
- }
-}
-
func (fd *netFD) Close() error {
- if !fd.fdmu.IncrefAndClose() {
+ if !fd.fdmu.increfAndClose() {
return errClosing
}
// Unblock any I/O. Once it all unblocks and returns,
// so that it cannot be referring to fd.sysfd anymore,
- // the final decref will close fd.sysfd. This should happen
+ // the final decref will close fd.sysfd. This should happen
// fairly quickly, since all the I/O is non-blocking, and any
// attempts to block in the pollDesc will return errClosing.
- fd.pd.Evict()
+ fd.pd.evict()
fd.decref()
return nil
}
@@ -239,15 +228,26 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
return 0, err
}
defer fd.readUnlock()
- if err := fd.pd.PrepareRead(); err != nil {
+ if len(p) == 0 {
+ // If the caller wanted a zero byte read, return immediately
+ // without trying. (But after acquiring the readLock.) Otherwise
+ // syscall.Read returns 0, nil and eofError turns that into
+ // io.EOF.
+ // TODO(bradfitz): make it wait for readability? (Issue 15735)
+ return 0, nil
+ }
+ if err := fd.pd.prepareRead(); err != nil {
return 0, err
}
+ if fd.isStream && len(p) > 1<<30 {
+ p = p[:1<<30]
+ }
for {
n, err = syscall.Read(fd.sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
}
@@ -266,7 +266,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return 0, nil, err
}
defer fd.readUnlock()
- if err := fd.pd.PrepareRead(); err != nil {
+ if err := fd.pd.prepareRead(); err != nil {
return 0, nil, err
}
for {
@@ -274,7 +274,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
if err != nil {
n = 0
if err == syscall.EAGAIN {
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
}
@@ -293,7 +293,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
return 0, 0, 0, nil, err
}
defer fd.readUnlock()
- if err := fd.pd.PrepareRead(); err != nil {
+ if err := fd.pd.prepareRead(); err != nil {
return 0, 0, 0, nil, err
}
for {
@@ -301,7 +301,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
if err != nil {
// TODO(dfc) should n and oobn be set to 0
if err == syscall.EAGAIN {
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
}
@@ -320,12 +320,16 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
return 0, err
}
defer fd.writeUnlock()
- if err := fd.pd.PrepareWrite(); err != nil {
+ if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
for {
var n int
- n, err = syscall.Write(fd.sysfd, p[nn:])
+ max := len(p)
+ if fd.isStream && max-nn > 1<<30 {
+ max = nn + 1<<30
+ }
+ n, err = syscall.Write(fd.sysfd, p[nn:max])
if n > 0 {
nn += n
}
@@ -333,7 +337,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
break
}
if err == syscall.EAGAIN {
- if err = fd.pd.WaitWrite(); err == nil {
+ if err = fd.pd.waitWrite(); err == nil {
continue
}
}
@@ -356,13 +360,13 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
return 0, err
}
defer fd.writeUnlock()
- if err := fd.pd.PrepareWrite(); err != nil {
+ if err := fd.pd.prepareWrite(); err != nil {
return 0, err
}
for {
err = syscall.Sendto(fd.sysfd, p, 0, sa)
if err == syscall.EAGAIN {
- if err = fd.pd.WaitWrite(); err == nil {
+ if err = fd.pd.waitWrite(); err == nil {
continue
}
}
@@ -382,13 +386,13 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
return 0, 0, err
}
defer fd.writeUnlock()
- if err := fd.pd.PrepareWrite(); err != nil {
+ if err := fd.pd.prepareWrite(); err != nil {
return 0, 0, err
}
for {
n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
- if err = fd.pd.WaitWrite(); err == nil {
+ if err = fd.pd.waitWrite(); err == nil {
continue
}
}
@@ -411,7 +415,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
var s int
var rsa syscall.Sockaddr
- if err = fd.pd.PrepareRead(); err != nil {
+ if err = fd.pd.prepareRead(); err != nil {
return nil, err
}
for {
@@ -423,7 +427,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
}
switch nerr.Err {
case syscall.EAGAIN:
- if err = fd.pd.WaitRead(); err == nil {
+ if err = fd.pd.waitRead(); err == nil {
continue
}
case syscall.ECONNABORTED:
@@ -472,7 +476,7 @@ func dupCloseOnExec(fd int) (newfd int, err error) {
// and fcntl there falls back (undocumented)
// to doing an ioctl instead, returning EBADF
// in this case because fd is not of the
- // expected device fd type. Treat it as
+ // expected device fd type. Treat it as
// EINVAL instead, so we fall back to the
// normal dup path.
// TODO: only do this on 10.6 if we can detect 10.6