Skip to content

Commit 05739d6

Browse files
runtime: wait for preemption signals before syscall.Exec
Fixes #41702 Fixes #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]>
1 parent 3eae1a9 commit 05739d6

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

src/runtime/proc.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,14 @@ found:
13111311
checkdead()
13121312
unlock(&sched.lock)
13131313

1314+
if GOOS == "darwin" {
1315+
// Make sure pendingPreemptSignals is correct when an M exits.
1316+
// For #41702.
1317+
if atomic.Load(&m.signalPending) != 0 {
1318+
atomic.Xadd(&pendingPreemptSignals, -1)
1319+
}
1320+
}
1321+
13141322
if osStack {
13151323
// Return from mstart and let the system thread
13161324
// library free the g0 stack and terminate the thread.
@@ -3510,11 +3518,24 @@ func syscall_runtime_AfterForkInChild() {
35103518
inForkedChild = false
35113519
}
35123520

3521+
// pendingPreemptSignals is the number of preemption signals
3522+
// that have been sent but not received. This is only used on Darwin.
3523+
// For #41702.
3524+
var pendingPreemptSignals uint32
3525+
35133526
// Called from syscall package before Exec.
35143527
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
35153528
func syscall_runtime_BeforeExec() {
35163529
// Prevent thread creation during exec.
35173530
execLock.lock()
3531+
3532+
// On Darwin, wait for all pending preemption signals to
3533+
// be received. See issue #41702.
3534+
if GOOS == "darwin" {
3535+
for int32(atomic.Load(&pendingPreemptSignals)) > 0 {
3536+
osyield()
3537+
}
3538+
}
35183539
}
35193540

35203541
// Called from syscall package after Exec.

src/runtime/signal_unix.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
335335
// Acknowledge the preemption.
336336
atomic.Xadd(&gp.m.preemptGen, 1)
337337
atomic.Store(&gp.m.signalPending, 0)
338+
339+
if GOOS == "darwin" {
340+
atomic.Xadd(&pendingPreemptSignals, -1)
341+
}
338342
}
339343

340344
const preemptMSupported = true
@@ -364,6 +368,10 @@ func preemptM(mp *m) {
364368
}
365369

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

0 commit comments

Comments
 (0)