sudog = nod(OTSTRUCT, N, N);
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8]))));
- sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("link")), typenod(ptrto(types[TUINT8]))));
+ sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("next")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
func (q *waitq) enqueue(sgp *sudog) {
sgp.next = nil
- if q.first == nil {
+ x := q.last
+ if x == nil {
+ sgp.prev = nil
q.first = sgp
q.last = sgp
return
}
- q.last.next = sgp
+ sgp.prev = x
+ x.next = sgp
q.last = sgp
}
if sgp == nil {
return nil
}
- q.first = sgp.next
- sgp.next = nil
- if q.last == sgp {
+ y := sgp.next
+ if y == nil {
+ q.first = nil
q.last = nil
+ } else {
+ y.prev = nil
+ q.first = y
+ sgp.next = nil // mark as removed (see dequeueSudog)
}
// if sgp participates in a select and is already signaled, ignore it
}
})
}
+
+func BenchmarkChanPopular(b *testing.B) {
+ const n = 1000
+ c := make(chan bool)
+ var a []chan bool
+ for j := 0; j < n; j++ {
+ d := make(chan bool)
+ a = append(a, d)
+ go func() {
+ for i := 0; i < b.N; i++ {
+ select {
+ case <-c:
+ case <-d:
+ }
+ }
+ }()
+ }
+ for i := 0; i < b.N; i++ {
+ for _, d := range a {
+ d <- true
+ }
+ }
+}
k.releasetime = sglist.releasetime
}
if sg == sglist {
+ // sg has already been dequeued by the G that woke us up.
cas = k
} else {
c = k._chan
return
}
-func (q *waitq) dequeueSudoG(s *sudog) {
- var prevsgp *sudog
- l := &q.first
- for {
- sgp := *l
- if sgp == nil {
+func (q *waitq) dequeueSudoG(sgp *sudog) {
+ x := sgp.prev
+ y := sgp.next
+ if x != nil {
+ if y != nil {
+ // middle of queue
+ x.next = y
+ y.prev = x
+ sgp.next = nil
+ sgp.prev = nil
return
}
- if sgp == s {
- *l = sgp.next
- if q.last == sgp {
- q.last = prevsgp
- }
- s.next = nil
- return
- }
- l = &sgp.next
- prevsgp = sgp
+ // end of queue
+ x.next = nil
+ q.last = x
+ sgp.prev = nil
+ return
+ }
+ if y != nil {
+ // start of queue
+ y.prev = nil
+ q.first = y
+ sgp.next = nil
+ return
+ }
+
+ // x==y==nil. Either sgp is the only element in the queue,
+ // or it has already been removed. Use q.first to disambiguate.
+ if q.first == sgp {
+ q.first = nil
+ q.last = nil
}
}