* I managed to block a whole erlang VM one day, spoke with Joe Armstrong on chat, but they won't fix this, as it's pretty niche use case.
I can think of a few ways:
- The VM just doesn’t JIT and can decide to stop executing a thread by just not interpreting the next piece of bytecode and switching to another green thread instead (this would be pretty slow due to the lack of JIT)
- The VM JITs, but inserts a preamble before every function call saying “Before executing this function, should I switch to another green thread first?”, and thus, so long as you call functions frequently enough, you “preempt” yourself. This is how Go does it, and it’s a well known thing in Go that if you never call a function for a while (like just doing a really huge for loop), the current goroutine doesn’t yield execution and hogs the whole OS thread.
I'm not sure of the implementation details, but this hasn't been true for a while in Go. As of Go 1.14, goroutines are asynchronously preemptible, so loops without function calls no longer deadlock the scheduler or GC: https://go.dev/doc/go1.14#runtime
In addition to Java virtual threads, similar systems exist in Go goroutines, Rust async and Haskell green threads for example.
There are upsides and downsides to cooperative userspace threads. An erratic or malicious green thread can hog all the CPU time and starve other threads for example.
An operating system can not trust the userspace to behave, starvation due to misbehaving thread is unacceptable.
So the OS can not implement green threads alone, it needs the userspace for the co-operative switching.