lock(&work.spanSPMCs.lock)
- // Mark each ring as dead. The sweeper will actually free them.
- //
- // N.B., we could free directly here, but work.spanSPMCs.all is a
- // singly-linked list, so we'd need to walk the entire list to find the
- // previous node. If the list becomes doubly-linked, we can free
- // directly.
+ // Remove and free each ring.
for r := (*spanSPMC)(q.chain.tail.Load()); r != nil; r = (*spanSPMC)(r.prev.Load()) {
- r.dead.Store(true)
+ prev := r.allprev
+ next := r.allnext
+ if prev != nil {
+ prev.allnext = next
+ }
+ if next != nil {
+ next.allprev = prev
+ }
+ if work.spanSPMCs.all == r {
+ work.spanSPMCs.all = next
+ }
+
+ r.deinit()
+ mheap_.spanSPMCAlloc.free(unsafe.Pointer(r))
}
q.chain.head = nil
// work.spanSPMCs.lock.
allnext *spanSPMC
+ // allprev is the link to the previous spanSPMC on the work.spanSPMCs
+ // list. This is used to find and free dead spanSPMCs. Protected by
+ // work.spanSPMCs.lock.
+ allprev *spanSPMC
+
// dead indicates whether the spanSPMC is no longer in use.
// Protected by the CAS to the prev field of the spanSPMC pointing
// to this spanSPMC. That is, whoever wins that CAS takes ownership
func newSpanSPMC(cap uint32) *spanSPMC {
lock(&work.spanSPMCs.lock)
r := (*spanSPMC)(mheap_.spanSPMCAlloc.alloc())
- r.allnext = work.spanSPMCs.all
+ next := work.spanSPMCs.all
+ r.allnext = next
+ if next != nil {
+ next.allprev = r
+ }
work.spanSPMCs.all = r
unlock(&work.spanSPMCs.lock)
r.head.Store(0)
r.tail.Store(0)
r.cap = 0
+ r.allnext = nil
+ r.allprev = nil
}
// slot returns a pointer to slot i%r.cap.
unlock(&work.spanSPMCs.lock)
return
}
- rp := &work.spanSPMCs.all
- for {
- r := *rp
- if r == nil {
- break
- }
+ r := work.spanSPMCs.all
+ for r != nil {
+ next := r.allnext
if r.dead.Load() {
// It's dead. Deinitialize and free it.
- *rp = r.allnext
+ prev := r.allprev
+ if prev != nil {
+ prev.allnext = next
+ }
+ if next != nil {
+ next.allprev = prev
+ }
+ if work.spanSPMCs.all == r {
+ work.spanSPMCs.all = next
+ }
+
r.deinit()
mheap_.spanSPMCAlloc.free(unsafe.Pointer(r))
- } else {
- // Still alive, likely in some P's chain.
- // Skip it.
- rp = &r.allnext
}
+ r = next
}
unlock(&work.spanSPMCs.lock)
}