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