Quale file nel kernel specifica fork (), vfork ()… per usare la chiamata di sistema sys_clone ()


9

Quando ltrace viene utilizzato per tracciare le chiamate di sistema, vedo che fork () usa sys_clone () anziché sys_fork (). Ma non sono riuscito a trovare il sorgente Linux dove è definito.

Il mio programma è

#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");

}

E l'output di ltrace è

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) +++

Questo potrebbe esserti utile: lxr.linux.no/linux+v3.10.9
riproduzione

@ mauro.stettler Non sono riuscito a trovarlo in lxr
user3539

Intendi git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/… intorno alla linea 1700? Cosa speravi di scoprire?
msw,

Risposte:


29

I wrapper fork()e vfork()in glibc sono implementati tramite la clone()chiamata di sistema. Per comprendere meglio la relazione tra fork()e clone(), dobbiamo considerare la relazione tra processi e thread in Linux.

Tradizionalmente, fork()pubblica tutte le risorse di proprietà del processo padre e assegna la copia al processo figlio. Questo approccio comporta un notevole sovraccarico, il che potrebbe essere inutile se il bambino chiama immediatamente exec(). In Linux, fork()utilizza pagine di copia su scrittura per ritardare o evitare del tutto la copia dei dati che possono essere condivisi tra i processi padre e figlio. Pertanto, l'unico sovraccarico che si verifica durante una normale fork()è la copia delle tabelle delle pagine del genitore e l'assegnazione di una struttura descrittore di processo univoca task_struct, per il figlio.

Linux ha anche un approccio eccezionale ai thread. In Linux, i thread sono semplicemente processi ordinari che condividono alcune risorse con altri processi. Questo è un approccio radicalmente diverso ai thread rispetto ad altri sistemi operativi come Windows o Solaris, in cui processi e thread sono completamente diversi tipi di bestie. In Linux, ogni thread ha un proprio ordinario task_structche sembra essere configurato in modo tale da condividere determinate risorse, come uno spazio di indirizzi, con il processo padre.

Il flagsparametro della clone()chiamata di sistema include un insieme di flag che indicano quali risorse, se presenti, devono essere condivise dai processi padre e figlio. Processi e thread vengono entrambi creati tramite clone(), l'unica differenza è l'insieme di flag a cui viene passato clone().

Una normale fork()potrebbe essere implementata come:

clone(SIGCHLD, 0);

Questo crea un'attività che non condivide alcuna risorsa con il suo genitore ed è impostata per inviare il SIGCHLDsegnale di terminazione al genitore quando esce.

Al contrario, un'attività che condivide lo spazio degli indirizzi, le risorse del filesystem, i descrittori di file e i gestori di segnale con il genitore, in altre parole un thread , potrebbe essere creata con:

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

vfork()a sua volta viene implementato tramite un CLONE_VFORKflag separato , che farà dormire il processo genitore fino a quando il processo figlio non lo riattiverà tramite un segnale. Il figlio sarà l'unico thread di esecuzione nello spazio dei nomi del genitore, fino a quando non chiama exec()o esce. Al bambino non è permesso scrivere nella memoria. La clone()chiamata corrispondente potrebbe essere la seguente:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

L'implementazione di sys_clone()è specifica per l'architettura, ma la maggior parte del lavoro avviene in do_fork()definito in kernel/fork.c. Questa funzione chiama statico clone_process(), che crea un nuovo processo come copia del genitore, ma non lo avvia ancora. clone_process()copia i registri, assegna un PID alla nuova attività e pubblica o condivide parti appropriate dell'ambiente di processo come specificato dal clone flags. Quando clone_process()ritorna, do_clone()riattiva il processo appena creato e lo pianifica per l'esecuzione.


2
+1 Bella spiegazione del significato di clone()in relazione a fili e forchette.
Riccioli d'oro


2

Il componente responsabile della traduzione delle funzioni di chiamata del sistema userland in chiamate di sistema del kernel in Linux è il libc. In GLibC, la libreria NPTL reindirizza questo alla clone(2)chiamata di sistema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.