Skip to content

Commit e577ba9

Browse files
cherrymuicagedmantis
authored andcommitted
[release-branch.go1.14] runtime: don't send preemption signal if there is a signal pending
If multiple threads call preemptone to preempt the same M, it may send many signals to the same M such that it hardly make progress, causing live-lock problem. Only send a signal if there isn't already one pending. Updates #37741. Fixes #37833. Change-Id: Id94adb0b95acbd18b23abe637a8dcd81ab41b452 Reviewed-on: https://go-review.googlesource.com/c/go/+/223737 Run-TryBot: Cherry Zhang <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]> (cherry picked from commit 0c0e8f2) Reviewed-on: https://go-review.googlesource.com/c/go/+/223939 Reviewed-by: Austin Clements <[email protected]>
1 parent 229247d commit e577ba9

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

src/runtime/runtime2.go

+4
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,10 @@ type m struct {
540540
// requested, but fails. Accessed atomically.
541541
preemptGen uint32
542542

543+
// Whether this is a pending preemption signal on this M.
544+
// Accessed atomically.
545+
signalPending uint32
546+
543547
dlogPerM
544548

545549
mOS

src/runtime/signal_unix.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
333333

334334
// Acknowledge the preemption.
335335
atomic.Xadd(&gp.m.preemptGen, 1)
336+
atomic.Store(&gp.m.signalPending, 0)
336337
}
337338

338339
const preemptMSupported = pushCallSupported
@@ -359,7 +360,14 @@ func preemptM(mp *m) {
359360
// required).
360361
return
361362
}
362-
signalM(mp, sigPreempt)
363+
if atomic.Cas(&mp.signalPending, 0, 1) {
364+
// If multiple threads are preempting the same M, it may send many
365+
// signals to the same M such that it hardly make progress, causing
366+
// live-lock problem. Apparently this could happen on darwin. See
367+
// issue #37741.
368+
// Only send a signal if there isn't already one pending.
369+
signalM(mp, sigPreempt)
370+
}
363371
}
364372

365373
// sigFetchG fetches the value of G safely when running in a signal handler.

0 commit comments

Comments
 (0)