Cuando ltrace se usa para rastrear las llamadas del sistema, pude ver que fork () usa sys_clone () en lugar de sys_fork (). Pero no pude encontrar la fuente de Linux donde está definida.
Mi programa es
#include<stdio.h>
main()
{
int pid,i=0,j=0;
pid=fork();
if(pid==0)
printf("\nI am child\n");
else
printf("\nI am parent\n");
}
Y la salida de ltrace es
SYS_brk(NULL) = 0x019d0000
SYS_access("/etc/ld.so.nohwcap", 00) = -2
SYS_mmap(0, 8192, 3, 34, 0xffffffff) = 0x7fe3cf84f000
SYS_access("/etc/ld.so.preload", 04) = -2
SYS_open("/etc/ld.so.cache", 0, 01) = 3
SYS_fstat(3, 0x7fff47007890) = 0
SYS_mmap(0, 103967, 1, 2, 3) = 0x7fe3cf835000
SYS_close(3) = 0
SYS_access("/etc/ld.so.nohwcap", 00) = -2
SYS_open("/lib/x86_64-linux-gnu/libc.so.6", 0, 00) = 3
SYS_read(3, "\177ELF\002\001\001", 832) = 832
SYS_fstat(3, 0x7fff470078e0) = 0
SYS_mmap(0, 0x389858, 5, 2050, 3) = 0x7fe3cf2a8000
SYS_mprotect(0x7fe3cf428000, 2097152, 0) = 0
SYS_mmap(0x7fe3cf628000, 20480, 3, 2066, 3) = 0x7fe3cf628000
SYS_mmap(0x7fe3cf62d000, 18520, 3, 50, 0xffffffff) = 0x7fe3cf62d000
SYS_close(3) = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7fe3cf834000
SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7fe3cf833000
SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7fe3cf832000
SYS_arch_prctl(4098, 0x7fe3cf833700, 0x7fe3cf832000, 34, 0xffffffff) = 0
SYS_mprotect(0x7fe3cf628000, 16384, 1) = 0
SYS_mprotect(0x7fe3cf851000, 4096, 1) = 0
SYS_munmap(0x7fe3cf835000, 103967) = 0
__libc_start_main(0x40054c, 1, 0x7fff47008298, 0x4005a0, 0x400590 <unfinished ...>
fork( <unfinished ...>
SYS_clone(0x1200011, 0, 0, 0x7fe3cf8339d0, 0) = 5967
<... fork resumed> ) = 5967
puts("\nI am parent" <unfinished ...>
SYS_fstat(1, 0x7fff47008060) = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff
) = 0x7fe3cf84e000
I am child
SYS_write(1, "\n", 1
) = 1
SYS_write(1, "I am parent\n", 12) = -512
--- SIGCHLD (Child exited) ---
SYS_write(1, "I am parent\n", 12I am parent
) = 12
<... puts resumed> ) = 13
SYS_exit_group(13 <no return ...>
+++ exited (status 13) +++
linux
linux-kernel
system-calls
trace
ltrace
usuario3539
fuente
fuente
Respuestas:
Los envoltorios
fork()
yvfork()
en glibc se implementan mediante laclone()
llamada al sistema. Para comprender mejor la relación entrefork()
yclone()
, debemos considerar la relación entre procesos y subprocesos en Linux.Tradicionalmente,
fork()
duplicaría todos los recursos que posee el proceso padre y asignaría la copia al proceso hijo. Este enfoque conlleva una sobrecarga considerable, que podría ser en vano si el niño llama de inmediatoexec()
. En Linux,fork()
utiliza páginas de copia en escritura para retrasar o evitar por completo la copia de los datos que se pueden compartir entre los procesos padre e hijo. Por lo tanto, la única sobrecarga en la que se incurre durante una normalidadfork()
es la copia de las tablas de página del padre y la asignación de una estructura de descriptor de proceso únicatask_struct
para el hijo.Linux también adopta un enfoque excepcional para los hilos. En Linux, los subprocesos son procesos meramente ordinarios que comparten algunos recursos con otros procesos. Este es un enfoque radicalmente diferente de los subprocesos en comparación con otros sistemas operativos como Windows o Solaris, donde los procesos y los subprocesos son tipos de bestias completamente diferentes. En Linux, cada subproceso tiene un
task_struct
aspecto propio que simplemente se configura de tal manera que comparte ciertos recursos, como un espacio de direcciones, con el proceso principal.El
flags
parámetro de laclone()
llamada al sistema incluye un conjunto de indicadores que indican qué recursos, si los hay, deben compartir los procesos padre e hijo. Los procesos y los subprocesos se crean a través declone()
, la única diferencia es el conjunto de indicadores a los que se pasaclone()
.Un normal
fork()
podría implementarse como:Esto crea una tarea que no comparte ningún recurso con su padre y está configurada para enviar la
SIGCHLD
señal de terminación al padre cuando salga.En contraste, una tarea que comparte el espacio de direcciones, los recursos del sistema de archivos, los descriptores de archivos y los manejadores de señales con el padre, en otras palabras, un hilo , podría crearse con:
vfork()
a su vez, se implementa a través de unCLONE_VFORK
indicador separado , lo que hará que el proceso principal se suspenda hasta que el proceso secundario lo despierte mediante una señal. El hijo será el único hilo de ejecución en el espacio de nombres del padre, hasta que llameexec()
o salga. El niño no tiene permiso para escribir en la memoria. Laclone()
llamada correspondiente podría ser la siguiente:La implementación de
sys_clone()
es específica de la arquitectura, pero la mayor parte del trabajo ocurre endo_fork()
definido enkernel/fork.c
. Esta función llama al staticclone_process()
, que crea un nuevo proceso como una copia del padre, pero aún no lo inicia.clone_process()
copia los registros, asigna un PID a la nueva tarea y duplica o comparte partes apropiadas del entorno del proceso según lo especificado por el clonflags
. Cuandoclone_process()
regrese,do_clone()
despertará el proceso recién creado y lo programará para ejecutarse.fuente
clone()
en relación con hilos y horquillas.El componente responsable de traducir las funciones de llamada del sistema de usuario a las llamadas del sistema kernel en Linux es la libc. En GLibC, la biblioteca NPTL redirige esto a la
clone(2)
llamada del sistema.fuente