Files
tinygo/src/internal/task/task_exit.go
T
Jake Bailey 16fc1ea2bb runtime: make fatal failures unrecoverable
Match the Go runtime by terminating for deadlocks, stack overflows,
runtime and GC invariants, invalid lock operations, and platform
initialization failures instead of routing them through panic/recover.

Keep language-level runtime errors and unsupported user operations
recoverable. Add crash coverage that verifies fatal errors bypass deferred
recover calls.
2026-07-25 07:14:00 +02:00

43 lines
909 B
Go

//go:build scheduler.tasks || scheduler.asyncify || scheduler.cores
package task
import "sync/atomic"
var (
mainTask *Task
liveTasks uint32
mainExitedByGoexit uint32
)
func addLiveTask(t *Task) {
if mainTask == nil {
mainTask = t
}
atomic.AddUint32(&liveTasks, 1)
}
// Exit exits the current task because runtime.Goexit was called.
func Exit() {
exit(true)
}
func exit(goexit bool) {
t := Current()
remaining := atomic.AddUint32(&liveTasks, ^uint32(0))
if t == mainTask {
if goexit {
if remaining == 0 {
runtimeFatal("all goroutines are asleep - deadlock!")
}
atomic.StoreUint32(&mainExitedByGoexit, 1)
}
} else if atomic.LoadUint32(&mainExitedByGoexit) != 0 && remaining == 0 {
runtimeFatal("all goroutines are asleep - deadlock!")
}
// TODO: explicitly free the stack after switching back to the scheduler.
Pause()
runtimeFatal("unreachable")
}