diff options
author | Austin Clements <austin@google.com> | 2016-02-18 09:34:43 -0500 |
---|---|---|
committer | Austin Clements <austin@google.com> | 2016-03-16 20:13:15 +0000 |
commit | db72b41bcd67ecb80890d586effbabd8d110952c (patch) | |
tree | d351d5b1adbbf61ef0161d472f27b027713f1716 /src/runtime/chan.go | |
parent | 3c2a21ff13c53b93db50cfb37b186d6200e2ceec (diff) | |
download | go-db72b41bcd67ecb80890d586effbabd8d110952c.tar.gz go-db72b41bcd67ecb80890d586effbabd8d110952c.zip |
runtime: protect sudog.elem with hchan.lock
Currently sudog.elem is never accessed concurrently, so in several
cases we drop the channel lock just before reading/writing the
sent/received value from/to sudog.elem. However, concurrent stack
shrinking is going to have to adjust sudog.elem to point to the new
stack, which means it needs a way to synchronize with accesses to
sudog.elem. Hence, add sudog.elem to the fields protected by
hchan.lock and scoot the unlocks down past the uses of sudog.elem.
While we're here, better document the channel synchronization rules.
For #12967.
Change-Id: I3ad0ca71f0a74b0716c261aef21b2f7f13f74917
Reviewed-on: https://go-review.googlesource.com/20040
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/runtime/chan.go')
-rw-r--r-- | src/runtime/chan.go | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/src/runtime/chan.go b/src/runtime/chan.go index cc64d30a68..e89831783e 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -33,7 +33,10 @@ type hchan struct { recvx uint // receive index recvq waitq // list of recv waiters sendq waitq // list of send waiters - lock mutex + + // lock protects all fields in hchan, as well as several + // fields in sudogs blocked on this channel. + lock mutex } type waitq struct { @@ -261,12 +264,12 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) { c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz } } - unlockf() if sg.elem != nil { sendDirect(c.elemtype, sg, ep) sg.elem = nil } gp := sg.g + unlockf() gp.param = unsafe.Pointer(sg) if sg.releasetime != 0 { sg.releasetime = cputicks() @@ -509,7 +512,6 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) { if raceenabled { racesync(c, sg) } - unlockf() if ep != nil { // copy data from sender // ep points to our own stack or heap, so nothing @@ -539,10 +541,10 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) { c.recvx = 0 } c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz - unlockf() } sg.elem = nil gp := sg.g + unlockf() gp.param = unsafe.Pointer(sg) if sg.releasetime != 0 { sg.releasetime = cputicks() |