22
33package 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.
1620func 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