¿Qué es un proceso ininterrumpido?

156

A veces, cada vez que escribo un programa en Linux y falla debido a algún tipo de error, se convertirá en un proceso ininterrumpido y continuará ejecutándose para siempre hasta que reinicie mi computadora (incluso si me desconecto). Mis preguntas son:

  • ¿Qué hace que un proceso se vuelva ininterrumpible?
  • ¿Cómo evito que eso suceda?
  • Esta es probablemente una pregunta tonta, pero ¿hay alguna forma de interrumpirla sin reiniciar mi computadora?
Jason Baker
fuente
¿Es posible que se pueda escribir un programa para iniciar un proceso que entra en un TASK_UNINTERUPTIBLEestado cada vez que el sistema no está en un estado inactivo, recolectando datos de manera forzada, esperando transmitir una vez que el superusuario sale? Esta sería una mina de oro para que los hackers recuperen información, regresen al estado zombie y transmitan información a través de la red en inactivo. Algunos pueden argumentar que esta es una forma de crear un poder Blackdoorpara los poderes fácticos, para ingresar y salir de cualquier sistema como se desee. Creo firmemente que esta escapatoria puede ser sellada para siempre, eliminando el `TASK_UNINTERUPTIB
Nuuwski
2
sería por favor comparte el código?
nuevo

Respuestas:

198

Un proceso ininterrumpible es un proceso que se encuentra en una llamada del sistema (función del núcleo) que no puede ser interrumpido por una señal.

Para comprender lo que eso significa, debe comprender el concepto de una llamada de sistema interrumpible. El ejemplo clásico es read(). Esta es una llamada al sistema que puede llevar mucho tiempo (segundos), ya que potencialmente puede implicar girar un disco duro o mover cabezas. Durante la mayor parte de este tiempo, el proceso estará inactivo, bloqueando el hardware.

Mientras el proceso está suspendido en la llamada del sistema, puede recibir una señal asincrónica de Unix (por ejemplo, SIGTERM), luego sucede lo siguiente:

  • El sistema llama a las salidas prematuramente y está configurado para devolver -EINTR al espacio de usuario.
  • Se ejecuta el manejador de señal.
  • Si el proceso aún se está ejecutando, obtiene el valor de retorno de la llamada del sistema y puede realizar la misma llamada nuevamente.

Al regresar temprano de la llamada del sistema, el código de espacio del usuario puede alterar inmediatamente su comportamiento en respuesta a la señal. Por ejemplo, terminando limpiamente en reacción a SIGINT o SIGTERM.

Por otro lado, algunas llamadas al sistema no pueden interrumpirse de esta manera. Si el sistema llama a puestos de venta por alguna razón, el proceso puede permanecer indefinidamente en este estado indestructible.

LWN publicó un buen artículo que tocó este tema en julio.

Para responder la pregunta original:

  • Cómo evitar que esto suceda: averigua qué controlador te está causando problemas y deja de usarlo o conviértete en un hacker del kernel y arréglalo.

  • Cómo matar un proceso ininterrumpido sin reiniciar: de alguna manera hacer que la llamada al sistema finalice. Con frecuencia, la forma más efectiva de hacerlo sin presionar el interruptor de alimentación es tirar del cable de alimentación. También puede convertirse en un hacker del kernel y hacer que el controlador use TASK_KILLABLE, como se explica en el artículo LWN.

ddaa
fuente
31
Saqué el cable de alimentación de mi computadora portátil y, por desgracia, no funciona. ;-)
thecarpy
1
¿No es EINTR en lugar de EAGAIN? También read () devuelve -1 y errno se establece en el error.
lethalman
2
@Dexter: De hecho, te estás perdiendo el punto. Lea el artículo de LWN : lwn.net/Articles/288056 . Esos problemas son causados ​​por programadores de controladores de dispositivos perezosos y deben corregirse en el código del controlador de dispositivos.
ddaa
44
@ddaa "La tradición de Unix (y, por lo tanto, casi todas las aplicaciones) cree que las escrituras del almacén de archivos no son interrumpibles por señal. No sería seguro ni práctico cambiar esa garantía". -> Esta es exactamente la parte más incorrecta de toda esta OMI. Simplemente interrumpa la solicitud de lectura / escritura del controlador, y cuando el dispositivo real (disco duro / tarjeta de red / etc.) entregue los datos, ignórelos. Un núcleo del sistema operativo debe estar hecho de manera que NINGÚN desarrollador pueda arruinarlo.
Dexter
2
@ ddaa Sé que Linux no es un microkernel, aunque no estoy seguro de qué parte de mi comentario se relaciona con él ... Y, entonces, ¿su comentario significa que un sistema operativo de microkernel no tiene un problema con esos procesos "ininterrumpibles"? Porque si no es así, tal vez es hora de que me convierta en un fan de microkernel ...: D
Dexter
49

Cuando un proceso está en modo de usuario, puede interrumpirse en cualquier momento (cambiar al modo kernel). Cuando el kernel vuelve al modo de usuario, comprueba si hay señales pendientes (incluidas las que se utilizan para matar el proceso, como SIGTERMy SIGKILL). Esto significa que un proceso solo se puede eliminar al volver al modo de usuario.

La razón por la que un proceso no se puede eliminar en modo kernel es que podría corromper las estructuras del kernel utilizadas por todos los demás procesos en la misma máquina (de la misma manera, matar un hilo puede dañar las estructuras de datos utilizadas por otros hilos en el mismo proceso) .

Cuando el kernel necesita hacer algo que podría llevar mucho tiempo (esperar en una tubería escrita por otro proceso o esperar a que el hardware haga algo, por ejemplo), duerme al marcarse como inactivo y llamar al programador para cambiar a otro proceso (si no hay un proceso que no duerma, cambia a un proceso "ficticio" que le dice a la CPU que disminuya la velocidad un poco y se sienta en un bucle: el bucle inactivo).

Si se envía una señal a un proceso de suspensión, debe despertarse antes de que regrese al espacio del usuario y así procesar la señal pendiente. Aquí tenemos la diferencia entre los dos tipos principales de sueño:

  • TASK_INTERRUPTIBLE, el sueño interrumpible. Si una tarea está marcada con esta bandera, está durmiendo, pero puede ser despertada por señales. Esto significa que el código que marcó la tarea como en espera está esperando una posible señal, y después de que se active, la verificará y regresará de la llamada al sistema. Una vez que se maneja la señal, la llamada del sistema puede reiniciarse automáticamente (y no entraré en detalles sobre cómo funciona).
  • TASK_UNINTERRUPTIBLE, el sueño ininterrumpido. Si una tarea está marcada con este indicador, no espera ser despertada por nada más que lo que esté esperando, ya sea porque no puede reiniciarse fácilmente o porque los programas esperan que la llamada del sistema sea atómica. Esto también se puede usar para dormir que se sabe que son muy cortos.

TASK_KILLABLE (mencionado en el artículo LWN vinculado por la respuesta de ddaa) es una nueva variante.

Esto responde a tu primera pregunta. En cuanto a su segunda pregunta: no puede evitar dormir ininterrumpidamente, son algo normal (sucede, por ejemplo, cada vez que un proceso lee / escribe desde / en el disco); sin embargo, deberían durar solo una fracción de segundo. Si duran mucho más, generalmente significa un problema de hardware (o un problema de controlador de dispositivo, que tiene el mismo aspecto para el núcleo), donde el controlador de dispositivo está esperando que el hardware haga algo que nunca sucederá. También puede significar que está utilizando NFS y que el servidor NFS está inactivo (está esperando que el servidor se recupere; también puede usar la opción "intr" para evitar el problema).

Finalmente, la razón por la que no puede recuperarse es la misma razón por la que el kernel espera hasta que regrese al modo de usuario para entregar una señal o matar el proceso: podría corromper las estructuras de datos del kernel (el código que espera un sueño interrumpible puede recibir un error que le indica para volver al espacio del usuario, donde se puede eliminar el proceso; el código que espera en una suspensión ininterrumpida no espera ningún error).

CesarB
fuente
1
El error de bloqueo del sistema de archivos también es una causa probable, IME.
Tobu
3
No entiendo todo esto. "no se puede evitar dormir ininterrumpidamente": ¿no se puede hacer el sistema operativo de tal manera que el sueño ininterrumpible simplemente NO EXISTA como un estado? Entonces, la parte sobre la corrupción: ¿no puede la parte en modo kernel del proceso en sí (o lo que PODRÍA causar la corrupción) terminar o simplemente su código modificado en la memoria para regresar? Por favor, explique por qué es esto tan difícil / imposible de hacer que incluso Linux no lo ha hecho. (Pensé que este problema solo existe en Windows)
Dexter
El único caso en el que puedo pensar que haría (de forma segura) matar esos procesos realmente imposible (y no solo, digamos, excepcionalmente difícil) es si el hardware en sí podría causar la corrupción. El hardware no se puede controlar; kernel can . Pero es el núcleo el que obtiene datos del hardware y modifica la memoria (es por eso que no debe liberarse antes de que el proceso vuelva al modo de usuario y por qué podría ocurrir la corrupción) ... cambie el código del núcleo en la memoria y no más problemas.
Dexter
@Dexter piensa en el kernel como si fuera un solo proceso multiproceso, donde la parte del modo kernel de cada proceso es un hilo dentro del kernel. Su sugerencia sería tan mala como matar un solo subproceso en un programa de subprocesos múltiples: podría dejar bloqueos colgantes, estructuras de datos modificadas temporalmente o en medio de ser modificadas, y así sucesivamente.
CesarB
@CesarB bueno, tienes razón al matar un hilo ... Pero, ¿no puede el hilo "principal" (que sería el núcleo del sistema operativo y otros hilos serían los controladores, por ejemplo) de alguna manera manejarlo? Aunque esas estructuras "en medio de la modificación" parecen ser un problema realmente difícil ... tal vez nunca veremos un sistema operativo donde los procesos ininterrumpidos serían imposibles :(
Dexter
23

Los procesos ininterrumpidos normalmente esperan E / S después de un error de página.

Considera esto:

  • El subproceso intenta acceder a una página que no está en el núcleo (ya sea un ejecutable que se carga por demanda, una página de memoria anónima que se ha intercambiado o un archivo mmap () 'd que se carga por demanda, que son la misma cosa)
  • El núcleo ahora está (intentando) cargarlo
  • El proceso no puede continuar hasta que la página esté disponible.

El proceso / tarea no se puede interrumpir en este estado, porque no puede manejar ninguna señal; si lo hiciera, ocurriría otra falla de página y volvería a estar donde estaba.

Cuando digo "proceso", realmente me refiero a "tarea", que en Linux (2.6) se traduce aproximadamente como "hilo" que puede tener o no una entrada individual de "grupo de hilos" en / proc

En algunos casos, puede estar esperando mucho tiempo. Un ejemplo típico de esto sería donde el archivo ejecutable o mmap'd está en un sistema de archivos de red donde el servidor ha fallado. Si la E / S finalmente tiene éxito, la tarea continuará. Si finalmente falla, la tarea generalmente obtendrá un SIGBUS o algo así.

MarkR
fuente
1
Si finalmente falla, la tarea generalmente obtendrá un SIGBUS o algo así. Espera, ¿no se puede hacer el kernel para que, al matar esos procesos "ininterrumpidos", simplemente les DIGA que la operación de E / S falló? ¿Entonces el proceso volvería al modo de usuario y desaparecería? Tiene que haber una manera de matar de forma segura esos procesos de estado 'D'. Supongo que no es fácil y por eso ni Windows ni Linux tienen esa posibilidad todavía. Por otro lado, me gustaría poder matar esos procesos al menos de forma insegura. No me importa el posible bloqueo del sistema o lo que sea ...
Dexter
@Dexter hmm, nunca he tenido este problema con Windows. ¿Cuál es una manera de reproducirlo allí? Al menos según esta publicación , todas las solicitudes de E / S se pueden interrumpir en Windows.
Ruslan
1

A su tercera pregunta: creo que puede matar los procesos ininterrumpidos mediante la ejecución sudo kill -HUP 1. Reiniciará init sin finalizar los procesos en ejecución y después de ejecutarlo, mis procesos ininterrumpidos desaparecieron.

Ron Granger
fuente
-3

Si está hablando de un proceso "zombie" (que se designa como "zombie" en la salida ps), este es un registro inofensivo en la lista de procesos que espera que alguien recopile su código de retorno y podría ignorarse con seguridad.

¿Podría por favor describir qué y "proceso ininterrumpido" es para usted? ¿Sobrevive al "kill -9" y felizmente avanza? Si ese es el caso, entonces está atascado en alguna llamada al sistema, que está atascado en algún controlador, y usted está atascado con este proceso hasta que se reinicie (y a veces es mejor reiniciarlo pronto) o la descarga del controlador relevante (lo que es poco probable que suceda) . Podrías intentar usar "strace" para descubrir dónde está atascado tu proceso y evitarlo en el futuro.

Adepto
fuente
¿No se pueden descargar a la fuerza los controladores de la misma manera que se podría matar un proceso? Sé que el modo kernel tiene un acceso más privilegiado que el modo de usuario, pero nunca puede ser más privilegiado que el propio sistema operativo. Cualquier cosa que se ejecute en modo kernel siempre puede alterar cualquier otra cosa que se ejecute en modo kernel: simplemente no hay control.
Dexter