@@ -21,7 +21,6 @@ import (
21
21
"strconv"
22
22
"strings"
23
23
"sync"
24
- "time"
25
24
26
25
"cmd/go/internal/base"
27
26
"cmd/go/internal/cfg"
@@ -1015,73 +1014,23 @@ func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...inter
1015
1014
}
1016
1015
}
1017
1016
1018
- nbusy := 0
1019
- for {
1020
- var buf bytes.Buffer
1021
- cmd := exec .Command (cmdline [0 ], cmdline [1 :]... )
1022
- cmd .Stdout = & buf
1023
- cmd .Stderr = & buf
1024
- cmd .Dir = dir
1025
- cmd .Env = base .MergeEnvLists (env , base .EnvForDir (cmd .Dir , os .Environ ()))
1026
- err := cmd .Run ()
1027
-
1028
- // cmd.Run will fail on Unix if some other process has the binary
1029
- // we want to run open for writing. This can happen here because
1030
- // we build and install the cgo command and then run it.
1031
- // If another command was kicked off while we were writing the
1032
- // cgo binary, the child process for that command may be holding
1033
- // a reference to the fd, keeping us from running exec.
1034
- //
1035
- // But, you might reasonably wonder, how can this happen?
1036
- // The cgo fd, like all our fds, is close-on-exec, so that we need
1037
- // not worry about other processes inheriting the fd accidentally.
1038
- // The answer is that running a command is fork and exec.
1039
- // A child forked while the cgo fd is open inherits that fd.
1040
- // Until the child has called exec, it holds the fd open and the
1041
- // kernel will not let us run cgo. Even if the child were to close
1042
- // the fd explicitly, it would still be open from the time of the fork
1043
- // until the time of the explicit close, and the race would remain.
1044
- //
1045
- // On Unix systems, this results in ETXTBSY, which formats
1046
- // as "text file busy". Rather than hard-code specific error cases,
1047
- // we just look for that string. If this happens, sleep a little
1048
- // and try again. We let this happen three times, with increasing
1049
- // sleep lengths: 100+200+400 ms = 0.7 seconds.
1050
- //
1051
- // An alternate solution might be to split the cmd.Run into
1052
- // separate cmd.Start and cmd.Wait, and then use an RWLock
1053
- // to make sure that copyFile only executes when no cmd.Start
1054
- // call is in progress. However, cmd.Start (really syscall.forkExec)
1055
- // only guarantees that when it returns, the exec is committed to
1056
- // happen and succeed. It uses a close-on-exec file descriptor
1057
- // itself to determine this, so we know that when cmd.Start returns,
1058
- // at least one close-on-exec file descriptor has been closed.
1059
- // However, we cannot be sure that all of them have been closed,
1060
- // so the program might still encounter ETXTBSY even with such
1061
- // an RWLock. The race window would be smaller, perhaps, but not
1062
- // guaranteed to be gone.
1063
- //
1064
- // Sleeping when we observe the race seems to be the most reliable
1065
- // option we have.
1066
- //
1067
- // https://golang.org/issue/3001
1068
- //
1069
- if err != nil && nbusy < 3 && strings .Contains (err .Error (), "text file busy" ) {
1070
- time .Sleep (100 * time .Millisecond << uint (nbusy ))
1071
- nbusy ++
1072
- continue
1073
- }
1074
-
1075
- // err can be something like 'exit status 1'.
1076
- // Add information about what program was running.
1077
- // Note that if buf.Bytes() is non-empty, the caller usually
1078
- // shows buf.Bytes() and does not print err at all, so the
1079
- // prefix here does not make most output any more verbose.
1080
- if err != nil {
1081
- err = errors .New (cmdline [0 ] + ": " + err .Error ())
1082
- }
1083
- return buf .Bytes (), err
1017
+ var buf bytes.Buffer
1018
+ cmd := exec .Command (cmdline [0 ], cmdline [1 :]... )
1019
+ cmd .Stdout = & buf
1020
+ cmd .Stderr = & buf
1021
+ cmd .Dir = dir
1022
+ cmd .Env = base .MergeEnvLists (env , base .EnvForDir (cmd .Dir , os .Environ ()))
1023
+ err := cmd .Run ()
1024
+
1025
+ // err can be something like 'exit status 1'.
1026
+ // Add information about what program was running.
1027
+ // Note that if buf.Bytes() is non-empty, the caller usually
1028
+ // shows buf.Bytes() and does not print err at all, so the
1029
+ // prefix here does not make most output any more verbose.
1030
+ if err != nil {
1031
+ err = errors .New (cmdline [0 ] + ": " + err .Error ())
1084
1032
}
1033
+ return buf .Bytes (), err
1085
1034
}
1086
1035
1087
1036
// joinUnambiguously prints the slice, quoting where necessary to make the
0 commit comments