1
0
mirror of https://github.com/golang/go synced 2024-11-17 21:24:55 -07:00

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>
This commit is contained in:
Ian Lance Taylor 2020-02-07 10:49:33 -08:00
parent b8061825e5
commit 60d437f994

View File

@ -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)
}