@@ -635,20 +635,9 @@ func (q *spanQueue) destroy() {
635635
636636 lock (& work .spanSPMCs .lock )
637637
638- // Remove and free each ring.
638+ // Remove, deinitialize, and free each ring.
639639 for r := (* spanSPMC )(q .chain .tail .Load ()); r != nil ; r = (* spanSPMC )(r .prev .Load ()) {
640- prev := r .allprev
641- next := r .allnext
642- if prev != nil {
643- prev .allnext = next
644- }
645- if next != nil {
646- next .allprev = prev
647- }
648- if work .spanSPMCs .all == r {
649- work .spanSPMCs .all = next
650- }
651-
640+ work .spanSPMCs .list .remove (unsafe .Pointer (r ))
652641 r .deinit ()
653642 mheap_ .spanSPMCAlloc .free (unsafe .Pointer (r ))
654643 }
@@ -688,15 +677,10 @@ func (q *spanQueue) destroy() {
688677type spanSPMC struct {
689678 _ sys.NotInHeap
690679
691- // allnext is the link to the next spanSPMC on the work.spanSPMCs list.
692- // This is used to find and free dead spanSPMCs. Protected by
693- // work.spanSPMCs.lock.
694- allnext * spanSPMC
695-
696- // allprev is the link to the previous spanSPMC on the work.spanSPMCs
697- // list. This is used to find and free dead spanSPMCs. Protected by
680+ // allnode is the linked list node for work.spanSPMCs list. This is
681+ // used to find and free dead spanSPMCs. Protected by
698682 // work.spanSPMCs.lock.
699- allprev * spanSPMC
683+ allnode listNodeManual
700684
701685 // dead indicates whether the spanSPMC is no longer in use.
702686 // Protected by the CAS to the prev field of the spanSPMC pointing
@@ -724,12 +708,7 @@ type spanSPMC struct {
724708func newSpanSPMC (cap uint32 ) * spanSPMC {
725709 lock (& work .spanSPMCs .lock )
726710 r := (* spanSPMC )(mheap_ .spanSPMCAlloc .alloc ())
727- next := work .spanSPMCs .all
728- r .allnext = next
729- if next != nil {
730- next .allprev = r
731- }
732- work .spanSPMCs .all = r
711+ work .spanSPMCs .list .push (unsafe .Pointer (r ))
733712 unlock (& work .spanSPMCs .lock )
734713
735714 // If cap < the capacity of a single physical page, round up.
@@ -765,8 +744,7 @@ func (r *spanSPMC) deinit() {
765744 r .head .Store (0 )
766745 r .tail .Store (0 )
767746 r .cap = 0
768- r .allnext = nil
769- r .allprev = nil
747+ r .allnode = listNodeManual {}
770748}
771749
772750// slot returns a pointer to slot i%r.cap.
@@ -795,26 +773,16 @@ func freeDeadSpanSPMCs() {
795773 // GOMAXPROCS, or if this list otherwise gets long, it would be nice to
796774 // have a way to batch work that allows preemption during processing.
797775 lock (& work .spanSPMCs .lock )
798- if gcphase != _GCoff || work .spanSPMCs .all == nil {
776+ if gcphase != _GCoff || work .spanSPMCs .list . empty () {
799777 unlock (& work .spanSPMCs .lock )
800778 return
801779 }
802- r := work .spanSPMCs .all
780+ r := ( * spanSPMC )( work .spanSPMCs .list . head ())
803781 for r != nil {
804- next := r . allnext
782+ next := ( * spanSPMC )( unsafe . Pointer ( r . allnode . next ))
805783 if r .dead .Load () {
806- // It's dead. Deinitialize and free it.
807- prev := r .allprev
808- if prev != nil {
809- prev .allnext = next
810- }
811- if next != nil {
812- next .allprev = prev
813- }
814- if work .spanSPMCs .all == r {
815- work .spanSPMCs .all = next
816- }
817-
784+ // It's dead. Remove, deinitialize and free it.
785+ work .spanSPMCs .list .remove (unsafe .Pointer (r ))
818786 r .deinit ()
819787 mheap_ .spanSPMCAlloc .free (unsafe .Pointer (r ))
820788 }
0 commit comments