runtime: don't try to interrupt other cores before they are started

The GC shouldn't try to interrupt other cores before they are started.
For example, it would be possible for the GC to run in a package
initializer (which is currently run on a single core). That would
suggest questionable program design, but it is something that should
work. So this commit makes sure the GC only tries to scan the stack of
other cores when those other cores have in fact started.
This commit is contained in:
Ayke van Laethem
2025-06-12 13:41:45 +02:00
committed by Ron Evans
parent e395c94e5f
commit f7d8502572
2 changed files with 27 additions and 0 deletions
+23
View File
@@ -14,6 +14,24 @@ var gcScanState atomic.Uint32
// Start GC scan by pausing the world (all other cores) and scanning their
// stacks. It doesn't resume the world.
func gcMarkReachable() {
// If the other cores haven't started yet (for example, when a GC cycle
// happens during init()), we only need to scan the stack of the current
// core.
if !secondaryCoresStarted {
// Scan the stack(s) of the current core.
scanCurrentStack()
if !task.OnSystemStack() {
// Mark system stack.
markRoots(task.SystemStack(), stackTop)
}
// Scan globals.
findGlobals(markRoots)
// Nothing more to do: the other cores haven't started yet.
return
}
core := currentCPU()
// Interrupt all other cores.
@@ -81,6 +99,11 @@ func scanstack(sp uintptr) {
// Resume the world after a call to gcMarkReachable.
func gcResumeWorld() {
if !secondaryCoresStarted {
// Nothing to do: the world wasn't stopped in gcMarkReachable.
return
}
// Signal each core that they can resume.
hartID := currentCPU()
for i := uint32(0); i < numCPU; i++ {
+4
View File
@@ -14,6 +14,9 @@ const hasParallelism = true
var mainExited atomic.Uint32
// True after the secondary cores have started.
var secondaryCoresStarted bool
// Which task is running on a given core (or nil if there is no task running on
// the core).
var cpuTasks [numCPU]*task.Task
@@ -141,6 +144,7 @@ func run() {
// After package initializers have finished, start all the other cores.
startSecondaryCores()
secondaryCoresStarted = true
// Run main.main.
callMain()