diff --git a/main_test.go b/main_test.go index 17b2b5a572..a2408f8f36 100644 --- a/main_test.go +++ b/main_test.go @@ -81,6 +81,7 @@ func TestBuild(t *testing.T) { "print.go", "reflect.go", "signal.go", + "signalnotify.go", "slice.go", "sort.go", "stdlib.go", diff --git a/src/runtime/signalstub.go b/src/runtime/signalstub.go index fd7d2606a9..0d701b02ba 100644 --- a/src/runtime/signalstub.go +++ b/src/runtime/signalstub.go @@ -18,4 +18,12 @@ func signal_ignore(uint32) {} func signal_waitUntilIdle() {} //go:linkname signal_recv os/signal.signal_recv -func signal_recv() uint32 { return ^uint32(0) } +func signal_recv() uint32 { + // Signals can never arrive on these platforms, so block forever, like the + // real implementation does while no signal is pending. os/signal.loop + // calls this function in a tight loop; returning immediately would make + // that goroutine spin, which starves cooperative schedulers: on wasm the + // program never yields back to the host again after signal.Notify. + deadlock() + return 0 +} diff --git a/testdata/signalnotify.go b/testdata/signalnotify.go new file mode 100644 index 0000000000..aa430c6270 --- /dev/null +++ b/testdata/signalnotify.go @@ -0,0 +1,22 @@ +package main + +// Verify that signal.Notify does not wedge the scheduler on platforms where +// signals can never arrive (wasm and baremetal, see runtime/signalstub.go). +// The signal watcher goroutine that Notify starts must block forever instead +// of spinning: on a cooperative scheduler a spinning goroutine starves every +// other goroutine, so the sleep below would never return. + +import ( + "os" + "os/signal" + "time" +) + +func main() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + // Yield so the signal watcher goroutine runs (and, before the fix, takes + // over the scheduler forever). + time.Sleep(10 * time.Millisecond) + println("done") +} diff --git a/testdata/signalnotify.txt b/testdata/signalnotify.txt new file mode 100644 index 0000000000..19f86f493a --- /dev/null +++ b/testdata/signalnotify.txt @@ -0,0 +1 @@ +done