| // 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 |
| |
| 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 |
| } |
| } |
| } |