Qué archivo en el núcleo especifica fork (), vfork () ... para usar la llamada al sistema sys_clone ()

9

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) +++
usuario3539
fuente
Esto podría ser útil para usted: lxr.linux.no/linux+v3.10.9
reproduzca el
@ mauro.stettler No pude encontrarlo en lxr
user3539
¿Te refieres a git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/… alrededor de la línea 1700? ¿Qué esperabas descubrir?
msw

Respuestas:

29

Los envoltorios fork()y vfork()en glibc se implementan mediante la clone()llamada al sistema. Para comprender mejor la relación entre fork()y clone(), 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 inmediato exec(). 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 normalidad fork()es la copia de las tablas de página del padre y la asignación de una estructura de descriptor de proceso única task_structpara 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_structaspecto propio que simplemente se configura de tal manera que comparte ciertos recursos, como un espacio de direcciones, con el proceso principal.

El flagsparámetro de la clone()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 de clone(), la única diferencia es el conjunto de indicadores a los que se pasa clone().

Un normal fork()podría implementarse como:

clone(SIGCHLD, 0);

Esto crea una tarea que no comparte ningún recurso con su padre y está configurada para enviar la SIGCHLDseñ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:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

vfork()a su vez, se implementa a través de un CLONE_VFORKindicador 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 llame exec()o salga. El niño no tiene permiso para escribir en la memoria. La clone()llamada correspondiente podría ser la siguiente:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

La implementación de sys_clone()es específica de la arquitectura, pero la mayor parte del trabajo ocurre en do_fork()definido en kernel/fork.c. Esta función llama al static clone_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 clon flags. Cuando clone_process()regrese, do_clone()despertará el proceso recién creado y lo programará para ejecutarse.

Thomas Nyman
fuente
2
+1 Buena explicación del significado de clone()en relación con hilos y horquillas.
Ricitos de Oro
1
Despejó todas mis dudas
user3539
2

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.

Ignacio Vazquez-Abrams
fuente