While the user threading library will schedule user threads, the kernel will schedule the underlying LWPs. Without coordination between the kernel and the thread library the kernel can make sub-optimal scheduling decisions. Further, it is possible for cases of deadlock to occur when user threads distributed over several LWPs try to acquire the same resources that are used by another user thread that is not currently running.
One solution to this problem is scheduler activation. This is a method for the kernel and the thread library to cooperate. The kernel notifies the thread library's scheduler about certain events (such as when a thread is about to block) and the thread library can make a decision on what action to take. The notification call from the kernel is called an "upcall".
A user level library has no control over the underlying mechanism, it only receives notifications from the kernel and schedules user threads onto available LWPs, not processors. The kernel's scheduler then decides how to schedule the LWPs onto the processors. This means that LWPs can be seen by the thread library as "virtual processors".
Read more about this topic: Light-weight Process