github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/runtime/semasleep_test.go (about)

     1  // Copyright 2018 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 !nacl,!plan9,!windows,!js
     6  
     7  package runtime_test
     8  
     9  import (
    10  	"internal/testenv"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"syscall"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  // Issue #27250. Spurious wakeups to pthread_cond_timedwait_relative_np
    21  // shouldn't cause semasleep to retry with the same timeout which would
    22  // cause indefinite spinning.
    23  func TestSpuriousWakeupsNeverHangSemasleep(t *testing.T) {
    24  	testenv.MustHaveGoBuild(t)
    25  	tempDir, err := ioutil.TempDir("", "issue-27250")
    26  	if err != nil {
    27  		t.Fatalf("Failed to create the temp directory: %v", err)
    28  	}
    29  	defer os.RemoveAll(tempDir)
    30  
    31  	repro := `
    32      package main
    33  
    34      import "time"
    35  
    36      func main() {
    37          <-time.After(1 * time.Second)
    38      }
    39      `
    40  	mainPath := filepath.Join(tempDir, "main.go")
    41  	if err := ioutil.WriteFile(mainPath, []byte(repro), 0644); err != nil {
    42  		t.Fatalf("Failed to create temp file for repro.go: %v", err)
    43  	}
    44  	binaryPath := filepath.Join(tempDir, "binary")
    45  
    46  	// Build the binary so that we can send the signal to its PID.
    47  	out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", binaryPath, mainPath).CombinedOutput()
    48  	if err != nil {
    49  		t.Fatalf("Failed to compile the binary: err: %v\nOutput: %s\n", err, out)
    50  	}
    51  	if err := os.Chmod(binaryPath, 0755); err != nil {
    52  		t.Fatalf("Failed to chmod binary: %v", err)
    53  	}
    54  
    55  	// Now run the binary.
    56  	cmd := exec.Command(binaryPath)
    57  	if err := cmd.Start(); err != nil {
    58  		t.Fatalf("Failed to start command: %v", err)
    59  	}
    60  	doneCh := make(chan error, 1)
    61  	go func() {
    62  		doneCh <- cmd.Wait()
    63  	}()
    64  
    65  	// With the repro running, we can continuously send to it
    66  	// a non-terminal signal such as SIGIO, to spuriously
    67  	// wakeup pthread_cond_timedwait_relative_np.
    68  	unfixedTimer := time.NewTimer(2 * time.Second)
    69  	for {
    70  		select {
    71  		case <-time.After(200 * time.Millisecond):
    72  			// Send the pesky signal that toggles spinning
    73  			// indefinitely if #27520 is not fixed.
    74  			cmd.Process.Signal(syscall.SIGIO)
    75  
    76  		case <-unfixedTimer.C:
    77  			t.Error("Program failed to return on time and has to be killed, issue #27520 still exists")
    78  			cmd.Process.Signal(syscall.SIGKILL)
    79  			return
    80  
    81  		case err := <-doneCh:
    82  			if err != nil {
    83  				t.Fatalf("The program returned but unfortunately with an error: %v", err)
    84  			}
    85  			return
    86  		}
    87  	}
    88  }