Lorsque ltrace est utilisé pour tracer les appels système, je pouvais voir que fork () utilise sys_clone () plutôt que sys_fork (). Mais je n'ai pas pu trouver la source Linux où elle est définie.
Mon programme est
#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");
}
Et la sortie ltrace est
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
user3539
la source
la source
Réponses:
Les wrappers
fork()
etvfork()
dans la glibc sont implémentés via l'clone()
appel système. Pour mieux comprendre la relation entrefork()
etclone()
, nous devons considérer la relation entre les processus et les threads sous Linux.Traditionnellement, la
fork()
duplication de toutes les ressources détenues par le processus parent était affectée et la copie au processus enfant. Cette approche entraîne des frais généraux considérables, qui pourraient tous être inutiles si l'enfant appelle immédiatementexec()
. Sous Linux,fork()
utilise des pages de copie sur écriture pour retarder ou éviter complètement de copier les données qui peuvent être partagées entre les processus parent et enfant. Ainsi, la seule surcharge qui est encourue pendant une normalefork()
est la copie des tables de pages du parent et l'affectation d'une structure de descripteur de processus unique,,task_struct
pour l'enfant.Linux adopte également une approche exceptionnelle des threads. Sous Linux, les threads ne sont que des processus ordinaires qui partagent des ressources avec d'autres processus. Il s'agit d'une approche radicalement différente des threads par rapport à d'autres systèmes d'exploitation tels que Windows ou Solaris, où les processus et les threads sont des types de bêtes entièrement différents. Sous Linux, chaque thread possède un ordinaire
task_struct
qui se trouve être configuré de telle sorte qu'il partage certaines ressources, comme un espace d'adressage, avec le processus parent.Le
flags
paramètre de l'clone()
appel système comprend un ensemble d'indicateurs qui indiquent, le cas échéant, les ressources que les processus parent et enfant doivent partager. Les processus et les threads sont tous deux créés viaclone()
, la seule différence est l'ensemble de drapeaux transmisclone()
.Un normal
fork()
pourrait être implémenté comme:Cela crée une tâche qui ne partage aucune ressource avec son parent et est définie pour envoyer le
SIGCHLD
signal de terminaison au parent à sa sortie.En revanche, une tâche qui partage l'espace d'adressage, les ressources du système de fichiers, les descripteurs de fichiers et les gestionnaires de signaux avec le parent, en d'autres termes un thread , pourrait être créée avec:
vfork()
à son tour, est implémenté via unCLONE_VFORK
indicateur distinct , ce qui entraînera le processus parent en veille jusqu'à ce que le processus enfant le réveille via un signal. L'enfant sera le seul fil d'exécution dans l'espace de noms du parent, jusqu'à ce qu'il appelleexec()
ou quitte. L'enfant n'est pas autorisé à écrire dans la mémoire. L'clone()
appel correspondant pourrait être le suivant:L'implémentation de
sys_clone()
est spécifique à l'architecture, mais l'essentiel du travail se déroule dansdo_fork()
défini danskernel/fork.c
. Cette fonction appelle le statiqueclone_process()
, qui crée un nouveau processus comme copie du parent, mais ne le démarre pas encore.clone_process()
copie les registres, attribue un PID à la nouvelle tâche et duplique ou partage les parties appropriées de l'environnement de processus comme spécifié par le cloneflags
. À sonclone_process()
retour,do_clone()
réveillera le processus nouvellement créé et planifiera son exécution.la source
clone()
par rapport aux fils et fourchettes.Le composant responsable de la traduction des fonctions d'appel système de l'espace utilisateur en appels système du noyau sous Linux est la libc. Dans GLibC, la bibliothèque NPTL redirige cela vers l'
clone(2)
appel système.la source