Wenn ltrace zum Verfolgen der Systemaufrufe verwendet wird, konnte ich sehen, dass fork () sys_clone () anstelle von sys_fork () verwendet. Aber ich konnte die Linux-Quelle nicht finden, wo sie definiert ist.
Mein Programm ist
#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");
}
Und ltrace Ausgabe ist
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
quelle
quelle
Antworten:
Die
fork()
undvfork()
Wrapper in glibc werden über denclone()
Systemaufruf implementiert . Um die Beziehung zwischenfork()
und besser zu verstehenclone()
, müssen wir die Beziehung zwischen Prozessen und Threads unter Linux berücksichtigen.Traditionell werden
fork()
alle Ressourcen des übergeordneten Prozesses freigegeben und die Kopie dem untergeordneten Prozess zugewiesen. Dieser Ansatz verursacht einen erheblichen Aufwand, der möglicherweise umsonst ist, wenn das Kind sofort anruftexec()
.fork()
Verwendet unter Linux Copy-on-Write- Seiten, um das Kopieren der Daten, die zwischen den übergeordneten und untergeordneten Prozessen gemeinsam genutzt werden können, zu verzögern oder ganz zu vermeiden. Der einzige Aufwand, der während eines normalenfork()
Prozesses anfällt, ist das Kopieren der Seitentabellen des übergeordneten Elements und die Zuweisung einer eindeutigen Prozessdeskriptorstrukturtask_struct
für das untergeordnete Element .Linux verfolgt auch einen außergewöhnlichen Ansatz bei Threads. Unter Linux sind Threads lediglich gewöhnliche Prozesse, die einige Ressourcen mit anderen Prozessen teilen. Dies ist ein radikal anderer Ansatz für Threads als für andere Betriebssysteme wie Windows oder Solaris, bei denen Prozesse und Threads völlig unterschiedliche Arten von Tieren sind. Unter Linux hat jeder Thread einen
task_struct
eigenen Thread , der zufällig so eingerichtet wird, dass er bestimmte Ressourcen, z. B. einen Adressraum, mit dem übergeordneten Prozess teilt.Der
flags
Parameter desclone()
Systemaufrufs enthält eine Reihe von Flags, die angeben, welche Ressourcen die übergeordneten und untergeordneten Prozesse gegebenenfalls gemeinsam nutzen sollen. Prozesse und Threads werden beide über erstelltclone()
. Der einzige Unterschied besteht in der Menge der Flags, an die übergeben wirdclone()
.Ein normaler
fork()
könnte implementiert werden als:Dadurch wird eine Aufgabe erstellt, die keine Ressourcen mit ihrem übergeordneten Element teilt und das
SIGCHLD
Beendigungssignal beim Beenden an das übergeordnete Element sendet .Im Gegensatz dazu könnte eine Aufgabe erstellt werden, die den Adressraum, die Dateisystemressourcen, die Dateideskriptoren und die Signalhandler mit dem übergeordneten Element, dh einem Thread , teilt.
vfork()
Dies wird wiederum über ein separatesCLONE_VFORK
Flag implementiert , wodurch der übergeordnete Prozess in den Ruhezustand versetzt wird, bis der untergeordnete Prozess ihn über ein Signal aufweckt. Das untergeordnete Element ist der einzige Ausführungsthread im Namespace des übergeordneten Elements, bis es aufgerufenexec()
oder beendet wird. Das Kind darf nicht in den Speicher schreiben. Der entsprechendeclone()
Aufruf könnte wie folgt lauten:Die Implementierung von
sys_clone()
ist architekturspezifisch, aber der Großteil der Arbeit erfolgt indo_fork()
definiert inkernel/fork.c
. Diese Funktion ruft die Statik aufclone_process()
, die einen neuen Prozess als Kopie des übergeordneten Prozesses erstellt, ihn jedoch noch nicht startet.clone_process()
kopiert die Register, weist der neuen Aufgabe eine PID zu und veröffentlicht oder teilt geeignete Teile der Prozessumgebung, wie vom Klon angegebenflags
. Wenn Sieclone_process()
zurückkehren,do_clone()
wird der neu erstellte Prozess aktiviert und für die Ausführung geplant.quelle
clone()
in Bezug auf Gewinde und Gabeln.Die Komponente, die für die Übersetzung von Userland-Systemaufruffunktionen in Kernel-Systemaufrufe unter Linux verantwortlich ist, ist die libc. In GLibC leitet die NPTL-Bibliothek dies an den
clone(2)
Systemaufruf weiter.quelle