aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2020-03-16 20:08:00 -0400
committerCarlos Amedee <carlos@golang.org>2020-03-18 18:38:30 +0000
commite577ba98d8d9f4464d6dfaaf2fa51d328233c81e (patch)
tree019caafc845254edee73864783d85779f649e1c1
parent229247d33b717ce7729e43a8fde3a095e376cf3d (diff)
downloadgo-e577ba98d8d9f4464d6dfaaf2fa51d328233c81e.tar.gz
go-e577ba98d8d9f4464d6dfaaf2fa51d328233c81e.zip
[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 <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org> (cherry picked from commit 0c0e8f224d5724e317952f77d215a752a3a7b7d9) Reviewed-on: https://go-review.googlesource.com/c/go/+/223939 Reviewed-by: Austin Clements <austin@google.com>
-rw-r--r--src/runtime/runtime2.go4
-rw-r--r--src/runtime/signal_unix.go10
2 files changed, 13 insertions, 1 deletions
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 99eb19eb0c..2a872bfba9 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -540,6 +540,10 @@ type m struct {
// requested, but fails. Accessed atomically.
preemptGen uint32
+ // Whether this is a pending preemption signal on this M.
+ // Accessed atomically.
+ signalPending uint32
+
dlogPerM
mOS
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index d2e6693805..f18e6b5785 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -333,6 +333,7 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
// Acknowledge the preemption.
atomic.Xadd(&gp.m.preemptGen, 1)
+ atomic.Store(&gp.m.signalPending, 0)
}
const preemptMSupported = pushCallSupported
@@ -359,7 +360,14 @@ func preemptM(mp *m) {
// required).
return
}
- signalM(mp, sigPreempt)
+ if atomic.Cas(&mp.signalPending, 0, 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
+ // issue #37741.
+ // Only send a signal if there isn't already one pending.
+ signalM(mp, sigPreempt)
+ }
}
// sigFetchG fetches the value of G safely when running in a signal handler.