¿Por qué un hijo de vfork o fork llama a _exit () en lugar de exit ()?

12

De la página del manual de vfork():

vfork () difiere de fork () en que el padre está suspendido hasta que el niño hace una llamada a execve (2) o _exit (2). El hijo comparte toda la memoria con su padre, incluida la pila, hasta que el hijo emita execve (). El hijo no debe regresar de la función actual o de la llamada a exit (), pero puede llamar a _exit ().

¿Por qué el niño debe usar un en _exit()lugar de simplemente llamar exit()? Espero que esto sea aplicable a ambos vfork()y fork().

Sen
fuente
2
si está interesado en una discusión
xenoterracide

Respuestas:

11

Como se vio anteriormente , vforkno permite que el proceso secundario acceda a la memoria de los padres. exites una función de biblioteca C (es por eso que a menudo se escribe como exit(3)). Realiza varias tareas de limpieza, como enjuagar y cerrar flujos C (los archivos se abren a través de funciones declaradas en stdio.h) y ejecutar funciones especificadas por el usuario registradas en atexit. Todas estas tareas implican leer y escribir en la memoria del proceso.

_exitsale sin limpieza. Es directamente una llamada al sistema (es por eso que se escribe como _exit(2)), generalmente implementada colocando el número de llamada del sistema en un registro del procesador y ejecutando una instrucción de procesador particular (bifurcación al manejador de llamadas del sistema). Esto no necesita acceder a la memoria del proceso, por lo que es seguro hacerlo después vfork.

Después fork, no existe tal restricción: el proceso padre e hijo ahora son completamente autónomos.

Gilles 'SO- deja de ser malvado'
fuente
¿vfork no permite que el proceso secundario acceda a la memoria de los padres ? Pero pensé que compartían el mismo espacio de direcciones, por lo que el niño puede acceder al espacio de direcciones de los padres. ¿Estaba mal ese entendimiento?
Sen
Después de la bifurcación, no existe tal restricción: el proceso primario y secundario ahora son completamente autónomos. ¿Eso significa que puedo llamar a una salida () de un hijo de un tenedor?
Sen
1
@Sen: el niño no puede acceder a la memoria de los padres. Si lo prueba, podría funcionar, porque el núcleo no lo protegerá. Pero el efecto podría no ser el que pretendes; por ejemplo, si su compilador decide dejar algún valor en un registro, el proceso padre no lo verá.
Gilles 'SO- deja de ser malvado'
@Sen: después de una bifurcación, puede hacer una llamada de salida o cualquier otra función. Cada proceso comienza después de una bifurcación (en Linux, incluso el proceso inicial inites bifurcado por el núcleo).
Gilles 'SO- deja de ser malvado'
3

exitrealice una limpieza adicional, como llamar a funciones registradas por atexitlo que accede a datos fuera de la parte copiada. _exitrealiza syscall directamente sin ninguna limpieza excepto en el núcleo.

Maciej Piechotka
fuente
... y debe tenerse en cuenta que fork () copia todo, por lo que puede llamar a exit (), y definitivamente puede regresar de la función actual.
derobert
3

Tiene el elemento secundario call _exit () para evitar el vaciado de buffers stdio (u otros) cuando finaliza el proceso secundario. Dado que el proceso hijo constituye una copia exacta del proceso padre, el proceso hijo todavía tiene lo que el padre tenía en "stdout" o "stderr", los almacenamientos intermedios de <stdio.h>. Puede (y lo hará, en momentos inoportunos) obtener salidas dobles llamando a exit (), una desde los controladores atexit del proceso hijo y otra desde el padre, cuando los buffers en el proceso padre se llenan y se vacían.

Me doy cuenta de que la respuesta anterior se concentra en los detalles de stdio.h, pero esa idea probablemente se traslade a otras E / S almacenadas, tal como indica una de las respuestas anteriores.

Bruce Ediger
fuente
1

exit(): realiza una tarea de limpieza, como cerrar las secuencias de E / S y muchas, y luego vuelve al núcleo. _exit(): - llega directamente al kernel (no realice ninguna tarea de limpieza).

fork() : tanto el padre como el hijo tienen una tabla de archivos diferente, por lo que el cambio realizado por el hijo no afecta los parámetros del entorno del padre y viceversa.

vfork(): tanto el padre como el hijo usan la misma tabla de archivos, por lo que el cambio realizado por el hijo afecta los parámetros del entorno del padre. por ejemplo, alguna variable var=10, ahora ejecutada var++por hijo y luego ejecutada principal, también puede ver el efecto var++en la salida de principal.

Como ya he dicho si se utiliza exit()en la vfork()entonces toda la E / S ya está cerrado. Entonces, incluso si el padre se ejecuta correctamente, no puede obtener la salida adecuada, porque todas las variables se vacían y todas las secuencias están cerradas.

usuario2670535
fuente