Skip to content

Commit e41d241

Browse files
committed
safely scan the runqueue on the list scheduler
1 parent c38c563 commit e41d241

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

src/runtime/gc_list.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
package runtime
44

5+
import (
6+
"internal/task"
7+
"runtime/interrupt"
8+
"unsafe"
9+
)
10+
511
// This memory manager is partially inspired by the memory allocator included in avr-libc.
612
// Unlike avr-libc malloc, this memory manager stores an allocation list instead of a free list.
713
// This gives an overhead of 2 pointers/allocation (up from avr-libc's 1 pointer-width/allocation).
@@ -10,8 +16,6 @@ package runtime
1016
// This allocator has an effective allocation complexity of O(n) and worst-case GC complexity of O(n^2).
1117
// Due to architectural quirks, as well as tiny heaps, this should almost always be faster than the standard conservative collector on AVR.
1218

13-
import "unsafe"
14-
1519
// isInHeap checks if an address is inside the heap.
1620
func isInHeap(addr uintptr) bool {
1721
return addr >= heapStart && addr < heapEnd
@@ -77,6 +81,23 @@ func GC() {
7781
// Mark phase: mark all reachable objects, recursively.
7882
markGlobals()
7983
markStack()
84+
var markedTaskQueue task.Queue
85+
runqueueScan:
86+
if baremetal && hasScheduler {
87+
// Channel operations in interrupts may move task pointers around while we are marking.
88+
// Therefore we need to scan the runqueue seperately.
89+
for !runqueue.Empty() {
90+
// Pop the next task off of the runqueue.
91+
t := runqueue.Pop()
92+
93+
// Mark the task if it has not already been marked.
94+
markRoot(uintptr(unsafe.Pointer(&runqueue)), uintptr(unsafe.Pointer(t)))
95+
96+
// Push the task onto our temporary queue.
97+
markedTaskQueue.Push(t)
98+
}
99+
}
100+
80101
var keep *allocNode
81102
for scanList != nil {
82103
// Pop a node off of the scan list.
@@ -102,6 +123,18 @@ func GC() {
102123
}
103124
}
104125

126+
if baremetal && hasScheduler {
127+
// Restore the runqueue.
128+
i := interrupt.Disable()
129+
if !runqueue.Empty() {
130+
// Something new came in while finishing the mark.
131+
interrupt.Restore(i)
132+
goto runqueueScan
133+
}
134+
runqueue = markedTaskQueue
135+
interrupt.Restore(i)
136+
}
137+
105138
// Sweep phase: replace the heap.
106139
allocList = keep
107140
}

0 commit comments

Comments
 (0)