Skip to content

Commit 3b1f07f

Browse files
[release-branch.go1.15] runtime: wait for preemption signals before syscall.Exec
For #41702 For #41704 For #42023 Change-Id: If07f40b1d73b8f276ee28ffb8b7214175e56c24d Reviewed-on: https://go-review.googlesource.com/c/go/+/262817 Trust: Ian Lance Taylor <[email protected]> Trust: Bryan C. Mills <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]> (cherry picked from commit 05739d6) Reviewed-on: https://go-review.googlesource.com/c/go/+/264022
1 parent 0d489b8 commit 3b1f07f

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

src/runtime/proc.go

+21
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,14 @@ found:
12811281
checkdead()
12821282
unlock(&sched.lock)
12831283

1284+
if GOOS == "darwin" {
1285+
// Make sure pendingPreemptSignals is correct when an M exits.
1286+
// For #41702.
1287+
if atomic.Load(&m.signalPending) != 0 {
1288+
atomic.Xadd(&pendingPreemptSignals, -1)
1289+
}
1290+
}
1291+
12841292
if osStack {
12851293
// Return from mstart and let the system thread
12861294
// library free the g0 stack and terminate the thread.
@@ -3475,11 +3483,24 @@ func syscall_runtime_AfterForkInChild() {
34753483
inForkedChild = false
34763484
}
34773485

3486+
// pendingPreemptSignals is the number of preemption signals
3487+
// that have been sent but not received. This is only used on Darwin.
3488+
// For #41702.
3489+
var pendingPreemptSignals uint32
3490+
34783491
// Called from syscall package before Exec.
34793492
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
34803493
func syscall_runtime_BeforeExec() {
34813494
// Prevent thread creation during exec.
34823495
execLock.lock()
3496+
3497+
// On Darwin, wait for all pending preemption signals to
3498+
// be received. See issue #41702.
3499+
if GOOS == "darwin" {
3500+
for int32(atomic.Load(&pendingPreemptSignals)) > 0 {
3501+
osyield()
3502+
}
3503+
}
34833504
}
34843505

34853506
// Called from syscall package after Exec.

src/runtime/signal_unix.go

+11
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
336336
// Acknowledge the preemption.
337337
atomic.Xadd(&gp.m.preemptGen, 1)
338338
atomic.Store(&gp.m.signalPending, 0)
339+
340+
if GOOS == "darwin" {
341+
atomic.Xadd(&pendingPreemptSignals, -1)
342+
}
339343
}
340344

341345
const preemptMSupported = true
@@ -365,6 +369,10 @@ func preemptM(mp *m) {
365369
}
366370

367371
if atomic.Cas(&mp.signalPending, 0, 1) {
372+
if GOOS == "darwin" {
373+
atomic.Xadd(&pendingPreemptSignals, 1)
374+
}
375+
368376
// If multiple threads are preempting the same M, it may send many
369377
// signals to the same M such that it hardly make progress, causing
370378
// live-lock problem. Apparently this could happen on darwin. See
@@ -436,6 +444,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
436444
// no non-Go signal handler for sigPreempt.
437445
// The default behavior for sigPreempt is to ignore
438446
// the signal, so badsignal will be a no-op anyway.
447+
if GOOS == "darwin" {
448+
atomic.Xadd(&pendingPreemptSignals, -1)
449+
}
439450
return
440451
}
441452
c.fixsigcode(sig)

0 commit comments

Comments
 (0)