Kernel-Quellcode: Was sind parent_tidptr und child_tidptr in do_fork()?

Kernel-Quellcode: Was sind parent_tidptr und child_tidptr in do_fork()?

Auf die obenVerknüpfungwas ist damit gemeint parent_tidptrund child_tidptrwodurch do_fork()entsteht ein neuer Prozess?

Antwort1

Beginnen wir mit einem Blick auf die reine Systemaufrufschnittstelle. Sie variiert je nach Architektur etwas, aber auf x86-64 sieht sie so aus:

   long clone(unsigned long flags, void *child_stack,
              int *ptid, int *ctid,
              unsigned long newtls);

ptidund ctidsind Ihre parent_tidptrund child_tidptr. Nun wollen wir sehen, was dieclone(2)Die Manualpage sagt:

   CLONE_CHILD_CLEARTID (since Linux 2.5.49)
          Erase  the  child  thread  ID  at the location ctid in
          child memory when the child exits, and do a wakeup  on
          the  futex  at that address.

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

   CLONE_PARENT_SETTID (since Linux 2.5.49)
          Store  the child thread ID at the location ptid in the
          parent's memory. 

Diese Flags wurden in erster Linie für die Implementierung von Threading-Bibliotheken entwickelt. Wenn wir uns die NPTL-Implementierung vonpthread_create()innerhalb von glibc finden wir schließlich Code insysdeps/unix/sysv/linux/createthread.cdas einen Aufruf tätigt , der und in clone()enthält .CLONE_PARENT_SETTIDCLONE_CHILD_CLEARTIDflags

In diesem clone()Aufruf können wir auch sehen, dass die Argumente ptidundctidverweisen auf die gleiche Adresse. (Denken Sie daran, dass POSIX-Threads einen Adressraum gemeinsam nutzen; dies wird mit dem clone() CLONE_VMFlag erreicht.)

Hier passiert also Folgendes.

  • CLONE_PARENT_SETTIDwird verwendet, um sicherzustellen, dass die Kernel-Thread-ID an einem bestimmten Ort im Benutzerbereich gespeichert wird. Die Benutzerbereichsseite der Thread-Implementierung muss diese Thread-ID kennen.
  • CLONE_CHILD_CLEARTIDwird verwendet, um denselben Speicherort zu löschen (d. h. auf Null zu setzen), wenn der von erstellte Thread clone()beendet wird.

Gehen wir noch einen Schritt weiter ...

ptidDie über / zurückgegebene Thread-ID ctidlautetnichtdasselbe wie eine POSIX-Thread-ID ( pthread_t), obwohl in den 1:1-Threading-Implementierungen wie NPTL eine Eins-zu-eins-Entsprechung zwischen Kernel-Thread-IDs und POSIX-Thread-IDs besteht. Die Kernel-Thread-ID ist dieselbe ID, die Sie erhalten, wenn Sie den Linux-Thread-ID-Befehl verwenden.gettid()clone()call. Es wird auch als Systemaufruf-Rückgabewert zurückgegeben , was die Frage aufwirft: Warum brauchen wir ptid/ ctid? Das Problem ist, dass die Dinge von der Benutzerseite aus folgendermaßen aussehen:

tid = clone(...);

Aus Sicht der Threading-Implementierung im User-Space gibt es hier ein Wettrennen, da die Zuweisung tidnur dann erfolgt ,nach clone()zurückgibt. Das bedeutet, dass die Threading-Bibliothek im Benutzerbereich auf bestimmte Probleme stoßen kann, wenn sie diese Informationen benötigt, bevor der neue Thread etwas tut (wie zum Beispiel beendet wird). Die Verwendung CLONE_PARENT_SETTIDstellt sicher, dass die neue Thread-ID an der Stelle platziert wird, auf die von verwiesen wirdptid Vor clone()gibt zurück und ermöglicht so einer Threading-Bibliothek, solche Race Conditions zu vermeiden. ( CLONE_CHILD_SETTIDkann auch mit ähnlicher Wirkung verwendet werden.)

Der Grund für CLONE_CHILD_CLEARTIDdas Löschen des ptid/ ctidbesteht darin, eine Möglichkeit für einenpthread_join()Aufruf in einem anderen Thread, um festzustellen, dass der Thread beendet wurde. Im Wesentlichen wird der ptid/ -Speicherort alsctidfutex, und dasfutex()Der Systemaufruf wird zum Blockieren verwendet und wartet darauf, dass sich die Ganzzahl an dieser Stelle ändert. (Die Details sind etwas kompliziert, aber grepfür die Verwendung von lll_wait_tidund lll_futex_waitim Glibc-Quellcode. Letztendlich findet eine FUTEX_WAITOperation statt. Erinnern Sie sich an oben, das CLONE_CHILD_CLEARTIDein Futex-Wakeup an der Zieladresse durchführt.)

Antwort2

tidsteht für „Thread-ID“. Die Parameter parent_tidptrund child_tidptrzeigen auf den Benutzerspeicher im Adressraum des übergeordneten bzw. des untergeordneten Prozesses. Die ID des neu erstellten Threads wird in den int-Variablen gespeichert, auf die die Zeiger zeigen.

Weitere Informationen finden Sie imclone(2)manpage.

verwandte Informationen