aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/chan.go
diff options
context:
space:
mode:
authorKeith Randall <khr@google.com>2018-09-17 12:25:36 -0700
committerKeith Randall <khr@golang.org>2018-09-18 17:28:37 +0000
commit83dfc3b001245f0b725afdc94c0b540fe1952d21 (patch)
tree98e163cfa41ec69883528ab967be4beb1bceeb39 /src/runtime/chan.go
parent77f9b2728eb08456899e6500328e00ec4829dddf (diff)
downloadgo-83dfc3b001245f0b725afdc94c0b540fe1952d21.tar.gz
go-83dfc3b001245f0b725afdc94c0b540fe1952d21.zip
runtime: ignore races between close and len/cap
They aren't really races, or at least they don't have any observable effect. The spec is silent on whether these are actually races or not. Fix this problem by not using the address of len (or of cap) as the location where channel operations are recorded to occur. Use a random other field of hchan for that. I'm not 100% sure we should in fact fix this. Opinions welcome. Fixes #27070 Change-Id: Ib4efd4b62e0d1ef32fa51e373035ef207a655084 Reviewed-on: https://go-review.googlesource.com/135698 Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Diffstat (limited to 'src/runtime/chan.go')
-rw-r--r--src/runtime/chan.go23
1 files changed, 16 insertions, 7 deletions
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 615643e6a6..a4ee51ca39 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -92,7 +92,7 @@ func makechan(t *chantype, size int) *hchan {
// Queue or element size is zero.
c = (*hchan)(mallocgc(hchanSize, nil, true))
// Race detector uses this location for synchronization.
- c.buf = unsafe.Pointer(c)
+ c.buf = c.raceaddr()
case elem.kind&kindNoPointers != 0:
// Elements do not contain pointers.
// Allocate hchan and buf in one call.
@@ -151,7 +151,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
}
if raceenabled {
- racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend))
+ racereadpc(c.raceaddr(), callerpc, funcPC(chansend))
}
// Fast path: check for failed non-blocking operation without acquiring the lock.
@@ -337,8 +337,8 @@ func closechan(c *hchan) {
if raceenabled {
callerpc := getcallerpc()
- racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan))
- racerelease(unsafe.Pointer(c))
+ racewritepc(c.raceaddr(), callerpc, funcPC(closechan))
+ racerelease(c.raceaddr())
}
c.closed = 1
@@ -361,7 +361,7 @@ func closechan(c *hchan) {
gp := sg.g
gp.param = nil
if raceenabled {
- raceacquireg(gp, unsafe.Pointer(c))
+ raceacquireg(gp, c.raceaddr())
}
glist.push(gp)
}
@@ -379,7 +379,7 @@ func closechan(c *hchan) {
gp := sg.g
gp.param = nil
if raceenabled {
- raceacquireg(gp, unsafe.Pointer(c))
+ raceacquireg(gp, c.raceaddr())
}
glist.push(gp)
}
@@ -454,7 +454,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
if c.closed != 0 && c.qcount == 0 {
if raceenabled {
- raceacquire(unsafe.Pointer(c))
+ raceacquire(c.raceaddr())
}
unlock(&c.lock)
if ep != nil {
@@ -732,6 +732,15 @@ func (q *waitq) dequeue() *sudog {
}
}
+func (c *hchan) raceaddr() unsafe.Pointer {
+ // Treat read-like and write-like operations on the channel to
+ // happen at this address. Avoid using the address of qcount
+ // or dataqsiz, because the len() and cap() builtins read
+ // those addresses, and we don't want them racing with
+ // operations like close().
+ return unsafe.Pointer(&c.buf)
+}
+
func racesync(c *hchan, sg *sudog) {
racerelease(chanbuf(c, 0))
raceacquireg(sg.g, chanbuf(c, 0))