mirror of https://github.com/golang/go.git
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/20041 Reviewed-by: Rick Hudson <rlh@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
db72b41bcd
commit
d45bf7228f
|
|
@ -36,6 +36,10 @@ type hchan struct {
|
||||||
|
|
||||||
// lock protects all fields in hchan, as well as several
|
// lock protects all fields in hchan, as well as several
|
||||||
// fields in sudogs blocked on this channel.
|
// 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
|
lock mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,6 +319,8 @@ func closechan(c *hchan) {
|
||||||
|
|
||||||
c.closed = 1
|
c.closed = 1
|
||||||
|
|
||||||
|
var glist *g
|
||||||
|
|
||||||
// release all readers
|
// release all readers
|
||||||
for {
|
for {
|
||||||
sg := c.recvq.dequeue()
|
sg := c.recvq.dequeue()
|
||||||
|
|
@ -333,7 +339,8 @@ func closechan(c *hchan) {
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
raceacquireg(gp, unsafe.Pointer(c))
|
raceacquireg(gp, unsafe.Pointer(c))
|
||||||
}
|
}
|
||||||
goready(gp, 3)
|
gp.schedlink.set(glist)
|
||||||
|
glist = gp
|
||||||
}
|
}
|
||||||
|
|
||||||
// release all writers (they will panic)
|
// release all writers (they will panic)
|
||||||
|
|
@ -351,9 +358,18 @@ func closechan(c *hchan) {
|
||||||
if raceenabled {
|
if raceenabled {
|
||||||
raceacquireg(gp, unsafe.Pointer(c))
|
raceacquireg(gp, unsafe.Pointer(c))
|
||||||
}
|
}
|
||||||
goready(gp, 3)
|
gp.schedlink.set(glist)
|
||||||
|
glist = gp
|
||||||
}
|
}
|
||||||
unlock(&c.lock)
|
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
|
// entry points for <- c from compiled code
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue