You let the blocking call do a non-blocking call internally and then instruct an IO-aware user-mode scheduler to reschedule the user-mode thread when the non-blocking call has a result. This is what Haskell/GHC, Erlang and Ruby 1.8 do. There are some great papers on GHC's IO manager. In general, it is always possible to build a blocking interface on top of a non-blocking.
I guess I wasn't clear in my previous question. I know you can build a blocking interface our of a non-blocking one. My question was how you go the other way. How do you create a non-blocking interface of of a blocking one. The parent post seemed to imply that Erlang was able to do this. As far as I can tell this can't actually be done. If you have a blocking call you still have to block an OS thread somewhere.
If this can't be done, then that brings me back to my previous point. It seems like the important thing is that you have non-blocking IO and not that you have an M:N threading model in the runtime. If you have non-blocking IO then it seems like you could easily implement an M:N threading model as a library without making it awkward to interact with.
Is there some assumption I'm making that doesn't make sense?
The Erlang runtime uses non-blocking IO calls to the kernel but exposes blocking functions on top of this. Is such a function really blocking? It depends on what level you're looking at; it's blocking at Erlang level but non-blocking at kernel level. I think this is the source of the confusion. You are of course correct in saying "If you have a blocking call you still have to block an OS thread somewhere." if you're looking at kernel level, but not Erlang level (since it can translate blocking to non-blocking).
> If you have non-blocking IO then it seems like you could easily implement an M:N threading model as a library without making it awkward to interact with.
Yes, but your language/system has to have some mechanism to manage control flow. Examples: F# does what you ask for via asynchronous workflows. Ruby via fibers/EM-Synchrony. Java via a bytecode weaver like Kilim.