Skip to content

Commit

Permalink
[release-branch.go1.20] cmd/go/internal/script: retry ETXTBSY errors …
Browse files Browse the repository at this point in the history
…in scripts

Fixes #58431.
Updates #58019.

Change-Id: Ib25d668bfede6e87a3786f44bdc0db1027e3ebec
Reviewed-on: https://go-review.googlesource.com/c/go/+/463748
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Bryan Mills <bcmills@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
(cherry picked from commit 23c0121)
Reviewed-on: https://go-review.googlesource.com/c/go/+/466856
Reviewed-by: David Chase <drchase@google.com>
  • Loading branch information
Bryan C. Mills authored and dr2chase committed Feb 10, 2023
1 parent 7628627 commit 00f5d30
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 15 deletions.
46 changes: 31 additions & 15 deletions src/cmd/go/internal/script/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,21 +432,37 @@ func Exec(cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd {
}

func startCommand(s *State, name, path string, args []string, cancel func(*exec.Cmd) error, waitDelay time.Duration) (WaitFunc, error) {
var stdoutBuf, stderrBuf strings.Builder
cmd := exec.CommandContext(s.Context(), path, args...)
if cancel == nil {
cmd.Cancel = nil
} else {
cmd.Cancel = func() error { return cancel(cmd) }
}
cmd.WaitDelay = waitDelay
cmd.Args[0] = name
cmd.Dir = s.Getwd()
cmd.Env = s.env
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
if err := cmd.Start(); err != nil {
return nil, err
var (
cmd *exec.Cmd
stdoutBuf, stderrBuf strings.Builder
)
for {
cmd = exec.CommandContext(s.Context(), path, args...)
if cancel == nil {
cmd.Cancel = nil
} else {
cmd.Cancel = func() error { return cancel(cmd) }
}
cmd.WaitDelay = waitDelay
cmd.Args[0] = name
cmd.Dir = s.Getwd()
cmd.Env = s.env
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
err := cmd.Start()
if err == nil {
break
}
if isETXTBSY(err) {
// If the script (or its host process) just wrote the executable we're
// trying to run, a fork+exec in another thread may be holding open the FD
// that we used to write the executable (see https://go.dev/issue/22315).
// Since the descriptor should have CLOEXEC set, the problem should
// resolve as soon as the forked child reaches its exec call.
// Keep retrying until that happens.
} else {
return nil, err
}
}

wait := func(s *State) (stdout, stderr string, err error) {
Expand Down
11 changes: 11 additions & 0 deletions src/cmd/go/internal/script/cmds_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// 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 || windows)

package script

func isETXTBSY(err error) bool {
return false
}
16 changes: 16 additions & 0 deletions src/cmd/go/internal/script/cmds_posix.go
Original file line number Diff line number Diff line change
@@ -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 || windows

package script

import (
"errors"
"syscall"
)

func isETXTBSY(err error) bool {
return errors.Is(err, syscall.ETXTBSY)
}

0 comments on commit 00f5d30

Please sign in to comment.