Go

What does this program do on Go 1.13 vs Go 1.14+?

Question 153HardGo 1.22 to 1.25
package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	runtime.GOMAXPROCS(1)
	go func() {
		for {
		}
	}()
	time.Sleep(10 * time.Millisecond)
	fmt.Println("done")
}

Go 1.13 and earlier: the program hangs forever. The spinning goroutine takes the only P when main goes to sleep. The loop contains no function call, so it has no preemption point. The timer fires, but main never gets a P to run on.

Go 1.14+: it prints done. sysmon sees that the goroutine has run for more than 10 ms and sends it SIGURG. The goroutine is preempted asynchronously, and main gets the P back.

Follow-up: busy loops are still wrong, even though they no longer deadlock. They burn a whole CPU. Use channels, sync.Cond or timers instead. With GODEBUG=asyncpreemptoff=1, the program hangs again.

More on Goroutines & the Scheduler

All 35 Goroutines & the Scheduler questions