Welche Datei im Kernel gibt fork (), vfork () ... an, um den Systemaufruf sys_clone () zu verwenden

9

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) +++
user3539
quelle
Dies könnte für Sie hilfreich sein: lxr.linux.no/linux+v3.10.9
Wiederholung
@ Mauro.stettler Ich konnte es nicht in lxr finden
user3539
Meinen Sie git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/… um Zeile 1700? Was wollten Sie herausfinden?
Msw

Antworten:

29

Die fork()und vfork()Wrapper in glibc werden über den clone()Systemaufruf implementiert . Um die Beziehung zwischen fork()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 anruft exec(). 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 normalen fork()Prozesses anfällt, ist das Kopieren der Seitentabellen des übergeordneten Elements und die Zuweisung einer eindeutigen Prozessdeskriptorstruktur task_structfü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_structeigenen Thread , der zufällig so eingerichtet wird, dass er bestimmte Ressourcen, z. B. einen Adressraum, mit dem übergeordneten Prozess teilt.

Der flagsParameter des clone()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 erstellt clone(). Der einzige Unterschied besteht in der Menge der Flags, an die übergeben wird clone().

Ein normaler fork()könnte implementiert werden als:

clone(SIGCHLD, 0);

Dadurch wird eine Aufgabe erstellt, die keine Ressourcen mit ihrem übergeordneten Element teilt und das SIGCHLDBeendigungssignal 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.

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

vfork()Dies wird wiederum über ein separates CLONE_VFORKFlag 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 aufgerufen exec()oder beendet wird. Das Kind darf nicht in den Speicher schreiben. Der entsprechende clone()Aufruf könnte wie folgt lauten:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

Die Implementierung von sys_clone()ist architekturspezifisch, aber der Großteil der Arbeit erfolgt in do_fork()definiert in kernel/fork.c. Diese Funktion ruft die Statik auf clone_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 angegeben flags. Wenn Sie clone_process()zurückkehren, do_clone()wird der neu erstellte Prozess aktiviert und für die Ausführung geplant.

Thomas Nyman
quelle
2
+1 Schöne Erklärung der Bedeutung von clone()in Bezug auf Gewinde und Gabeln.
Goldlöckchen
1
Alle meine Zweifel
ausgeräumt
2

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.

Ignacio Vazquez-Abrams
quelle