¿Cómo la copia en escritura en fork () maneja múltiples fork?

23

Según Wikipedia (que podría estar equivocado)

Cuando se emite una llamada al sistema fork (), se crea una copia de todas las páginas correspondientes al proceso principal, que el sistema operativo carga en una ubicación de memoria separada para el proceso secundario. Pero esto no es necesario en ciertos casos. Considere el caso cuando un niño ejecuta una " exec" llamada al sistema (que se usa para ejecutar cualquier archivo ejecutable desde un programa C) o sale muy pronto después del fork(). Cuando se necesita el hijo solo para ejecutar un comando para el proceso padre, no hay necesidad de copiar las páginas del proceso padre, ya que execreemplaza el espacio de direcciones del proceso que lo invocó con el comando que se ejecutará.

En tales casos, se utiliza una técnica llamada copia en escritura (COW). Con esta técnica, cuando se produce una bifurcación, las páginas del proceso principal no se copian para el proceso secundario. En cambio, las páginas se comparten entre el proceso secundario y el proceso primario. Cada vez que un proceso (padre o hijo) modifica una página, se realiza una copia separada de esa página en particular solo para ese proceso (padre o hijo) que realizó la modificación. Este proceso utilizará la página recién copiada en lugar de la compartida en todas las referencias futuras. El otro proceso (el que no modificó la página compartida) continúa utilizando la copia original de la página (que ahora ya no se comparte). Esta técnica se llama copia en escritura ya que la página se copia cuando algún proceso escribe en ella.

Parece que cuando cualquiera de los procesos intenta escribir en la página, se asigna una nueva copia de la página y se le asigna al proceso que generó la falla de la página. La página original se marca como escribible luego.

Mi pregunta es: ¿qué sucede si fork()se llama varias veces antes de que alguno de los procesos intente escribir en una página compartida?

ssgao
fuente
Wikipedia tiene razón en este caso, solo un nivel más alto.
Didi Kohen
1
Sí, copiar en escritura es una copia perezosa, el proceso secundario copia la página cuando intenta escribirla. Básicamente, después de una bifurcación, casi la memoria del niño se comparte con los padres. Sin embargo, antes de que se realice cualquiera de los procesos, cada proceso secundario todavía tiene algo de memoria privada, modificada de la asignación principal o nueva. Eso significa que, incluso sin ninguna acción, el proceso secundario bifurcado tiene algo de memoria privada. Podemos verificarlo con pmap -XX PIDo cat /proc/PID/smap.
where23
En cuanto a: "La página original se marca como editable después", ¿quién será el propietario? Aquí el otro proceso que no ha intentado escribirlo?
Adil
Esto es adorable. Comencemos a enseñar esto en los jardines de infancia
ed22

Respuestas:

18

No pasa nada en particular. Todos los procesos comparten el mismo conjunto de páginas y cada uno obtiene su propia copia privada cuando desea modificar una página.

jlliagre
fuente
Correcto. El punto es que es el proceso hijo el que es especial, que tiene el trabajo de copiar si intenta escribir en la página compartida. Ni el padre ni los otros niños necesitan saber sobre el cambio si se realiza correctamente.
Charles Stewart
99
El proceso hijo no es tan especial. Tanto el proceso secundario como el primario tienen el mismo conjunto de páginas de solo lectura después de la bifurcación. En lo que respecta a estas páginas, el manejo de la página es simétrico.
jlliagre
3

El comportamiento de fork () depende de si el sistema * nix tiene una MMU o no. En un sistema que no es MMU (como los primeros PDP-11), la llamada al sistema fork () copiaba toda la memoria de los padres para cada hijo. En un sistema * nix basado en MMU, el núcleo marca todas las páginas no apiladas como R / O y las comparte entre padre e hijo. Luego, cuando cualquiera de los procesos escribe en cualquier página, la MMU atrapa el intento, el núcleo asigna una página que se puede escribir y actualiza las tablas de páginas de MMU para que apunten a la página ahora que se puede escribir. Este comportamiento de Copia en escritura proporciona una aceleración ya que inicialmente solo se necesita asignar y clonar una pila privada para cada proceso secundario.

Si ejecuta algún código primario entre cada llamada fork (), los procesos secundarios resultantes diferirán según las páginas que hayan sido alteradas por el primario. Por otro lado, si el padre simplemente emite múltiples llamadas fork (), por ejemplo, en un bucle, los procesos hijos serán casi idénticos. Si se usa una variable de bucle local, entonces será diferente dentro de la pila de cada niño.

CyberFonic
fuente
0

Cuando el sistema realiza una bifurcación, generalmente (esto puede depender de la implementación) también marca las páginas como de solo lectura y marca el proceso principal como el maestro de estas páginas.
Al intentar escribir en estas páginas, se produce un error de página y el sistema operativo se hace cargo, copiando la lista completa de páginas o solo las modificadas (de nuevo, dependiendo de la implementación), por lo que el proceso de escritura tendrá una copia grabable.
Cuando hay varios procesos bifurcados del mismo, cuando el proceso "maestro" escribe en su memoria, los otros procesos obtienen sus páginas equivalentes copiadas.

Didi Kohen
fuente
¿Qué sistema hace esto? Linux utiliza una implementación de copia en escritura
brauliobo
Así es como funciona la copia en escritura ...
Didi Kohen
3
@DavidKohen no es así como funciona la copia en escritura en ninguna versión de la que haya oído hablar. No hay proceso "maestro". Si un solo proceso escribe las páginas compartidas, su copia se transfiere a una privada mientras todos los demás procesos continúan compartiéndola.
Celada
1
Creo que David Kohen tiene razón en algún momento. Esta es una forma de implementar copia en escritura. Lo esencial sería que con esta marca, escribir en esa página activaría un controlador de falla de página que luego tomaría las medidas apropiadas, es decir, copiar en escritura. Lamentablemente, este detalle (que sería específico del sistema) es irrelevante para la pregunta. Tenga en cuenta que CoW tiene dos dimensiones: la visible para el proceso y la de cómo el núcleo podría implementarlo.
0xC0000022L