aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-02-07 10:49:33 -0800
committerIan Lance Taylor <iant@golang.org>2020-02-07 23:43:36 +0000
commit60d437f99468906935f35e5c6fbd31c7228a1045 (patch)
tree529978bbbf8eaff168b9c02648a2882fcd2dc025
parentb8061825e57dcee97a37fe49272ca52e84600f5e (diff)
downloadgo-60d437f99468906935f35e5c6fbd31c7228a1045.tar.gz
go-60d437f99468906935f35e5c6fbd31c7228a1045.zip
runtime: avoid double notewakeup in netpoll stub code
Otherwise we can see - goroutine 1 calls netpollBreak, the atomic.Cas succeeds, then suspends - goroutine 2 calls noteclear, sets netpollBroken to 0 - goroutine 3 calls netpollBreak, the atomic.Cas succeeds, calls notewakeup - goroutine 1 wakes up calls notewakeup, crashes due to double wakeup This doesn't happen on Plan 9 because it only runs one thread at a time. But Fuschia wants to use this code too. Change-Id: Ib636e4f327bb15e44a2c40fd681aae9a91073a30 Reviewed-on: https://go-review.googlesource.com/c/go/+/218537 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
-rw-r--r--src/runtime/netpoll_stub.go17
1 files changed, 14 insertions, 3 deletions
diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go
index fe45cfbd40..f86f2f6174 100644
--- a/src/runtime/netpoll_stub.go
+++ b/src/runtime/netpoll_stub.go
@@ -13,16 +13,23 @@ var netpollWaiters uint32
var netpollStubLock mutex
var netpollNote note
-var netpollBroken uint32
+
+// netpollBroken, protected by netpollBrokenLock, avoids a double notewakeup.
+var netpollBrokenLock mutex
+var netpollBroken bool
func netpollGenericInit() {
atomic.Store(&netpollInited, 1)
}
func netpollBreak() {
- if atomic.Cas(&netpollBroken, 0, 1) {
+ lock(&netpollBrokenLock)
+ broken := netpollBroken
+ netpollBroken = true
+ if !broken {
notewakeup(&netpollNote)
}
+ unlock(&netpollBrokenLock)
}
// Polls for ready network connections.
@@ -34,8 +41,12 @@ func netpoll(delay int64) gList {
// This lock ensures that only one goroutine tries to use
// the note. It should normally be completely uncontended.
lock(&netpollStubLock)
+
+ lock(&netpollBrokenLock)
noteclear(&netpollNote)
- atomic.Store(&netpollBroken, 0)
+ netpollBroken = false
+ unlock(&netpollBrokenLock)
+
notetsleep(&netpollNote, delay)
unlock(&netpollStubLock)
}