aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/io
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-01-14 00:05:42 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-01-14 00:05:42 +0000
commitc2047754c300b68c05d65faa8dc2925fe67b71b4 (patch)
treee183ae81a1f48a02945cb6de463a70c5be1b06f6 /libgo/go/io
parent829afb8f05602bb31c9c597b24df7377fed4f059 (diff)
downloadgcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.zip
gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.gz
gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.bz2
libgo: update to Go 1.8 release candidate 1
Compiler changes: * Change map assignment to use mapassign and assign value directly. * Change string iteration to use decoderune, faster for ASCII strings. * Change makeslice to take int, and use makeslice64 for larger values. * Add new noverflow field to hmap struct used for maps. Unresolved problems, to be fixed later: * Commented out test in go/types/sizes_test.go that doesn't compile. * Commented out reflect.TestStructOf test for padding after zero-sized field. Reviewed-on: https://go-review.googlesource.com/35231 gotools/: Updates for Go 1.8rc1. * Makefile.am (go_cmd_go_files): Add bug.go. (s-zdefaultcc): Write defaultPkgConfig. * Makefile.in: Rebuild. From-SVN: r244456
Diffstat (limited to 'libgo/go/io')
-rw-r--r--libgo/go/io/io.go8
-rw-r--r--libgo/go/io/ioutil/ioutil.go9
-rw-r--r--libgo/go/io/ioutil/tempfile.go5
-rw-r--r--libgo/go/io/ioutil/tempfile_test.go16
-rw-r--r--libgo/go/io/multi.go11
-rw-r--r--libgo/go/io/multi_test.go60
-rw-r--r--libgo/go/io/pipe.go19
-rw-r--r--libgo/go/io/pipe_test.go12
8 files changed, 120 insertions, 20 deletions
diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go
index 19d0ae5..9e4b865 100644
--- a/libgo/go/io/io.go
+++ b/libgo/go/io/io.go
@@ -402,11 +402,10 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
break
}
}
- if er == EOF {
- break
- }
if er != nil {
- err = er
+ if er != EOF {
+ err = er
+ }
break
}
}
@@ -421,6 +420,7 @@ func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
// A LimitedReader reads from R but limits the amount of
// data returned to just N bytes. Each call to Read
// updates N to reflect the new amount remaining.
+// Read returns EOF when N <= 0 or when the underlying R returns EOF.
type LimitedReader struct {
R Reader // underlying reader
N int64 // max bytes remaining
diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go
index 8ecbb2d..f0da616 100644
--- a/libgo/go/io/ioutil/ioutil.go
+++ b/libgo/go/io/ioutil/ioutil.go
@@ -88,13 +88,6 @@ func WriteFile(filename string, data []byte, perm os.FileMode) error {
return err
}
-// byName implements sort.Interface.
-type byName []os.FileInfo
-
-func (f byName) Len() int { return len(f) }
-func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
-func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-
// ReadDir reads the directory named by dirname and returns
// a list of directory entries sorted by filename.
func ReadDir(dirname string) ([]os.FileInfo, error) {
@@ -107,7 +100,7 @@ func ReadDir(dirname string) ([]os.FileInfo, error) {
if err != nil {
return nil, err
}
- sort.Sort(byName(list))
+ sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
return list, nil
}
diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go
index 42718cc..e5e315c 100644
--- a/libgo/go/io/ioutil/tempfile.go
+++ b/libgo/go/io/ioutil/tempfile.go
@@ -90,6 +90,11 @@ func TempDir(dir, prefix string) (name string, err error) {
}
continue
}
+ if os.IsNotExist(err) {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ return "", err
+ }
+ }
if err == nil {
name = try
}
diff --git a/libgo/go/io/ioutil/tempfile_test.go b/libgo/go/io/ioutil/tempfile_test.go
index d2a132a..6a70aed 100644
--- a/libgo/go/io/ioutil/tempfile_test.go
+++ b/libgo/go/io/ioutil/tempfile_test.go
@@ -51,3 +51,19 @@ func TestTempDir(t *testing.T) {
}
}
}
+
+// test that we return a nice error message if the dir argument to TempDir doesn't
+// exist (or that it's empty and os.TempDir doesn't exist)
+func TestTempDir_BadDir(t *testing.T) {
+ dir, err := TempDir("", "TestTempDir_BadDir")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ badDir := filepath.Join(dir, "not-exist")
+ _, err = TempDir(badDir, "foo")
+ if pe, ok := err.(*os.PathError); !ok || !os.IsNotExist(err) || pe.Path != badDir {
+ t.Errorf("TempDir error = %#v; want PathError for path %q satisifying os.IsNotExist", err, badDir)
+ }
+}
diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go
index 3a9d036..d784846 100644
--- a/libgo/go/io/multi.go
+++ b/libgo/go/io/multi.go
@@ -4,13 +4,19 @@
package io
+type eofReader struct{}
+
+func (eofReader) Read([]byte) (int, error) {
+ return 0, EOF
+}
+
type multiReader struct {
readers []Reader
}
func (mr *multiReader) Read(p []byte) (n int, err error) {
for len(mr.readers) > 0 {
- // Optimization to flatten nested multiReaders (Issue 13558)
+ // Optimization to flatten nested multiReaders (Issue 13558).
if len(mr.readers) == 1 {
if r, ok := mr.readers[0].(*multiReader); ok {
mr.readers = r.readers
@@ -19,6 +25,9 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
}
n, err = mr.readers[0].Read(p)
if err == EOF {
+ // Use eofReader instead of nil to avoid nil panic
+ // after performing flatten (Issue 18232).
+ mr.readers[0] = eofReader{} // permit earlier GC
mr.readers = mr.readers[1:]
}
if n > 0 || err != EOF {
diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go
index 447e7f5..70f2a48 100644
--- a/libgo/go/io/multi_test.go
+++ b/libgo/go/io/multi_test.go
@@ -14,6 +14,7 @@ import (
"runtime"
"strings"
"testing"
+ "time"
)
func TestMultiReader(t *testing.T) {
@@ -212,7 +213,7 @@ func (b byteAndEOFReader) Read(p []byte) (n int, err error) {
return 1, EOF
}
-// In Go 1.7, this yielded bytes forever.
+// This used to yield bytes forever; issue 16795.
func TestMultiReaderSingleByteWithEOF(t *testing.T) {
got, err := ioutil.ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10))
if err != nil {
@@ -235,3 +236,60 @@ func TestMultiReaderFinalEOF(t *testing.T) {
t.Errorf("got %v, %v; want 1, EOF", n, err)
}
}
+
+func TestMultiReaderFreesExhaustedReaders(t *testing.T) {
+ if runtime.Compiler == "gccgo" {
+ t.Skip("skipping finalizer test on gccgo with conservative GC")
+ }
+
+ var mr Reader
+ closed := make(chan struct{})
+ {
+ buf1 := bytes.NewReader([]byte("foo"))
+ buf2 := bytes.NewReader([]byte("bar"))
+ mr = MultiReader(buf1, buf2)
+ runtime.SetFinalizer(buf1, func(*bytes.Reader) {
+ close(closed)
+ })
+ }
+
+ buf := make([]byte, 4)
+ if n, err := ReadFull(mr, buf); err != nil || string(buf) != "foob" {
+ t.Fatalf(`ReadFull = %d (%q), %v; want 3, "foo", nil`, n, buf[:n], err)
+ }
+
+ runtime.GC()
+ select {
+ case <-closed:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout waiting for collection of buf1")
+ }
+
+ if n, err := ReadFull(mr, buf[:2]); err != nil || string(buf[:2]) != "ar" {
+ t.Fatalf(`ReadFull = %d (%q), %v; want 2, "ar", nil`, n, buf[:n], err)
+ }
+}
+
+func TestInterleavedMultiReader(t *testing.T) {
+ r1 := strings.NewReader("123")
+ r2 := strings.NewReader("45678")
+
+ mr1 := MultiReader(r1, r2)
+ mr2 := MultiReader(mr1)
+
+ buf := make([]byte, 4)
+
+ // Have mr2 use mr1's []Readers.
+ // Consume r1 (and clear it for GC to handle) and consume part of r2.
+ n, err := ReadFull(mr2, buf)
+ if got := string(buf[:n]); got != "1234" || err != nil {
+ t.Errorf(`ReadFull(mr2) = (%q, %v), want ("1234", nil)`, got, err)
+ }
+
+ // Consume the rest of r2 via mr1.
+ // This should not panic even though mr2 cleared r1.
+ n, err = ReadFull(mr1, buf)
+ if got := string(buf[:n]); got != "5678" || err != nil {
+ t.Errorf(`ReadFull(mr1) = (%q, %v), want ("5678", nil)`, got, err)
+ }
+}
diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go
index 7e98cd2..b6e7755 100644
--- a/libgo/go/io/pipe.go
+++ b/libgo/go/io/pipe.go
@@ -85,6 +85,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
}
if p.werr != nil {
err = ErrClosedPipe
+ break
}
p.wwait.Wait()
}
@@ -148,7 +149,7 @@ type PipeWriter struct {
}
// Write implements the standard Write interface:
-// it writes data to the pipe, blocking until readers
+// it writes data to the pipe, blocking until one or more readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is ErrClosedPipe.
@@ -175,11 +176,17 @@ func (w *PipeWriter) CloseWithError(err error) error {
// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
-// Reads on one end are matched with writes on the other,
-// copying data directly between the two; there is no internal buffering.
-// It is safe to call Read and Write in parallel with each other or with
-// Close. Close will complete once pending I/O is done. Parallel calls to
-// Read, and parallel calls to Write, are also safe:
+//
+// Reads and Writes on the pipe are matched one to one
+// except when multiple Reads are needed to consume a single Write.
+// That is, each Write to the PipeWriter blocks until it has satisfied
+// one or more Reads from the PipeReader that fully consume
+// the written data.
+// The data is copied directly from the Write to the corresponding
+// Read (or Reads); there is no internal buffering.
+//
+// It is safe to call Read and Write in parallel with each other or with Close.
+// Parallel calls to Read and parallel calls to Write are also safe:
// the individual calls will be gated sequentially.
func Pipe() (*PipeReader, *PipeWriter) {
p := new(pipe)
diff --git a/libgo/go/io/pipe_test.go b/libgo/go/io/pipe_test.go
index b16e653..95930e8 100644
--- a/libgo/go/io/pipe_test.go
+++ b/libgo/go/io/pipe_test.go
@@ -247,6 +247,18 @@ func TestPipeWriteClose(t *testing.T) {
}
}
+// Test close on Write side during Write.
+func TestPipeWriteClose2(t *testing.T) {
+ c := make(chan int, 1)
+ _, w := Pipe()
+ go delayClose(t, w, c, pipeTest{})
+ n, err := w.Write(make([]byte, 64))
+ <-c
+ if n != 0 || err != ErrClosedPipe {
+ t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
+ }
+}
+
func TestWriteEmpty(t *testing.T) {
r, w := Pipe()
go func() {