Go's GC forced Go to add signal-based preemption
Not sure where I am going with this garbage collection rabbit hole

Go, Kotlin, and Erlang/Elixir each solve M:N scheduling differently, and their choices about who controls task switching shape everything from preemption to garbage collection. Go's GC originally relied on cooperative preemption, which let tight loops without function calls hang the entire process. The fix—signal-based preemption via SIGURG—was driven by this GC deadlock, not just fairness. This deep dive traces Go's evolution from cooperative to asynchronous safe-points, explaining the GMP scheduler, the tricolor mark-sweep GC, and why Go rejected loop-back-edge checks for a 7.8% throughput cost.
A goroutine stuck in a tight loop with no function calls blocked this indefinitely.