Commit d45bf722 authored by Austin Clements's avatar Austin Clements

runtime: define lock order between G status and channel lock

Currently, locking a G's stack by setting its status to _Gcopystack or
_Gscan is unordered with respect to channel locks. However, when we
make stack shrinking concurrent, stack shrinking will need to lock the
G and then acquire channel locks, which imposes an order on these.

Document this lock ordering and fix closechan to respect it.
Everything else already happens to respect it.

For #12967.

Change-Id: I4dd02675efffb3e7daa5285cf75bf24f987d90d4
Reviewed-on: https://go-review.googlesource.com/20041Reviewed-by: default avatarRick Hudson <rlh@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent db72b41b
......@@ -36,6 +36,10 @@ type hchan struct {
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
......@@ -315,6 +319,8 @@ func closechan(c *hchan) {
c.closed = 1
var glist *g
// release all readers
for {
sg := c.recvq.dequeue()
......@@ -333,7 +339,8 @@ func closechan(c *hchan) {
if raceenabled {
raceacquireg(gp, unsafe.Pointer(c))
}
goready(gp, 3)
gp.schedlink.set(glist)
glist = gp
}
// release all writers (they will panic)
......@@ -351,9 +358,18 @@ func closechan(c *hchan) {
if raceenabled {
raceacquireg(gp, unsafe.Pointer(c))
}
goready(gp, 3)
gp.schedlink.set(glist)
glist = gp
}
unlock(&c.lock)
// Ready all Gs now that we've dropped the channel lock.
for glist != nil {
gp := glist
glist = glist.schedlink.ptr()
gp.schedlink = 0
goready(gp, 3)
}
}
// entry points for <- c from compiled code
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment