diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-17 14:20:29 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-17 14:20:29 +0000 |
commit | c6d6367f848cfd8381aba41e035c5e7e873667c5 (patch) | |
tree | a218e98243463fc27f5053b4444e2544c63cd57a /libgo/go/os/pipe_test.go | |
parent | 9bff0086915f544fa648ea81131f035cb9ce79a4 (diff) | |
download | gcc-c6d6367f848cfd8381aba41e035c5e7e873667c5.tar.gz |
libgo: update to Go1.10beta2 release
Reviewed-on: https://go-review.googlesource.com/87897
From-SVN: r256794
Diffstat (limited to 'libgo/go/os/pipe_test.go')
-rw-r--r-- | libgo/go/os/pipe_test.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/libgo/go/os/pipe_test.go b/libgo/go/os/pipe_test.go index 9d79d84575d..aad6c27f1b1 100644 --- a/libgo/go/os/pipe_test.go +++ b/libgo/go/os/pipe_test.go @@ -10,6 +10,7 @@ package os_test import ( "fmt" "internal/testenv" + "io" "io/ioutil" "os" osexec "os/exec" @@ -17,6 +18,7 @@ import ( "runtime" "strconv" "strings" + "sync" "syscall" "testing" "time" @@ -220,3 +222,86 @@ func TestReadNonblockingFd(t *testing.T) { t.Errorf("child process failed: %v", err) } } + +func TestCloseWithBlockingReadByNewFile(t *testing.T) { + var p [2]int + err := syscall.Pipe(p[:]) + if err != nil { + t.Fatal(err) + } + // os.NewFile returns a blocking mode file. + testCloseWithBlockingRead(t, os.NewFile(uintptr(p[0]), "reader"), os.NewFile(uintptr(p[1]), "writer")) +} + +func TestCloseWithBlockingReadByFd(t *testing.T) { + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + // Calling Fd will put the file into blocking mode. + _ = r.Fd() + testCloseWithBlockingRead(t, r, w) +} + +// Test that we don't let a blocking read prevent a close. +func testCloseWithBlockingRead(t *testing.T, r, w *os.File) { + defer r.Close() + defer w.Close() + + c1, c2 := make(chan bool), make(chan bool) + var wg sync.WaitGroup + + wg.Add(1) + go func(c chan bool) { + defer wg.Done() + // Give the other goroutine a chance to enter the Read + // or Write call. This is sloppy but the test will + // pass even if we close before the read/write. + time.Sleep(20 * time.Millisecond) + + if err := r.Close(); err != nil { + t.Error(err) + } + close(c) + }(c1) + + wg.Add(1) + go func(c chan bool) { + defer wg.Done() + var b [1]byte + _, err := r.Read(b[:]) + close(c) + if err == nil { + t.Error("I/O on closed pipe unexpectedly succeeded") + } + if err != io.EOF { + t.Errorf("got %v, expected io.EOF", err) + } + }(c2) + + for c1 != nil || c2 != nil { + select { + case <-c1: + c1 = nil + // r.Close has completed, but the blocking Read + // is hanging. Close the writer to unblock it. + w.Close() + case <-c2: + c2 = nil + case <-time.After(1 * time.Second): + switch { + case c1 != nil && c2 != nil: + t.Error("timed out waiting for Read and Close") + w.Close() + case c1 != nil: + t.Error("timed out waiting for Close") + case c2 != nil: + t.Error("timed out waiting for Read") + default: + t.Error("impossible case") + } + } + } + + wg.Wait() +} |