Una forma de hacer esto es hacer que el paquete de subprocesamiento en el código de usuario se registre a sí mismo para algún tipo de interrupción de temporizador del kernel. Cada vez que recibe una interrupción de este tipo, puede decirle al kernel que detenga la ejecución de todos los hilos del núcleo que están ejecutando varios hilos diferentes. Para cada uno de esos hilos, el código de interrupción del temporizador puede inspeccionar la pila para esos hilos, registrar información importante (registros, puntero de pila, contador de programa, etc.) en una ubicación auxiliar, y luego cargar la información almacenada para otra de las simulaciones hilos que se ejecutan en ese hilo real. Luego puede reanudar el hilo del kernel ejecutando el hilo simulado. De esta forma, puede simular el cambio de contexto entre los múltiples hilos que se ejecutan en una única cadena del kernel.
Para implementar algo así como el bloqueo, puede realizar un seguimiento de toda la información de bloqueo localmente en su espacio de usuario. Cada vez que un subproceso simulado intenta adquirir un bloqueo, puede verificar si el subproceso puede obtener el bloqueo correctamente. Si es así, simplemente dale la cerradura. De lo contrario, simula un cambio de contexto intercambiando el hilo simulado que se está ejecutando en ese hilo real, luego marcando el hilo simulado como bloqueado hasta que el bloqueo vuelva a estar libre.
Esto es solo un comienzo: hay muchos otros detalles aquí (¿qué pasa si uno de los hilos simulados intenta hacer una operación de E/S de bloqueo? No se puede simplemente bloquear el hilo del kernel, ya que eso detendría todo ¡los hilos simulados!), pero esta es la esencia de la idea.
Coroutines, ¿eh? –