Other Alias
cloneÜBERSICHT
/* Prototyp für die Glibc-Wrapper-Funktion */
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, …
/* pid_t *ptid, struct user_desc *tls,
pid_t *ctid */ );
/* Prototyp für den rohen Systemaufruf */
long clone(unsigned long flags, void *child_stack,
void *ptid, void *ctid,
struct pt_regs *regs);
BESCHREIBUNG
clone() erzeugt auf eine ähnliche Weise wie fork(2) einen neuen Prozess.Diese Seite beschreibt sowohl 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.
Im Gegensatz zu fork(2) erlaubt clone(), dass der Kindprozess Teile seines Kontextes mit dem aufrufenden Prozess teilt. Dazu zählen der Speicherplatz, die Tabelle der Dateideskriptoren und die Tabelle der Signal-Handler. (Beachten Sie, dass »aufrufender Prozess« auf dieser Handbuchseite »Elternprozess« entspricht. Aber lesen Sie im Folgenden die Beschreibung von CLONE_PARENT.)
clone() wird benutzt, um Threads zu implementieren: mehrere Steuer-Threads in einem Programm, die gleichzeitig in einem gemeinsamen Speicherbereich ausgeführt werden.
Wird mit clone() ein Kindprozess erzeugt, führt er die Funktion fn(arg) aus. (Dies ist ein Unterschied zu fork(2), wo die Ausführung im Kindprozess vom Punkt des fork(2)-Aufrufs fortfährt.) Das Argument fn ist ein Zeiger auf eine Funktion, die vom Kindprozess zu Beginn seiner Ausführung abgearbeitet wird. arg wird der Funktion fn als Argument übergeben.
Kehrt die Funktion fn(arg) zurück, so beendet sich der Kindprozess. Der Ganzzahlwert, der von fn zurückgeliefert wird, entspricht dem Exit-Code des Kindprozesses. Der Kindprozess kann auch durch den expliziten Aufruf von exit(2) oder durch den Empfang eines fatalen Signals beendet werden.
Das Argument child_stack 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 child_stack für gewöhnlich auf die oberste Adresse im bereitgehaltenen Speicherbereich zeigt.
Das niederwertige Byte von flags enthält die Nummer des Beendigungssignals, das an den Elternprozess gesandt wird, wenn der Kindprozess endet. 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.
flags kann darüber hinaus noch durch bitweises »Oder« mit keiner oder mehreren der folgenden Konstanten verknüpft werden. Dadurch wird festgelegt, welche Ressourcen sich Eltern- und Kindprozess teilen:
- CLONE_CHILD_CLEARTID (seit Linux 2.5.49)
- Die Kind-Thread-ID an der Stelle ctid im Kindspeicher löschen, wenn das Kind existiert 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)
- Speichert die Kind-Thread-ID an der Stelle ctid im Kindspeicher
- 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. (Die kopierten Dateideskriptoren im Kindprozess beziehen sich auf die gleichen offenen Dateideskriptoren (siehe open(2)) wie die entsprechenden Dateideskriptoren im aufrufenden Prozess.) Anschließende Operationen, 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.
- 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 von clone() mit einer Kopie der Dateisysteminformationen des aufrufenden Prozesses zur Zeit des clone()-Aufrufs. Spätere Aufrufe von chroot(2), chdir(2) und 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-Steuerprogramms, d.h., welches das E/A-Steuerprogramm zur Modellplanung für E/As des Prozesses benutzt. Falls sich Prozesse den gleichen E/A-Kontext teilen, werden sie vom E/A-Steuerprogramm als ein einziger betrachtet. Als Konsequenz daraus müssen sie sich die gleiche Plattenzeitzugriffzeit teilen. Einige E/A-Steuerprogramme 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)
-
Erstellt den Prozess in einem neuen cgroup-Namensraum. Falls dieser Schalter
nicht gesetzt ist, dann wird (wie mit fork(2)) der Prozess in den
gleichen cgroup-Namensräumen wie der aufrufende Prozess erstellt. Der
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)
-
Ist CLONE_NEWIPC gesetzt, dann wird der Prozess in einem neuen
IPC-Namensraum erstellt. Falls dieser Schalter nicht gesetzt ist, dann wird
der Prozess (wie bei 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 eine isolierte Ansicht von System-V-IPC-Objekten (siehe svipc(7)) und (seit 2.6.30) POSIX-Nachrichtenwarteschlangen (siehe mq_overview(7)) bereit. Das gemeinsame Merkmal dieser IPC-Mechanismen ist, dass IPC-Objekte durch andere Mechanismen als Dateisystempfadnamen identifiziert werden.
Objekte, die in einem IPC-Namensraum erstellt wurden, sind für alle anderen Prozesse sichtbar, die Mitglieder des Namensraums sind. Die Objekte sind jedoch nicht für Prozesse in anderen Namensräumen sichtbar.
Wenn ein IPC-Namensraum zerstört wird, d.h. wenn der letzte Prozess im Namensraum beendet wird, werden alle IPC-Objekte im 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 Netzwerk-Namensraum stellt eine isolierte Ansicht des Netzwerk-Stapelspeichers (Netzwerkgeräteschnittstellen, IPv4- und IPv6-Protokoll-Stapelspeicher, IP-Routing-Tabellen, Firewall-Regeln, die Verzeichnisbäume /proc/net und /sys/class/net, Sockets, etc.) bereit. Ein physisches Netzwerkgerät kann in genau einem Netzwerknamensraum bestehen. Ein virtuelles Netzwerkgerätepaar (»veth«) stellt eine einer Pipe ähnliche Abstraktion bereit, die benutzt werden kann, um Tunnel zwischen Netzwerk-Namensräumen aufzubauen und eine Brücke in ein physisches Netzwerkgerät in einem anderen Namensraum zu erstellen.
Wenn ein Netzwerk-Namensraum freigegeben wird, d.h. wenn der letzte Prozess im Namensraum beendet wird, werden seine physischen Netzwerkgeräte zurück in den ursprünglichen Namensraum verschoben (nicht zum Elternprozess). Weitere Informationen zu Netzwerk-Namensräumen finden Sie in 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.
Weitere Informationen über Einhänge-Namensräume finden Sie unter namespaces(7).
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.
- 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 (wie mit
fork(2)), dann wird der Prozess in dem gleichen PID-Namensraum wie der
aufrufende Prozess erstellt. Der 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.
Für weitere Informationen über Benutzernamensräume lesen Sie namespaces(7) und user_namespaces(7)
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.
Weitere Informationen über Benutzer-Namensräume finden Sie unter 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 eine Zusammenstellung von Bezeichnern, die von uname(2) zurückgegeben werden; von denen können der Domain-Name und der Rechnername durch setdomainname(2) beziehungsweise sethostname(2) geändert werden. Änderungen, die an Bezeichnern in einem UTS-Namensraum vorgenommen werden, sind für alle anderen Prozesse im gleichen Namensraum sichtbar, nicht jedoch 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-ID an der Stelle ptid im Elternspeicher ablegen. (In Linux 2.5.32-2.5.48 gab es einen Schalter CLONE_SETTID, der das tat.)
- CLONE_PID (veraltet)
- Falls CLONE_PID gesetzt ist, wird der Kindprozess mit der gleichen Prozess-ID wie der aufrufende Prozess erstellt. Dies ist gut, um das System zu hacken, aber andererseits zu nicht viel mehr zu gebrauchen. Seit 2.3.21 konnte dieser Schalter nur durch den Boot-Prozess angegeben werden (PID 0). Er verschwand in Linux 2.5.16. Seitdem ignoriert der Kernel ihn ohne Fehler.
- 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)
- Das Argument newtls ist der neue TLS-Desktiptor (Thread Local Storage). (Lesen Sie set_thread_area(2).)
- 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. Einzelne Signale könnten daher 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 durch den clone-Aufruf 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 müssen die flags 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)
- If CLONE_SYSVSEM is set, then the child and the calling process share a single list of System V semaphore adjustment (semadj) values (see semop(2)). In this case, the shared list accumulates semadj values across all processes sharing the list, and semaphore adjustments are performed only when the last process that is sharing the list terminates (or ceases sharing the list using unshare(2)). If this flag is not set, then the child has a separate semadj list that is initially empty.
- 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-ID (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 der, der clone() aufruft (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 per 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 müssen die flags 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 geschickt werden (d.h. einer TGID) unter Benutzung von kill(2) oder an einen bestimmten Thread unter Benutzung von tgkill(2).
Signalanordnungen 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 Signalmaske, wie sie von sigprocmask(2) gesetzt wird, Signale können aber entweder für den ganzen Prozess anstehen (d.h. an jedes Mitglied der Thread-Gruppe zu liefern sein), wenn sie mit kill(2) gesandt wurden oder für einen einzelnen Thread, wenn sie mit tgkill(2) gesandt wurden. Ein Aufruf von sigpending(2) gibt eine Signalzusammenstellung zurück, die eine Verbindung ausstehender Signale für den ganzen Prozess und der Signale ist, die für den aufrufenden Prozess anstehen.
Falls kill(2) benutzt wird, um ein Signal an eine Thread-Gruppe zu senden 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 das per kill(2) gesandt Signal zu empfangen.
- 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 zur Zeit des clone()-Aufrufs. 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).
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. Zudem wird die Reihenfolge der Argumente geändert. Die rohe Schnittstelle für Systemaufrufe auf x86 und vielen anderen Architekturen sieht ungefähr so aus:long clone(unsigned long flags, void *child_stack, void *ptid, void *ctid, struct pt_regs *regs);Ein weiterer Unterschied für den rohen Systemaufruf besteht darin, dass das Argument child_stack Null sein könnte, so dass in diesem Fall »copy-on-write«-Semantik sicherstellt, 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.
Für einige Architekturen unterscheidet sich die Reihenfolge der Argumente für den Systemaufruf von der oben gezeigten. In der Masse der MicroBlaze-, ARM-, ARM-64-, PA-RISC-, Arc-, Power PC-, Xtensa- und MIPS-Architekturen ist die Reihenfolge des vierten und fünften Arguments vertauscht. Auf den Cris- und S390-Architekturen ist die Reihenfolge des ersten und zweiten Arguments vertauscht.
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 *child_stack_base, size_t stack_size, int flags, void *arg, … /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
Der oben gezeigte Prototyp ist für die Glibc-Wrapper-Funktion. Die rohe Systemaufrufschnittstelle hat kein fn- oder arg-Argument und ändert die Reihenfolge der Argumente, so dass flags das erste und tls das letzte Argument ist.
__clone2() arbeitet auf die gleiche Weise wie clone(), außer dass child_stack_base auf die niedrigste Adresse im Stapelspeicherbereich des Kindprozesses zeigt und stack_size die Größe des Stapelspeichers angibt, auf die child_stack_base zeigt.
Linux 2.4 und früher
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-ID 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 angegeben, aber nicht CLONE_VM. (Seit Linux 2.6.0-test6.)
- EINVAL
- CLONE_THREAD wurde angegeben, aber nicht CLONE_SIGHAND. (Seit Linux 2.5.35.)
- EINVAL
- In flags wurden sowohl CLONE_FS als auch CLONE_NEWNS angegeben.
- EINVAL (seit Linux 3.9)
- In flags wurden sowohl CLONE_NEWUSER als auch CLONE_FS angegeben.
- EINVAL
- In flags wurden sowohl CLONE_NEWIPC als auch CLONE_SYSVSEM angegeben.
- EINVAL
- Eines (oder beides) von CLONE_NEWPID oder CLONE_NEWUSER und eines (oder beides) von CLONE_THREAD oder CLONE_PARENT wurde in flags angegeben.
- EINVAL
- Wird von clone() zurückgegeben, wenn ein Wert von Null für child_stack angegeben wurde.
- EINVAL
- In flags wurde CLONE_NEWIPC angegeben, der Kernel wurde jedoch nicht mit den Optionen CONFIG_SYSVIPC und CONFIG_IPC_NS konfiguriert.
- EINVAL
- In flags wurde CLONE_NEWNET angegeben, der Kernel wurde jedoch nicht mit der Option CONFIG_NET_NS konfiguriert.
- EINVAL
- In flags wurde CLONE_NEWPID angegeben, der Kernel wurde jedoch nicht mit der Option CONFIG_PID_NS konfiguriert.
- EINVAL
- In flags wurde CLONE_NEWUTS angegeben, der Kernel wurde jedoch nicht mit der Option CONFIG_UTS konfiguriert.
- EINVAL
- child_stack is not aligned to a suitable boundary for this architecture. For example, on aarch64, child_stack must be a multiple of 16.
- 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.
- EPERM
- CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID oder CLONE_NEWUTS wurde von einem nicht privilegierten Prozess angegeben (Prozess ohne CAP_SYS_ADMIN).
- EPERM
- CLONE_PID wurde von einem anderen Prozess als Prozess 0 angegeben.
- EPERM
- CLONE_NEWUSER was specified in flags, but either the effective user ID or the effective group ID of the caller does not have a mapping in the parent namespace (see user_namespaces(7)).
- EPERM (seit Linux 3.9)
- CLONE_NEWUSER was specified in flags and the caller is in a chroot environment (i.e., the caller's root directory does not match the root directory of the mount namespace in which it resides).
- EUSERS (seit Linux 3.11)
- CLONE_NEWUSER was specified in flags, and the call would cause the limit on the number of nested user namespaces to be exceeded. See user_namespaces(7).
- ERESTARTNOINTR (seit Linux 2.6.17)
- System call was interrupted by a signal and will be restarted. (This can be seen only during a trace.)
VERSIONEN
Es gibt keinen Eintrag für clone() in der libc5. Die Glibc2 stellt clone() wie in dieser Handbuchseite beschrieben bereit.KONFORM ZU
clone() ist Linux-spezifisch und sollte nicht in portierbaren Programmen benutzt werden.ANMERKUNGEN
In den 2.4.x-Kerneln 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).Für eine Weile gab es CLONE_DETACHED (eingeführt in 2.5.32): Elternprozesse wollen kein Ende-Signal des Kindprozesses. In 2.6.2 verschwand die Notwendigkeit, dies zusammen mit CLONE_THREAD zu übergeben. Dieser Schalter ist immer noch definiert, hat aber keine Auswirkungen.
Auf i386-Architekturen sollte clone() nicht durch vsyscall aufgerufen werden, sondern direkt durch int $0x80.
FEHLER
Versionen der GNU-C-Bibiliothek, die die NPTL-Threading-Bibliothek enthalten, enthalten eine Wrapper-Funktion für getpid(2), die die Zwischenspeicherung der PIDs verrichtet. Diese Zwischenspeicherung beruht auf der Unterstützung für clone() im Glibc-Wrapper, der Zwischenspeicher könnte aber der derzeitigen Implementierung unter Umständen nicht aktuell sein. Insbesondere wenn ein Signal sofort nach dem clone()-Aufruf an den Kindprozess gesandt wird, könnte 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 flags CLONE_VM enthält.) Um die Wahrheit zu erfahren, könnte es nötig sein Kode wie den folgenden zu verwenden:#include <syscall.h> pid_t mypid; mypid = syscall(SYS_getpid);
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(msg) do { perror(msg); 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 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); }
KOLOPHON
Diese Seite ist Teil der Veröffentlichung 4.06 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 <[email protected]>, Chris Leick <[email protected]>, Mario Blättermann <[email protected]> und Helge Kreutzmann <[email protected]> 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 <[email protected]>.