linux - ¿Qué es un proceso ininterrumpible?
scheduling preemption (6)
A veces, cada vez que escribo un programa en Linux y se cuelga debido a un error de algún tipo, se convertirá en un proceso ininterrumpido y continuará ejecutándose para siempre hasta que reinicie mi computadora (incluso si cierro la sesión). Mis preguntas son:
- ¿Qué causa que un proceso se vuelva ininterrumpido?
- ¿Cómo evito que eso suceda?
- Esta es probablemente una pregunta tonta, pero ¿hay alguna manera de interrumpirla sin reiniciar mi computadora?
¿Es posible que un programa se pueda escribir para iniciar un proceso que entra en un estado TASK_UNINTERUPTIBLE
siempre que el sistema no esté en un estado inactivo, por lo tanto recolectando datos a la fuerza, esperando para transmitir una vez que el súper usuario 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 Blackdoor
para los poderes existentes, para ingresar y salir de cualquier sistema como se desee. Creo firmemente que esta laguna se puede TASK_UNINTERUPTIBLE
para siempre, al eliminar el estado TASK_UNINTERUPTIBLE
.
Veo esto como un problema serio pero sutil de seguridad para los sistemas Linux, que tienen una reputación de seguridad, a través del empoderamiento del súper usuario. Estoy trabajando para convertirme en un Kernel Hacker, sin embargo, creo que hay hackers kernel que pueden solucionar esta debacle.
¿Podría describir qué es y "proceso ininterrumpido"? ¿Sobrevive al "matar -9" y felizmente se lleva a casa? Si ese es el caso, está atascado en algunos syscall, que está atascado en algún controlador, y usted está atascado con este proceso hasta que se reinicia (y en ocasiones es mejor reiniciarlo pronto) o la descarga del controlador relevante (lo que es poco probable que suceda) . Podría tratar de utilizar "strace" para descubrir dónde está atrapado su proceso y evitarlo en el futuro.
Pero si se trata de un proceso "zombie" (que se designa como "zombie" en ps output), este es un registro inofensivo en la lista de procesos en espera de que alguien recoja su código de retorno y se puede ignorar de forma segura.
A su tercera pregunta: Creo que puede matar los procesos ininterrumpibles ejecutando sudo kill -HUP 1
. Se reiniciará init sin finalizar los procesos en ejecución y, después de ejecutarlo, mis procesos ininterrumpibles desaparecieron.
Cuando un proceso está en modo de usuario, se puede interrumpir en cualquier momento (cambiando al modo kernel). Cuando el kernel vuelve al modo de usuario, verifica si hay señales pendientes (incluidas las que se utilizan para matar el proceso, como SIGTERM
y SIGKILL
). Esto significa que un proceso puede ser eliminado solo al regresar al modo de usuario.
La razón por la que un proceso no puede eliminarse en modo kernel es que podría dañar las estructuras del kernel utilizadas por todos los demás procesos en la misma máquina (de la misma forma que matar un hilo puede dañar las estructuras de datos utilizadas por otros hilos en el mismo proceso) .
Cuando el núcleo 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), duerme marcándose a sí mismo como inactivo y llamando al programador para cambiar a otro proceso (si no hay un proceso que no duerme, cambia a un proceso "ficticio" que le dice a la CPU que reduzca la velocidad un poco y se sienta en un bucle, el ciclo inactivo).
Si se envía una señal a un proceso inactivo, se debe activar 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 despertarse mediante señales. Esto significa que el código que marcó la tarea como estar dormido espera una señal posible, y después de que se despierta lo buscará y regresará de la llamada al sistema. Después de manejar la señal, la llamada al sistema puede reiniciarse automáticamente (y no entraré en detalles sobre cómo funciona). -
TASK_UNINTERRUPTIBLE
, el sueño ininterrumpible. Si una tarea está marcada con esta marca, no espera ser despertada por otra cosa que no sea lo que está esperando, ya sea porque no se puede reiniciar fácilmente o porque los programas esperan que la llamada al sistema sea atómica. Esto también se puede usar para dormir que se sabe que es muy corto.
TASK_KILLABLE
(mencionado en el artículo de LWN vinculado por la respuesta de ddaa) es una nueva variante.
Esto responde su primera pregunta. En cuanto a su segunda pregunta: no puede evitar las interrupciones ininterrumpidas, son algo normal (sucede, por ejemplo, cada vez que un proceso lee / escribe desde / hacia 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 con el controlador del dispositivo, que se ve igual en el núcleo), donde el controlador del dispositivo está esperando que el hardware haga algo que nunca sucederá. También puede significar que está utilizando NFS y 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 entregar una señal o matar el proceso: potencialmente corrompería las estructuras de datos del kernel (código esperando en un sueño interrumpible puede recibir un error que le dice para regresar al espacio de usuario, donde el proceso puede ser eliminado, el código en espera en un modo de suspensión ininterrumpida no espera ningún error).
Los procesos ininterrumpibles ESTÁN generalmente esperando 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 archivo ejecutable cargado por demanda, una página de memoria anónima que se ha intercambiado, o un archivo mmap () ''cargado a demanda, que son mucho la misma cosa)
- El kernel está ahora (tratando de) 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 de página y volvería a estar donde estaba.
Cuando digo "proceso", realmente me refiero a "tarea", que bajo Linux (2.6) se traduce aproximadamente como "hilo" que puede o no tener una entrada individual de "grupo de hilos" en / proc
En algunos casos, puede estar esperando durante 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í.
Un proceso ininterrumpible es un proceso que sucede en una llamada al sistema (función kernel) que no puede ser interrumpida por una señal.
Para entender lo que eso significa, debe comprender el concepto de una llamada al sistema interrumpible. El ejemplo clásico es read()
. Esta es una llamada al sistema que puede llevar mucho tiempo (segundos) ya que puede involucrar girar un disco duro o mover cabezas. Durante la mayor parte de este tiempo, el proceso estará durmiendo, bloqueando el hardware.
Mientras el proceso duerme en la llamada al sistema, puede recibir una señal asíncrona de Unix (por ejemplo, SIGTERM), entonces sucede lo siguiente:
- El sistema llama a las salidas prematuramente y está configurado para devolver -EINTR al espacio de usuario.
- El manejador de señal se ejecuta.
- Si el proceso aún se está ejecutando, obtiene el valor de retorno de la llamada al sistema y puede realizar la misma llamada nuevamente.
Si regresa antes de la llamada del sistema, el código de espacio del usuario cambia 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 por algún motivo, el proceso puede permanecer indefinidamente en este estado no recuperable.
LWN publicó un buen artículo que tocó este tema en julio.
Para responder 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 pirata informático del kernel y fíjelo.
Cómo matar un proceso ininterrumpible 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 encendido es jalar el cable de alimentación. También puede convertirse en un hacker de kernel y hacer que el controlador use TASK_KILLABLE, como se explica en el artículo de LWN.