diff --git a/src/runtime/gc_stack_cores.go b/src/runtime/gc_stack_cores.go index 32c7e6823..faabfb0c6 100644 --- a/src/runtime/gc_stack_cores.go +++ b/src/runtime/gc_stack_cores.go @@ -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++ { diff --git a/src/runtime/scheduler_cores.go b/src/runtime/scheduler_cores.go index e261058a3..698596a71 100644 --- a/src/runtime/scheduler_cores.go +++ b/src/runtime/scheduler_cores.go @@ -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()