summaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/bufio/bufio.go17
-rw-r--r--src/pkg/bufio/bufio_test.go22
-rw-r--r--src/pkg/runtime/proc.c2
-rw-r--r--src/pkg/runtime/time.goc5
-rw-r--r--src/pkg/syscall/rlimit_linux_test.go41
-rw-r--r--src/pkg/syscall/syscall_linux_386.go4
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go4
-rw-r--r--src/pkg/time/sleep_test.go20
8 files changed, 105 insertions, 10 deletions
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index df3501f2c..10e12d42b 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -585,23 +585,28 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
}
var m int
for {
+ if b.Available() == 0 {
+ if err1 := b.Flush(); err1 != nil {
+ return n, err1
+ }
+ }
m, err = r.Read(b.buf[b.n:])
if m == 0 {
break
}
b.n += m
n += int64(m)
- if b.Available() == 0 {
- if err1 := b.Flush(); err1 != nil {
- return n, err1
- }
- }
if err != nil {
break
}
}
if err == io.EOF {
- err = nil
+ // If we filled the buffer exactly, flush pre-emptively.
+ if b.Available() == 0 {
+ err = b.Flush()
+ } else {
+ err = nil
+ }
}
return n, err
}
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 79ed0f178..9fcbfda68 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -847,6 +847,10 @@ func TestWriterReadFrom(t *testing.T) {
t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input))
continue
}
+ if err := w.Flush(); err != nil {
+ t.Errorf("Flush returned %v", err)
+ continue
+ }
if got, want := b.String(), string(input); got != want {
t.Errorf("ws[%d], rs[%d]:\ngot %q\nwant %q\n", wi, ri, got, want)
}
@@ -1003,6 +1007,24 @@ func TestReaderClearError(t *testing.T) {
}
}
+// Test for golang.org/issue/5947
+func TestWriterReadFromWhileFull(t *testing.T) {
+ buf := new(bytes.Buffer)
+ w := NewWriterSize(buf, 10)
+
+ // Fill buffer exactly.
+ n, err := w.Write([]byte("0123456789"))
+ if n != 10 || err != nil {
+ t.Fatalf("Write returned (%v, %v), want (10, nil)", n, err)
+ }
+
+ // Use ReadFrom to read in some data.
+ n2, err := w.ReadFrom(strings.NewReader("abcdef"))
+ if n2 != 6 || err != nil {
+ t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n, err)
+ }
+}
+
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
r io.Reader
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 31876b62a..5734509e0 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -1371,6 +1371,8 @@ runtime·exitsyscall(void)
runtime·unlock(&runtime·sched);
if(p) {
acquirep(p);
+ m->p->tick++;
+ g->status = Grunning;
g->gcstack = (uintptr)nil;
g->gcsp = (uintptr)nil;
return;
diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc
index 6de989f51..be0c1f83d 100644
--- a/src/pkg/runtime/time.goc
+++ b/src/pkg/runtime/time.goc
@@ -131,6 +131,11 @@ runtime·deltimer(Timer *t)
{
int32 i;
+ // Dereference t so that any panic happens before the lock is held.
+ // Discard result, because t might be moving in the heap.
+ i = t->i;
+ USED(i);
+
runtime·lock(&timers);
// t may not be registered anymore and may have
diff --git a/src/pkg/syscall/rlimit_linux_test.go b/src/pkg/syscall/rlimit_linux_test.go
new file mode 100644
index 000000000..4ec720e93
--- /dev/null
+++ b/src/pkg/syscall/rlimit_linux_test.go
@@ -0,0 +1,41 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall_test
+
+import (
+ "syscall"
+ "testing"
+)
+
+func TestRlimit(t *testing.T) {
+ var rlimit, zero syscall.Rlimit
+ err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Getrlimit: save failed: %v", err)
+ }
+ if zero == rlimit {
+ t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
+ }
+ set := rlimit
+ set.Cur = set.Max - 1
+ err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
+ if err != nil {
+ t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
+ }
+ var get syscall.Rlimit
+ err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
+ if err != nil {
+ t.Fatalf("Getrlimit: get failed: %v", err)
+ }
+ set = rlimit
+ set.Cur = set.Max - 1
+ if set != get {
+ t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
+ }
+ err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
+ }
+}
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index a0ded43dc..a61695676 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -78,7 +78,7 @@ const rlimInf32 = ^uint32(0)
const rlimInf64 = ^uint64(0)
func Getrlimit(resource int, rlim *Rlimit) (err error) {
- err = prlimit(0, resource, rlim, nil)
+ err = prlimit(0, resource, nil, rlim)
if err != ENOSYS {
return err
}
@@ -106,7 +106,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
func Setrlimit(resource int, rlim *Rlimit) (err error) {
- err = prlimit(0, resource, nil, rlim)
+ err = prlimit(0, resource, rlim, nil)
if err != ENOSYS {
return err
}
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 7839d5288..4aadf9e4c 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -119,7 +119,7 @@ const rlimInf32 = ^uint32(0)
const rlimInf64 = ^uint64(0)
func Getrlimit(resource int, rlim *Rlimit) (err error) {
- err = prlimit(0, resource, rlim, nil)
+ err = prlimit(0, resource, nil, rlim)
if err != ENOSYS {
return err
}
@@ -147,7 +147,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
func Setrlimit(resource int, rlim *Rlimit) (err error) {
- err = prlimit(0, resource, nil, rlim)
+ err = prlimit(0, resource, rlim, nil)
if err != ENOSYS {
return err
}
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index 1322f0611..603adc9b8 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -314,3 +314,23 @@ func TestOverflowSleep(t *testing.T) {
t.Fatalf("negative timeout didn't fire")
}
}
+
+// Test that a panic while deleting a timer does not leave
+// the timers mutex held, deadlocking a ticker.Stop in a defer.
+func TestIssue5745(t *testing.T) {
+ ticker := NewTicker(Hour)
+ defer func() {
+ // would deadlock here before the fix due to
+ // lock taken before the segfault.
+ ticker.Stop()
+
+ if r := recover(); r == nil {
+ t.Error("Expected panic, but none happened.")
+ }
+ }()
+
+ // cause a panic due to a segfault
+ var timer *Timer
+ timer.Stop()
+ t.Error("Should be unreachable.")
+}