aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/chan.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2020-07-27 12:40:18 -0700
committerMatthew Dempsky <mdempsky@google.com>2020-08-18 20:05:33 +0000
commit30a68bfb806b5217932e280f5a5f521237e69077 (patch)
treec5c83a80382f8806db56dc3a2205cf881d25133f /src/runtime/chan.go
parent861a9483357a1a13609430ec6684b3dc9209e80c (diff)
downloadgo-30a68bfb806b5217932e280f5a5f521237e69077.tar.gz
go-30a68bfb806b5217932e280f5a5f521237e69077.zip
runtime: add "success" field to sudog
The current wakeup protocol for channel communications is that the second goroutine sets gp.param to the sudog when a value is successfully communicated over the channel, and to nil when the wakeup is due to closing the channel. Setting nil to indicate channel closure works okay for chansend and chanrecv, because they're only communicating with one channel, so they know it must be the channel that was closed. However, it means selectgo has to re-poll all of the channels to figure out which one was closed. This commit adds a "success" field to sudog, and changes the wakeup protocol to always set gp.param to sg, and to use sg.success to indicate successful communication vs channel closure. While here, this also reorganizes the chansend code slightly so that the sudog is still released to the pool if the send blocks and then is awoken because the channel closed. Updates #40410. Change-Id: I6cd9a20ebf9febe370a15af1b8afe24c5539efc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/245019 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/runtime/chan.go')
-rw-r--r--src/runtime/chan.go25
1 files changed, 15 insertions, 10 deletions
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index f6f4ffd02e..0afe5d962b 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -263,18 +263,19 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
}
gp.waiting = nil
gp.activeStackChans = false
- if gp.param == nil {
- if c.closed == 0 {
- throw("chansend: spurious wakeup")
- }
- panic(plainError("send on closed channel"))
- }
+ closed := !mysg.success
gp.param = nil
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
}
mysg.c = nil
releaseSudog(mysg)
+ if closed {
+ if c.closed == 0 {
+ throw("chansend: spurious wakeup")
+ }
+ panic(plainError("send on closed channel"))
+ }
return true
}
@@ -311,6 +312,7 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
gp := sg.g
unlockf()
gp.param = unsafe.Pointer(sg)
+ sg.success = true
if sg.releasetime != 0 {
sg.releasetime = cputicks()
}
@@ -384,7 +386,8 @@ func closechan(c *hchan) {
sg.releasetime = cputicks()
}
gp := sg.g
- gp.param = nil
+ gp.param = unsafe.Pointer(sg)
+ sg.success = false
if raceenabled {
raceacquireg(gp, c.raceaddr())
}
@@ -402,7 +405,8 @@ func closechan(c *hchan) {
sg.releasetime = cputicks()
}
gp := sg.g
- gp.param = nil
+ gp.param = unsafe.Pointer(sg)
+ sg.success = false
if raceenabled {
raceacquireg(gp, c.raceaddr())
}
@@ -575,11 +579,11 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2)
}
- closed := gp.param == nil
+ success := mysg.success
gp.param = nil
mysg.c = nil
releaseSudog(mysg)
- return true, !closed
+ return true, success
}
// recv processes a receive operation on a full channel c.
@@ -632,6 +636,7 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
gp := sg.g
unlockf()
gp.param = unsafe.Pointer(sg)
+ sg.success = true
if sg.releasetime != 0 {
sg.releasetime = cputicks()
}