]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/cgo/internal/test/issue18146.go
misc/cgo/test: add cgo build constraints
[gostls13.git] / src / cmd / cgo / internal / test / issue18146.go
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         "os/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=NoSuchTestExists")
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 }