github.com/ronhuafeng/gofrontend@v0.0.0-20220715151246-ff23266b8bc5/libgo/misc/cgo/test/issue18146.go (about) 1 // Copyright 2016 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 //go:build !windows 6 // +build !windows 7 8 // Issue 18146: pthread_create failure during syscall.Exec. 9 10 package cgotest 11 12 import ( 13 "bytes" 14 "crypto/md5" 15 "os" 16 "os/exec" 17 "runtime" 18 "syscall" 19 "testing" 20 "time" 21 ) 22 23 func test18146(t *testing.T) { 24 if testing.Short() { 25 t.Skip("skipping in short mode") 26 } 27 28 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { 29 t.Skipf("skipping flaky test on %s; see golang.org/issue/18202", runtime.GOOS) 30 } 31 32 if runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" { 33 t.Skipf("skipping on %s", runtime.GOARCH) 34 } 35 36 attempts := 1000 37 threads := 4 38 39 // Restrict the number of attempts based on RLIMIT_NPROC. 40 // Tediously, RLIMIT_NPROC was left out of the syscall package, 41 // probably because it is not in POSIX.1, so we define it here. 42 // It is not defined on Solaris. 43 var nproc int 44 setNproc := true 45 switch runtime.GOOS { 46 default: 47 setNproc = false 48 case "aix": 49 nproc = 9 50 case "linux": 51 nproc = 6 52 case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd": 53 nproc = 7 54 } 55 if setNproc { 56 var rlim syscall.Rlimit 57 if syscall.Getrlimit(nproc, &rlim) == nil { 58 max := int(rlim.Cur) / (threads + 5) 59 if attempts > max { 60 t.Logf("lowering attempts from %d to %d for RLIMIT_NPROC", attempts, max) 61 attempts = max 62 } 63 } 64 } 65 66 if os.Getenv("test18146") == "exec" { 67 runtime.GOMAXPROCS(1) 68 for n := threads; n > 0; n-- { 69 go func() { 70 for { 71 _ = md5.Sum([]byte("Hello, !")) 72 } 73 }() 74 } 75 runtime.GOMAXPROCS(threads) 76 argv := append(os.Args, "-test.run=NoSuchTestExists") 77 if err := syscall.Exec(os.Args[0], argv, os.Environ()); err != nil { 78 t.Fatal(err) 79 } 80 } 81 82 var cmds []*exec.Cmd 83 defer func() { 84 for _, cmd := range cmds { 85 cmd.Process.Kill() 86 } 87 }() 88 89 args := append(append([]string(nil), os.Args[1:]...), "-test.run=Test18146") 90 for n := attempts; n > 0; n-- { 91 cmd := exec.Command(os.Args[0], args...) 92 cmd.Env = append(os.Environ(), "test18146=exec") 93 buf := bytes.NewBuffer(nil) 94 cmd.Stdout = buf 95 cmd.Stderr = buf 96 if err := cmd.Start(); err != nil { 97 // We are starting so many processes that on 98 // some systems (problem seen on Darwin, 99 // Dragonfly, OpenBSD) the fork call will fail 100 // with EAGAIN. 101 if pe, ok := err.(*os.PathError); ok { 102 err = pe.Err 103 } 104 if se, ok := err.(syscall.Errno); ok && (se == syscall.EAGAIN || se == syscall.EMFILE) { 105 time.Sleep(time.Millisecond) 106 continue 107 } 108 109 t.Error(err) 110 return 111 } 112 cmds = append(cmds, cmd) 113 } 114 115 failures := 0 116 for _, cmd := range cmds { 117 err := cmd.Wait() 118 if err == nil { 119 continue 120 } 121 122 t.Errorf("syscall.Exec failed: %v\n%s", err, cmd.Stdout) 123 failures++ 124 } 125 126 if failures > 0 { 127 t.Logf("Failed %v of %v attempts.", failures, len(cmds)) 128 } 129 }