CLONE(2) | Linux-Programmierhandbuch | CLONE(2) |
BEZEICHNUNG¶
clone, __clone2 - erzeugt einen Kindprozess
ÜBERSICHT¶
/* Prototyp für die Glibc-Wrapper-Funktion */
#define _GNU_SOURCE #include <sched.h>
int clone(int (*fn)(void *), void *child_stack, int Schalter, void *arg, … /* pid_t *ptid, void *newtls, pid_t *ctid */ );
/* Für den Prototyp des rohen Systemaufrufs siehe ANMERKUNGEN */
BESCHREIBUNG¶
clone() erzeugt auf eine ähnliche Weise wie fork(2) einen neuen Prozess.
Diese Seite beschreibt die clone()-Wrapper-Funktion von Glibc als auch den darunterliegenden Systemaufruf, auf dem sie basiert. Der Haupttext erklärt die Wrapper-Funktion. Die Unterschiede zum rohen Systemaufruf werden gegen Ende dieser Seite erläutert.
Anders als fork(2) erlaubt clone() es dem Kindprozess, einen Teil seines Ausführungskontextes zusammen mit dem aufrufenden Prozess zu verwenden, wie beispielsweise virtuellen Adressraum, die Tabelle der Dateideskriptoren und die Tabelle der Signal-Handler. (Beachten Sie, dass in dieser Handbuchseite der »aufrufende Prozess« normalerweise dem »Elternprozess« entspricht. Siehe aber die nachfolgende Beschreibung von CLONE_PARENT).
clone() wird benutzt, um Threads zu implementieren: mehrere Steuerflüsse in einem Programm, die gleichzeitig in einem gemeinsamen Speicherbereich ausgeführt werden.
Wird mit clone() ein Kindprozess erzeugt, beginnt es die Ausführung durch Aufruf der Funktion, auf die das Argument fn zeigt. (Dies ist ein Unterschied zu fork(2), wo die Ausführung im Kindprozess vom Punkt des fork(2)-Aufrufs fortfährt.) Das Argument arg wird als Argument der Funktion fn übergeben.
Kehrt die Funktion fn(arg) zurück, so beendet sich der Kindprozess. Der Ganzzahlwert, der von fn zurückgeliefert wird, entspricht dem Exit-Status des Kindprozesses. Der Kindprozess kann auch durch den expliziten Aufruf von exit(2) oder durch den Empfang eines fatalen Signals beendet werden.
Das Argument Kindstapel bestimmt den Ort des Stapelspeichers, der vom Kindprozess verwendet wird. Da der aufrufende und der Kindprozess sich Speicherbereiche teilen können, kann der Kindprozess nicht auf dem selben Stapelspeicher wie der aufrufende Prozess laufen. Der aufrufende Prozess muss daher einen Speicherbereich als Stapelspeicher für den Kindprozess bereithalten und per clone einen Zeiger darauf an den Kindprozess übergeben. Der Stapelspeicher wächst (mit Ausnahme der PA-Prozessoren von HP) auf allen von Linux unterstützten Prozessoren nach unten, so dass Kindstapel für gewöhnlich auf die oberste Adresse im bereitgehaltenen Speicherbereich zeigt.
Das niedrige Byte von Schalter enthält die Anzahl der an den Elternprozess gesandten Beendigungssignale, wenn der Kindprozess stirbt. Falls dieses Signal als etwas anderes als SIGCHLD angegeben wurde, dann muss der Elternprozess die Optionen __WALL oder __WCLONE angeben, wenn er mit wait(2) auf den Kindprozess wartet. Falls kein Signal angegeben wurde, wird dem Elternprozess nicht signalisiert, wenn der Kindprozess endet.
Schalter können auch bitweise-ODER-verknüpft mit keinem oder mehreren der folgenden Konstanten werden, um festzulegen, was zwischen dem aufrufenden Prozess und dem Kindprozess gemeinsam benutzt wird:
- CLONE_CHILD_CLEARTID (seit Linux 2.5.49)
- Die Kind-Thread-Kennung an der durch ctid im Kindspeicher bereinigen (nullen), wenn das Kind sich beendet und beim Futex (»fast userspace mutual exclusion«/schneller gegenseitiger Ausschluss im Userspace) an dieser Adresse aufwachen lassen. Die betroffene Adresse könnte durch den Systemaufruf set_tid_address(2) geändert werden. Dies wird von Threading-Bibliotheken benutzt.
- CLONE_CHILD_SETTID (seit Linux 2.5.49)
- Die Kindprozess-Thread-Kennung an der Stelle ctid im Kindspeicher ablegen. Die Speicheraktion wird abgeschlossen, bevor clone() die Steuerung an den Benutzerraum zurückgibt.
- CLONE_FILES (since Linux 2.0)
- Ist CLONE_FILES gesetzt, teilen sich der aufrufende und der Kindprozess ihre Dateideskriptor-Tabellen. Jeder Dateideskriptor, der im aufrufenden Prozess oder vom Kindprozess erzeugt wird, ist auch im anderen Prozess gültig. Ebenso wirkt sich das Schließen eines Dateideskriptors oder das Ändern der zugehörigen Schalter (benutzen der F_SETFD-Operation von fcntl(2)) auf den anderen Prozess aus. Falls sich ein Prozess eine Dateideskriptor-Tabelle teilt und execve(2) aufruft, wird seine Dateideskriptor-Tabelle dupliziert (nicht länger geteilt).
- Ist CLONE_FILES nicht gesetzt, erbt der Kindprozess zur Ausführungszeit von clone() eine Kopie der aktuell geöffneten Dateideskriptoren. Anschließende Aktionen, die Dateideskriptoren öffnen oder schließen bzw. deren Schalter ändern, werden entweder vom aufrufenden Prozess oder dem Kindprozess durchgeführt und betreffen nicht den jeweils anderen Prozess. Beachten Sie aber, dass sich die duplizierten Dateideskriptoren im Kind auf die gleiche offene Dateideskription wie der korrespondierende Dateideskriptor im aufrufenden Prozess bezieht und sich daher den Dateiversatz und die Dateistatusschalter mit diesem teilt (siehe open(2)).
- CLONE_FS (seit Linux 2.0)
- Ist CLONE_FS gesetzt, teilen sich aufrufender Prozess und Kindprozess ihre Informationen über das Dateisystem. Dazu zählen der Ort des Wurzelverzeichnisses, das aktuelle Arbeitsverzeichnis und die Maske der Dateizugriffsrechte (umask). Jeder Aufruf von chroot(2), chdir(2) oder umask(2), entweder durch den aufrufenden Prozess oder den Kindprozess, beeinflusst auch den jeweils anderen Prozess.
- Ist CLONE_FS nicht gesetzt, arbeitet der Kindprozess mit einer Kopie der Dateisysteminformationen des aufrufenden Prozesses zur Zeit des clone()-Aufrufs. Spätere Aufrufe von chroot(2), chdir(2) oder umask(2) beeinflussen den anderen Prozess nicht.
- CLONE_IO (seit Linux 2.6.25)
- Ist CLONE_FS gesetzt, teilt sich der neue Prozess einen E/A-Kontext mit dem aufrufenden Prozess. Falls dieser Schalter nicht gesetzt ist (wie bei fork(2)), hat der neue Prozess seinen eigenen E/A-Kontext.
- Der E/A-Kontext entspricht dem E/A-Gültigkeitsbereich des Platten-Schedulers, d.h. welches der E/A-Scheduler zur Modellplanung für E/As des Prozesses benutzt. Falls sich Prozesse den gleichen E/A-Kontext teilen, werden sie vom E/A-Scheduler als ein einziger betrachtet. Als Konsequenz daraus müssen sie sich die gleiche Plattenzeitzugriffzeit teilen. Einige E/A-Scheduler ermöglichen zwei Prozessen, die einen E/A-Kontext teilen, ihren Plattenzugriff zu verzahnen. Falls mehrere Prozesse E/A im Auftrag des gleichen Prozesses durchführen (aio_read(3) zum Beispiel), sollten sie für eine bessere E/A-Leistung CLONE_IO verwenden.
- Falls der Kernel nicht mit der Option CONFIG_BLOCK konfiguriert wurde, bewirkt dieser Schalter nichts.
- CLONE_NEWCGROUP (seit Linux 4.6)
- Der Prozess wird in einem neuen cgroup-Namensraum erstellt. Falls dieser Schalter nicht gesetzt ist, dann wird der Prozess (wie mit fork(2)) im gleichen cgroup-Namensraum wie der aufrufende Prozess erstellt. Dieser Schalter ist für die Implementierung von Containern gedacht.
- Weitere Informationen über cgroup-Namensräume finden Sie unter cgroup_namespaces(7).
- Nur ein privilegierter Prozess (CAP_SYS_ADMIN) kann CLONE_NEWCGROUP angeben.
- CLONE_NEWIPC (seit Linux 2.6.19)
- Wenn CLONE_NEWIPC gesetzt ist, dann wird der Prozess in einem neuen IPC-Namensraum erstellt. Falls dieser Schalter nicht gesetzt ist, dann wird der Prozess (wie mit fork(2)) im gleichen IPC-Namensraum wie der aufrufende Prozess erstellt. Dieser Schalter ist für die Implementierung von Containern gedacht.
- Ein IPC-Namensraum stellt einen isolierten Blick auf die System-V-IPC-Objekte (siehe svipc(7)) und (seit Linux 2.6.30) POSIX-Nachrichtenwarteschlangen (siehe mq_overview(7)) bereit. Die gemeinsame Eigenschaft dieser IPC-Mechanismen besteht darin, dass IPC-Objekte durch Mechanismen, die sich von Dateisystempfadnamen unterscheiden, identifiziert werden.
- In einem IPC-Namensraum erstellte Objekte sind für alle anderen Prozesse, die Mitglied in diesem Namensraum sind, sichtbar, aber nicht für Prozesse in anderen IPC-Namensräumen.
- Wenn ein IPC-Namensraum zerstört wird (d.h. wenn der letzte Prozess, der Mitglied in einem Namensraum ist, sich beendet), dann werden alle IPC-Objekte in diesem Namensraum automatisch zerstört.
- Nur ein privilegierter Prozess (CAP_SYS_ADMIN) kann CLONE_NEWIPC angeben. Dieser Schalter darf nicht zusammen mit CLONE_SYSVSEM angegeben werden.
- Weitere Informationen zu IPC-Namensräumen finden Sie in namespaces(7).
- CLONE_NEWNET (seit Linux 2.6.24)
- (Die Implementierung dieses Schalters wurde erst ungefähr mit der Kernel-Version 2.6.29 abgeschlossen.)
- Wenn CLONE_NEWNET gesetzt ist, dann wird der Prozess in einem neuen Netzwerk-Namensraum erstellt. Falls dieser Schalter nicht gesetzt ist, dann wird der Prozess (wie mit fork(2)) im gleichen Netzwerk-Namensraum wie der aufrufende Prozess erstellt. Dieser Schalter ist für die Implementierung von Containern gedacht.
- Ein Netzwerknamensraum stellt einen isolierten Blick auf den Netzwerk-Stapel (Netzwerkgeräteschnittstelle, IPv4- und IPv6-Prokollstapel, IP-Routing-Tabellen, Firewall-Regeln, die Verzeichnisbäume /proc/net und /sys/class/net, Sockets usw.) bereit. Ein physisches Netzwerkgerät kann in genau einem Netzwerknamensraum leben. Ein Gerätepaar für ein virtuelles Netzwerk (veth(4)) stellt eine Pipe-artige Abstraktion bereit, die zum Erzeugen von Tunneln zwischen Netzwerknamensräumen und zum Überbrücken zu einem physischen Netzwerkgerät in einem anderen Namensraum verwandt werden kann.
- Wenn ein Netzwerknamensraum freigegeben wird (d.h. wenn sich der letzte Prozess in dem Namensraum beendet), wird sein physisches Netzwerkgerät zurück in den anfänglichen Netzwerknamensraum geschoben (nicht zum Elternprozess). Für weitere Informationen über Netzwerknamensräume, siehe namespaces(7).
- Nur ein privilegierter Prozess (CAP_SYS_ADMIN) kann CLONE_NEWNET angeben.
- CLONE_NEWNS (seit Linux 2.4.19)
- Wenn der Schalter CLONE_NEWNS gesetzt ist, wird der geklonte Kindprozess in einem neuen, eingehängten Namensraum gestartet, der mit einer Kopie des Namensraums des Elternprozesses initialisiert wurde. Wenn CLONE_NEWNS nicht gesetzt ist, bleibt der Kindprozess im gleichen Namensraum wie der Elternprozess.
- Nur ein privilegierter Prozess (einer der die Fähigkeit CAP_SYS_ADMIN hat) kann den Schalter CLONE_NEWNS angeben. Es ist nicht erlaubt, sowohl CLONE_NEWNS als auch CLONE_FS im gleichen Aufruf von clone() anzugeben.
- Für weitere Informationen über Einhängenamensräume lesen Sie namespaces(7) und mount_namespaces(7)
- CLONE_NEWPID (seit Linux 2.6.24)
- Wenn CLONE_NEWPID gesetzt ist, dann wird der Prozess in einem neuen PID-Namensraum erstellt. Falls dieser Schalter nicht gesetzt ist, dann wird der Prozess (wie mit fork(2)) im gleichen PID-Namensraum wie der aufrufende Prozess erstellt. Dieser Schalter ist für die Implementierung von Containern gedacht.
- Weitere Informationen zu PID-Namensräumen finden Sie in namespaces(7) und pid_namespaces(7).
- Nur ein privilegierter Prozess (CAP_SYS_ADMIN) kann CLONE_NEWPID angeben. Dieser Schalter darf nicht zusammen mit CLONE_THREAD oder CLONE_PARENT angegeben werden.
- CLONE_NEWUSER
- (Dieser Schalter hatte für clone() erstmals in Linux 2.6.23 eine Bedeutung, die aktuelle clone()-Semantik wurde in Linux 3.5 aufgenommen und die letzten Anteile, um Benutzernamensräume komplett nutzbar zu bekommen, wurden in Linux 3.8 aufgenommen.)
- Wenn CLONE_NEWUSER gesetzt ist, dann wird der Prozess in einem neuen Benutzer-Namensraum erstellt. Falls dieser Schalter nicht gesetzt ist, dann wird der Prozess (wie mit fork(2)) im gleichen Benutzer-Namensraum wie der aufrufende Prozess erstellt.
- Vor Linux 3.8 verlangte die Verwendung von CLONE_NEWUSER, dass der Aufrufende drei Capabilities hatte: CAP_SYS_ADMIN, CAP_SETUID und CAP_SETGID. Seit Linux 3.8 werden für die Erstellung eines Benutzernamensraums keine Privilegien benötigt.
- Dieser Schalter kann nicht zusammen mit CLONE_THREAD oder CLONE_PARENT angegeben werden. Aus Sicherheitsgründen darf CLONE_NEWUSER nicht zusammen mit CLONE_FS angegeben werden.
- Für weitere Informationen über Benutzernamensräume lesen Sie namespaces(7) und user_namespaces(7).
- CLONE_NEWUTS (seit Linux 2.6.19)
- Falls CLONE_NEWUTS gesetzt ist, erzeugt der Prozess einen neuen UTS-Namensraum, dessen Bezeichner durch Duplizieren der Bezeichner aus dem UTS-Namensraum des aufrufenden Prozesses initialisiert werden. Wenn dieser Schalter nicht gesetzt ist (wie mit fork(2)), dann wird der Prozess im gleichen UTS-Namensraum wie der aufrufende Prozess erzeugt. Dieser Schalter ist für die Implementierung von Containern gedacht.
- Ein UTS-Namensraum ist die Menge der von uname(2) zurückgelieferten Kennzeichner, unter diesen können der Domain-Name und der Rechnername mit setdomainname(2) bzw. sethostname(2) verändert werden. Änderungen in einem UTS-Namensraum an diesen Kennzeichnern sind für alle anderen Prozesse in dem gleichen Namensraum sichtbar, aber nicht für Prozesse in anderen UTS-Namensräumen.
- Nur ein privilegierter Prozess (CAP_SYS_ADMIN) kann CLONE_NEWUTS angeben.
- Weitere Informationen zu UTS-Namensräumen finden Sie in namespaces(7).
- CLONE_PARENT (seit Linux 2.3.12)
- Falls CLONE_PARENT gesetzt ist, dann wird der Elternprozess des neuen Kindprozesses (wie er von getppid(2) zurückgegeben wird) der gleiche wie der aufrufende Prozess sein.
- Falls CLONE_PARENT nicht gesetzt ist (wie bei fork(2)), dann ist der Elternprozess des Kindprozesses der aufrufende Prozess.
- Beachten Sie, dass dem Elternprozess, wie er von getppid(2) zurückgegeben wird, signalisiert wird wenn der Kindprozess endet. Wenn also CLONE_PARENT gesetzt ist, wird dem Elternprozess des aufrufenden Prozesses anstatt dem aufrufenden Prozess selbst das Signal gesandt.
- CLONE_PARENT_SETTID (seit Linux 2.5.49)
- Die Kindprozess-Thread-Kennung an der Stelle ptid im Elternspeicher ablegen. (In Linux 2.5.32-2.5.48 gab es einen Schalter CLONE_SETTID, der das tat.) Die Speicheraktion wird abgeschlossen, bevor der clone()-Aufruf die Steuerung an den Benutzerraum zurückgibt.
- CLONE_PID (Linux 2.0 bis 2.5.15)
- Falls CLONE_PID gesetzt ist, wird der Kindprozess mit der gleichen Prozesskennung wie der aufrufende Prozess erstellt. Dies ist gut, um das System zu hacken, aber andererseits zu nicht viel mehr zu gebrauchen. Seit Linux 2.3.21 konnte dieser Schalter nur durch den Boot-Prozess festgelegt werden (PID 0). Dieser Schalter verschwand in Linux 2.5.16 komplett aus den Kernelquellen. Seitdem ignorierte der Kernel dieses Bit, falls es in Schalter angegeben wurde.
- CLONE_PTRACE (seit Linux 2.2)
- Falls CLONE_PTRACE angegeben ist und der aufrufende Prozess verfolgt wird, dann wird der Kindprozess ebenfalls verfolgt (siehe ptrace(2)).
- CLONE_SETTLS (seit Linux 2.5.32)
- Der TLS (Thread Local Storage)-Deskriptor ist auf newtls gesetzt.
- Die Interpretation von newtls und der resultierende Effekt ist architekturabhängig. Auf X86 ist newtls als ein struct user_desc * interpretiert (siehe set_thread_area(2)). Auf X86-64 ist es der neue für das Basisregister %fs zu setzende Wert (siehe das Argument ARCH_SET_FS von arch_prctl(2)). Auf Architekturen mit einem dedizierten TLS-Register ist es der neue Wert dieses Registers.
- CLONE_SIGHAND (seit Linux 2.0)
- Ist CLONE_SIGHAND gesetzt, teilen sich der aufrufende Prozess und der Kindprozess die Tabelle der Signal-Handler. Ruft einer der beiden Prozesse sigaction(2) auf, um das Antwortverhalten auf ein Signal zu verändern, so betrifft dies auch den anderen Prozess. Jedoch besitzen aufrufender Prozess und Kindprozess nach wie vor getrennte Signalmasken und getrennte Listen der noch ausstehenden Signale. Daher könnten Signale durch Aufruf von sigprocmask(2) für einen Prozess geblockt oder zugelassen werden ohne den anderen Prozess zu beeinflussen.
- Ist CLONE_SIGHAND nicht gesetzt, erbt der Kindprozess zum Zeitpunkt des Aufrufs von clone() eine Kopie des Signal-Handlers vom aufrufenden Prozess. Spätere Aufrufe von sigaction(2) durch einen der Prozesse hat dann keine Auswirkung auf den anderen Prozess.
- Seit Linux 2.6.0-test6 muss Schalter außerdem CLONE_VM enthalten, falls CLONE_SIGHAND angegeben wurde.
- CLONE_STOPPED (seit Linux 2.6.0-test2)
- Falls CLONE_STOPPED gesetzt ist, ist der Kindprozess anfangs gestoppt (als ob ein SIGSTOP-Signal gesendet worden wäre) und muss durch Senden eines SIGCONT-Signals wieder aufgenommen werden.
- Dieser Schalter war ab Linux 2.6.25 missbilligt und wurde in Linux 2.6.38 vollständig entfernt. Seitdem ignoriert der Kernel ihn ohne Fehler. Seit Linux 4.6 wird dasselbe Bit für den Schalter CLONE_NEWCGROUP wiederverwendet.
- CLONE_SYSVSEM (seit Linux 2.5.10)
- Wenn CLONE_SYSVSEM gesetzt ist, dann teilen sich der Kindprozess und der aufrufende Prozess eine einzige Liste von System-V-Semaphore-Anpassungswerten, (siehe semop(2)). In diesem Fall sammelt die gemeinsame Liste semadj Werte über alle Prozesse, die die Liste gemeinsam nutzen und Semaphore-Anpassungen werden nur durchgeführt, wenn der letzte Prozess, der die Liste gemeinsam nutzt, sich beendet (oder mittels unshare(2) aufhört, die Liste mitzunutzen). Falls dieser Schalter nicht gesetzt ist, besitzt der Kindprozess eine separate semadj-Liste, die anfangs leer ist.
- CLONE_THREAD (seit Linux 2.4.0-test8)
- Falls CLONE_THREAD gesetzt ist, wird der Kindprozess in die gleiche Thread-Gruppe wie der aufrufende Prozess platziert. Um den Rest der Diskussion von CLONE_THREAD leserlicher zu machen, wird der Begriff »Thread« benutzt, um Bezug auf Prozesse innerhalb einer Thread-Gruppe zu nehmen.
- Thread-Gruppen waren ein Leistungsmerkmal, das in Linux 2.4 hinzugefügt wurde, um den POSIX-Thread-Gedanken von einer Thread-Zusammenstellung zu unterstützen, die sich eine einzelne PID teilt. Intern ist diese gemeinsame PID ein sogenannter Thread-Gruppen-Bezeichner (TGID) für die Thread-Gruppe. Seit Linux 2.4 geben Aufrufe von getpid(2) die TGID des Aufrufers zurück.
- Die Threads innerhalb einer Gruppe können durch ihre (systemweit) einheitliche Thread-Kennung (TID) unterschieden werden. Die TID eines neuen Threads ist als Funktionsergebnis verfügbar, das an den Aufrufenden von clone() zurückgegeben wird. Ein Thread kann durch Benutzen von gettid(2) seine eigene TID erhalten.
- Wenn clone() ohne Angabe von CLONE_THREAD aufgerufen wurde, dann wird der resultierende Thread in eine neue Thread-Gruppe platziert, deren TGID der TID des Threads entspricht. Dieser Thread ist der Führer der neuen Thread-Gruppe.
- Ein neuer mit CLONE_THREAD erzeugter Thread hat den gleichen Elternprozess wie Aufrufende von clone() (d.h. wie CLONE_PARENT), so dass Aufrufe von getppid(2) den gleichen Wert für alle Threads in der Thread-Gruppe zurückliefern. Wenn ein CLONE_THREAD-Thread endet, wird dem Thread, der ihn mittels clone() erstellt hat, weder ein SIGCHLD-Signal (oder ein anderes Ende-Signal) gesandt, noch kann der Status eines solchen Threads per wait(2) abgefragt werden. (Der Thread wird als losgelöst bezeichnet.)
- Nachdem alle Threads in einer Thread-Gruppe beendet sind, wird dem Elternprozess ein SIGCHLD-Signal (oder ein anderes Ende-Signal) gesandt.
- Falls einige der Threads in einer Thread-Gruppe ein execve(2) durchführen, dann werden alle Threads außer dem Thread-Führer beendet und das neue Programm wird im Thread-Gruppenführer ausgeführt.
- Falls einer der Threads in einer Thread-Gruppe per fork(2) einen Kindprozess erzeugt, dann kann jeder Thread in der Gruppe wait(2) für diesen Kindprozess ausführen.
- Seit Linux 2.5.35 muss Schalter auch CLONE_SIGHAND enthalten, wenn CLONE_THREAD angegeben wurde. Beachten Sie auch, dass seit Linux 2.6.0-test6 CLONE_SIGHAND auch CLONE_VM enthalten muss.
- Signale können an eine Thread-Gruppe als ganzes (d.h. einer TGID) mittels kill(2) oder zu einem bestimmten Thread (d.h. TID) mittels tgkill(2) gesandt werden.
- Signalzuordnungen und -aktionen sind prozessweit: Falls ein nicht abgefangenes Signal an den Thread geschickt wird, dann wird es alle Mitglieder in der Thread-Gruppe beeinflussen (beenden, stoppen, fortfahren, darin ignoriert werden).
- Jeder Thread hat seine eigene, durch sigprocmask(2) gesetzte Signalmaske, aber Signale können entweder für den gesamten Prozess (d.h. Auslieferung an ein Mitglied der Thread-Gruppe) anhängig sein, wenn sie mit kill(2) gesandt werden oder für einen individuellen Thread, wenn sie mit tgkill(2) gesandt werden. Ein Aufruf von sigpending(2) liefert eine Signalmenge, die die Vereinigung der anhängenden Signale für den gesamten Prozess und der für den aufrufenden Thread anhängenden Signale ist.
- Falls kill(2) zum Senden eines Signals an eine Thread-Gruppe verwandt wird und die Thread-Gruppe einen Handler für dieses Signal installiert hat, dann dann wird der Handler in exakt einem willkürlich ausgewählten Mitglied der Thread-Gruppe aufrufen, das das Signal nicht blockiert hat. Falls mehrere Threads in einer Gruppe darauf warten das gleiche Signal per sigwaitinfo(2) zu akzeptieren, wird der Kernel einen dieser Threads willkürlich auswählen, um ein Signal zu empfangen, das mittels kill(2) gesandt wurde.
- CLONE_UNTRACED (seit Linux 2.5.46)
- Falls CLONE_UNTRACED angegeben ist, kann ein verfolgender Prozess kein CLONE_PTRACE auf diesem Kindprozess erzwingen.
- CLONE_VFORK (seit Linux 2.2)
- Falls CLONE_VFORK gesetzt ist, wird die Ausführung des aufrufenden Prozesses aufgeschoben bis der Kindprozess seine virtuellen Speicherressourcen durch Aufrufen von execve(2) oder _exit(2) (wie bei vfork(2)) freigibt.
- Falls CLONE_VFORK nicht gesetzt ist, dann werden sowohl der aufrufende Prozess, als auch der Kindprozess nach dem Aufruf planbar und eine Anwendung sollte sich nicht darauf verlassen, dass die Ausführung in einer speziellen Reihenfolge erfolgt.
- CLONE_VM (seit Linux 2.0)
- Ist CLONE_VM gesetzt, laufen aufrufender Prozess und Kindprozess im selben Speicherbereich. Insbesondere sind Schreibzugriffe des aufrufenden Prozesses oder des Kindprozesses in den gemeinsamen Speicher auch vom anderen Prozess aus sichtbar. Zudem beeinflusst jede Veränderung der Speicher-Mappings mit mmap(2) oder munmap(2) durch den Kindprozess oder den aufrufenden Prozess auch den jeweils anderen Prozess.
- Ist CLONE_VM nicht gesetzt, erhält der Kindprozess eine eigene Kopie des Speicherbereichs des aufrufenden Prozesses zum Zeitpunkt des Aufrufs von clone(). Führt ein Prozess Schreibzugriffe auf den Speicher oder Änderungen am Dateispeicher-Mapping aus, beeinflussen diese Operationen nicht den jeweils anderen, wie bei fork(2).
ANMERKUNGEN¶
Beachten Sie, dass die Glibc-Wrapperfunktion clone() einige Änderungen am Speicher, auf den Kindstapel zeigt, vornimmt (Änderungen, um den Stapel korrekt für das Kind einzurichten), bevor der Systemaufruf clone() ausgelöst wird. Verwenden Sie daher in Fällen, in denen clone() zur rekursiven Erstellung von Kindern verwandt wird, nicht den Puffer, der für den Stapel der Eltern eingesetzt wird, als Stapel der Kinder.
Unterschiede C-Bibliothek/Kernel¶
Der rohe sys_clone-Systemaufruf entspricht eher fork(2), da er mit der Ausführung des Kindprozesses am Zeitpunkt des Aufrufs fortfährt. Von daher werden die Argumente fn und arg der clone()-Wrapper-Funktion weggelassen.
Ein anderer Unterschied zum rohen Systemaufruf clone() besteht darin, dass das Argument Kindstapel NULL sein darf. In diesem Fall verwendet das Kind eine Dublette des Stapels des Elternprozesses. (»Copy-on-write«-Semantik stellt sicher, dass der Kindprozess getrennte Kopien des Stapelspeichers erhält, wenn einer der beiden Prozesse den Stapelspeicher verändert.) In diesem Fall sollte die Option CLONE_VM nicht angegeben werden, damit es korrekt funktioniert. (Falls das Kind sich aufgrund des Schalters CLONE_VM mit dem Elternprozess den Speicher teilt, dann tritt keine copy-on-write-Duplizierung auf und wahrscheinlich tritt Chaos ein.
Die Reihenfolge der Argumente unterscheidet sich auch im rohen Systemaufruf und es gibt über die Architekturen hinweg Variationen in den Argumenten, wie dies in den folgenden Absätzen dargestellt wird.
Die rohe Schnittstelle für Systemaufrufe auf x86-64 und einigen anderen Architekturen (darunter Sh, Tile und Alpha) sieht so aus:
long clone(unsigned long Schalter, void *Kindstapel, int *ptid, int *ctid, unsigned long newtls);
Auf x86-32 und mehreren anderen häufigen Architekturen (darunter Score, ARM, ARM 64, PA-RISC, Arc, Power PC, Xtensa und MIPS) ist die Reihenfolge der letzten zwei Argumente gedreht:
long clone(unsigned long Schalter, void *Kindstapel, int *ptid, unsigned long newtls, int *ctid);
Auf der Cris- und S30-Architektur ist die Reihenfolge der ersten zwei Argumente gedreht:
long clone(void *Kindstapel, unsigned long Schalter, int *ptid, int *ctid, unsigned long newtls);
Auf der Microblaze-Architektur wird ein zusätzliches Argument übergeben:
long clone(unsigned long Schalter, void *Kindstapel, int Stapelgröße, /* Größe des Stapels */ int *ptid, int *ctid, unsigned long newtls);
Blackfin, M68k und Sparc¶
Die Konventionen der Argumentübergabe weichen auf Blackfin, M68k und Sparc von der obigen Beschreibung ab. Einzelheiten finden Sie in der Kernel- (und Glibc-) Quelle.
Ia64¶
Auf ia64 wird eine andere Schnittstelle benutzt:
int __clone2(int (*fn)(void *), void *Kindstapelbasis, size_t Stapelgröße, int Schalter, void *arg, … /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
Der oben gezeigte Prototyp ist für die Glibc-Wrapper-Funktion; der rohe Systemaufruf verfügt nicht über das Argument fn und arg und die Reihenfolge der Argumente ist anders, so dass Schalter das erste Argument ist und tls das letzte.
__clone2() arbeitet auf die gleiche Weise wie clone(), außer dass Kindstapelbasis auf die niedrigste Adresse im Stapelspeicherbereich des Kindprozesses zeigt und Stapelgröße die Größe des Stapelspeichers angibt, auf die Kindstapelbasis zeigt.
Linux 2.4 und älter¶
Unter Linux 2.4 und früher gab es die Argumente ptid, tls und ctid noch nicht.
RÜCKGABEWERT¶
Bei Erfolg wird im ausgeführten Thread des Aufrufenden die Thread-Kennung des Kindprozesses zurückgegeben. Im Fehlerfall wird im Kontext des Aufrufenden -1 zurückgegeben, kein Kindprozess erzeugt und errno entsprechend gesetzt.
FEHLER¶
- EAGAIN
- Es laufen bereits zu viele Prozesse; siehe fork(2).
- EINVAL
- CLONE_SIGHAND wurde festgelegt, aber nicht CLONE_VM. (Seit Linux 2.6.0-test6.)
- EINVAL
- CLONE_THREAD wurde festgelegt, aber nicht CLONE_SIGHAND. (Seit Linux 2.5.35.)
- EINVAL
- In Schalter wurden sowohl CLONE_FS als auch CLONE_NEWNS festgelegt.
- EINVAL (seit Linux 3.9)
- In Schalter wurden sowohl CLONE_NEWUSER als auch CLONE_FS festgelegt.
- EINVAL
- In Schalter wurden sowohl CLONE_NEWIPC als auch CLONE_SYSVSEM festgelegt.
- EINVAL
- Eines (oder beides) von CLONE_NEWPID oder CLONE_NEWUSER und eines (oder beides) von CLONE_THREAD oder CLONE_PARENT wurde in Schalter festgelegt.
- EINVAL
- Wird von der Glibc-Wrapper-Funktion clone() zurückgegeben, wenn ein Wert von NULL für fn oder Kindstapel festgelegt wurde.
- EINVAL
- CLONE_NEWIPC wurde in Schalter festgelegt, aber der Kernel ist nicht mit den Optionen CONFIG_SYSVIPC und CONFIG_IPC_NS konfiguriert.
- EINVAL
- CLONE_NEWNET wurde in Schalter festgelegt, aber der Kernel ist nicht mit der Option CONFIG_NET_NS konfiguriert.
- EINVAL
- CLONE_NEWPID wurde in Schalter festgelegt, aber der Kernel ist nicht mit der Option CONFIG_PID_NS konfiguriert.
- EINVAL
- CLONE_NEWUTS wurde in Schalter festgelegt, aber der Kernel ist nicht mit der Option CONFIG_UTS_NS konfiguriert.
- EINVAL
- Kindstapel ist nicht an einer geeigneten Grenze für diese Architektur ausgerichtet. Beispielsweise muss Kindstapel auf Aarch64 ein Vielfaches von 16 sein.
- ENOMEM
- Es kann nicht ausreichend Speicher für eine Aufgabenstruktur des Kindprozesses reserviert werden oder um benötigte Teile vom Kontext des Aufrufenden zu kopieren.
- ENOSPC (seit Linux 3.7)
- CLONE_NEWPID wurde in den Schalteren festgelegt, aber die Begrenzung der Verschachtelungstiefe von PID-Namensräumen würde überschritten; siehe pid_namespaces(7).
- ENOSPC (seit Linux 4.9; vorher EUSERS)
- CLONE_NEWUSER wurde in Schalter festgelegt und der Aufruf würde zu einer Überschreitung der Begrenzung für die Anzahl von verschachtelten Benutzernamensräumen führen. Siehe user_namespaces(7).
- Von Linux 3.11 bis Linux 4.8 war der in diesem Fall diagnostizierte Fehler EUSERS.
- ENOSPC (seit Linux 4.9)
- Einer der Werte in Schalter legte die Erstellung eines neuen Benutzer-Namensraums fest, dadurch würde aber die in der entsprechenden Datei in /proc/sys/user festgelegte Begrenzung überschritten. Für weitere Details siehe namespaces(7).
- EPERM
- CLONE_NEWCGROUP, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID oder CLONE_NEWUTS wurde von einem nicht privilegierten Prozess festgelegt (Prozess ohne CAP_SYS_ADMIN).
- EPERM
- CLONE_PID wurde von einem anderen Prozess als Prozess 0 festgelegt. (Dieser Fehler tritt nur unter Linux 2.5.15 und früheren Versionen auf.)
- EPERM
- CLONE_NEWUSER wurde in Schalter festgelegt, aber weder die effektive Benutzerkennung noch die effektive Gruppenkennung des Aufrufenden hat eine Abbildung in den Namensraum der Eltern (siehe user_namespaces(7)).
- EPERM (seit Linux 3.9)
- CLONE_NEWUSER wurde in Schalter festgelegt und der Aufrufende ist in einer Chroot-Umgebung (d.h. das Wurzelverzeichnis des Aufrufenden passt nicht zum Wurzelverzeichnis des Einhängenamensraums, in dem er sich befindet).
- ERESTARTNOINTR (seit Linux 2.6.17)
- Ein Systemaufruf wurde durch ein Signal unterbrochen und wird neu gestartet. (Dies wird nur während einer Verfolgung sichtbar sein.)
- EUSERS (Linux 3.11 bis Linux 4.8)
- CLONE_NEWUSER wurde in Schalter festgelegt und die Begrenzung für die Anzahl von verschachtelten Benutzernamensräumen würde überschritten. Siehe die Diskussion des Fehlers ENOSPC oben.
KONFORM ZU¶
clone() ist Linux-spezifisch und sollte nicht in portierbaren Programmen benutzt werden.
ANMERKUNGEN¶
Der Systemaufruf kcmp(2) kann zum Testen, ob zwei Prozesse sich verschiedene Ressourcen, wie die Dateideskriptortabelle, die Rücksetz-Aktionen der System-V-Semaphoren oder einen virtuellen Adressraum, teilen, verwandt werden.
Handler, die mittels pthread_atfork(3) registriert sind, werden während eines Aufrufs von clone() nicht ausgeführt.
In der Linux 2.4.x-Serie gibt CLONE_THREAD generell dem neuen Prozess nicht den gleichen Elternprozess, wie dem aufrufenden Prozess. Für die Kernel-Versionen 2.4.7 bis 2.4.18 implizierte der Schalter CLONE_THREAD jedoch den Schalter CLONE_PARENT (wie in Kernel 2.6.0 und neuer).
Eine Zeitlang gab es CLONE_DETACHED (eingeführt in 2.5.32): der Elternprozess möchte kein Child-Exit-Signal. In Linux 2.6.2 verschwand die Notwendigkeit, diesen Schalter anzugeben zusammen mit CLONE_THREAD. Der Schalter ist weiterhin definiert, hat aber keine Wirkung.
Auf i386-Architekturen sollte clone() nicht durch vsyscall aufgerufen werden, sondern direkt durch int $0x80.
FEHLER¶
GNU-C-Bibliotheksversionen 2.3.4 bis einschließlich 2.24 enthielten eine Wrapper-Funktion für getpid(2), die Zwischenspeichern von PIDs vornahm. Dieses Zwischenspeichern beruhte auf der Unterstützung in dem Glibc-Wrapper von clone(), aber Einschränkungen in der Implementierung bedeuteten, dass unter einigen Umständen der Zwischenspeicher nicht aktuell war. Insbesondere wenn ein Signal sofort nach dem clone()-Aufruf an den Kindprozess gesandt wurde, konnte ein Aufruf von getpid(2) in einem Signal-Handler die PID des aufrufenden Prozesses (des »Elternprozesses«) zurückgeben, falls der Clone-Wrapper noch keine Chance hatte den PID-Zwischenspeicher im Kindprozess zu aktualisieren. (Diese Diskussion ignoriert den Fall, dass der Kindprozess mit CLONE_THREAD erstellt wurde, in dem getpid(2) den gleichen Wert im Kindprozess zurückgeben sollte und im Prozess, der clone() aufrief, wie sich der Aufrufende und der Kindprozess in der gleichen Thread-Gruppe befinden. Das Problem des nicht mehr frischen Zwischenspeichers tritt auch auf, wenn das Argument Schalter CLONE_VM enthält.) Um die Wahrheit zu erfahren, war es manchmal notwendig gewesen, Code wie den folgenden zu verwenden:
#include <syscall.h> pid_t mypid; mypid = syscall(SYS_getpid);
Aufgrund des Problems mit dem nicht mehr frischem Zwischenspeicher sowie anderen in getpid(2) bemerkten Problemen, wurde die Funktionalität des PID-Zwischenspeicherns in Glibc 2.25 entfernt.
BEISPIEL¶
Das folgende Programm demonstriert die Benutzung von clone() zum Erzeugen eines Kindprozesses, der in einem separaten UTS-Namensraum ausgeführt wird. Der Kindprozess ändert in seinem UTS-Namensraum den Rechnernamen. Dann zeigen sowohl Eltern- als auch Kindprozess den Rechnernamen des Systems an, wodurch sichtbar wird, dass der Rechnername sich im UTS-Namensraum von Eltern- und Kindprozess unterscheidet. Ein Beispiel für die Verwendung dieses Programms finden Sie in setns(2).
Programmquelltext¶
#define _GNU_SOURCE #include <sys/wait.h> #include <sys/utsname.h> #include <sched.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define errExit(Nachricht) do { perror(Nachricht); exit(EXIT_FAILURE); \
} while (0) static int /* Startfunktion für geklonten Kindprozess */ childFunc(void *arg) {
struct utsname uts;
/* Rechnername im UTS-Namensraum des Kindprozesses ändern */
if (sethostname(arg, strlen(arg)) == -1)
errExit("sethostname");
/* Rechnernamen abfragen und anzeigen */
if (uname(&uts) == -1)
errExit("uname");
printf("uts.nodename im Kindprozess: %s\n", uts.nodename);
/* Der Namensraum wird für eine Weile durch Schlafen offen gehalten.
Dies ermöglicht etwas zu experimentieren – zum Beispiel
kann ein weiterer Prozess dem Namensraum beitreten. */
sleep(200);
return 0; /* Kindprozess wird nun beendet */ } #define STACK_SIZE (1024 * 1024) /* Stapelspeichergröße für geklonten
Kindprozess */ int main(int argc, char *argv[]) {
char *stack; /* Start des Stapelspeicherpuffers */
char *stackTop; /* Ende des Stapelspeicherpuffers */
pid_t pid;
struct utsname uts;
if (argc < 2) {
fprintf(stderr, "Aufruf: %s <Kindprozess-Rechnername>\n", argv[0]);
exit(EXIT_SUCCESS);
}
/* Stapelspeicher für den Kindprozess reservieren */
stack = malloc(STACK_SIZE);
if (stack == NULL)
errExit("malloc");
stackTop = stack + STACK_SIZE; /* Annahme, dass Stapelspeicher nach */
unten wächst */
/* Es wird ein Kindprozess erzeugt, der seinen eigenen Namensraum hat.
Der Kindprozess beginnt die Ausführung in childFunc() */
pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);
if (pid == -1)
errExit("clone");
printf("clone() gab %ld zurück\n", (long) pid);
/* Elternprozess fällt bis hierher durch */
sleep(1); /* gibt dem Kindprozess Zeit zum Ändern des Rechnernamens */
/* Den Rechnernamen im UTS-Namensraum des Elternprozesses anzeigen.
Dieser wird sich vom Rechnernamen im UTS-Namensraum des Kindprozesses
unterscheiden. */
if (uname(&uts) == -1)
errExit("uname");
printf("uts.nodename im Elternprozess: %s\n", uts.nodename);
if (waitpid(pid, NULL, 0) == -1) /* Warten auf Kindprozess */
errExit("waitpid");
printf("Kindprozess wurde beendet\n");
exit(EXIT_SUCCESS); }
SIEHE AUCH¶
fork(2), futex(2), getpid(2), gettid(2), kcmp(2), set_thread_area(2), set_tid_address(2), setns(2), tkill(2), unshare(2), wait(2), capabilities(7), namespaces(7), pthreads(7)
KOLOPHON¶
Diese Seite ist Teil der Veröffentlichung 4.16 des Projekts Linux-man-pages. Eine Beschreibung des Projekts, Informationen, wie Fehler gemeldet werden können, sowie die aktuelle Version dieser Seite finden sich unter https://www.kernel.org/doc/man-pages/.
ÜBERSETZUNG¶
Die deutsche Übersetzung dieser Handbuchseite wurde von Daniel Kobras <kobras@linux.de>, Chris Leick <c.leick@vollbio.de>, Mario Blättermann <mario.blaettermann@gmail.com>, Dr. Tobias Quathamer <toddy@debian.org> und Helge Kreutzmann <debian@helgefjell.de> erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer bezüglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an die Mailingliste der Übersetzer.
15. September 2017 | Linux |