clone, __clone2, clone3 - erzeugt einen Kindprozess
ÜBERSICHT
/* Prototyp für die Glibc-Wrapper-Funktion */
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *), void *Stapel, int Schalter, void *arg, …
/* pid_t *Eltern_tid, void *tls, pid_t *Kind_tid */ );
/* Für den Prototyp des rohen clone()-Systemaufrufs siehe ANMERKUNGEN */
long clone3(struct clone_args *cl_args, size_t size);
Hinweis: Es gibt noch keinen Glibc-Wrapper für
clone3(); siehe ANMERKUNGEN.
Diese Systemaufrufe erzeugen auf eine ähnliche Weise wie
fork(2) einen neuen Prozess (»Kind«).
Im Gegensatz zu fork(2) bieten diese Systemaufrufe eine
genauere Kontrolle darüber, welche Teile des
Ausführungskontextes vom aufrufenden und vom Kindprozess gemeinsam
benutzt werden. Beispielsweise kann der Aufrufende mittels dieser
Systemaufrufe steuern, ob die zwei Prozesse den virtuellen Adressraum, die
Tabelle der Dateideskriptoren und die Tabelle der Signal-Handler gemeinsam
benutzen. Diese Systemaufrufe ermöglichen es auch, den neuen
Kindprozess in einen separaten Namensraum (siehe namespaces(7))
abzulegen.
Beachten Sie, dass in dieser Handbuchseite der »aufrufende
Prozess« normalerweise der »Elternprozess« ist. Siehe
aber auch die nachfolgende Beschreibung von CLONE_PARENT und
CLONE_THREAD.
Diese Seite beschreibt die folgenden Schnittstellen:
- 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.
- Der neuere Systemaufruf clone3().
Im Rest der Seite wird die Terminologie »der
Clone-Aufruf« verwandt, wenn Details erklärt werden, die auf
alle diese Schnittstellen zutreffen.
Wird mit der clone()-Wrapper-Funktion 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 Stapel 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 Stapel für gewöhnlich
auf die oberste Adresse im bereitgehaltenen Speicherbereich zeigt. Beachten
Sie, dass clone() keine Möglichkeit bereitstellt, mit der der
Aufrufende den Kernel über die Größe des
Stapel-Bereichs informieren könnte.
Die verbliebenen Argumente für clone() werden unten
behandelt.
Der Systemaufruf clone3() stellt eine Obermenge der
Funktionalität der älteren Schnittstelle clone()
bereit. Er stellt auch eine Reihe von API-Verbesserungen bereit,
einschließlich: Platz für zusätzliche Schalter-Bits;
deutlichere Trennung beim Einsatz der verschiedenen Argumente, die
Möglichkeit, die Größe des Stapel-Bereichs des
Kindprozesses festzulegen.
Wie bei fork(2) kehrt clone3() sowohl im Eltern- als
auch im Kindprozess zurück. Er liefert 0 im Kindprozess und die PID
des Kindprozesses im Elternprozess zurück.
Das Argument cl_args von clone3() ist eine Struktur
der folgenden Form:
struct clone_args {
u64 flags; /* Schalter-Bit-Maske */
u64 pidfd; /* Wo der PID-Dateideskriptor gespeichert
werden soll (pid_t *) */
u64 child_tid; /* Wo die Kind-TID gespeichert werden soll,
im Speicher des Kindes (pid_t *) */
u64 parent_tid; /* Wo die Kind-TID gespeichert werden soll,
im Speicher des Elternprozesses (int *) */
u64 exit_signal; /* Beim Beenden des Kindprozesses an den Elternprozess
zu sendendes Signal */
u64 stack; /* Zeiger auf das niedrigste Byte des Stapels */
u64 stack_size; /* Größe des Stapels */
u64 tls; /* Ort eines neuen TLS */
u64 set_tid; /* Zeiger auf ein pid_t-Feld
(seit Linux 5.5) */
u64 set_tid_size; /* Anzahl von Elementen in set_tid
(seit Linux 5.5) */
u64 cgroup; /* Dateideskriptor für Ziel-Cgroup
eines Kindes (seit Linux 5.7) */
};
Das an clone3() übergebene Argument size
sollte auf die Größe dieser Struktur initialisiert werden.
(Die Existenz des Arguments size ermöglicht zukünftige
Erweiterungen der clone_args-Struktur.)
Der Stapel für den Kindprozess wird in
cl_args.stack, der auf das niedrigste Byte des Stapel-Bereichs zeigt,
und cl_args.stack_size, der die Größe des
Stapel-Bereichs in Byte festlegt, angegeben. Falls der Schalter
CLONE_VM (siehe unten) angegeben ist, muss ein Stapel explizit
reserviert und festgelegt werden. Andernfalls können diese Felder als
NULL und 0 angegeben werden, wodurch der Kindprozess den gleichen
Stapel-Bereich wie der Elternprozess verwendet (im eigenen virtuellen
Adressraum des Kindprozesses).
Die verbliebenen Felder im Argument cl_args werden unten
behandelt.
Äquivalenz zwischen den Argumenten von clone() und
clone3()
Anders als die ältere clone()-Schnittstelle, bei der
die Argumente individuell übergeben werden, werden die Argumente bei
der neueren clone3()-Schnittstelle in die oben gezeigte Struktur
clone_args gepackt. Diese Struktur erlaubt es, dass eine Obermenge an
Informationen über die clone()-Argumente übergeben
wird.
Die folgende Tabelle zeigt die Äquivalenz zwischen den
Argumenten von clone() und den Feldern in den an clone3()
übergebenen clone_args:
clone() |
clone3() |
Hinweise |
|
Feld cl_args |
Schalter & ~0xff |
flags |
Für die meisten Schalter; Details unten |
parent_tid |
pidfd |
Siehe CLONE_PIDFD |
child_tid |
child_tid |
Siehe CLONE_CHILD_SETTID |
parent_tid |
parent_tid |
Siehe CLONE_PARENT_SETTID |
Schalter & 0xff |
exit_signal |
Stapel |
Stapel |
--- |
stack_size |
tls |
tls |
Siehe CLONE_SETTLS |
--- |
set_tid |
Siehe weiter unten für Details. |
--- |
set_tid_size |
--- |
cgroup |
Siehe CLONE_INTO_CGROUP |
Wenn sich der Kindprozess beendet, kann ein Signal an den
Elternprozess gesandt werden. Das Beendigungssignal wird in den niedrigen
Bytes von Schalter (clone()) oder in
cl_args.exit_signal (clone3()) angegeben. 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 (d.h.
Null) angegeben wurde, wird dem Elternprozess nicht signalisiert, wenn der
Kindprozess endet.
Standardmäßig wählt der Kernel die
nächste sequenzielle PID für den neuen Prozess in jedem der
PID-Namensräume, in denen er vorhanden ist. Beim Erstellen eines
Prozesses mit clone3() kann das (seit Linux 5.5 verfügbare)
Feld set_tid zur Auswahl bestimmter PIDs für den Prozess in
einem oder allen der PID-Namensräume, in denen er vorhanden ist,
eingesetzt werden. Falls die PID des neu erstellten Prozesses nur im
aktuellen PID-Namensraum oder in dem neu erstellten PID-Namensraum (falls
Schalter CLONE_NEWPID enthält) gesetzt werden soll,
dann muss das erste Element in dem Feld set_tid auf die
gewünschte PID gesetzt werden und set_tid_size muss 1
sein.
Falls die PID des neu erstellten Prozesses einen bestimmten Wert
in mehreren PID-Namensräumen haben soll, dann kann dass Feld
set_tid über mehrere Einträge verfügen. Der
erste Eintrag definiert die PID im am tiefsten verschachtelten
PID-Namensraum und jeder der nachfolgenden Einträge enthält
die PID in dem entsprechenden Vorfahren-PID-Namensraum. Die Anzahl der
PID-Namensräume in denen eine PID gesetzt werden soll, wird mit
set_tid_size gesetzt; dieser Wert kann nicht größer als
die Anzahl der derzeit verschachtelten PID-Namensräume sein.
Um einen Prozess zu erzeugen, der die nachfolgenden PIDs in einem
PID-Namensraum hat:
PID-NS-Stufe |
Angeforderte PID |
Hinweise |
0 |
31496 |
Äußerster PID-Namensraum |
1 |
42 |
2 |
7 |
Innerster PID-Namensraum |
Setzen Sie das Feld auf:
set_tid[0] = 7;
set_tid[1] = 42;
set_tid[2] = 31496;
set_tid_size = 3;
Falls nur die PIDs in den zwei innersten PID-Namensräumen
festgelegt werden müssen, setzen Sie das Feld auf:
set_tid[0] = 7;
set_tid[1] = 42;
set_tid_size = 2;
Die PID in den PID-Namensräumen außerhalb der zwei
innersten PID-Namensräume wird genauso wie jede andere PID
ausgewählt.
Die Funktionalität set_tid benötigt
CAP_SYS_ADMIN oder (seit Linux 5.9) CAP_CHECKPOINT_RESTORE in
allen Benutzernamensräumen, die dem des Ziel-PID-Namensraumes
gehören.
Aufrufende dürfen in einem gegebenen PID-Namensraum nur
eine PID größer als 1 auswählen, falls ein
init-Prozess (d.h. ein Prozess mit der PID 1) in diesem Namensraum
bereits existiert. Andernfalls muss der PID-Eintrag für diesen
PID-Namensraum 1 sein.
Sowohl clone() als auch clone3() erlauben eine
Schalter-Bit-Maske, die das Verhalten verändert und dem Aufrufenden
festzulegen erlaubt, was von dem aufrufenden Prozess und dem Kindprozess
gemeinsam benutzt wird. Diese Bitmaske—das Argument Schalter
von clone() oder das an clone3() übergebene Feld
cl_args.flags—wird im Rest dieser Handbuchseite als die
Schalter-Maske bezeichnet.
Die Schalter-Maske wird als bitweises ODER von Null oder
mehreren der oben aufgeführten Konstanten angegeben. Falls nicht
unten anders angegeben, sind diese Schalter sowohl in clone() als
auch clone3() verfügbar (und haben die gleiche Wirkung).
- CLONE_CHILD_CLEARTID
(seit Linux 2.5.49)
- Die Kind-Thread-Kennung an der durch Kind_tid gezeigten Stelle
(clone()) oder cl_args.child_tid (clone3()) 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)
- Speichert die Kind-Thread-Kennung an der Stelle, auf die Kind_tid
(clone()) oder cl_args.child_tid (clone3()) zeigt, im
Kindspeicher. Die Speicheraktion wird abgeschlossen, bevor der
Clone-Aufruf die Steuerung an den Benutzerraum im Kindprozess
zurückgibt. (Beachten Sie, dass die Speicheraktion noch nicht
abgeschlossen sein könnte, bevor der Clone-Aufruf den Elternprozess
zurückliefert, was relevant wird, wenn auch der Schalter
CLONE_VM eingesetzt wird.)
- CLONE_CLEAR_SIGHAND
(seit Linux 5.5)
- Standardmäßig sind die Signal-Zuordnungen im Kind-Thread
identisch zu denen im Eltern-Prozess. Falls dieser Schalter angegeben ist,
dann werden alle Signale, die im Eltern-Prozess gehandhabt werden, im
Kind-Thread auf ihre Standardzuordnung (SIG_DFL)
zurückgesetzt.
- Es ergibt keinen Sinn, diesen Schalter zusammen mit CLONE_SIGHAND
anzugeben; daher ist diese Kombination nicht erlaubt.
- CLONE_DETACHED
(historisch)
- Eine Zeit lang (während der Linux-2.5-Entwicklungsserie) gab es
einen Schalter CLONE_DETACHED, der dazu führte, dass der
Elternprozess kein Signal empfing, wenn sich das Kind beendete.
Schließlich wurde die Auswirkung dieses Schalters in dem Schalter
CLONE_THREAD mit aufgenommen und zum Zeitpunkt der
Veröffentlichung von Linux 2.6.0 hatte dieser Schalter keine
Auswirkung. Beginnend mit Linux 2.6.2 verschwand die Notwendigkeit, diesen
Schalter mit CLONE_THREAD zusammen anzugeben.
- Dieser Schalter ist noch definiert, wird aber beim Aufruf von
clone() normalerweise ignoriert. Siehe allerdings die Beschreibung
von CLONE_PIDFD für einige Ausnahmen.
- 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_INTO_CGROUP
(seit Linux 5.7)
- Standardmäßig wird ein Kindprozess in die gleiche
Version-2-Cgroup wie sein Elternprozess abgelegt. Der Schalter
CLONE_INTO_CGROUP ermöglicht es, den Kindprozess in einer
anderen Version-2-Cgroup zu erstellen. (Beachten Sie, dass
CLONE_INTO_CGROUP nur für Version-2-Cgroups wirksam
wird.)
- Um den Kindprozess in eine andere Cgroup abzulegen, legt der Aufrufende
CLONE_INTO_CGROUP in cl_args.flags fest und übergibt
im Feld cl_args.cgroup einen Dateideskriptor, der sich auf eine
Version-2-Cgroup bezieht. (Dieser Dateideskriptor kann erhalten werden,
indem ein Cgroup-v2-Verzeichnis mittels des Schalters O_RDONLY oder
O_PATH geöffnet wird.) Beachten Sie, dass sämtliche
übliche Einschränkungen (beschrieben in cgroups(7))
über das Ablegen eines Prozesses in einer Version-2-Cgroup
gültig bleiben.
- Folgende Anwendungsfälle für CLONE_INTO_CGROUP sind
unter anderen möglich:
- Das Erzeugen eines Prozesses in einer Cgroup, die sich von der des
Elternprozesses unterscheidet, ermöglicht es einem
Diensteverwalter, neue Dienste direkt in dedizierte Cgroups zu erzeugen.
Dies beseitigt das Flackern bei der Buchführung, das erzeugt
würde, falls der Kindprozess erst in der gleichen Cgroup wie der
Elternprozess erzeugt und dann in die Ziel-Cgroup verschoben würde.
Desweiteren ist die Erzeugung des Kindprozesses direkt in der Ziel-Cgroup
deutlich billiger als das Verschieben des Kindprozesses in die
Ziel-Cgroup, nachdem er erstellt wurde.
- Der Schalter CLONE_INTO_CGROUP erlaubt auch die Erstellung
eingefrorener Kindprozesse durch Erzeugung dieser in einer eingefrorenen
Cgroup. (Siehe cgroups(7) für eine Beschreibung des
Einfrier-Controllers.)
- Für Anwendungen mit Threads (oder sogar Thread-Implementierungen,
die Cgroups verwenden, um einzelne Threads zu begrenzen) ist es
möglich, ein festes Cgroup-Layout zu errichten, bevor jeder Thread
direkt in seine Ziel-Cgroup erzeugt wird.
- 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.
- 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.
- Weitere Informationen zu IPC-Namensräumen finden Sie in
ipc_namespaces(7).
- Nur ein privilegierter Prozess (CAP_SYS_ADMIN) kann
CLONE_NEWIPC angeben. Dieser Schalter darf nicht zusammen mit
CLONE_SYSVSEM angegeben werden.
- 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.
- Weitere Informationen zu Netzwerk-Namensräumen finden Sie in
network_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.
- Für weitere Informationen über
Einhängenamensräume lesen Sie namespaces(7) und
mount_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, dann
wird der Prozess (wie mit fork(2)) im gleichen PID-Namensraum wie
der aufrufende Prozess erstellt.
- 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.
- 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.
- Weitere Informationen zu UTS-Namensräumen finden Sie in
uts_namespaces(7).
- Nur ein privilegierter Prozess (CAP_SYS_ADMIN) kann
CLONE_NEWUTS angeben.
- 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.
- Der Schalter CLONE_PARENT kann in Clone-Aufrufen durch den globalen
Init-Prozess (PID 1 im anfänglichen PID-Namensraum) und in
Init-Prozessen in anderen PID-Namensräumen nicht verwandt werden.
Diese Einschränkung verhindert die Erstellung von
Prozessbäumen mit mehreren Wurzeln sowie die Erstellung von nicht
zerstörbaren Zombies im anfänglichen PID-Namensraum.
- CLONE_PARENT_SETTID
(seit Linux 2.5.49)
- Die Kindprozess-Thread-Kennung an der Stelle im Elternspeicher ablegen,
auf die Eltern_tid (clone()) oder cl_args.parent_tid
(clone3()) zeigt. (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. In der Folge ignorierte der Kernel dieses Bit, falls es
in der Schalter-Maske angegeben wurde. Viel später wurde das
Bit für die Verwendung als Schalter CLONE_PIDFD
recyclet.
- CLONE_PIDFD
(seit Linux 5.2)
- Falls dieser Schalter angegeben ist, wird ein PID-Dateideskriptor, der
sich auf einen Kindprozess bezieht, reserviert und an dem angegebenen Ort
im Speicher des Elternprozesses abgelegt. Der Schalter
»close-on-exec« wird bei diesem neuen Dateideskriptor
gesetzt. PID-Dateideskriptoren können für die in
pidfd_open(2) beschriebenen Zwecke verwandt werden.
- Bei der Verwendung von clone3() wird der PID-Dateideskriptor an dem
durch cl_args.pidfd angezeigten Ort abgelegt.
- Bei der Verwendung von clone() wird der PID-Dateideskriptor an dem
Ort abgelegt, auf den Eltern_tid zeigt. Da das Argument
Eltern_tid zur Rückgabe des PID-Dateideskriptors verwandt
wird, kann CLONE_PIDFD beim Aufruf von clone() nicht mit
CLONE_PARENT_SETTID benutzt werden.
- Es ist derzeit nicht möglich, diesen Schalter zusammen mit
CLONE_THREAD zu verwenden. Das bedeutet, dass ein durch den
PID-Dateideskriptor identifizierter Prozess immer der Prozessgruppenleiter
sein wird.
- Falls der veraltete Schalter CLONE_DETACHED beim Aufruf von
clone() zusammen mit CLONE_PIDFD angegeben wird, wird ein
Fehler zurückgeliefert. Falls CLONE_DETACHED beim Aufruf von
clone3() angegeben wird, wird auch ein Fehler
zurückgeliefert. Dieses Fehlerverhalten stellt sicher, dass das
CLONE_DETACHED entsprechende Bit für weitere
PID-Dateideskriptorenfunktionalitäten in der Zukunft recyclet
werden kann.
- 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 tls gesetzt.
- Die Interpretation von tls und der resultierende Effekt ist
architekturabhängig. Auf X86 ist tls 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.
- Der Einsatz dieses Schalters verlangt detaillierte Kenntnisse und sollte
im Allgemeinen nicht erfolgen, außer in einigen Bibliotheken, die
Threading implementieren.
- 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 Clone-Aufrufs 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 muss die Schalter-Maske außerdem
CLONE_VM enthalten, falls CLONE_SIGHAND angegeben
wurde.
- CLONE_STOPPED
(seit Linux 2.6.0)
- 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)
- 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 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 aufrufen hat (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
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 die Schalter-Maske auch CLONE_SIGHAND
enthalten, wenn CLONE_THREAD angegeben wurde. Beachten Sie auch,
dass seit Linux 2.6.0 CLONE_SIGHAND auch CLONE_VM enthalten
muss.
- 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 Signalmaske, wie von sigprocmask(2)
gesetzt.
- Ein Signal kann Prozess-orientiert oder Thread-orientiert sein. Ein
Prozess-orientiertes Signal kann auf eine Thread-Gruppe (d.h. einer TGID)
abzielen und wird an einen beliebig ausgewählten Thread innerhalb
dieser, der das Signal nicht blockiert, ausgeliefert. Ein Signal kann
Prozess-orientiert sein, da es vom Kernel aus anderen Gründen
(neben Hardware-Ausnahmebehandlungen) erstellt wurde oder da mittels
kill(2) oder sigqueue(3) gesandt wurde. Ein
Thread-orientiertes Signal zielt auf ein bestimmten Thread (d.h. wird an
ihn ausgeliefert). Ein Signal kann Thread-orientiert sein, da es mittels
tgkill(2) oder pthread_sigqueue(3) gesandt wurde oder da der
Thread einen Maschinensprachenbefehl ausführte, der eine
Hardware-Ausnahmebehandlung auslöste (z.B. löst ein
ungültiger Speicherzugriff SIGSEGV oder eine
Fließkommaausnahmebehandlung SIGFPE aus).
- Ein Aufruf von sigpending(2) liefert eine Signalmenge
zurück, die die Vereinigung der anhängigen
Prozess-orientierten Signale und der Signale, die für den
aufrufenden Thread anhängig sind, ist.
- Falls ein Prozess-orientiertes Signal an eine Thread-Gruppe ausgeliefert
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 das 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 zum Zeitpunkt
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).
- Falls der Schalter CLONE_VM angegeben und der Schalter
CLONE_VM nicht angegeben ist, dann wird jeder alternative Stapel,
der durch sigaltstack(2) etabliert wurde, im Kindprozess
bereinigt.
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.
- EAGAIN
- Es laufen bereits zu viele Prozesse; siehe fork(2).
- EBUSY (nur
clone3())
- CLONE_INTO_CGROUP wurde in cl_args.flags angegeben, aber der
in cl_args.cgroup angegebene Dateideskriptor bezieht sich auf eine
Version-2-Cgroup, in der ein Domain-Controller aktiviert wurde.
- EEXIST (nur
clone3())
- Eine (oder mehrere) der in set_tid festgelegten PIDs existiert im
entsprechenden PID-Namensraum bereits.
- EINVAL
- In der Schalter-Maske wurden sowohl CLONE_SIGHAND als auch
CLONE_CLEAR_SIGHAND festgelegt.
- EINVAL
- CLONE_SIGHAND wurde in der Schalter-Maske festgelegt, aber
nicht CLONE_VM. (Seit Linux 2.6.0.)
- EINVAL
- CLONE_THREAD wurde in der Schalter-Maske festgelegt, aber
nicht CLONE_SIGHAND. (Seit Linux 2.5.35.)
- EINVAL
- CLONE_THREAD wurde in der Schalter-Maske festgelegt, aber
der aktuelle Prozess hatte vorher unshare(2) mit dem Schalter
CLONE_NEWPID aufgerufen oder setns(2) verwandt, um sich
wieder einem PID-Namensraum zuzuordnen.
- EINVAL
- In der Schalter-Maske wurden sowohl CLONE_FS als auch
CLONE_NEWNS festgelegt.
- EINVAL (seit
Linux 3.9)
- In der Schalter-Maske wurden sowohl CLONE_NEWUSER als auch
CLONE_FS festgelegt.
- EINVAL
- In der Schalter-Maske 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 der Schalter-Maske festgelegt.
- EINVAL (seit
Linux 2.6.32)
- CLONE_PARENT wurde angegeben und der Aufrufende ist ein
Init-Prozess.
- EINVAL
- Wird von der Glibc-Wrapper-Funktion clone() zurückgegeben,
wenn ein Wert von NULL für fn oder Stapel festgelegt
wurde.
- EINVAL
- CLONE_NEWIPC wurde in der Schalter-Maske festgelegt, aber
der Kernel ist nicht mit den Optionen CONFIG_SYSVIPC und
CONFIG_IPC_NS konfiguriert.
- EINVAL
- CLONE_NEWNET wurde in der Schalter-Maske festgelegt, aber
der Kernel ist nicht mit der Option CONFIG_NET_NS
konfiguriert.
- EINVAL
- CLONE_NEWPID wurde in der Schalter-Maske festgelegt, aber
der Kernel ist nicht mit der Option CONFIG_PID_NS
konfiguriert.
- EINVAL
- CLONE_NEWUSER wurde in der Schalter-Maske festgelegt, aber
der Kernel ist nicht mit der Option CONFIG_USER_NS
konfiguriert.
- EINVAL
- CLONE_NEWUTS wurde in der Schalter-Maske festgelegt, aber
der Kernel ist nicht mit der Option CONFIG_UTS_NS
konfiguriert.
- EINVAL
- Stapel ist nicht an einer geeigneten Grenze für diese
Architektur ausgerichtet. Beispielsweise muss Stapel auf Aarch64
ein Vielfaches von 16 sein.
- EINVAL (nur
clone3())
- In der Schalter-Maske wurden CLONE_DETACHED festgelegt.
- EINVAL (nur
clone())
- CLONE_PIDFD wurde zusammen mit CLONE_DETACHED in der
Schalter-Maske festgelegt.
- EINVAL
- CLONE_PIDFD wurde zusammen mit CLONE_THREAD in der
Schalter-Maske festgelegt.
- EINVAL (nur
clone())
- CLONE_PIDFD wurde zusammen mit CLONE_PARENT_SETTID in der
Schalter-Maske festgelegt.
- EINVAL (nur
clone3())
- set_tid_size ist größer als die Anzahl der
geschachtelten PID-Namensräume.
- EINVAL (nur
clone3())
- Eine der in set_tid festgelegten PIDs war ungültig.
- EINVAL (nur
AArch64, Linux 4.6 und älter)
- Stapel war nicht an einer 126-Bit-Grenze ausgerichtet.
- 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 der Schalter-Maske 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 der Schalter-Maske 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 der Schalter-Maske legte die Erstellung eines
neuen Benutzer-Namensraums fest, dadurch würde aber die in der
enstprechenden Datei in /proc/sys/user festgelegte Begrenzung
überschritten. Für weitere Details siehe
namespaces(7).
- EOPNOTSUPP
(nur clone3())
- CLONE_INTO_CGROUP wurde in cl_args.flags angegeben, aber der
in cl_args.cgroup angegebene Dateideskriptor bezieht sich auf eine
Version-2-Cgroup, die im Zustand Domain ungültig ist.
- 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 der Schalter-Maske 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 der Schalter-Maske 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).
- EPERM (nur
clone3())
- set_tid_size war größer als Null und dem Aufrufenden
fehlt in einem oder mehreren Benutzernamensräumen, dem die
entsprechenden PID-Namensräume gehören, die Capability
CAP_SYS_ADMIN.
- 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 der Schalter-Maske festgelegt und die
Begrenzung für die Anzahl von verschachtelten
Benutzernamensräumen würde überschritten. Siehe die
Diskussion des Fehlers ENOSPC oben.
Der Systemaufruf clone3() erschien erstmalig in Linux
5.3.
Diese Systemaufrufe sind Linux-spezifisch und sollten nicht in
portierbaren Programmen benutzt werden.
Diese Systemaufrufe werden benutzt, um Threads zu implementieren:
mehrere Steuerflüsse in einem Programm, die gleichzeitig in einem
gemeinsamen Speicherbereich ausgeführt werden.
Glibc stellt keinen Wrapper für clone3() bereit;
rufen Sie ihn mittels syscall(2) auf.
Beachten Sie, dass die Glibc-Wrapperfunktion clone() einige
Änderungen am Speicher, auf den Stapel 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.
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 Clone-Aufrufs 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).
Auf i386-Architekturen sollte clone() nicht durch vsyscall
aufgerufen werden, sondern direkt durch int $0x80.
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.
Im Gegensatz zum Glibc-Wrapper akzeptiert der rohe Systemaufruf
clone() NULL als Stapel-Argument (und clone3() erlaubt
entsprechend cl_args.stack NULL zu sein). 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 *Stapel,
int *Eltern_tid, int *Kind_tid,
unsigned long tls);
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 *Stapel,
int *Eltern_tid, unsigned long tls,
int *Kind_tid);
Auf der Cris- und S30-Architektur ist die Reihenfolge der ersten
zwei Argumente gedreht:
long clone(void *Stapel, unsigned long Schalter,
int *Eltern_tid, int *Kind_tid,
unsigned long tls);
Auf der Microblaze-Architektur wird ein zusätzliches
Argument übergeben:
long clone(unsigned long Schalter, void *Stapel,
int Stapelgröße, /* Größe des Stapels */
int *Eltern_tid, int *Kind_tid,
unsigned long tls);
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.
Auf ia64 wird eine andere Schnittstelle benutzt:
int __clone2(int (*fn)(void *),
void *Stapelbasis, size_t Stapelgröße,
int Schalter, void *arg, …
/* pid_t *Eltern_tid, struct user_desc *tls,
pid_t *Kind_tid */ );
Der oben gezeigte Prototyp ist für die
Glibc-Wrapper-Funktion; für den Systemaufruf selbst wird der Prototyp
wie folgt beschrieben (er ist identisch zum clone()-Prototyp auf
Microblaze):
long clone2(unsigned long Schalter, void *Stapelbasis,
int Stapelgröße, /* Größe des Stapels */
int *Eltern_tid, int *Kind_tid,
unsigned long tls);
__clone2() arbeitet auf die gleiche Weise wie
clone(), außer dass Stapelbasis auf die niedrigste
Adresse im Stapelspeicherbereich des Kindprozesses zeigt und
stack_size die Größe des Stapelspeichers angibt, auf
die Stapelbasis zeigt.
Unter Linux 2.4 und früher gab es die Argumente
Eltern_tid, tls und Kind_tid noch nicht.
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.
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).
Innerhalb des Beispielprogramms reservieren wir Speicher, der
für den Stapel des Kindprogramms verwandt werden soll. Dabei
verwenden wir aus den folgenden Gründen mmap(2) statt
malloc(3):
- mmap(2) reserviert einen Speicherblock, der an einer Seitengrenze
beginnt und ein Vielfaches der Seitengröße groß ist.
Dies ist nützlich, um am Ende des Stapels mittels
mprotect(2) eine Wächterseite (eine Seite mit dem Schutz
PROT_NONE) einzurichten.
- Wir können den Schalter MAP_STACK angeben, um ein für
den Stapel geeignetes Mapping festzulegen. Derzeit führt dieser
Schalter unter Linux zu keiner Aktion, aber er existiert und hat auf
anderen Systemen Auswirkungen, daher sollten wir ihn zwecks
Portabilität aufnehmen.
#define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sched.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.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);
}
/* Speicher für den Stapel des Kindprozess reservieren */
stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED)
errExit("mmap");
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 %jd zurück\n", (intmax_t) 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);
}
fork(2), futex(2), getpid(2),
gettid(2), kcmp(2), mmap(2), pidfd_open(2),
set_thread_area(2), set_tid_address(2), setns(2),
tkill(2), unshare(2), wait(2), capabilities(7),
namespaces(7), pthreads(7)
Diese Seite ist Teil der Veröffentlichung 5.10 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.