De la lectura de las páginas del manual sobre el read()
y write()
llamadas parece que estas llamadas quedan interrumpidos por las señales independientemente de si tienen o no bloquear.
En particular, asuma
- Un proceso establece un controlador para alguna señal.
- se abre un dispositivo (por ejemplo, un terminal) con el
O_NONBLOCK
no configurado (es decir, opera en modo de bloqueo) - el proceso realiza una
read()
llamada al sistema para leer desde el dispositivo y, como resultado, ejecuta una ruta de control de kernel en kernel-space. - mientras el preceso está ejecutando su
read()
espacio en el núcleo, la señal para la que se instaló el controlador anteriormente se entrega a ese proceso y se invoca su controlador de señal.
Al leer las páginas de manual y las secciones correspondientes en SUSv3 'Volumen de interfaces del sistema (XSH)' , se encuentra que:
yo. Si a read()
es interrumpido por una señal antes de leer cualquier dato (es decir, tuvo que bloquear porque no había datos disponibles), devuelve -1 con errno
set en [EINTR].
ii) Si a read()
es interrumpido por una señal después de haber leído con éxito algunos datos (es decir, fue posible comenzar a atender la solicitud de inmediato), devuelve el número de bytes leídos.
Pregunta A):
¿Estoy en lo cierto al suponer que en cualquier caso (bloqueo / no bloqueo) la entrega y el manejo de la señal no es completamente transparente para el read()
?
Caso i. parece comprensible ya que el bloqueo read()
normalmente colocaría el proceso en el TASK_INTERRUPTIBLE
estado de modo que cuando se entrega una señal, el núcleo coloca el proceso en TASK_RUNNING
estado.
Sin embargo, cuando read()
no es necesario bloquear (caso ii.) Y está procesando la solicitud en kernel-space, habría pensado que la llegada de una señal y su manejo serían transparentes, como la llegada y el manejo adecuado de un HW la interrupción sería En particular, habría asumido que al entregar la señal, el proceso se colocaría temporalmente en modo de usuario para ejecutar su controlador de señal desde el cual volvería finalmente para terminar de procesar el interrumpido read()
(en el espacio del kernel) para que se read()
ejecute su curso hasta su finalización después de lo cual el proceso vuelve al punto justo después de la llamada a read()
(en el espacio de usuario), con todos los bytes disponibles leídos como resultado.
Pero ii. parece implicar que read()
se interrumpe, ya que los datos están disponibles de inmediato, pero devuelve solo algunos de los datos (en lugar de todos).
Esto me lleva a mi segunda (y última) pregunta:
Pregunta B):
Si mi suposición bajo A) es correcta, ¿por qué read()
se interrumpe, a pesar de que no necesita bloquearse porque hay datos disponibles para satisfacer la solicitud de inmediato? En otras palabras, ¿por qué read()
no se reanuda después de ejecutar el controlador de señal, y finalmente se devuelven todos los datos disponibles (que estaban disponibles después de todo)?
fuente
Para responder la pregunta A :
Sí, la entrega y el manejo de la señal no es completamente transparente para el
read()
.La
read()
carrera a mitad de camino puede estar ocupando algunos recursos mientras está interrumpida por la señal. Y el manejador de señal de la señal también puede llamar a otroread()
(o a cualquier otra llamada al sistema segura de señal asíncrona ). Por lo tanto, loread()
interrumpido por la señal debe detenerse primero para liberar los recursos que utiliza, de lo contrario, laread()
llamada del manejador de señales accederá a los mismos recursos y causará problemas reentrantes.Debido a que las llamadas al sistema
read()
pueden ser llamadas desde el controlador de señales y también pueden ocupar un conjunto idéntico de recursos como loread()
hace. Para evitar los problemas de reentrada anteriores, el diseño más simple y seguro es detener la interrupciónread()
cada vez que ocurre una señal durante su ejecución.fuente