aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan C. Mills <bcmills@google.com>2023-08-22 17:33:50 -0400
committerGopher Robot <gobot@golang.org>2023-08-30 21:32:23 +0000
commit0a9582163c3392ea0e51cadec9ee5fc5c46cfeee (patch)
treeec3c2b7c97704ae86002eca5555213cd5730c4fc
parent91a4e74b98179f63a27dbff1ad68ddd0ed64363a (diff)
downloadgo-0a9582163c3392ea0e51cadec9ee5fc5c46cfeee.tar.gz
go-0a9582163c3392ea0e51cadec9ee5fc5c46cfeee.zip
[release-branch.go1.21] cmd/go: retry ETXTBSY errors when running test binaries
An ETXTBSY error when starting a test binary is almost certainly caused by the race reported in #22315. That race will resolve quickly on its own, so we should just retry the command instead of reporting a spurious failure. Fixes #62222. Updates #62221. Change-Id: I408f3eaa7ab5d7efbc7a2b1c8bea3dbc459fc794 Reviewed-on: https://go-review.googlesource.com/c/go/+/522015 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Bryan Mills <bcmills@google.com> Auto-Submit: Bryan Mills <bcmills@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> (cherry picked from commit 4dc2564933146efc411efad16b662589306744d1) Reviewed-on: https://go-review.googlesource.com/c/go/+/522176 Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
-rw-r--r--src/cmd/go/internal/test/test.go114
-rw-r--r--src/cmd/go/internal/test/test_nonunix.go12
-rw-r--r--src/cmd/go/internal/test/test_unix.go16
-rw-r--r--src/cmd/go/testdata/script/test_compile_multi_pkg.txt6
4 files changed, 101 insertions, 47 deletions
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 7df6f421d6..3bce0265f8 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -1363,65 +1363,87 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
ctx, cancel := context.WithTimeout(ctx, testKillTimeout)
defer cancel()
- cmd := exec.CommandContext(ctx, args[0], args[1:]...)
- cmd.Dir = a.Package.Dir
-
- env := slices.Clip(cfg.OrigEnv)
- env = base.AppendPATH(env)
- env = base.AppendPWD(env, cmd.Dir)
- cmd.Env = env
- if addToEnv != "" {
- cmd.Env = append(cmd.Env, addToEnv)
- }
-
- cmd.Stdout = stdout
- cmd.Stderr = stdout
-
- // If there are any local SWIG dependencies, we want to load
- // the shared library from the build directory.
- if a.Package.UsesSwig() {
- env := cmd.Env
- found := false
- prefix := "LD_LIBRARY_PATH="
- for i, v := range env {
- if strings.HasPrefix(v, prefix) {
- env[i] = v + ":."
- found = true
- break
- }
- }
- if !found {
- env = append(env, "LD_LIBRARY_PATH=.")
- }
- cmd.Env = env
- }
+ // Now we're ready to actually run the command.
+ //
+ // If the -o flag is set, or if at some point we change cmd/go to start
+ // copying test executables into the build cache, we may run into spurious
+ // ETXTBSY errors on Unix platforms (see https://go.dev/issue/22315).
+ //
+ // Since we know what causes those, and we know that they should resolve
+ // quickly (the ETXTBSY error will resolve as soon as the subprocess
+ // holding the descriptor open reaches its 'exec' call), we retry them
+ // in a loop.
var (
+ cmd *exec.Cmd
+ t0 time.Time
cancelKilled = false
cancelSignaled = false
)
- cmd.Cancel = func() error {
- if base.SignalTrace == nil {
- err := cmd.Process.Kill()
+ for {
+ cmd = exec.CommandContext(ctx, args[0], args[1:]...)
+ cmd.Dir = a.Package.Dir
+
+ env := slices.Clip(cfg.OrigEnv)
+ env = base.AppendPATH(env)
+ env = base.AppendPWD(env, cmd.Dir)
+ cmd.Env = env
+ if addToEnv != "" {
+ cmd.Env = append(cmd.Env, addToEnv)
+ }
+
+ cmd.Stdout = stdout
+ cmd.Stderr = stdout
+
+ // If there are any local SWIG dependencies, we want to load
+ // the shared library from the build directory.
+ if a.Package.UsesSwig() {
+ env := cmd.Env
+ found := false
+ prefix := "LD_LIBRARY_PATH="
+ for i, v := range env {
+ if strings.HasPrefix(v, prefix) {
+ env[i] = v + ":."
+ found = true
+ break
+ }
+ }
+ if !found {
+ env = append(env, "LD_LIBRARY_PATH=.")
+ }
+ cmd.Env = env
+ }
+
+ cmd.Cancel = func() error {
+ if base.SignalTrace == nil {
+ err := cmd.Process.Kill()
+ if err == nil {
+ cancelKilled = true
+ }
+ return err
+ }
+
+ // Send a quit signal in the hope that the program will print
+ // a stack trace and exit.
+ err := cmd.Process.Signal(base.SignalTrace)
if err == nil {
- cancelKilled = true
+ cancelSignaled = true
}
return err
}
+ cmd.WaitDelay = testWaitDelay
+
+ base.StartSigHandlers()
+ t0 = time.Now()
+ err = cmd.Run()
- // Send a quit signal in the hope that the program will print
- // a stack trace and exit.
- err := cmd.Process.Signal(base.SignalTrace)
- if err == nil {
- cancelSignaled = true
+ if !isETXTBSY(err) {
+ // We didn't hit the race in #22315, so there is no reason to retry the
+ // command.
+ break
}
- return err
}
- cmd.WaitDelay = testWaitDelay
- base.StartSigHandlers()
- t0 := time.Now()
- err = cmd.Run()
out := buf.Bytes()
a.TestOutput = &buf
t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
diff --git a/src/cmd/go/internal/test/test_nonunix.go b/src/cmd/go/internal/test/test_nonunix.go
new file mode 100644
index 0000000000..df8448730d
--- /dev/null
+++ b/src/cmd/go/internal/test/test_nonunix.go
@@ -0,0 +1,12 @@
+// Copyright 2023 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.
+
+//go:build !unix
+
+package test
+
+func isETXTBSY(err error) bool {
+ // syscall.ETXTBSY is only meaningful on Unix platforms.
+ return false
+}
diff --git a/src/cmd/go/internal/test/test_unix.go b/src/cmd/go/internal/test/test_unix.go
new file mode 100644
index 0000000000..f50ef98703
--- /dev/null
+++ b/src/cmd/go/internal/test/test_unix.go
@@ -0,0 +1,16 @@
+// Copyright 2023 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.
+
+//go:build unix
+
+package test
+
+import (
+ "errors"
+ "syscall"
+)
+
+func isETXTBSY(err error) bool {
+ return errors.Is(err, syscall.ETXTBSY)
+}
diff --git a/src/cmd/go/testdata/script/test_compile_multi_pkg.txt b/src/cmd/go/testdata/script/test_compile_multi_pkg.txt
index 1f298b6fd5..921ef5c6c5 100644
--- a/src/cmd/go/testdata/script/test_compile_multi_pkg.txt
+++ b/src/cmd/go/testdata/script/test_compile_multi_pkg.txt
@@ -2,6 +2,10 @@
# Verify test -c can output multiple executables to a directory.
+# This test also serves as a regression test for https://go.dev/issue/62221:
+# prior to the fix for that issue, it occasionally failed with ETXTBSY when
+# run on Unix platforms.
+
go test -c -o $WORK/some/nonexisting/directory/ ./pkg/...
exists -exec $WORK/some/nonexisting/directory/pkg1.test$GOEXE
exists -exec $WORK/some/nonexisting/directory/pkg2.test$GOEXE
@@ -43,4 +47,4 @@ package pkg1
package pkg2
-- anotherpkg/pkg1/pkg1_test.go --
-package pkg1 \ No newline at end of file
+package pkg1