aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2016-06-14 14:38:22 -0700
committerIan Lance Taylor <iant@golang.org>2016-06-15 15:03:48 +0000
commit26d6dc6bf8a7e5487844a63aa26a4de3afdd688e (patch)
tree48d0f94e0fcb8e330c50a1732788736a5c4ddc90
parent48cc3c4b587f9549f7426776d032da99b3ba471b (diff)
downloadgo-26d6dc6bf8a7e5487844a63aa26a4de3afdd688e.tar.gz
go-26d6dc6bf8a7e5487844a63aa26a4de3afdd688e.zip
runtime: if the test program hangs, try to get a stack trace
This is an attempt to get more information for #14809, which seems to occur rarely. Updates #14809. Change-Id: Idbeb136ceb57993644e03266622eb699d2685d02 Reviewed-on: https://go-review.googlesource.com/24110 Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com> Reviewed-by: Austin Clements <austin@google.com>
-rw-r--r--src/runtime/crash_nonunix_test.go13
-rw-r--r--src/runtime/crash_test.go44
-rw-r--r--src/runtime/crash_unix_test.go4
3 files changed, 59 insertions, 2 deletions
diff --git a/src/runtime/crash_nonunix_test.go b/src/runtime/crash_nonunix_test.go
new file mode 100644
index 0000000000..2ce995c069
--- /dev/null
+++ b/src/runtime/crash_nonunix_test.go
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+// +build windows plan9 nacl
+
+package runtime_test
+
+import "os"
+
+// sigquit is the signal to send to kill a hanging testdata program.
+// On Unix we send SIGQUIT, but on non-Unix we only have os.Kill.
+var sigquit = os.Kill
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index ec740990dc..0b4a1f538a 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -5,6 +5,7 @@
package runtime_test
import (
+ "bytes"
"fmt"
"internal/testenv"
"io/ioutil"
@@ -13,9 +14,11 @@ import (
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"sync"
"testing"
+ "time"
)
var toRemove []string
@@ -65,8 +68,45 @@ func runTestProg(t *testing.T, binary, name string) string {
if err != nil {
t.Fatal(err)
}
- got, _ := testEnv(exec.Command(exe, name)).CombinedOutput()
- return string(got)
+
+ cmd := testEnv(exec.Command(exe, name))
+ var b bytes.Buffer
+ cmd.Stdout = &b
+ cmd.Stderr = &b
+ if err := cmd.Start(); err != nil {
+ t.Fatalf("starting %s %s: %v", binary, name, err)
+ }
+
+ // If the process doesn't complete within 1 minute,
+ // assume it is hanging and kill it to get a stack trace.
+ p := cmd.Process
+ done := make(chan bool)
+ go func() {
+ scale := 1
+ // This GOARCH/GOOS test is copied from cmd/dist/test.go.
+ // TODO(iant): Have cmd/dist update the environment variable.
+ if runtime.GOARCH == "arm" || runtime.GOOS == "windows" {
+ scale = 2
+ }
+ if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
+ if sc, err := strconv.Atoi(s); err == nil {
+ scale = sc
+ }
+ }
+
+ select {
+ case <-done:
+ case <-time.After(time.Duration(scale) * time.Minute):
+ p.Signal(sigquit)
+ }
+ }()
+
+ if err := cmd.Wait(); err != nil {
+ t.Logf("%s %s exit status: %v", binary, name, err)
+ }
+ close(done)
+
+ return b.String()
}
func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) {
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index 0a79661f1e..6e4d04bd20 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -19,6 +19,10 @@ import (
"testing"
)
+// sigquit is the signal to send to kill a hanging testdata program.
+// Send SIGQUIT to get a stack trace.
+var sigquit = syscall.SIGQUIT
+
func TestCrashDumpsAllThreads(t *testing.T) {
switch runtime.GOOS {
case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":