diff options
Diffstat (limited to 'libgo/go/runtime/crash_unix_test.go')
-rw-r--r-- | libgo/go/runtime/crash_unix_test.go | 100 |
1 files changed, 85 insertions, 15 deletions
diff --git a/libgo/go/runtime/crash_unix_test.go b/libgo/go/runtime/crash_unix_test.go index b4b015e09de..7ce5bb207d1 100644 --- a/libgo/go/runtime/crash_unix_test.go +++ b/libgo/go/runtime/crash_unix_test.go @@ -15,9 +15,11 @@ import ( "os/exec" "path/filepath" "runtime" - "strings" + "sync" "syscall" "testing" + "time" + "unsafe" ) // sigquit is the signal to send to kill a hanging testdata program. @@ -33,6 +35,29 @@ func init() { } } +func TestBadOpen(t *testing.T) { + // make sure we get the correct error code if open fails. Same for + // read/write/close on the resulting -1 fd. See issue 10052. + nonfile := []byte("/notreallyafile") + fd := runtime.Open(&nonfile[0], 0, 0) + if fd != -1 { + t.Errorf("open(%q)=%d, want -1", nonfile, fd) + } + var buf [32]byte + r := runtime.Read(-1, unsafe.Pointer(&buf[0]), int32(len(buf))) + if got, want := r, -int32(syscall.EBADF); got != want { + t.Errorf("read()=%d, want %d", got, want) + } + w := runtime.Write(^uintptr(0), unsafe.Pointer(&buf[0]), int32(len(buf))) + if got, want := w, -int32(syscall.EBADF); got != want { + t.Errorf("write()=%d, want %d", got, want) + } + c := runtime.Close(-1) + if c != -1 { + t.Errorf("close()=%d, want -1", c) + } +} + func TestCrashDumpsAllThreads(t *testing.T) { if *flagQuick { t.Skip("-quick") @@ -53,8 +78,6 @@ func TestCrashDumpsAllThreads(t *testing.T) { testenv.MustHaveGoBuild(t) - checkStaleRuntime(t) - t.Parallel() dir, err := ioutil.TempDir("", "go-build") @@ -76,18 +99,17 @@ func TestCrashDumpsAllThreads(t *testing.T) { cmd = exec.Command(filepath.Join(dir, "a.exe")) cmd = testenv.CleanCmdEnv(cmd) - cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") - - // Set GOGC=off. Because of golang.org/issue/10958, the tight - // loops in the test program are not preemptible. If GC kicks - // in, it may lock up and prevent main from saying it's ready. - newEnv := []string{} - for _, s := range cmd.Env { - if !strings.HasPrefix(s, "GOGC=") { - newEnv = append(newEnv, s) - } - } - cmd.Env = append(newEnv, "GOGC=off") + cmd.Env = append(cmd.Env, + "GOTRACEBACK=crash", + // Set GOGC=off. Because of golang.org/issue/10958, the tight + // loops in the test program are not preemptible. If GC kicks + // in, it may lock up and prevent main from saying it's ready. + "GOGC=off", + // Set GODEBUG=asyncpreemptoff=1. If a thread is preempted + // when it receives SIGQUIT, it won't show the expected + // stack trace. See issue 35356. + "GODEBUG=asyncpreemptoff=1", + ) var outbuf bytes.Buffer cmd.Stdout = &outbuf @@ -288,3 +310,51 @@ func TestSignalDuringExec(t *testing.T) { t.Fatalf("want %s, got %s\n", want, output) } } + +func TestSignalM(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("no signalM for gccgo") + } + + r, w, errno := runtime.Pipe() + if errno != 0 { + t.Fatal(syscall.Errno(errno)) + } + defer func() { + runtime.Close(r) + runtime.Close(w) + }() + runtime.Closeonexec(r) + runtime.Closeonexec(w) + + var want, got int64 + var wg sync.WaitGroup + ready := make(chan *runtime.M) + wg.Add(1) + go func() { + runtime.LockOSThread() + want, got = runtime.WaitForSigusr1(r, w, func(mp *runtime.M) { + ready <- mp + }) + runtime.UnlockOSThread() + wg.Done() + }() + waitingM := <-ready + runtime.SendSigusr1(waitingM) + + timer := time.AfterFunc(time.Second, func() { + // Write 1 to tell WaitForSigusr1 that we timed out. + bw := byte(1) + if n := runtime.Write(uintptr(w), unsafe.Pointer(&bw), 1); n != 1 { + t.Errorf("pipe write failed: %d", n) + } + }) + defer timer.Stop() + + wg.Wait() + if got == -1 { + t.Fatal("signalM signal not received") + } else if want != got { + t.Fatalf("signal sent to M %d, but received on M %d", want, got) + } +} |