github.com/aloncn/graphics-go@v0.0.1/src/runtime/crash_unix_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package runtime_test 8 9 import ( 10 "bytes" 11 "internal/testenv" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "runtime" 17 "strings" 18 "syscall" 19 "testing" 20 ) 21 22 func TestCrashDumpsAllThreads(t *testing.T) { 23 switch runtime.GOOS { 24 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": 25 default: 26 t.Skipf("skipping; not supported on %v", runtime.GOOS) 27 } 28 29 // We don't use executeTest because we need to kill the 30 // program while it is running. 31 32 testenv.MustHaveGoBuild(t) 33 34 checkStaleRuntime(t) 35 36 dir, err := ioutil.TempDir("", "go-build") 37 if err != nil { 38 t.Fatalf("failed to create temp directory: %v", err) 39 } 40 defer os.RemoveAll(dir) 41 42 if err := ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte(crashDumpsAllThreadsSource), 0666); err != nil { 43 t.Fatalf("failed to create Go file: %v", err) 44 } 45 46 cmd := exec.Command("go", "build", "-o", "a.exe") 47 cmd.Dir = dir 48 out, err := testEnv(cmd).CombinedOutput() 49 if err != nil { 50 t.Fatalf("building source: %v\n%s", err, out) 51 } 52 53 cmd = exec.Command(filepath.Join(dir, "a.exe")) 54 cmd = testEnv(cmd) 55 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") 56 57 // Set GOGC=off. Because of golang.org/issue/10958, the tight 58 // loops in the test program are not preemptible. If GC kicks 59 // in, it may lock up and prevent main from saying it's ready. 60 newEnv := []string{} 61 for _, s := range cmd.Env { 62 if !strings.HasPrefix(s, "GOGC=") { 63 newEnv = append(newEnv, s) 64 } 65 } 66 cmd.Env = append(newEnv, "GOGC=off") 67 68 var outbuf bytes.Buffer 69 cmd.Stdout = &outbuf 70 cmd.Stderr = &outbuf 71 72 rp, wp, err := os.Pipe() 73 if err != nil { 74 t.Fatal(err) 75 } 76 cmd.ExtraFiles = []*os.File{wp} 77 78 if err := cmd.Start(); err != nil { 79 t.Fatalf("starting program: %v", err) 80 } 81 82 if err := wp.Close(); err != nil { 83 t.Logf("closing write pipe: %v", err) 84 } 85 if _, err := rp.Read(make([]byte, 1)); err != nil { 86 t.Fatalf("reading from pipe: %v", err) 87 } 88 89 if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil { 90 t.Fatalf("signal: %v", err) 91 } 92 93 // No point in checking the error return from Wait--we expect 94 // it to fail. 95 cmd.Wait() 96 97 // We want to see a stack trace for each thread. 98 // Before https://golang.org/cl/2811 running threads would say 99 // "goroutine running on other thread; stack unavailable". 100 out = outbuf.Bytes() 101 n := bytes.Count(out, []byte("main.loop(")) 102 if n != 4 { 103 t.Errorf("found %d instances of main.loop; expected 4", n) 104 t.Logf("%s", out) 105 } 106 } 107 108 const crashDumpsAllThreadsSource = ` 109 package main 110 111 import ( 112 "fmt" 113 "os" 114 "runtime" 115 ) 116 117 func main() { 118 const count = 4 119 runtime.GOMAXPROCS(count + 1) 120 121 chans := make([]chan bool, count) 122 for i := range chans { 123 chans[i] = make(chan bool) 124 go loop(i, chans[i]) 125 } 126 127 // Wait for all the goroutines to start executing. 128 for _, c := range chans { 129 <-c 130 } 131 132 // Tell our parent that all the goroutines are executing. 133 if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil { 134 fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err) 135 os.Exit(2) 136 } 137 138 select {} 139 } 140 141 func loop(i int, c chan bool) { 142 close(c) 143 for { 144 for j := 0; j < 0x7fffffff; j++ { 145 } 146 } 147 } 148 ` 149 150 func TestSignalExitStatus(t *testing.T) { 151 testenv.MustHaveGoBuild(t) 152 switch runtime.GOOS { 153 case "netbsd", "solaris": 154 t.Skipf("skipping on %s; see https://golang.org/issue/14063", runtime.GOOS) 155 } 156 exe, err := buildTestProg(t, "testprog") 157 if err != nil { 158 t.Fatal(err) 159 } 160 err = testEnv(exec.Command(exe, "SignalExitStatus")).Run() 161 if err == nil { 162 t.Error("test program succeeded unexpectedly") 163 } else if ee, ok := err.(*exec.ExitError); !ok { 164 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err) 165 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok { 166 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys()) 167 } else if !ws.Signaled() || ws.Signal() != syscall.SIGTERM { 168 t.Errorf("got %v; expected SIGTERM", ee) 169 } 170 } 171 172 func TestSignalIgnoreSIGTRAP(t *testing.T) { 173 output := runTestProg(t, "testprognet", "SignalIgnoreSIGTRAP") 174 want := "OK\n" 175 if output != want { 176 t.Fatalf("want %s, got %s\n", want, output) 177 } 178 }