Skip to content

Commit 768b647

Browse files
[release-branch.go1.14] runtime: wait for preemption signals before syscall.Exec
For #41702 For #41703 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/+/264023
1 parent b581ccd commit 768b647

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
@@ -1221,6 +1221,14 @@ found:
12211221
checkdead()
12221222
unlock(&sched.lock)
12231223

1224+
if GOOS == "darwin" {
1225+
// Make sure pendingPreemptSignals is correct when an M exits.
1226+
// For #41702.
1227+
if atomic.Load(&m.signalPending) != 0 {
1228+
atomic.Xadd(&pendingPreemptSignals, -1)
1229+
}
1230+
}
1231+
12241232
if osStack {
12251233
// Return from mstart and let the system thread
12261234
// library free the g0 stack and terminate the thread.
@@ -3375,11 +3383,24 @@ func syscall_runtime_AfterForkInChild() {
33753383
inForkedChild = false
33763384
}
33773385

3386+
// pendingPreemptSignals is the number of preemption signals
3387+
// that have been sent but not received. This is only used on Darwin.
3388+
// For #41702.
3389+
var pendingPreemptSignals uint32
3390+
33783391
// Called from syscall package before Exec.
33793392
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
33803393
func syscall_runtime_BeforeExec() {
33813394
// Prevent thread creation during exec.
33823395
execLock.lock()
3396+
3397+
// On Darwin, wait for all pending preemption signals to
3398+
// be received. See issue #41702.
3399+
if GOOS == "darwin" {
3400+
for int32(atomic.Load(&pendingPreemptSignals)) > 0 {
3401+
osyield()
3402+
}
3403+
}
33833404
}
33843405

33853406
// 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
@@ -334,6 +334,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
334334
// Acknowledge the preemption.
335335
atomic.Xadd(&gp.m.preemptGen, 1)
336336
atomic.Store(&gp.m.signalPending, 0)
337+
338+
if GOOS == "darwin" {
339+
atomic.Xadd(&pendingPreemptSignals, -1)
340+
}
337341
}
338342

339343
const preemptMSupported = pushCallSupported
@@ -368,6 +372,10 @@ func preemptM(mp *m) {
368372
}
369373

370374
if atomic.Cas(&mp.signalPending, 0, 1) {
375+
if GOOS == "darwin" {
376+
atomic.Xadd(&pendingPreemptSignals, 1)
377+
}
378+
371379
// If multiple threads are preempting the same M, it may send many
372380
// signals to the same M such that it hardly make progress, causing
373381
// live-lock problem. Apparently this could happen on darwin. See
@@ -439,6 +447,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
439447
// no non-Go signal handler for sigPreempt.
440448
// The default behavior for sigPreempt is to ignore
441449
// the signal, so badsignal will be a no-op anyway.
450+
if GOOS == "darwin" {
451+
atomic.Xadd(&pendingPreemptSignals, -1)
452+
}
442453
return
443454
}
444455
c.fixsigcode(sig)

0 commit comments

Comments
 (0)