shell - reglas - proceso de llamadas al sistema
¿Qué deberían hacer los shells interactivos en grupos de proceso huérfanos? (1)
Esto es lo que dice strace que está sucediendo:
--- SIGTTIN (Stopped (tty input)) @ 0 (0) --- rt_sigaction(SIGTTIN, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0 ioctl(255, TIOCGPGRP, [9954]) = 0 rt_sigaction(SIGTTIN, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0 kill(0, SIGTTIN) = 0 --- SIGTTIN (Stopped (tty input)) @ 0 (0) --- rt_sigaction(SIGTTIN, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0 ioctl(255, TIOCGPGRP, [9954]) = 0 rt_sigaction(SIGTTIN, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0 kill(0, SIGTTIN) = 0 [repeat...]
y aquí es por qué, desde jobs.c, bash 4.2:
while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1)
{
if (shell_pgrp != terminal_pgrp)
{
SigHandler *ottin;
ottin = set_signal_handler(SIGTTIN, SIG_DFL);
kill (0, SIGTTIN);
set_signal_handler (SIGTTIN, ottin);
continue;
}
break;
}
En cuanto a qué hacer al respecto ... bueno, eso está más allá de mi capacidad. Pero, pensé que esto era información útil, y un poco demasiado para un comentario.
La pregunta corta es: ¿qué debe hacer una shell si está en un grupo de proceso huérfano que no es dueño del tty? Pero recomiendo leer la pregunta larga porque es divertida.
Esta es una manera divertida y emocionante de convertir su computadora portátil en un calentador portátil, usando su shell favorito (a menos que usted sea uno de esos raritos tcsh):
#include <unistd.h>
int main(void) {
if (fork() == 0) {
execl("/bin/bash", "/bin/bash", NULL);
}
return 0;
}
Esto hace que bash pegue 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 la plataforma: OS X y Linux están afectados.
Mi explicación (potencialmente incorrecta) es la siguiente: la shell secundaria detecta que no está en primer plano: tcgetpgrp(0) != getpgrp()
. Por lo tanto, trata de detenerse: killpg(getpgrp(), SIGTTIN)
. Pero su grupo de proceso está huérfano, porque su padre (el programa C) era el líder y murió, y SIGTTIN enviado a un grupo de proceso huérfano simplemente se elimina (de lo contrario, nada podría volver a iniciarlo). Por lo tanto, el shell infantil no se detiene, pero aún está en segundo plano, así 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 correcto para hacer? Mi idea es que el shell intenta read
desde stdin, y simplemente sale si read le da EIO.
Gracias por tus pensamientos!
Edición : intenté hacer una lectura de longitud cero () en / dev / tty, y eso tuvo éxito, lo cual es malo. Para obtener el EIO, tengo que estar preparado para leer algunos datos de / dev / tty.
Edit : Otro pensamiento que tuve fue kill(getpgrp(), 0)
. Si el grupo de proceso está huérfano, entonces creo que esto siempre fallará. Sin embargo, también puede fallar porque no tengo permiso para señalar al líder de la sesión.
Edición : para quien encuentre esto más tarde, lo que terminé haciendo se describe en https://github.com/fish-shell/fish-shell/issues/422 . Además, ¿cómo es el futuro?