Cada dispositivo Linux parece estar implementado de forma ligeramente diferente, y la manera preferida parece variar cada pocos Linux libera a medida que se añaden características del núcleo más seguros/más rápido, pero en general:
controlador
- El dispositivo crea leer y escribir colas de espera para un dispositivo.
- Cualquier secuencia de proceso que desee esperar para E/S se coloca en la cola de espera apropiada. Cuando se produce una interrupción , el controlador despierta uno o más hilos de espera . (Obviamente, los subprocesos no se ejecutan inmediatamente ya que estamos en el contexto de interrupción , pero se agregan a la cola de programación del kernel ).
- Cuando programado por el kernel, el hilo comprueba si las condiciones son correctas para que proceda; si no es así, vuelve a la cola de espera.
Un ejemplo típico (ligeramente simplificada):
En el controlador en la inicialización:
init_waitqueue_head(&readers_wait_q);
En la función de lectura de un conductor:
if (filp->f_flags & O_NONBLOCK)
{
return -EAGAIN;
}
if (wait_event_interruptible(&readers_wait_q, read_avail != 0))
{
/* signal interrupted the wait, return */
return -ERESTARTSYS;
}
to_copy = min(user_max_read, read_avail);
copy_to_user(user_buf, read_ptr, to_copy);
A continuación, el controlador de interrupción solo problemas:
wake_up_interruptible(&readers_wait_q);
Tenga en cuenta que wait_event_interruptible() es una macro que oculta un bucle que comprueba una condición - read_avail != 0
en este caso - y agrega repetidas veces a la cola de espera si se despierta cuando la condición no es verdadera.
Como se mencionó, hay una serie de variaciones, la principal es que si hay mucho trabajo para el manejador de interrupciones entonces hace el mínimo y retrasa el resto a una cola de trabajo o tasklet (generalmente conocida como la "mitad inferior") y es esto lo que activaría los hilos de espera.
Ver libro del controlador de dispositivo Linux para más detalles - pdf disponible aquí: http://lwn.net/Kernel/LDD3
Más o menos, ha puesto el dedo en la cabeza (a excepción de la última observación, no hay votación, en su mayor parte). La multiplexión entre múltiples camareros y archivos la realiza el kernel, que es un proceso invisible que coordina cosas como esta en nombre de todos los demás procesos. –