You make an excellent point. In fact, user-level threads packages are
usually just n-ary coroutine managers in disguise. Thus, when a user-
level thread blocks, it is simply making a coroutine transfer to another
(suspended) user-level thread, via some scheduling mechanism that is
entirely under the user's control. One downside to this is that such
threads managers are nonpreemptive, and so part of the threads
scheduling policy may have to be embedded in the code executed by the
threads, in the form of thread_yield (or whatever) calls, to prevent
that code from hogging the CPU. The other downside, of course, is that
(pure) user-level threads cannot take advantage of multiple CPUs.
Tom Dailey