]> Cypherpunks repositories - gostls13.git/commitdiff
os, net, internal/poll: return consistent error for closed socket
authorIan Lance Taylor <iant@golang.org>
Fri, 7 Apr 2017 22:53:19 +0000 (15:53 -0700)
committerIan Lance Taylor <iant@golang.org>
Wed, 26 Apr 2017 00:03:14 +0000 (00:03 +0000)
In the past we returned "use of closed network connection" when using
a closed network descriptor in some way. In CL 36799 that was changed
to return "use of closed file or network connection". Because programs
have no access to a value of this error type (see issue #4373) they
resort to doing direct string comparisons (see issue #19252). This CL
restores the old error string so that we don't break programs
unnecessarily with the 1.9 release.

This adds a test to the net package for the expected string.

For symmetry check that the os package returns the expected error,
which for os already exists as os.ErrClosed.

Updates #4373.
Fixed #19252.

Change-Id: I5b83fd12cfa03501a077cad9336499b819f4a38b
Reviewed-on: https://go-review.googlesource.com/39997
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
19 files changed:
src/internal/poll/fd.go
src/internal/poll/fd_mutex.go
src/internal/poll/fd_plan9.go
src/internal/poll/fd_poll_nacl.go
src/internal/poll/fd_poll_runtime.go
src/internal/poll/fd_posix_test.go
src/internal/poll/fd_unix.go
src/internal/poll/fd_windows.go
src/internal/poll/sendfile_bsd.go
src/internal/poll/sendfile_linux.go
src/internal/poll/sendfile_solaris.go
src/internal/poll/writev.go
src/net/error_test.go
src/net/fd_unix.go
src/net/file_test.go
src/net/net_test.go
src/os/file.go
src/os/file_unix.go
src/os/pipe_test.go

index 3d3f36edb3ba71b05c771876a76881e2ebad21d5..f1454dba9087dccba2bfcfdc88ec384446b2b1c9 100644 (file)
@@ -11,8 +11,23 @@ package poll
 
 import "errors"
 
-// ErrClosing is returned when a descriptor is used after it has been closed.
-var ErrClosing = errors.New("use of closed file or network connection")
+// ErrNetClosing is returned when a network descriptor is used after
+// it has been closed. Keep this string consistent because of issue
+// #4373: since historically programs have not been able to detect
+// this error, they look for the string.
+var ErrNetClosing = errors.New("use of closed network connection")
+
+// ErrFileClosing is returned when a file descriptor is used after it
+// has been closed.
+var ErrFileClosing = errors.New("use of closed file")
+
+// Return the appropriate closing error based on isFile.
+func errClosing(isFile bool) error {
+       if isFile {
+               return ErrFileClosing
+       }
+       return ErrNetClosing
+}
 
 // ErrTimeout is returned for an expired deadline.
 var ErrTimeout error = &TimeoutError{}
index 38d4be248dbf11272557da12e8af8260895699a2..76174e5e9cf765ddb80d63dfc869770a650b9cce 100644 (file)
@@ -198,7 +198,7 @@ func runtime_Semrelease(sema *uint32)
 // It returns an error when fd cannot be used.
 func (fd *FD) incref() error {
        if !fd.fdmu.incref() {
-               return ErrClosing
+               return errClosing(fd.isFile)
        }
        return nil
 }
@@ -217,7 +217,7 @@ func (fd *FD) decref() error {
 // It returns an error when fd cannot be used for reading.
 func (fd *FD) readLock() error {
        if !fd.fdmu.rwlock(true) {
-               return ErrClosing
+               return errClosing(fd.isFile)
        }
        return nil
 }
@@ -235,7 +235,7 @@ func (fd *FD) readUnlock() {
 // It returns an error when fd cannot be used for writing.
 func (fd *FD) writeLock() error {
        if !fd.fdmu.rwlock(false) {
-               return ErrClosing
+               return errClosing(fd.isFile)
        }
        return nil
 }
index 574036e0bf45d722b456c16b8ae7e28290eabbd2..49590ab13c416cbc249da33024fef8accc376e9c 100644 (file)
@@ -29,6 +29,12 @@ type FD struct {
        wtimer    *time.Timer
        rtimedout atomicBool // set true when read deadline has been reached
        wtimedout atomicBool // set true when write deadline has been reached
+
+       // Whether this is a normal file.
+       // On Plan 9 we do not use this package for ordinary files,
+       // so this is always false, but the field is present because
+       // shared code in fd_mutex.go checks it.
+       isFile bool
 }
 
 // We need this to close out a file descriptor when it is unlocked,
@@ -45,7 +51,7 @@ func (fd *FD) destroy() error {
 // is in the net package.
 func (fd *FD) Close() error {
        if !fd.fdmu.increfAndClose() {
-               return ErrClosing
+               return errClosing(fd.isFile)
        }
        return nil
 }
index 45256a42d33d445b30da80200ab13f0f8c14d243..8fa75c5a265a01a266c99ea0cc8012d366d5a929 100644 (file)
@@ -25,27 +25,27 @@ func (pd *pollDesc) evict() {
        }
 }
 
-func (pd *pollDesc) prepare(mode int) error {
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
        if pd.closing {
-               return ErrClosing
+               return errClosing(isFile)
        }
        return nil
 }
 
-func (pd *pollDesc) prepareRead() error { return pd.prepare('r') }
+func (pd *pollDesc) prepareRead(isFile bool) error { return pd.prepare('r', isFile) }
 
-func (pd *pollDesc) prepareWrite() error { return pd.prepare('w') }
+func (pd *pollDesc) prepareWrite(isFile bool) error { return pd.prepare('w', isFile) }
 
-func (pd *pollDesc) wait(mode int) error {
+func (pd *pollDesc) wait(mode int, isFile bool) error {
        if pd.closing {
-               return ErrClosing
+               return errClosing(isFile)
        }
        return ErrTimeout
 }
 
-func (pd *pollDesc) waitRead() error { return pd.wait('r') }
+func (pd *pollDesc) waitRead(isFile bool) error { return pd.wait('r', isFile) }
 
-func (pd *pollDesc) waitWrite() error { return pd.wait('w') }
+func (pd *pollDesc) waitWrite(isFile bool) error { return pd.wait('w', isFile) }
 
 func (pd *pollDesc) waitCanceled(mode int) {}
 
index b1e3a84fc2b900416be201dfa726efc7051a7707..08b40c272012effe4985ef02ce7a5469968842ae 100644 (file)
@@ -62,36 +62,36 @@ func (pd *pollDesc) evict() {
        runtime_pollUnblock(pd.runtimeCtx)
 }
 
-func (pd *pollDesc) prepare(mode int) error {
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
        if pd.runtimeCtx == 0 {
                return nil
        }
        res := runtime_pollReset(pd.runtimeCtx, mode)
-       return convertErr(res)
+       return convertErr(res, isFile)
 }
 
-func (pd *pollDesc) prepareRead() error {
-       return pd.prepare('r')
+func (pd *pollDesc) prepareRead(isFile bool) error {
+       return pd.prepare('r', isFile)
 }
 
-func (pd *pollDesc) prepareWrite() error {
-       return pd.prepare('w')
+func (pd *pollDesc) prepareWrite(isFile bool) error {
+       return pd.prepare('w', isFile)
 }
 
-func (pd *pollDesc) wait(mode int) error {
+func (pd *pollDesc) wait(mode int, isFile bool) error {
        if pd.runtimeCtx == 0 {
                return errors.New("waiting for unsupported file type")
        }
        res := runtime_pollWait(pd.runtimeCtx, mode)
-       return convertErr(res)
+       return convertErr(res, isFile)
 }
 
-func (pd *pollDesc) waitRead() error {
-       return pd.wait('r')
+func (pd *pollDesc) waitRead(isFile bool) error {
+       return pd.wait('r', isFile)
 }
 
-func (pd *pollDesc) waitWrite() error {
-       return pd.wait('w')
+func (pd *pollDesc) waitWrite(isFile bool) error {
+       return pd.wait('w', isFile)
 }
 
 func (pd *pollDesc) waitCanceled(mode int) {
@@ -101,12 +101,12 @@ func (pd *pollDesc) waitCanceled(mode int) {
        runtime_pollWaitCanceled(pd.runtimeCtx, mode)
 }
 
-func convertErr(res int) error {
+func convertErr(res int, isFile bool) error {
        switch res {
        case 0:
                return nil
        case 1:
-               return ErrClosing
+               return errClosing(isFile)
        case 2:
                return ErrTimeout
        }
index edc2dcb97d077a8efd38055cc9ee52caa88194fe..cbe015edbd1205aec6ab2973f6144ee902669c3d 100644 (file)
@@ -20,17 +20,17 @@ var eofErrorTests = []struct {
 }{
        {100, nil, &FD{ZeroReadIsEOF: true}, nil},
        {100, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
-       {100, ErrClosing, &FD{ZeroReadIsEOF: true}, ErrClosing},
+       {100, ErrNetClosing, &FD{ZeroReadIsEOF: true}, ErrNetClosing},
        {0, nil, &FD{ZeroReadIsEOF: true}, io.EOF},
        {0, io.EOF, &FD{ZeroReadIsEOF: true}, io.EOF},
-       {0, ErrClosing, &FD{ZeroReadIsEOF: true}, ErrClosing},
+       {0, ErrNetClosing, &FD{ZeroReadIsEOF: true}, ErrNetClosing},
 
        {100, nil, &FD{ZeroReadIsEOF: false}, nil},
        {100, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
-       {100, ErrClosing, &FD{ZeroReadIsEOF: false}, ErrClosing},
+       {100, ErrNetClosing, &FD{ZeroReadIsEOF: false}, ErrNetClosing},
        {0, nil, &FD{ZeroReadIsEOF: false}, nil},
        {0, io.EOF, &FD{ZeroReadIsEOF: false}, io.EOF},
-       {0, ErrClosing, &FD{ZeroReadIsEOF: false}, ErrClosing},
+       {0, ErrNetClosing, &FD{ZeroReadIsEOF: false}, ErrNetClosing},
 }
 
 func TestEOFError(t *testing.T) {
index c461f04c398bc1371040f8553085d58bfde204c3..782ecd5a874d9b2d240ec5a8163b6e211e63f1af 100644 (file)
@@ -33,11 +33,23 @@ type FD struct {
        // Whether a zero byte read indicates EOF. This is false for a
        // message based socket connection.
        ZeroReadIsEOF bool
+
+       // Whether this is a file rather than a network socket.
+       isFile bool
 }
 
 // Init initializes the FD. The Sysfd field should already be set.
 // This can be called multiple times on a single FD.
-func (fd *FD) Init() error {
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file".
+func (fd *FD) Init(net string, pollable bool) error {
+       // We don't actually care about the various network types.
+       if net == "file" {
+               fd.isFile = true
+       }
+       if !pollable {
+               return nil
+       }
        return fd.pd.init(fd)
 }
 
@@ -56,13 +68,13 @@ func (fd *FD) destroy() error {
 // destroy method when there are no remaining references.
 func (fd *FD) Close() error {
        if !fd.fdmu.increfAndClose() {
-               return ErrClosing
+               return errClosing(fd.isFile)
        }
        // 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
        // fairly quickly, since all the I/O is non-blocking, and any
-       // attempts to block in the pollDesc will return ErrClosing.
+       // attempts to block in the pollDesc will return errClosing(fd.isFile).
        fd.pd.evict()
        // The call to decref will call destroy if there are no other
        // references.
@@ -99,7 +111,7 @@ func (fd *FD) Read(p []byte) (int, error) {
                // TODO(bradfitz): make it wait for readability? (Issue 15735)
                return 0, nil
        }
-       if err := fd.pd.prepareRead(); err != nil {
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
                return 0, err
        }
        if fd.IsStream && len(p) > maxRW {
@@ -110,7 +122,7 @@ func (fd *FD) Read(p []byte) (int, error) {
                if err != nil {
                        n = 0
                        if err == syscall.EAGAIN {
-                               if err = fd.pd.waitRead(); err == nil {
+                               if err = fd.pd.waitRead(fd.isFile); err == nil {
                                        continue
                                }
                        }
@@ -146,7 +158,7 @@ func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
                return 0, nil, err
        }
        defer fd.readUnlock()
-       if err := fd.pd.prepareRead(); err != nil {
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
                return 0, nil, err
        }
        for {
@@ -154,7 +166,7 @@ func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
                if err != nil {
                        n = 0
                        if err == syscall.EAGAIN {
-                               if err = fd.pd.waitRead(); err == nil {
+                               if err = fd.pd.waitRead(fd.isFile); err == nil {
                                        continue
                                }
                        }
@@ -170,7 +182,7 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er
                return 0, 0, 0, nil, err
        }
        defer fd.readUnlock()
-       if err := fd.pd.prepareRead(); err != nil {
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
                return 0, 0, 0, nil, err
        }
        for {
@@ -178,7 +190,7 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er
                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(fd.isFile); err == nil {
                                        continue
                                }
                        }
@@ -194,7 +206,7 @@ func (fd *FD) Write(p []byte) (int, error) {
                return 0, err
        }
        defer fd.writeUnlock()
-       if err := fd.pd.prepareWrite(); err != nil {
+       if err := fd.pd.prepareWrite(fd.isFile); err != nil {
                return 0, err
        }
        var nn int
@@ -211,7 +223,7 @@ func (fd *FD) Write(p []byte) (int, error) {
                        return nn, err
                }
                if err == syscall.EAGAIN {
-                       if err = fd.pd.waitWrite(); err == nil {
+                       if err = fd.pd.waitWrite(fd.isFile); err == nil {
                                continue
                        }
                }
@@ -261,13 +273,13 @@ func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
                return 0, err
        }
        defer fd.writeUnlock()
-       if err := fd.pd.prepareWrite(); err != nil {
+       if err := fd.pd.prepareWrite(fd.isFile); 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(fd.isFile); err == nil {
                                continue
                        }
                }
@@ -284,13 +296,13 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err
                return 0, 0, err
        }
        defer fd.writeUnlock()
-       if err := fd.pd.prepareWrite(); err != nil {
+       if err := fd.pd.prepareWrite(fd.isFile); 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(fd.isFile); err == nil {
                                continue
                        }
                }
@@ -308,7 +320,7 @@ func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
        }
        defer fd.readUnlock()
 
-       if err := fd.pd.prepareRead(); err != nil {
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
                return -1, nil, "", err
        }
        for {
@@ -318,7 +330,7 @@ func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
                }
                switch err {
                case syscall.EAGAIN:
-                       if err = fd.pd.waitRead(); err == nil {
+                       if err = fd.pd.waitRead(fd.isFile); err == nil {
                                continue
                        }
                case syscall.ECONNABORTED:
@@ -353,7 +365,7 @@ func (fd *FD) ReadDirent(buf []byte) (int, error) {
                if err != nil {
                        n = 0
                        if err == syscall.EAGAIN {
-                               if err = fd.pd.waitRead(); err == nil {
+                               if err = fd.pd.waitRead(fd.isFile); err == nil {
                                        continue
                                }
                        }
@@ -385,5 +397,5 @@ func (fd *FD) Fstat(s *syscall.Stat_t) error {
 
 // WaitWrite waits until data can be read from fd.
 func (fd *FD) WaitWrite() error {
-       return fd.pd.waitWrite()
+       return fd.pd.waitWrite(fd.isFile)
 }
index 4d7ec686d4eb50ab39c35d86ea2c4d9535d64fba..d312cfed7e9338586f67399c2e1fb26b2a88ec37 100644 (file)
@@ -160,7 +160,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 
        fd := o.fd
        // Notify runtime netpoll about starting IO.
-       err := fd.pd.prepare(int(o.mode))
+       err := fd.pd.prepare(int(o.mode), fd.isFile)
        if err != nil {
                return 0, err
        }
@@ -188,7 +188,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
                return 0, err
        }
        // Wait for our request to complete.
-       err = fd.pd.wait(int(o.mode))
+       err = fd.pd.wait(int(o.mode), fd.isFile)
        if err == nil {
                // All is good. Extract our IO results and return.
                if o.errno != 0 {
@@ -200,7 +200,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
        // IO is interrupted by "close" or "timeout"
        netpollErr := err
        switch netpollErr {
-       case ErrClosing, ErrTimeout:
+       case ErrNetClosing, ErrFileClosing, ErrTimeout:
                // will deal with those.
        default:
                panic("unexpected runtime.netpoll error: " + netpollErr.Error())
@@ -380,7 +380,7 @@ func (fd *FD) destroy() error {
 // the destroy method when there are no remaining references.
 func (fd *FD) Close() error {
        if !fd.fdmu.increfAndClose() {
-               return ErrClosing
+               return errClosing(fd.isFile)
        }
        // unblock pending reader and writer
        fd.pd.evict()
index 13ef205240bd0361dcd02a590a18a461f93c718a..980a75afa7fc322e8202df77ba59f30cc8f1eb51 100644 (file)
@@ -37,7 +37,7 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
                        break
                }
                if err1 == syscall.EAGAIN {
-                       if err1 = dstFD.pd.waitWrite(); err1 == nil {
+                       if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
                                continue
                        }
                }
index 4014e05bdcbc247531ed633fd0f9e11d62eb0af5..52955a19d0b4fcc89d67a85ed3143f726c691f45 100644 (file)
@@ -34,7 +34,7 @@ func SendFile(dstFD *FD, src int, remain int64) (int64, error) {
                        break
                }
                if err1 == syscall.EAGAIN {
-                       if err1 = dstFD.pd.waitWrite(); err1 == nil {
+                       if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
                                continue
                        }
                }
index 816c17cac186fee4bd09469d0de37b6553239698..2ce53232085069972f5ab23db66951cb08013718 100644 (file)
@@ -47,7 +47,7 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
                        break
                }
                if err1 == syscall.EAGAIN {
-                       if err1 = dstFD.pd.waitWrite(); err1 == nil {
+                       if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
                                continue
                        }
                }
index 574e0de989c67db2bb48049b3e32644c66c690a2..4bf8804e217c1119a5cca0fa067ce2c35f566e74 100644 (file)
@@ -18,7 +18,7 @@ func (fd *FD) Writev(v *[][]byte) (int64, error) {
                return 0, err
        }
        defer fd.writeUnlock()
-       if err := fd.pd.prepareWrite(); err != nil {
+       if err := fd.pd.prepareWrite(fd.isFile); err != nil {
                return 0, err
        }
 
@@ -65,7 +65,7 @@ func (fd *FD) Writev(v *[][]byte) (int64, error) {
                n += int64(wrote)
                consume(v, int64(wrote))
                if e0 == syscall.EAGAIN {
-                       if err = fd.pd.waitWrite(); err == nil {
+                       if err = fd.pd.waitWrite(fd.isFile); err == nil {
                                continue
                        }
                } else if e0 != 0 {
index 021968b0797546af8eb85ad1550ca80e9aa16a7b..9791e6fe4defb61e86367e43e05fb1d923329be2 100644 (file)
@@ -13,6 +13,7 @@ import (
        "net/internal/socktest"
        "os"
        "runtime"
+       "strings"
        "testing"
        "time"
 )
@@ -98,7 +99,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case errCanceled, poll.ErrClosing, errMissingAddress, errNoSuitableAddress,
+       case errCanceled, poll.ErrNetClosing, errMissingAddress, errNoSuitableAddress,
                context.DeadlineExceeded, context.Canceled:
                return nil
        }
@@ -433,7 +434,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case poll.ErrClosing, poll.ErrTimeout:
+       case poll.ErrNetClosing, poll.ErrTimeout:
                return nil
        }
        return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -475,7 +476,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case errCanceled, poll.ErrClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+       case errCanceled, poll.ErrNetClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
                return nil
        }
        return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -490,11 +491,21 @@ third:
 // parseCloseError parses nestedErr and reports whether it is a valid
 // error value from Close functions.
 // It returns nil when nestedErr is valid.
-func parseCloseError(nestedErr error) error {
+func parseCloseError(nestedErr error, isShutdown bool) error {
        if nestedErr == nil {
                return nil
        }
 
+       // Because historically we have not exported the error that we
+       // return for an operation on a closed network connection,
+       // there are programs that test for the exact error string.
+       // Verify that string here so that we don't break those
+       // programs unexpectedly. See issues #4373 and #19252.
+       want := "use of closed network connection"
+       if !isShutdown && !strings.Contains(nestedErr.Error(), want) {
+               return fmt.Errorf("error string %q does not contain expected string %q", nestedErr, want)
+       }
+
        switch err := nestedErr.(type) {
        case *OpError:
                if err := err.isValid(); err != nil {
@@ -518,7 +529,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case poll.ErrClosing:
+       case poll.ErrNetClosing:
                return nil
        }
        return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -548,23 +559,23 @@ func TestCloseError(t *testing.T) {
 
        for i := 0; i < 3; i++ {
                err = c.(*TCPConn).CloseRead()
-               if perr := parseCloseError(err); perr != nil {
+               if perr := parseCloseError(err, true); perr != nil {
                        t.Errorf("#%d: %v", i, perr)
                }
        }
        for i := 0; i < 3; i++ {
                err = c.(*TCPConn).CloseWrite()
-               if perr := parseCloseError(err); perr != nil {
+               if perr := parseCloseError(err, true); perr != nil {
                        t.Errorf("#%d: %v", i, perr)
                }
        }
        for i := 0; i < 3; i++ {
                err = c.Close()
-               if perr := parseCloseError(err); perr != nil {
+               if perr := parseCloseError(err, false); perr != nil {
                        t.Errorf("#%d: %v", i, perr)
                }
                err = ln.Close()
-               if perr := parseCloseError(err); perr != nil {
+               if perr := parseCloseError(err, false); perr != nil {
                        t.Errorf("#%d: %v", i, perr)
                }
        }
@@ -577,7 +588,7 @@ func TestCloseError(t *testing.T) {
 
        for i := 0; i < 3; i++ {
                err = pc.Close()
-               if perr := parseCloseError(err); perr != nil {
+               if perr := parseCloseError(err, false); perr != nil {
                        t.Errorf("#%d: %v", i, perr)
                }
        }
@@ -614,7 +625,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case poll.ErrClosing, poll.ErrTimeout:
+       case poll.ErrNetClosing, poll.ErrTimeout:
                return nil
        }
        return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -693,7 +704,7 @@ second:
                goto third
        }
        switch nestedErr {
-       case poll.ErrClosing:
+       case poll.ErrNetClosing:
                return nil
        }
        return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
index 505a1f1a02a7d366d94b3a883abce7fc16c16048..1122ee4dbee43a2e208dab9e3de0c498f1e463e4 100644 (file)
@@ -43,7 +43,7 @@ func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
 }
 
 func (fd *netFD) init() error {
-       return fd.pfd.Init()
+       return fd.pfd.Init(fd.net, true)
 }
 
 func (fd *netFD) setAddr(laddr, raddr Addr) {
@@ -75,7 +75,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
                        return mapErr(ctx.Err())
                default:
                }
-               if err := fd.pfd.Init(); err != nil {
+               if err := fd.pfd.Init(fd.net, true); err != nil {
                        return err
                }
                runtime.KeepAlive(fd)
@@ -93,7 +93,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret erro
        default:
                return os.NewSyscallError("connect", err)
        }
-       if err := fd.pfd.Init(); err != nil {
+       if err := fd.pfd.Init(fd.net, true); err != nil {
                return err
        }
        if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
index 6566ce21a1f6fd7c26fbf9733cfcf99bee4b86c4..abf8b3a6995f9d92797d180ce072e104495a95ee 100644 (file)
@@ -90,7 +90,7 @@ func TestFileConn(t *testing.T) {
                        f, err = c1.File()
                }
                if err := c1.Close(); err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, false); perr != nil {
                                t.Error(perr)
                        }
                        t.Error(err)
@@ -256,7 +256,7 @@ func TestFilePacketConn(t *testing.T) {
                        f, err = c1.File()
                }
                if err := c1.Close(); err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, false); perr != nil {
                                t.Error(perr)
                        }
                        t.Error(err)
index 9a9a7e552c4c444fb17a4cf65494a5b03f7caaff..024505e7c628a6cf15ca2ecaeecba1625173676c 100644 (file)
@@ -54,7 +54,7 @@ func TestCloseRead(t *testing.T) {
                        err = c.CloseRead()
                }
                if err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, true); perr != nil {
                                t.Error(perr)
                        }
                        t.Fatal(err)
@@ -94,7 +94,7 @@ func TestCloseWrite(t *testing.T) {
                        err = c.CloseWrite()
                }
                if err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, true); perr != nil {
                                t.Error(perr)
                        }
                        t.Error(err)
@@ -139,7 +139,7 @@ func TestCloseWrite(t *testing.T) {
                        err = c.CloseWrite()
                }
                if err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, true); perr != nil {
                                t.Error(perr)
                        }
                        t.Fatal(err)
@@ -184,7 +184,7 @@ func TestConnClose(t *testing.T) {
                defer c.Close()
 
                if err := c.Close(); err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, false); perr != nil {
                                t.Error(perr)
                        }
                        t.Fatal(err)
@@ -215,7 +215,7 @@ func TestListenerClose(t *testing.T) {
 
                dst := ln.Addr().String()
                if err := ln.Close(); err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, false); perr != nil {
                                t.Error(perr)
                        }
                        t.Fatal(err)
@@ -269,7 +269,7 @@ func TestPacketConnClose(t *testing.T) {
                defer c.Close()
 
                if err := c.Close(); err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, false); perr != nil {
                                t.Error(perr)
                        }
                        t.Fatal(err)
@@ -292,7 +292,7 @@ func TestListenCloseListen(t *testing.T) {
                }
                addr := ln.Addr().String()
                if err := ln.Close(); err != nil {
-                       if perr := parseCloseError(err); perr != nil {
+                       if perr := parseCloseError(err, false); perr != nil {
                                t.Error(perr)
                        }
                        t.Fatal(err)
index e5a3efa8843b368d8836d477f78ff2460e287d83..271197a90ea2adb5333219be8213e5a29e7d25ec 100644 (file)
@@ -102,7 +102,7 @@ func (f *File) Read(b []byte) (n int, err error) {
        }
        n, e := f.read(b)
        if e != nil {
-               if e == poll.ErrClosing {
+               if e == poll.ErrFileClosing {
                        e = ErrClosed
                }
                if e == io.EOF {
index 6850ff7a56623e623fd0bf669eda3ab7a119273c..847316492b34f6cf16f630b570ce94dff3f6bd51 100644 (file)
@@ -87,20 +87,18 @@ func newFile(fd uintptr, name string, pollable bool) *File {
                pollable = false
        }
 
-       if pollable {
-               if err := f.pfd.Init(); err != nil {
-                       // An error here indicates a failure to register
-                       // with the netpoll system. That can happen for
-                       // a file descriptor that is not supported by
-                       // epoll/kqueue; for example, disk files on
-                       // GNU/Linux systems. We assume that any real error
-                       // will show up in later I/O.
-               } else {
-                       // We successfully registered with netpoll, so put
-                       // the file into nonblocking mode.
-                       if err := syscall.SetNonblock(fdi, true); err == nil {
-                               f.nonblock = true
-                       }
+       if err := f.pfd.Init("file", pollable); err != nil {
+               // An error here indicates a failure to register
+               // with the netpoll system. That can happen for
+               // a file descriptor that is not supported by
+               // epoll/kqueue; for example, disk files on
+               // GNU/Linux systems. We assume that any real error
+               // will show up in later I/O.
+       } else if pollable {
+               // We successfully registered with netpoll, so put
+               // the file into nonblocking mode.
+               if err := syscall.SetNonblock(fdi, true); err == nil {
+                       f.nonblock = true
                }
        }
 
index 032173b7592f8519e29d3cf31c7faa871070a37d..a7bd41ff40c2221a426b09e2ec1524f2a03fb3ad 100644 (file)
@@ -144,6 +144,8 @@ func TestClosedPipeRace(t *testing.T) {
                t.Error("Read of closed pipe unexpectedly succeeded")
        } else if pe, ok := err.(*os.PathError); !ok {
                t.Errorf("Read of closed pipe returned unexpected error type %T; expected os.PathError", pe)
+       } else if pe.Err != os.ErrClosed {
+               t.Errorf("got error %q but expected %q", pe.Err, os.ErrClosed)
        } else {
                t.Logf("Read returned expected error %q", err)
        }