¿Existe alguna variante de UNIX en la que un proceso hijo muere con su padre?

41

Llevo bastante tiempo estudiando el comportamiento del kernel de Linux, y siempre me ha quedado claro que:

Cuando un proceso muere, todos sus hijos son devueltos al initproceso (PID 1) hasta que finalmente mueren.

Sin embargo, recientemente, alguien con mucha más experiencia que yo con el núcleo me dijo que:

Cuando finaliza un proceso, todos sus elementos secundarios también mueren (a menos que use NOHUPen cuyo caso vuelven a init).

Ahora, aunque no lo creo, aún escribí un programa simple para asegurarme de ello. Sé que no debería depender del tiempo ( sleep) para las pruebas, ya que todo depende de la programación del proceso, pero para este caso simple, creo que es bastante suficiente.

int main(void){
    printf("Father process spawned (%d).\n", getpid());
    sleep(5);

    if(fork() == 0){
        printf("Child process spawned (%d => %d).\n", getppid(), getpid());
        sleep(15);
        printf("Child process exiting (%d => %d).\n", getppid(), getpid());
        exit(0);
    }

    sleep(5);
    printf(stdout, "Father process exiting (%d).\n", getpid());
    return EXIT_SUCCESS;
}

Aquí está la salida del programa, con el psresultado asociado cada vez que printfhabla:

$ ./test &
Father process spawned (435).

$ ps -ef | grep test
myuser    435    392   tty1    ./test

Child process spawned (435 => 436).

$ ps -ef | grep test
myuser    435    392   tty1    ./test
myuser    436    435   tty1    ./test

Father process exiting (435).

$ ps -ef | grep test
myuser    436    1     tty1    ./test

Child process exiting (436).

Ahora, como puede ver, esto se comporta como esperaba. El proceso huérfano (436) se devuelve a init(1) hasta que muere.

Sin embargo, ¿hay algún sistema basado en UNIX en el que este comportamiento no se aplique por defecto? ¿Existe algún sistema en el que la muerte de un proceso desencadene inmediatamente la muerte de todos sus hijos?

John WH Smith
fuente

Respuestas:

68

Cuando finaliza un proceso, todos sus elementos secundarios también mueren (a menos que use NOHUP, en cuyo caso volverán a init).

Esto está mal. Completamente equivocado. La persona que dijo que estaba equivocada o confundió una situación particular con el caso general.

Hay dos formas en que la muerte de un proceso puede causar indirectamente la muerte de sus hijos. Están relacionados con lo que sucede cuando un terminal está cerrado. Cuando un desaparece terminales (históricamente porque la línea serie fue cortada debido a un módem cuelgue, hoy en día por lo general porque el usuario cierra la ventana de emulador de terminal), una señal SIGHUP se envía al proceso de control que se ejecuta en ese terminal - típicamente, comenzó la cáscara inicial en esa terminal Los proyectiles normalmente reaccionan a esto al salir. Antes de salir, los shells destinados para uso interactivo envían HUP a cada trabajo que comenzaron.

Iniciar un trabajo desde un shell con nohupinterrupciones de esa segunda fuente de señales HUP porque el trabajo ignorará la señal y, por lo tanto, no se le pedirá que muera cuando el terminal desaparezca. Otras formas de interrumpir la propagación de las señales de HUP desde el shell a los trabajos incluyen el uso del disownbuiltin incorporado del shell si tiene uno (el trabajo se elimina de la lista de trabajos del shell) y la doble bifurcación (el shell lanza un niño que lanza un niño por sí mismo y sale inmediatamente; el caparazón no tiene conocimiento de su nieto).

Una vez más, los trabajos iniciados en la terminal mueren no porque su proceso padre (el shell) muere, sino porque su proceso padre decide matarlos cuando se le dice que los mate. Y el shell inicial en el terminal muere no porque su proceso padre muera, sino porque su terminal desaparece (lo que puede ser coincidencia o no porque el terminal lo proporciona un emulador de terminal que es el proceso padre del shell).

Gilles 'SO- deja de ser malvado'
fuente
1
Hay una tercera forma, algo con grupos de control. Todo lo que sé es que systemd lo usa para imponer asesinatos limpios.
o11c
55
@JanHudec Creo que estás confundiendo nohupcon disown. disownes un componente incorporado en algún shell que elimina un trabajo en ejecución de la tabla de trabajos (tomando un argumento como %1), y el principal efecto secundario útil de eso es que el shell no enviará un SIGHUP al subproceso. nohupes una utilidad externa que ignora SIGHUP (y hace algunas otras cosas) y luego inicia el comando pasado en su línea de comando.
Gilles 'SO- deja de ser malvado'
@Gilles: No, no lo estaba, pero mirar strace nohupde hecho ignora la señal antes de que sea execel comando.
Jan Hudec
¡Gracias por su respuesta! Particularmente me gustó el poco de antecedentes históricos relacionados con los bloqueos de módem. Estaba empezando a preocuparme porque había estado malinterpretando el núcleo todo este tiempo ...
John WH Smith
3
También se debe tener en cuenta que un programa sale cuando recibe SIGHUP porque el manejador de señal predeterminado para SIGHUP es salir. Pero cualquier programa puede implementar su propio controlador SIGHUP, lo que puede hacer que no salga cuando el shell principal lo envíe SIGHUP.
slebetman
12

Cuando finaliza un proceso, todos sus elementos secundarios también mueren (a menos que use NOHUP, en cuyo caso volverán a init).

Esto es correcto si el proceso es un líder de sesión. Cuando un líder de sesión muere, se envía un SIGHUP a todos los miembros de esa sesión. En la práctica eso significa sus hijos y sus descendientes.

Un proceso se convierte en líder de la sesión llamando setsid. Las conchas usan esto.

Dennis
fuente
Acabo de hacer una prueba sobre esto, pero no pude reproducir el comportamiento que estás describiendo ... Generé un proceso, le di una nueva sesión ( fork, proceso de matar a los padres, setsid) y bifurqué a otro niño en esta nueva sesión. Sin embargo, cuando el proceso de los padres (nuevo líder de sesión) murió, el niño no recibió SIGHUP y se apegó inithasta que finalmente salió.
John WH Smith
Desde la página de setpgid(2)manual: si una sesión tiene un terminal de control, y el indicador CLOCAL para ese terminal no está configurado, y se produce un bloqueo del terminal, entonces el líder de la sesión recibe un SIGHUP. Si el líder de la sesión sale, también se enviará una señal SIGHUP a cada proceso en el grupo de procesos en primer plano del terminal de control.
ninjalj
1
@ninjalj Entonces supongo que esta respuesta es válida si y solo si el líder de la sesión también es el proceso de control de un terminal. Un líder de sesión estándar, independiente de cualquier terminal, no matará a sus hijos. ¿Es correcto?
John WH Smith
-1

Entonces, lo que dicen los carteles anteriores es que los niños no mueren, los padres los matan (o les envían una señal en la que terminan). Para que pueda tener lo que pide, si programa al padre para (1) mantener un registro de todos sus hijos y (2) enviar una señal a todos sus hijos.

Esto es lo que hace el Shell, y debería ser lo que hace el proceso principal. Puede ser necesario captar la señal HUP en el padre para que todavía tenga el control suficiente para matar a los niños.

marco
fuente
Muchas causas pueden hacer que los padres mueran. No hay forma de prevenir la supervivencia de los niños si el padre está SIGKILLADO, por ejemplo.
Emil Jeřábek apoya a Monica el
-1

Me faltan un poco en las respuestas que están ligeramente relacionadas con los padres moribundos: cuando un proceso escribe en una tubería para la que ya no hay un proceso de lectura, obtiene un SIGPIPE. La acción estándar para SIGPIPE es la terminación.

De hecho, esto puede causar que los procesos mueran. De hecho, es la forma estándar en que el programa yesmuere.

Si ejecuto

(yes;echo $? >&2)|head -10

en mi sistema, la respuesta es

y
y
y
y
y
y
y
y
y
y
141

y 141 es de hecho 128 + SIGPIPE:

   SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                 readers

de man 7 signal.

usuario86542
fuente
2
Pero el proceso de lectura de la tubería no es necesariamente (o incluso generalmente) su padre. Así que este es realmente un caso muy diferente de lo que se está haciendo la pregunta.
Barmar