]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: regression test for semasleep indefinite hang
authorEmmanuel T Odeke <emmanuel@orijtech.com>
Wed, 12 Sep 2018 18:22:42 +0000 (12:22 -0600)
committerEmmanuel Odeke <emm.odeke@gmail.com>
Thu, 13 Sep 2018 03:07:59 +0000 (03:07 +0000)
A regression test in which: for a program that invokes semasleep,
we send non-terminal signals such as SIGIO.
Since the signal wakes up pthread_cond_timedwait_relative_np,
after CL 133655, we should only re-spin for the amount of
time left, instead of re-spinning with the original duration
which would cause an indefinite spin.

Updates #27520

Change-Id: I744a6d04cf8923bc4e13649446aff5e42b7de5d8
Reviewed-on: https://go-review.googlesource.com/135015
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/runtime/semasleep_test.go [new file with mode: 0644]

diff --git a/src/runtime/semasleep_test.go b/src/runtime/semasleep_test.go
new file mode 100644 (file)
index 0000000..4a8b4db
--- /dev/null
@@ -0,0 +1,88 @@
+// 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.
+
+//+build !nacl,!windows,!js
+
+package runtime_test
+
+import (
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "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) {
+       testenv.MustHaveGoBuild(t)
+       tempDir, err := ioutil.TempDir("", "issue-27250")
+       if err != nil {
+               t.Fatalf("Failed to create the temp directory: %v", err)
+       }
+       defer os.RemoveAll(tempDir)
+
+       repro := `
+    package main
+
+    import "time"
+
+    func main() {
+        <-time.After(1 * time.Second)
+    }
+    `
+       mainPath := filepath.Join(tempDir, "main.go")
+       if err := ioutil.WriteFile(mainPath, []byte(repro), 0644); err != nil {
+               t.Fatalf("Failed to create temp file for repro.go: %v", err)
+       }
+       binaryPath := filepath.Join(tempDir, "binary")
+
+       // Build the binary so that we can send the signal to its PID.
+       out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", binaryPath, mainPath).CombinedOutput()
+       if err != nil {
+               t.Fatalf("Failed to compile the binary: err: %v\nOutput: %s\n", err, out)
+       }
+       if err := os.Chmod(binaryPath, 0755); err != nil {
+               t.Fatalf("Failed to chmod binary: %v", err)
+       }
+
+       // Now run the binary.
+       cmd := exec.Command(binaryPath)
+       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)
+                       }
+                       return
+               }
+       }
+}