]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.15] runtime: wait for preemption signals before syscall.Exec
authorIan Lance Taylor <iant@golang.org>
Thu, 15 Oct 2020 21:39:12 +0000 (14:39 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 20 Oct 2020 23:46:24 +0000 (23:46 +0000)
For #41702
For #41704
For #42023

Change-Id: If07f40b1d73b8f276ee28ffb8b7214175e56c24d
Reviewed-on: https://go-review.googlesource.com/c/go/+/262817
Trust: Ian Lance Taylor <iant@golang.org>
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
(cherry picked from commit 05739d6f17c57f09264272621b88725a463234d0)
Reviewed-on: https://go-review.googlesource.com/c/go/+/264022

src/runtime/proc.go
src/runtime/signal_unix.go

index 035822216d2bb860e544f2a0f83d31674718075b..2f1272d310b6f401d1b00dd21bfe638813e2335f 100644 (file)
@@ -1281,6 +1281,14 @@ found:
        checkdead()
        unlock(&sched.lock)
 
+       if GOOS == "darwin" {
+               // Make sure pendingPreemptSignals is correct when an M exits.
+               // For #41702.
+               if atomic.Load(&m.signalPending) != 0 {
+                       atomic.Xadd(&pendingPreemptSignals, -1)
+               }
+       }
+
        if osStack {
                // Return from mstart and let the system thread
                // library free the g0 stack and terminate the thread.
@@ -3475,11 +3483,24 @@ func syscall_runtime_AfterForkInChild() {
        inForkedChild = false
 }
 
+// pendingPreemptSignals is the number of preemption signals
+// that have been sent but not received. This is only used on Darwin.
+// For #41702.
+var pendingPreemptSignals uint32
+
 // Called from syscall package before Exec.
 //go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
 func syscall_runtime_BeforeExec() {
        // Prevent thread creation during exec.
        execLock.lock()
+
+       // On Darwin, wait for all pending preemption signals to
+       // be received. See issue #41702.
+       if GOOS == "darwin" {
+               for int32(atomic.Load(&pendingPreemptSignals)) > 0 {
+                       osyield()
+               }
+       }
 }
 
 // Called from syscall package after Exec.
index f9784b84a759a7d3d36e3c20dd924aa6087cbdf1..80fd2d660491f111f5efade781cb663201b8a344 100644 (file)
@@ -336,6 +336,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
        // Acknowledge the preemption.
        atomic.Xadd(&gp.m.preemptGen, 1)
        atomic.Store(&gp.m.signalPending, 0)
+
+       if GOOS == "darwin" {
+               atomic.Xadd(&pendingPreemptSignals, -1)
+       }
 }
 
 const preemptMSupported = true
@@ -365,6 +369,10 @@ func preemptM(mp *m) {
        }
 
        if atomic.Cas(&mp.signalPending, 0, 1) {
+               if GOOS == "darwin" {
+                       atomic.Xadd(&pendingPreemptSignals, 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
                // live-lock problem. Apparently this could happen on darwin. See
@@ -436,6 +444,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
                        // no non-Go signal handler for sigPreempt.
                        // The default behavior for sigPreempt is to ignore
                        // the signal, so badsignal will be a no-op anyway.
+                       if GOOS == "darwin" {
+                               atomic.Xadd(&pendingPreemptSignals, -1)
+                       }
                        return
                }
                c.fixsigcode(sig)