2016-05-11 9 views
6

In eglibc der nptl/sysdeps/unix/sysv/linux/i386/fork.c gibt es eine Definition:Warum wird sys_fork nicht von glibcs ​​Implementierung von fork verwendet?

#define ARCH_FORK() \ 
    INLINE_SYSCALL (clone, 5,       \ 
      CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,  \ 
      NULL, NULL, &THREAD_SELF->tid) 

, die in tatsächlichen __libc_fork() als das Herz der Umsetzung verwendet wird. Aber z.B. in Linux arch/x86/entry/syscalls/syscall_32.tbl existiert ein sys_fork Eintrag, sowie in syscalls_64.tbl. Offensichtlich hat Linux seinen speziellen Syscall für fork.

So frage ich mich jetzt: Warum implementiert Glibc fork() in Bezug auf clone, wenn der Kernel bereits die fork Syscall bietet?

Antwort

6

Ich schaute auf das Commit, bei dem Ulrich Drepper diesen Code zu glibc hinzufügte, und es gab keine Erklärung im Commit-Protokoll (oder anderswo).

Hier finden Sie aktuelle Linux-Implementierung von fork, aber:

return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0); 

Und hier ist clone:

return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls); 

Offensichtlich sind sie fast genau das gleiche. Der einzige Unterschied besteht darin, dass Sie beim Aufruf von clone verschiedene Flags setzen können, eine Stack-Größe für den neuen Prozess angeben können usw. fork akzeptiert keine Argumente.

Mit Blick auf Drepper-Code sind die clone Flags CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD. Wenn fork verwendet wurde, wäre das einzige Flag SIGCHLD. Hier

ist, was der clone manpage sagt über diese zusätzliche Fahnen:

CLONE_CHILD_CLEARTID (since Linux 2.5.49) 
      Erase child thread ID at location ctid in child memory when the child 
      exits, and do a wakeup on the futex at that address. The address 
      involved may be changed by the set_tid_address(2) system call. This is 
      used by threading libraries. 

CLONE_CHILD_SETTID (since Linux 2.5.49) 
      Store child thread ID at location ctid in child memory. 

... Und man kann sehen, dass er einen Zeiger auf nicht passiert, wo der Kernel soll zuerst das Thread-ID des Kindes speichern und dann später mach ein Futex Wakeup. Steht glibc auf die Adresse? Ich weiß es nicht. Wenn ja, würde das erklären, warum Drepper clone gewählt hat.

(Und wenn nicht, wäre es nur ein weiteres Beispiel für die extreme Anhäufung von Cruft, die unser geliebter Glibc ist! Wenn du einen schönen, sauberen, gepflegten Code finden wolltest, bleib einfach in Bewegung! schau dir musl libc an!)

+1

'pthread_join()' macht das Wecken. Ähnlich wie bei der Verbindung mit Threads ruft glibc 'set_tid_address()' auf, so dass der "main" -Thread verknüpft werden kann: http://StackOverflow.com/questions/6975098/when-is-the-system-call-set -tid-address-used – ninjalj

+0

@usr: Dieser neue Prozess kann Threads erzeugen. Wenn diese Threads in der Lage sein sollen, 'pthread_join()' auf dem Haupt-Thread des neuen Prozesses zu verwenden, benötigt glibc die Adresse des Futex. – ninjalj

+0

@usr: 'execve()' kümmert sich darum, indem er 'set_tid_address()' aufruft. BTW, wenn Sie sofort exec ausführen, gibt es 'vfork()' oder 'posix_spawn()', wenn Ihre libc das bietet. – ninjalj

0

Auf den Punkt gebracht: warum nicht?

Sie haben einen Syscall, der garantiert auf allen Plattformen existiert (Sie wissen, dass Intel nicht die einzige Plattform da draußen ist, oder?), Und ein anderer ist veraltet, weil er unnötig ist. Beide tragen genau die gleiche Semantik. Ihr Code ist viel kompakter, wenn Sie nur denjenigen anrufen, der garantiert existiert.

Ich werde ein wenig darauf eingehen.

Fork wird von Posix definiert, während der Klon Linux-spezifisch ist. Manchmal nimmt Linux jedoch Posix definierte "Systemaufrufe" vor und implementiert sie im Benutzerbereich. Dies ist der Fall für fork (und vfork und pthread_create). Sie werden alle im Benutzerbereich implementiert, indem "clone" aufgerufen wird.

Daher wird fork auf Kernel-Ebene als unnötig erachtet. Wenn ein Thin User Space Wrapper es implementieren kann, ist der Kernel damit einverstanden. Als solcher, auf Linux, Clone ist garantiert, auf allen Plattformen zu existieren, während Gabel möglicherweise existiert oder nicht, abhängig von spezifischer Plattform.

+0

Ich glaube 'fork (2)' existierte vor 'clone (2)'. –

+0

Das ist korrekt und irrelevant. Ich habe die Antwort bearbeitet, um zu erklären, warum. –

Verwandte Themen