]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: avoid double notewakeup in netpoll stub code
authorIan Lance Taylor <iant@golang.org>
Fri, 7 Feb 2020 18:49:33 +0000 (10:49 -0800)
committerIan Lance Taylor <iant@golang.org>
Fri, 7 Feb 2020 23:43:36 +0000 (23:43 +0000)
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>
src/runtime/netpoll_stub.go

index fe45cfbd400f2ba5275942a7d313acc053131fbd..f86f2f61748ed8c78fb8b647a191f14431915c00 100644 (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)
        }