Pregunta

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

  • ¿Qué hace que un proceso se vuelva ininterrumpido?
  • ¿Cómo puedo evitar que eso suceda?
  • Esta es probablemente una pregunta tonta, pero ¿hay alguna forma de interrumpirla sin reiniciar mi computadora?
¿Fue útil?

Solución

Un proceso ininterrumpido es un proceso que ocurre en una llamada del sistema (función del núcleo) que no puede ser interrumpida 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 tardar mucho tiempo (segundos), ya que 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á inactivo en la llamada del sistema, puede recibir una señal asíncrona de Unix (por ejemplo, SIGTERM), luego sucede lo siguiente:

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

El retorno temprano de la llamada al sistema permite que el código de espacio del usuario altere 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 ser interrumpidas de esta manera. Si el sistema llama a las paradas por algún motivo, el proceso puede permanecer indefinidamente en este estado implacable.

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

Para responder a la pregunta original:

  • Cómo evitar que esto suceda: descubra qué controlador le está causando problemas y deje de usarlo, o conviértase en un hacker del kernel y corríjalo.

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

Otros consejos

Cuando un proceso está en modo usuario, se puede interrumpir 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 detener el proceso, como SIGTERM y SIGKILL ). Esto significa que un proceso solo puede interrumpirse al volver al modo de usuario.

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

Cuando el kernel necesita hacer algo que puede llevar mucho tiempo (esperar en una tubería escrita por otro proceso o esperar que el hardware haga algo, por ejemplo), se inactiva marcándose como inactivo y llamando al programador a cambie a otro proceso (si no hay un proceso que no esté inactivo, cambia a un proceso "ficticio" que le dice a la CPU que reduzca la velocidad un poco y se siente en un bucle: el bucle inactivo).

Si se envía una señal a un proceso de suspensión, debe activarse antes de que regrese al espacio del usuario y, por lo tanto, procese 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á inactiva, pero puede ser activada por señales. Esto significa que el código que marcó la tarea como inactivo está esperando una posible señal y, una vez que se despierte, lo comprobará y regresará de la llamada del sistema. Una vez que se maneja la señal, la llamada al sistema se puede reiniciar automáticamente (y no entraré en detalles sobre cómo funciona).
  • TASK_UNINTERRUPTIBLE , el sueño ininterrumpible. Si una tarea está marcada con este indicador, no espera que lo despierte nada más que lo que está esperando, ya sea porque no se puede reiniciar 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 de LWN vinculado a la respuesta de ddaa) es una nueva variante.

Esto responde a tu primera pregunta. En cuanto a su segunda pregunta: no puede evitar los tiempos de inactividad ininterrumpidos, son algo normal (sucede, por ejemplo, cada vez que un proceso lee / escribe desde / en el disco); sin embargo, deben durar sólo una fracción de segundo. Si duran mucho más tiempo, generalmente significa un problema de hardware (o un problema de controlador de dispositivo, que se parece al kernel), 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 regresar al modo de usuario para enviar una señal o anular el proceso: podría corromper las estructuras de datos del kernel (el código que espera en un modo de espera interrumpible puede recibir un error) que le dice que regrese al espacio del usuario, donde el proceso puede ser eliminado; el código que espera en un modo de espera ininterrumpible no está esperando ningún error).

Los procesos ininterrumpidos generalmente ESTÁN esperando la E / S después de un error de página.

Considera esto:

  • El hilo intenta acceder a una página que no está en el núcleo (ya sea un ejecutable cargado 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 mucho lo mismo)
  • El núcleo está ahora (intentando) cargarlo en
  • 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 en la 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 a "hilo" que puede o no tener un " grupo de hilos " entrada en / proc

En algunos casos, puede estar esperando mucho tiempo. Un ejemplo típico de esto sería cuando 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í.

A tu tercera pregunta: Creo que puedes matar los procesos ininterrumpidos ejecutando sudo kill -HUP 1 . Reiniciará init sin finalizar los procesos en ejecución y después de ejecutarlo, mis procesos ininterrumpidos desaparecieron.

Si estás hablando de un " zombie " proceso (que se designa como " zombie " en la salida de ps), entonces este es un registro inofensivo en la lista de procesos en espera de que alguien recoja su código de retorno y podría ser ignorado de forma segura.

¿Podrías describir qué y " proceso ininterrumpido " ¿es para ti? ¿Sobrevive al " kill -9 " y felizmente sigue adelante? Si ese es el caso, entonces está atascado en algún syscall, que está atascado en algún controlador, y está atascado con este proceso hasta el reinicio (y, a veces, es mejor reiniciar pronto) o la descarga del controlador relevante (lo cual es poco probable que ocurra) . Puedes intentar usar " strace " para averiguar dónde está bloqueado su proceso y evitarlo en el futuro.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top