mirror of
https://github.com/golang/go
synced 2024-11-23 14:00:03 -07:00
runtime: dequeue the correct SudoG
select { case <- c: case <- c: } In this case, c.recvq lists two SudoGs which have the same G. So we can't use the G as the key to dequeue the correct SudoG, as that key is ambiguous. Dequeueing the wrong SudoG ends up freeing a SudoG that is still in c.recvq. The fix is to use the actual SudoG pointer as the key. LGTM=dvyukov R=rsc, bradfitz, dvyukov, khr CC=austin, golang-codereviews https://golang.org/cl/159040043
This commit is contained in:
parent
1cd78eedd0
commit
e330cc16f4
@ -482,6 +482,35 @@ func TestShrinkStackDuringBlockedSend(t *testing.T) {
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestSelectDuplicateChannel(t *testing.T) {
|
||||
// This test makes sure we can queue a G on
|
||||
// the same channel multiple times.
|
||||
c := make(chan int)
|
||||
d := make(chan int)
|
||||
e := make(chan int)
|
||||
|
||||
// goroutine A
|
||||
go func() {
|
||||
select {
|
||||
case <-c:
|
||||
case <-c:
|
||||
case <-d:
|
||||
}
|
||||
e <- 9
|
||||
}()
|
||||
time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
|
||||
|
||||
// goroutine B
|
||||
go func() {
|
||||
<-c
|
||||
}()
|
||||
time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing
|
||||
|
||||
d <- 7 // wake up A, it dequeues itself from c. This operation used to corrupt c.recvq.
|
||||
<-e // A tells us it's done
|
||||
c <- 8 // wake up B. This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B)
|
||||
}
|
||||
|
||||
func BenchmarkChanNonblocking(b *testing.B) {
|
||||
myc := make(chan int)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
@ -398,9 +398,9 @@ loop:
|
||||
} else {
|
||||
c = k._chan
|
||||
if k.kind == _CaseSend {
|
||||
c.sendq.dequeueg(gp)
|
||||
c.sendq.dequeueSudoG(sglist)
|
||||
} else {
|
||||
c.recvq.dequeueg(gp)
|
||||
c.recvq.dequeueSudoG(sglist)
|
||||
}
|
||||
}
|
||||
sgnext = sglist.waitlink
|
||||
@ -628,7 +628,7 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (q *waitq) dequeueg(gp *g) {
|
||||
func (q *waitq) dequeueSudoG(s *sudog) {
|
||||
var prevsgp *sudog
|
||||
l := &q.first
|
||||
for {
|
||||
@ -636,7 +636,7 @@ func (q *waitq) dequeueg(gp *g) {
|
||||
if sgp == nil {
|
||||
return
|
||||
}
|
||||
if sgp.g == gp {
|
||||
if sgp == s {
|
||||
*l = sgp.next
|
||||
if q.last == sgp {
|
||||
q.last = prevsgp
|
||||
|
Loading…
Reference in New Issue
Block a user