diff options
Diffstat (limited to 'libgo/go/net/fd_unix.go')
-rw-r--r-- | libgo/go/net/fd_unix.go | 184 |
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 |