diff options
Diffstat (limited to 'libgo/go/net/fd_unix.go')
-rw-r--r-- | libgo/go/net/fd_unix.go | 160 |
1 files changed, 65 insertions, 95 deletions
diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go index ff498c2..6fbb9cb 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. @@ -36,16 +36,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 } 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 +64,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) 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 +96,27 @@ 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) - go func() { - select { - case <-cancel: - // Force the runtime's poller to immediately give - // up waiting for writability. - fd.setWriteDeadline(aLongTimeAgo) - case <-done: - } - }() - } + + // Wait for the goroutine converting context.Done into a write timeout + // to exist, otherwise our caller might cancel the context and + // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial. + done := make(chan bool) // must be unbuffered + defer func() { done <- true }() + go func() { + select { + case <-ctx.Done(): + // Force the runtime's poller to immediately give + // up waiting for writability. + fd.setWriteDeadline(aLongTimeAgo) + <-done + case <-done: + } + }() + for { // Performing multiple connect system calls on a // non-blocking socket under Unix variants does not @@ -124,10 +126,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 +141,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 +160,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,7 +201,15 @@ 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 } for { @@ -247,7 +217,7 @@ func (fd *netFD) Read(p []byte) (n int, 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 } } @@ -266,7 +236,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 +244,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 +263,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 +271,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,7 +290,7 @@ 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 { @@ -333,7 +303,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 +326,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 +352,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 +381,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 +393,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 +442,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 |