¿Qué deben hacer los shells interactivos en los grupos de procesos huérfanos?

10

(Volver a publicar en Unix según la sugerencia en /programming/13718394/what-should-interactive-shells-do-in-orphaned-process-groups )

La pregunta corta es, ¿qué debe hacer un shell si está en un grupo de proceso huérfano que no posee el tty? Pero recomiendo leer la larga pregunta porque es divertida.

Aquí hay una manera divertida y emocionante de convertir su computadora portátil en un calentador de espacio portátil, utilizando su carcasa favorita (a menos que sea uno de esos bichos raros):

#include <unistd.h>   
int main(void) {
    if (fork() == 0) {
        execl("/bin/bash", "/bin/bash", NULL);
    }
    return 0;
}

Esto hace que bash fije la CPU al 100%. zsh y fish hacen lo mismo, mientras que ksh y tcsh murmuran algo sobre el control del trabajo y luego se desploman, lo cual es un poco mejor, pero no mucho. Ah, y es un delincuente agnóstico de plataforma: OS X y Linux están afectados.

Mi (potencialmente mal) explicación es la siguiente: la cáscara niño detecta que no está en primer plano: tcgetpgrp(0) != getpgrp(). Por lo tanto, trata de detener a sí mismo: killpg(getpgrp(), SIGTTIN). Pero su grupo de proceso es huérfano, porque su padre (el programa C) fue el líder y murió, y se lo SIGTTINenvió a un grupo de proceso huérfano (de lo contrario, nada podría iniciarlo de nuevo). Por lo tanto, el shell hijo no se detiene, pero todavía está en segundo plano, por lo que lo hace todo de nuevo, de inmediato. Enjuague y repita.

Mi pregunta es, ¿cómo puede un shell de línea de comando detectar este escenario y qué es lo que debe hacer? Tengo dos soluciones, ninguna de las cuales es ideal:

  1. Intente señalar el proceso cuyo pid coincide con nuestra ID de grupo. Si eso falla ESRCH, significa que probablemente estamos huérfanos.
  2. Intente una lectura sin bloqueo de un byte de /dev/tty. Si eso falla EIO, significa que probablemente estamos huérfanos.

(Nuestro problema para rastrear esto es https://github.com/fish-shell/fish-shell/issues/422 )

Gracias por tus pensamientos!

pez ridículo
fuente

Respuestas:

4

Estoy de acuerdo con su análisis y estoy de acuerdo en que parece que tiene que detectar si su grupo de procesos es huérfano o no.

tcsetattrtambién está destinado a regresar EIOsi el grupo de procesos queda huérfano (y no estamos bloqueando / ignorando SIGTT OU . Esa podría ser una forma menos intrusiva que una readen el terminal.

Tenga en cuenta que puede reproducirlo con:

(bash<&1 &)

Necesita la redirección; de lo contrario, stdin se redirige a / dev / null cuando se ejecuta un comando en segundo plano.

(bash<&1 & sleep 2)

Da un comportamiento aún más extraño, ya que terminas leyendo dos proyectiles desde la terminal. Están ignorando SIGTTINy el nuevo no está detectando, una vez que comienza, ya no está en el grupo de procesos en primer plano.

ksh93La solución no es tan mala: solo ve hasta 20 veces (en lugar de infinito) a través de ese ciclo antes de rendirte.

Stéphane Chazelas
fuente