diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-04-13 15:04:20 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-04-14 22:35:19 +0000 |
commit | 75f499e3a0e8830efb861c9ba6ca61bc03583962 (patch) | |
tree | 264a1cd5bdefbaad88afdf51744d65aab41cba86 | |
parent | a55645fa3481413b335561924d8fa626ce440ad4 (diff) | |
download | go-75f499e3a0e8830efb861c9ba6ca61bc03583962.tar.gz go-75f499e3a0e8830efb861c9ba6ca61bc03583962.zip |
os/exec: create extra threads when starting a subprocess
TestExtraFiles seems to be flaky on GNU/Linux systems when using cgo
because creating a new thread will call malloc which can create a new
arena which can open a file to see how many processors there are.
Try to avoid the flake by creating several new threads at process
startup time.
For #25628
Change-Id: Ie781acdbba475d993c39782fe172cf7f29a05b24
Reviewed-on: https://go-review.googlesource.com/c/go/+/228099
Reviewed-by: Bryan C. Mills <bcmills@google.com>
-rw-r--r-- | src/os/exec/exec_linux_test.go | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/os/exec/exec_linux_test.go b/src/os/exec/exec_linux_test.go new file mode 100644 index 0000000000..6f850204d6 --- /dev/null +++ b/src/os/exec/exec_linux_test.go @@ -0,0 +1,45 @@ +// Copyright 2020 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 linux,cgo + +// On systems that use glibc, calling malloc can create a new arena, +// and creating a new arena can read /sys/devices/system/cpu/online. +// If we are using cgo, we will call malloc when creating a new thread. +// That can break TestExtraFiles if we create a new thread that creates +// a new arena and opens the /sys file while we are checking for open +// file descriptors. Work around the problem by creating threads up front. +// See issue 25628. + +package exec_test + +import ( + "os" + "sync" + "syscall" + "time" +) + +func init() { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + + // Start some threads. 10 is arbitrary but intended to be enough + // to ensure that the code won't have to create any threads itself. + // In particular this should be more than the number of threads + // the garbage collector might create. + const threads = 10 + + var wg sync.WaitGroup + wg.Add(threads) + ts := syscall.NsecToTimespec((100 * time.Microsecond).Nanoseconds()) + for i := 0; i < threads; i++ { + go func() { + defer wg.Done() + syscall.Nanosleep(&ts, nil) + }() + } + wg.Wait() +} |