// required).
return
}
+
+ // On Darwin, don't try to preempt threads during exec.
+ // Issue #41702.
+ if GOOS == "darwin" {
+ execLock.rlock()
+ }
+
if atomic.Cas(&mp.signalPending, 0, 1) {
// If multiple threads are preempting the same M, it may send many
// signals to the same M such that it hardly make progress, causing
// Only send a signal if there isn't already one pending.
signalM(mp, sigPreempt)
}
+
+ if GOOS == "darwin" {
+ execLock.runlock()
+ }
}
// sigFetchG fetches the value of G safely when running in a signal handler.
import (
"internal/testenv"
"io"
+ "math/rand"
"os"
"os/exec"
"os/signal"
+ "runtime"
"syscall"
"testing"
+ "time"
"unsafe"
)
signal.Reset()
}
+
+// TestExec is for issue #41702.
+func TestExec(t *testing.T) {
+ cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper")
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2")
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("%s\n%v", o, err)
+ }
+}
+
+// TestExecHelper is used by TestExec. It does nothing by itself.
+// In testing on macOS 10.14, this used to fail with
+// "signal: illegal instruction" more than half the time.
+func TestExecHelper(t *testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "2" {
+ return
+ }
+
+ // We don't have to worry about restoring these values.
+ // We are in a child process that only runs this test,
+ // and we are going to call syscall.Exec anyhow.
+ runtime.GOMAXPROCS(50)
+ os.Setenv("GO_WANT_HELPER_PROCESS", "3")
+
+ stop := time.Now().Add(time.Second)
+ for i := 0; i < 100; i++ {
+ go func(i int) {
+ r := rand.New(rand.NewSource(int64(i)))
+ for time.Now().Before(stop) {
+ r.Uint64()
+ }
+ }(i)
+ }
+
+ time.Sleep(10 * time.Millisecond)
+
+ argv := []string{os.Args[0], "-test.run=TestExecHelper"}
+ syscall.Exec(os.Args[0], argv, os.Environ())
+
+ t.Error("syscall.Exec returned")
+}