Erlang's message passing system is probably more important to the success of its concurrency model than the specifics of the scheduler. As proven perhaps by the success of Akka and other actor-based systems built on a different threading model.
Erlang's scheduler is preemptive. Erlang processes can be preempted by the scheduler in the middle of execution and moved to the back of the scheduler queue or to another scheduler thread. There is no requirement for a process itself to yield time back to the scheduler to make sure that other processes receive some execution time. This is one component of how it achieves "soft-realtime" semantics. Eight processes, on a system with 8 scheduler threads, running in a tight loop cannot cause all other processes in the Erlang VM to be blocked. Other processes will be given time.
The only thing that violates this guarantee is long-running or blocking code executing on the native side of the NIF boundary.
Akka, goroutines, Cloud Haskell, etc. are exactly the kinds of things I'm talking about when I say I don't understand the point of actor frameworks running in environments that can't preempt actor execution. You had better hope all your actor implementations are well-behaved or that the implementations you're going to import from someone else are all well behaved... otherwise you're going to lockup your scheduler's thread pool.
OS processes are preemptive, however process threads are not. I'm not sure what you are trying to say about Erlang's scheduler itself being cooperative. It is a preemptive scheduler.
> Erlang's message passing system is probably more important to the success of its concurrency model than the specifics of the scheduler.
I disagree, preemptive concurrency is a fundamental piece of BEAM's success. Preemption gives Erlang its fault tolerance and low latency guarantees. If by message passing you mean immutability, then perhaps they are of equal importance.
From what I know Erlang's scheduler preempts processes it executes. Can you explain what you mean by it being "cooperative". It precisely useful because it is not cooperative. And processes don't have to "yield to" the scheduler.
The Erlang VM can intercede into a running process, and also does this with some of it's BIFs implemented in C.
From what I know, they cannot, not at arbitrary places, and that's why the scheduler is a cooperative one.
From the Erlang docs on process priority.
The BEAM VM can kill, halt, or suspend a running process at anytime from outside the process. It does not need to wait around for the process to exceed its reduction count limit.
Some of this capability is even exposed to user-land applications. The exit/2 function builds on top of this capability when sending in th atom 'kill' as the second argument. As do the suspend_process/1, suspend_process/2, and resume_process/1 functions.
The reduction count system is just there as a kind of fair-scheduling determinism semantic. Exhausting reduction allocations is not the only way the VM has to interact with running processes.
> From the Erlang docs on process priority.
Well, apparently you're right. I must take back what I said about Erlang scheduler.
The system simply uses the TPL for scheduling (which is actually very good).