| // Copyright 2018 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. | |
| //go:build !plan9 && !windows && !js | |
| // +build !plan9,!windows,!js | |
| package runtime_test | |
| import ( | |
| "os/exec" | |
| "syscall" | |
| "testing" | |
| "time" | |
| ) | |
| // Issue #27250. Spurious wakeups to pthread_cond_timedwait_relative_np | |
| // shouldn't cause semasleep to retry with the same timeout which would | |
| // cause indefinite spinning. | |
| func TestSpuriousWakeupsNeverHangSemasleep(t *testing.T) { | |
| if *flagQuick { | |
| t.Skip("-quick") | |
| } | |
| exe, err := buildTestProg(t, "testprog") | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| start := time.Now() | |
| cmd := exec.Command(exe, "After1") | |
| if err := cmd.Start(); err != nil { | |
| t.Fatalf("Failed to start command: %v", err) | |
| } | |
| doneCh := make(chan error, 1) | |
| go func() { | |
| doneCh <- cmd.Wait() | |
| }() | |
| // With the repro running, we can continuously send to it | |
| // a non-terminal signal such as SIGIO, to spuriously | |
| // wakeup pthread_cond_timedwait_relative_np. | |
| unfixedTimer := time.NewTimer(2 * time.Second) | |
| for { | |
| select { | |
| case <-time.After(200 * time.Millisecond): | |
| // Send the pesky signal that toggles spinning | |
| // indefinitely if #27520 is not fixed. | |
| cmd.Process.Signal(syscall.SIGIO) | |
| case <-unfixedTimer.C: | |
| t.Error("Program failed to return on time and has to be killed, issue #27520 still exists") | |
| cmd.Process.Signal(syscall.SIGKILL) | |
| return | |
| case err := <-doneCh: | |
| if err != nil { | |
| t.Fatalf("The program returned but unfortunately with an error: %v", err) | |
| } | |
| if time.Since(start) < 100*time.Millisecond { | |
| t.Fatalf("The program stopped too quickly.") | |
| } | |
| return | |
| } | |
| } | |
| } |