1
0
mirror of https://github.com/golang/go synced 2024-11-18 13:54:59 -07:00

runtime: make mSpanList more go:notinheap-friendly

Currently mspan links to its previous mspan using a **mspan field that
points to the previous span's next field. This simplifies some of the
list manipulation code, but is going to make it very hard to convince
the compiler that mspan list manipulations don't need write barriers.

Fix this by using a more traditional ("boring") linked list that uses
a simple *mspan pointer to the previous mspan. This complicates some
of the list manipulation slightly, but it will let us eliminate all
write barriers from the mspan list manipulation code by marking mspan
go:notinheap.

Change-Id: I0d0b212db5f20002435d2a0ed2efc8aa0364b905
Reviewed-on: https://go-review.googlesource.com/30940
Reviewed-by: Rick Hudson <rlh@golang.org>
This commit is contained in:
Austin Clements 2016-10-11 11:47:14 -04:00
parent 77527a316b
commit 991a85c889

View File

@ -122,15 +122,14 @@ var mSpanStateNames = []string{
// mSpanList heads a linked list of spans. // mSpanList heads a linked list of spans.
// //
// Linked list structure is based on BSD's "tail queue" data structure.
type mSpanList struct { type mSpanList struct {
first *mspan // first span in list, or nil if none first *mspan // first span in list, or nil if none
last **mspan // last span's next field, or first if none last *mspan // last span in list, or nil if none
} }
type mspan struct { type mspan struct {
next *mspan // next span in list, or nil if none next *mspan // next span in list, or nil if none
prev **mspan // previous span's next field, or list head's first field if none prev *mspan // previous span in list, or nil if none
list *mSpanList // For debugging. TODO: Remove. list *mSpanList // For debugging. TODO: Remove.
startAddr uintptr // address of first byte of span aka s.base() startAddr uintptr // address of first byte of span aka s.base()
@ -997,28 +996,30 @@ func (span *mspan) init(base uintptr, npages uintptr) {
} }
func (span *mspan) inList() bool { func (span *mspan) inList() bool {
return span.prev != nil return span.list != nil
} }
// Initialize an empty doubly-linked list. // Initialize an empty doubly-linked list.
func (list *mSpanList) init() { func (list *mSpanList) init() {
list.first = nil list.first = nil
list.last = &list.first list.last = nil
} }
func (list *mSpanList) remove(span *mspan) { func (list *mSpanList) remove(span *mspan) {
if span.prev == nil || span.list != list { if span.list != list {
println("runtime: failed MSpanList_Remove", span, span.prev, span.list, list) println("runtime: failed MSpanList_Remove", span, span.prev, span.list, list)
throw("MSpanList_Remove") throw("MSpanList_Remove")
} }
if span.next != nil { if list.first == span {
span.next.prev = span.prev list.first = span.next
} else { } else {
// TODO: After we remove the span.list != list check above, span.prev.next = span.next
// we could at least still check list.last == &span.next here. }
list.last = span.prev if list.last == span {
list.last = span.prev
} else {
span.next.prev = span.prev
} }
*span.prev = span.next
span.next = nil span.next = nil
span.prev = nil span.prev = nil
span.list = nil span.list = nil
@ -1035,12 +1036,14 @@ func (list *mSpanList) insert(span *mspan) {
} }
span.next = list.first span.next = list.first
if list.first != nil { if list.first != nil {
list.first.prev = &span.next // The list contains at least one span; link it in.
// The last span in the list doesn't change.
list.first.prev = span
} else { } else {
list.last = &span.next // The list contains no spans, so this is also the last span.
list.last = span
} }
list.first = span list.first = span
span.prev = &list.first
span.list = list span.list = list
} }
@ -1049,10 +1052,15 @@ func (list *mSpanList) insertBack(span *mspan) {
println("failed MSpanList_InsertBack", span, span.next, span.prev, span.list) println("failed MSpanList_InsertBack", span, span.next, span.prev, span.list)
throw("MSpanList_InsertBack") throw("MSpanList_InsertBack")
} }
span.next = nil
span.prev = list.last span.prev = list.last
*list.last = span if list.last != nil {
list.last = &span.next // The list contains at least one span.
list.last.next = span
} else {
// The list contains no spans, so this is also the first span.
list.first = span
}
list.last = span
span.list = list span.list = list
} }