]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: if the test program hangs, try to get a stack trace
authorIan Lance Taylor <iant@golang.org>
Tue, 14 Jun 2016 21:38:22 +0000 (14:38 -0700)
committerIan Lance Taylor <iant@golang.org>
Wed, 15 Jun 2016 15:03:48 +0000 (15:03 +0000)
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>
src/runtime/crash_nonunix_test.go [new file with mode: 0644]
src/runtime/crash_test.go
src/runtime/crash_unix_test.go

diff --git a/src/runtime/crash_nonunix_test.go b/src/runtime/crash_nonunix_test.go
new file mode 100644 (file)
index 0000000..2ce995c
--- /dev/null
@@ -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
index ec740990dc4eace57900a917acc7918de3ba9775..0b4a1f538a947872666a6e1d039805e21de45f25 100644 (file)
@@ -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) {
index 0a79661f1ead831c3b3652a07afea9715a9cbb49..6e4d04bd200d0fe949ddb953f9ed6f7389e9d266 100644 (file)
@@ -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":