clone
Section: System Calls (2)
Updated: 5 février 2023
Index
Return to Main Contents
NOM
clone, __clone2, clone3 - Créer un processus enfant (child)
BIBLIOTHÈQUE
Bibliothèque C standard (libc, -lc)
SYNOPSIS
/* Prototype de la fonction enveloppe de la glibc */
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *_Nullable), void *stack, int flags,
void *_Nullable arg, ... /* pid_t *_Nullable parent_tid,
void *_Nullable tls,
pid_t *_Nullable child_tid */ );
/* Pour le prototype de l'appel système clone() brut, voir REMARQUES */
#include <linux/sched.h> /* Définition de struct clone_args */
#include <sched.h> /* Définition des constantes CLONE_* */
#include <sys/syscall.h> /* Définition des constantes SYS_* */
#include <unistd.h>
long syscall(SYS_clone3, struct clone_args *cl_args, size_t size);
Remarque : La glibc ne fournit pas d'enveloppe pour clone3() ;
appelez-la en utilisant syscall(2).
DESCRIPTION
Ces appels système créent un nouveau processus « enfant », de façon analogue
à fork(2).
Contrairement à fork(2), ces appels système offrent un contrôle plus
précis du contexte d'exécution partagé entre le processus appelant et son
enfant. Par exemple, en utilisant ces appels système, l'appelant peut
contrôler si les deux processus partagent ou non l'espace d'adresse virtuel,
la table des descripteurs de fichier et celle des gestionnaires de
signal. Ces appels système permettent également au nouveau processus enfant
d'aller dans un namespaces(7) à part.
Remarquez que dans cette page de manuel, le « processus appelant »
correspond en principe au « processus parent ». Mais voir les descriptions
de CLONE_PARENT et de CLONE_THREAD ci-dessous.
Cette page décrit les interfaces suivantes :
- •
-
Cette page présente à la fois la fonction enveloppe clone() de la glibc
et l'appel système sous-jacent sur lequel elle s'appuie. Le texte principal
décrit la fonction enveloppe ; les différences avec l'appel système brut
sont précisées vers la fin de cette page.
- •
-
Le nouvel appel système clone3().
Dans la suite de cette page, le terme « appel clone » est utilisé pour
évoquer les détails applicables à toutes ces interfaces,
La fonction enveloppe clone()
Quand le processus enfant est créé par la fonction enveloppe clone(), il
débute son exécution par un appel à la fonction vers laquelle pointe
l'argument fn (cela est différent de fork(2), pour lequel l'exécution
continue dans le processus enfant à partir du moment de l'appel de
fork(2)). L'argument arg est passé comme argument de la fonction
fn.
Quand la fonction fn(arg) renvoie, le processus enfant se termine. La
valeur entière renvoyée par fn est utilisée comme code de retour du
processus enfant. Ce dernier peut également se terminer de manière explicite
en invoquant la fonction exit(2) ou après la réception d'un signal fatal.
L'argument stack indique l'emplacement de la pile utilisée par le
processus enfant. Comme les processus enfant et appelant peuvent partager de
la mémoire, il n'est généralement pas possible pour l'enfant d'utiliser la
même pile que son parent. Le processus appelant doit donc préparer un espace
mémoire pour stocker la pile de son enfant, et transmettre à clone un
pointeur sur cet emplacement. Les piles croissent vers le bas sur tous les
processeurs implémentant Linux (sauf le HP PA), donc stack doit pointer
sur la plus haute adresse de l'espace mémoire prévu pour la pile du
processus enfant. Remarquez que clone() ne fournit aucun moyen pour que
l'appelant puisse informer le noyau de la taille de la zone de la pile.
Les paramètres restants de clone() sont décrits ci-dessous.
clone3()
L'appel système clone3() fournit un sur-ensemble de la fonctionnalité de
l'ancienne interface de clone(). Il offre également un certain nombre
d'améliorations de l'API dont : un espace pour des bits d'attributs
supplémentaires, une séparation plus propre dans l'utilisation de plusieurs
paramètres et la possibilité d'indiquer la taille de la zone de la pile de
l'enfant.
Comme avec fork(2), clone3() renvoie à la fois au parent et à
l'enfant. Il renvoie 0 dans le processus enfant et il renvoie le PID de
l'enfant dans le parent.
Le paramètre cl_args de clone3() est une structure ayant la forme
suivante :
struct clone_args {
u64 flags; /* Masque de bit d'attribut */
u64 pidfd; /* Où stocker le descripteur de fichier du PID
(int *) */
u64 child_tid; /* Où stocker le TID enfant,
dans la mémoire de l'enfant (pid_t *) */
u64 parent_tid; /* Où stocker le TID enfant,
dans la mémoire du parent (pid_t *) */
u64 exit_signal; /* Signal à envoyer au parent quand
l'enfant se termine */
u64 stack; /* Pointeur vers l'octet le plus faible de la pile */
u64 stack_size; /* Taille de la pile */
u64 tls; /* Emplacement du nouveau TLS */
u64 set_tid; /* Pointeur vers un tableau pid_t
(depuis Linux 5.5) */
u64 set_tid_size; /* Nombre d'éléments dans set_tid
(depuis Linux 5.5) */
u64 cgroup; /* Descripteur de fichier du cgroup cible
de l'enfant (depuis Linux 5.7) */
};
Le paramètre size fourni à clone3() doit être initialisé à la taille
de cette structure (l'existence du paramètre size autorise des extensions
futures de la structure clone_args).
La pile du processus enfant est indiquée avec cl_args.stack, qui pointe
vers l'octet le plus faible de la zone de la pile, et avec
cl_args.stack_size, qui indique la taille de la pile en octets. Si
l'attribut CLONE_VM est indiqué (voir ci-dessous), une pile doit être
explicitement allouée et indiquée. Sinon, ces deux champs peuvent valoir
NULL et 0, ce qui amène l'enfant à utiliser la même zone de pile que son
parent (dans l'espace d'adressage virtuel de son propre enfant).
Les autres champs du paramètre cl_args sont abordés ci-dessous.
Équivalence entre les paramètres de clone() et de clone3()
Contrairement à l'ancienne interface clone(), où les paramètres sont
passés individuellement, ceux de la nouvelle interface clone3() sont
empaquetés dans la structure clone_args présentée ci-dessus. Cette
structure permet de passer un ensemble d'informations à l’aide des arguments
de clone().
Le tableau suivant montre l'équivalence entre les paramètres de clone()
et les champs du paramètre clone_args fournis à clone3() :
-
clone() | clone3() | Notes
|
| Champ cl_args |
|
attributs & ~0xff | attributs |
Pour la plupart des attributs, détails ci-dessous
|
parent_tid | pidfd | Voir CLONE_PIDFD
|
child_tid | child_tid | Voir CLONE_CHILD_SETTID
|
parent_tid | parent_tid | Voir CLONE_PARENT_SETTID
|
attributs & 0xff | exit_signal |
|
stack | stack |
|
--- | stack_size |
|
tls | tls | Voir CLONE_SETTLS
|
--- | set_tid | Voir ci-dessous pour des détails
|
--- | set_tid_size |
|
--- | cgroup | Voir CLONE_INTO_CGROUP
|
Signal de fin de l'enfant
Quand le processus enfant se termine, un signal peut être envoyé au
parent. Le signal de fin est indiqué dans l'octet de poids faible de
flags (clone()) ou dans cl_args.exit_signal (clone3()). Si ce
signal est différent de SIGCHLD, le processus parent doit également
spécifier les options __WALL ou __WCLONE lorsqu'il attend la fin de
l'enfant avec wait(2). Si aucun signal n'est indiqué (donc zéro), le
processus parent ne sera pas notifié de la terminaison de l'enfant.
Le tableau set_tid
Par défaut, le noyau choisit le PID séquentiel suivant pour le nouveau
processus dans chacun des espaces de noms de PID où il est présent. Lors de
la création d'un processus avec clone3(), le tableau set_tid (depuis
Linux 5.5) peut être utilisé pour sélectionner des PID spécifiques pour le
processus dans tout ou partie des espaces de noms où il est présent. Si le
PID du processus nouvellement créé ne doit être positionné que dans l'espace
de noms du processus actuel ou dans celui du PID nouvellement créé (si
flags contient CLONE_NEWPID), le premier élément du tableau set_tid
doit être le PID souhaité et set_tid_size doit valoir 1.
Si le PID du processus nouvellement créé doit avoir une certaine valeur dans
plusieurs espaces de noms de PID, le tableau set_tid peut avoir plusieurs
entrées. La première entrée définit le PID de l'espace de noms le plus
imbriqué, puis chacune des entrées suivantes contient le PID de l'espace de
noms supérieur correspondant. Le nombre d'espaces de noms de PID où un PID
doit être positionné est défini par set_tid_size, qui ne peut pas être
plus grand que le nombre d'espaces de noms de PID imbriqués.
Pour créer un processus dont les PID suivants s'inscrivent dans la
hiérarchie de l'espace de noms de PID :
-
Niveau esp. noms du PID | PID demandé | Notes
|
0 | 31496 | Espace de noms du PID le plus à l'extérieur
|
1 | 42 |
|
2 | 7 | Espace de noms du PID le plus à l'intérieur
|
Positionner le tableau sur :
set_tid[0] = 7;
set_tid[1] = 42;
set_tid[2] = 31496;
set_tid_size = 3;
Si seuls les PID des deux espaces de noms de PID les plus à l’intérieur
doivent être indiqués, positionnez le tableau sur :
set_tid[0] = 7;
set_tid[1] = 42;
set_tid_size = 2;
Le PID dans les espaces de noms de PID en dehors des deux espaces de noms
les plus à l’intérieur sera sélectionné de la même manière qu'on sélectionne
n'importe quel autre PID.
La fonctionnalité set_tid exige CAP_SYS_ADMIN ou (depuis Linux 5.9)
CAP_CHECKPOINT_RESTORE dans tous les espaces de noms appartenant à
l'utilisateur des espaces de noms du processus cible.
Les appelants ne peuvent choisir qu'un PID supérieur à 1 dans un espace
de noms de PID donné si un processus init (à savoir un processus dont le
PID est 1) existe déjà dans cet espace de noms. Sinon, l'entrée du PID
dans cet espace de noms de PID doit valoir 1.
Le masque flags
Tant clone() que clone3() permettent d'utiliser un masque de bit flags
pour modifier leur comportement, et elles permettent à l'appelant d'indiquer
ce qui est partagé entre le processus appelant et son enfant. Ce masque de
bit – le paramètre flags de clone() ou le champ cl_args.flags passé
à clone3() – est désigné comme le masque flags dans le reste de cette
page.
Le masque flags est indiqué comme un OU bit à bit de zéro ou plus des
constantes ci-dessous. Sauf explicitement indiqués, ces attributs sont
disponibles (et ont le même effet) dans clone() et dans clone3().
- CLONE_CHILD_CLEARTID (depuis Linux 2.5.49)
-
Effacer (zéro) l'ID du thread enfant situé là où pointe child_tid
(clone()) ou cl_args.child_tid (clone3()) dans la mémoire de
l'enfant lorsqu'il se termine, et provoquer le réveil avec le futex à cette
adresse. L'adresse concernée peut être modifiée par l'appel système
set_tid_address(2). Cela est utilisé dans les bibliothèques de gestion de
threads.
- CLONE_CHILD_SETTID (depuis Linux 2.5.49)
-
Enregistrer l'ID du thread de l'enfant là où pointe child_tid
((clone()) ou cl_args.child_tid (clone3()) dans la mémoire de
l'enfant. L'opération d'enregistrement se termine avant que l'appel clone ne
redonne le contrôle à l'espace utilisateur dans le processus enfant
(remarquez que l'opération d'enregistrement peut ne pas être terminée avant
que l'appel clone ne renvoie au processus parent, ce qui sera pertinent si
l'attribut CLONE_VM est également utilisé).
- CLONE_CLEAR_SIGHAND (depuis Linux 5.5)
-
Par défaut, l'état des signaux du thread de l'enfant est le même que celui
du parent. Si cet attribut est positionné, tous les signaux gérés par le
parent sont réinitialisés à leur état par défaut (SIG_DFL) dans l'enfant.
-
Indiquer cet attribut avec CLONE_SIGHAND n'a pas de sens et n'est pas
autorisé.
- CLONE_DETACHED (historique)
-
Pendant un moment (pendant la série de versions au cours du développement de
Linux 2.5), il y a eu un attribut CLONE_DETACHED, avec lequel le parent
ne recevait pas de signal quand l'enfant se terminait. Au final, l'effet de
cet attribut a été inhibé par l'attribut CLONE_THREAD et quand Linux
2.6.0 a été publié, cet attribut n'avait pas d'effet. À partir de Linux
2.6.2, il n'a plus été nécessaire de fournir cet attribut avec
CLONE_THREAD.
-
Cet attribut est toujours défini, mais il est généralement ignoré lors d'un
appel clone(). Toutefois, voir la description de CLONE_PIDFD pour
certaines exceptions.
- CLONE_FILES (depuis Linux 2.0)
-
Si l'attribut CLONE_FILES est positionné, le processus appelant et le
processus enfant partagent la même table de descripteurs de fichier. Tout
descripteur créé par un processus est également valable pour l'autre
processus. De même si un processus ferme un descripteur, ou modifie ses
attributs (en utilisant l'opération fcntl(2) F_SETFD), l'autre
processus en est aussi affecté. Si un processus qui partage une table de
descripteurs de fichier appelle execve(2), sa table est dupliquée (non
partagée).
-
Si CLONE_FILES n'est pas positionné, le processus enfant hérite d'une
copie des descripteurs de fichier ouverts par l'appelant au moment de
l'appel clone(). Les opérations d'ouverture et de fermeture ou de
modification d'attributs du descripteur de fichier subséquentes, effectuées
par le processus appelant ou son enfant, ne concernent pas l'autre
processus. Remarquez toutefois que les copies des descripteurs de fichier
dans l'enfant sont associées aux mêmes descriptions de fichiers ouverts que
les descripteurs de fichier correspondants dans le processus appelant,
partageant ainsi les attributs de position et d’états du fichier (consultez
open(2)).
- CLONE_FS (depuis Linux 2.0)
-
Si l'attribut CLONE_FS est positionné, le processus appelant et le
processus enfant partagent les mêmes informations concernant le système de
fichiers. Cela inclut la racine du système de fichiers, le répertoire de
travail, et l'umask. Tout appel à chroot(2), chdir(2) ou umask(2)
effectué par un processus aura également une influence sur l'autre
processus.
-
Si CLONE_FS n'est pas positionné, le processus enfant travaille sur une
copie des informations de l'appelant concernant le système de fichiers au
moment de l'appel clone. Les appels à chroot(2), chdir(2), umask(2)
effectués ensuite par un processus n'affectent pas l'autre processus.
- CLONE_INTO_CGROUP (depuis Linux 5.7)
-
Par défaut, un processus enfant est mis dans le même cgroup version 2 que
son parent. L'attribut CLONE_INTO_CGROUP permet au processus enfant
d'être créé dans un cgroup version 2 différent (remarquez que
CLONE_INTO_CGROUP n'a d'effet que sur les cgroup version 2).
-
Pour mettre le processus enfant dans un cgroup différent, l'appelant indique
CLONE_INTO_CGROUP dans cl_args.flags et passe un descripteur de
fichier qui se rapporte à un cgroup version 2 du champ cl_args.cgroup (le
descripteur de fichier peut être obtenu en ouvrant un répertoire cgroup v2,
en utilisant l'attribut O_RDONLY ou O_PATH). Remarquez que toutes les
restrictions habituelles (décrites dans cgroups(7)) quant au
positionnement d'un processus dans un cgroup version 2 s'appliquent.
-
Voici certains des cas d'utilisation possibles de CLONE_INTO_CGROUP :
-
- •
-
Créer un processus dans un autre cgroup que celui du parent permet au
gestionnaire de service de placer directement de nouveaux services dans des
cgroup dédiés. Cela élimine les contraintes comptables qui existeraient si
le processus enfant était créé d'abord dans le même cgroup que le parent
puis déplacé dans un cgroup cible. De plus, la création d'un processus
enfant directement dans un cgroup cible coûte beaucoup moins cher que de
déplacer le processus enfant dans le cgroup cible après l'avoir créé.
- •
-
L'attribut CLONE_INTO_CGROUP permet également la création de processus
enfants gelés en les créant dans un cgroup gelé (voir cgroups(7) pour une
description des contrôleurs de gel).
- •
-
Pour les applications threadées (voire même les implémentations de thread
qui utilisent des cgroup pour limiter les threads individuels), il est
possible d'établir une couche de cgroup fixe avant de créer chaque thread
directement dans son cgroup cible.
- CLONE_IO (depuis Linux 2.6.25)
-
Si CLONE_IO est défini, alors le nouveau processus partage un contexte
d'entrées-sorties avec le processus appelant. Si cet attribut n'est pas
défini, alors (comme pour fork(2)) le nouveau processus a son propre
contexte d'entrées-sorties.
-
Le contexte d'entrées-sorties correspond à la visibilité que l'ordonnanceur
de disques a des entrées-sorties (c'est-à-dire, ce que l'ordonnanceur
d'entrées-sorties utilise pour modéliser l'ordonnancement des
entrées-sorties d'un processus). Si des processus partagent le même contexte
d'entrées-sorties, ils sont traités comme un seul par l'ordonnanceur
d'entrées-sorties. Par conséquent, ils partagent le même temps d'accès aux
disques. Pour certains ordonnanceurs d'entrées-sorties, si deux processus
partagent un contexte d'entrées-sorties, ils seront autorisés à intercaler
leurs accès disque. Si plusieurs threads utilisent des entrées-sorties pour
le même processus (aio_read(3), par exemple), ils devraient utiliser
CLONE_IO pour obtenir de meilleures performances d'entrées-sorties.
-
Si le noyau n'a pas été configuré avec l'option CONFIG_BLOCK, cet
attribut n'a aucun effet.
- CLONE_NEWCGROUP (depuis Linux 4.6)
-
Créer le processus dans un nouvel espace de noms cgroup. Si cet attribut
n'est pas invoqué, alors (comme pour fork(2)) le processus est créé dans
le même espace de noms cgroup que le processus appelant.
-
Pour plus d'informations sur les espaces de noms cgroup, consultez
cgroup_namespaces(7).
-
Seul un processus disposant de privilèges (CAP_SYS_ADMIN) peut utiliser
CLONE_NEWCGROUP.
- CLONE_NEWIPC (depuis Linux 2.6.19)
-
Si CLONE_NEWIPC est invoqué, alors le processus est créé dans un nouvel
espace de noms utilisateur IPC. Si cet attribut n'est pas invoqué, alors
(comme pour fork(2)) le processus est créé dans le même espace de noms
utilisateur IPC que le processus appelant.
-
Pour plus d'informations sur les espaces de noms IPC, reportez vous à
ipc_namespaces(7).
-
Seul un processus disposant de privilèges (CAP_SYS_ADMIN) peut utiliser
CLONE_NEWIPC. Cet attribut ne peut pas être employé en association avec
CLONE_SYSVSEM.
- CLONE_NEWNET (depuis Linux 2.6.24)
-
(L'implémentation de cet attribut n'est complète que depuis Linux 2.6.29.)
-
Si CLONE_NEWNET est invoqué, alors le processus est créé dans un nouvel
espace de noms réseau. Si cet attribut n'est pas invoqué, alors (comme pour
fork(2)) le processus est créé dans le même espace de noms réseau que le
processus appelant.
-
Pour plus d'informations sur les espaces de noms réseau, reportez vous à
network_namespaces(7).
-
Seul un processus disposant de privilèges (CAP_SYS_ADMIN) peut appeler
CLONE_NEWNET.
- CLONE_NEWNS (depuis Linux 2.4.19)
-
Si l'attribut CLONE_NEWNS est invoqué, l'enfant cloné démarre dans un
nouvel espace de noms de montage, initialisé avec une copie de l'espace de
noms du parent. Si CLONE_NEWNS n'est pas invoqué, alors l'enfant existe
dans le même espace de noms de montage que le parent.
-
Pour plus d'informations sur les espaces de noms de montage, consultez
namespaces(7) et mount_namespaces(7).
-
Seul un processus disposant de privilèges (CAP_SYS_ADMIN) peut utiliser
l'attribut CLONE_NEWNS. Il n'est pas possible de spécifier à la fois
CLONE_NEWNS et CLONE_FS pour le même appel clone.
- CLONE_NEWPID (depuis Linux 2.6.24)
-
Si CLONE_NEWPID est invoqué, alors le processus est créé dans un nouvel
espace de noms PID. Si cet attribut n'est pas invoqué, alors (comme pour
fork(2)) le processus est créé dans le même espace de noms PID que le
processus appelant.
-
Pour plus d'informations sur les espaces de noms PID, consultez
namespaces(7) et pid_namespaces(7).
-
Seul un processus disposant de privilèges (CAP_SYS_ADMIN) peut utiliser
CLONE_NEWPID. Cet attribut ne peut pas être utilisé en association avec
CLONE_THREAD ou avec CLONE_PARENT.
- CLONE_NEWUSER
-
(Cet attribut est apparu dans clone() pour la première fois dans
Linux 2.6.23, les sémantiques actuelles de clone() ont été ajoutées dans
Linux 3.5, et les derniers modules rendant les espaces de noms utilisateur
complètement opérationnels sont apparus dans Linux 3.8.)
-
Si CLONE_NEWUSER est invoqué, alors le processus est créé dans un nouvel
espace de noms utilisateur. Si cet attribut n'est pas invoqué, alors (comme
pour fork(2)) le processus est créé dans le même espace de noms
utilisateur que le processus appelant.
-
Pour plus d'informations sur les espaces de noms utilisateur, consultez
namespaces(7) et user_namespaces(7).
-
Avant Linux 3.8, les processus appelant devaient disposer de trois capacités
pour utiliser CLONE_NEWUSER : CAP_SYS_ADMIN, CAP_SETUID et
CAP_SETGID. À partir de Linux 3.8, il n'est plus nécessaire de disposer
de privilèges pour créer des espaces de noms utilisateur.
-
Cet attribut ne peut pas être utilisé en association avec CLONE_THREAD ou
avec CLONE_PARENT. Pour des raisons de sécurité, CLONE_NEWUSER ne peut
pas être utilisé en association avec CLONE_FS.
- CLONE_NEWUTS (depuis Linux 2.6.19)
-
Si CLONE_NEWUTS est défini, créez le processus dans un nouvel espace de
noms UTS, dont les identifiants sont initialisés en dupliquant les
identifiants de l'espace de noms UTS du processus appelant. Si cet attribut
n'est pas défini, alors (comme pour fork(2)) le processus est créé dans
le même espace de noms UTS que le processus appelant.
-
Pour obtenir plus d'informations sur les espaces de noms UTS, consultez
namespaces(7).
-
Seul un processus disposant de privilèges (CAP_SYS_ADMIN) peut utiliser
CLONE_NEWUTS.
- CLONE_PARENT (depuis Linux 2.3.12)
-
Si CLONE_PARENT est présent, le parent du nouvel enfant (comme il est
indiqué par getppid(2)) sera le même que celui du processus appelant.
-
Si CLONE_PARENT n'est pas fourni, alors (comme pour fork(2)) le parent
du processus enfant sera le processus appelant.
-
Remarquez que c'est le processus parent, tel qu'indiqué par getppid(2),
qui est notifié lors de la fin de l'enfant. Ainsi, si CLONE_PARENT est
présent, alors c'est le parent du processus appelant, et non ce dernier, qui
sera notifié.
-
L'attribut CLONE_PARENT ne peut pas être utilisé dans des appels clone
par le processus d'initialisation global (PID 1 dans l'espace de noms PID
initial) et par les processus initiaux dans les autres espaces de noms
PID. Cette restriction empêche la création d'arbres de processus à plusieurs
racines ou de zombies non récupérables dans l'espace de noms PID initial.
- CLONE_PARENT_SETTID (depuis Linux 2.5.49)
-
Enregistrer l'ID du thread enfant à l'endroit vers lequel pointe
parent_tid (clone()) ou cl_args.parent_tid (clone3()) dans la
mémoire du parent (dans Linux 2.5.32-2.5.48 il y a un attribut
CLONE_SETTID qui fait cela). L'opération d'enregistrement s'achève avant
que l'opération clone ne donne le contrôle à l'espace utilisateur.
- CLONE_PID (de Linux 2.0 à Linux 2.5.15)
-
Si l'attribut CLONE_PID est positionné, les processus appelant et enfant
ont le même numéro de processus. C'est bien pour bidouiller le système, mais
autrement il n'est plus utilisé. Depuis Linux 2.3.21, cet attribut ne peut
être utilisé que par le processus de démarrage du système (PID 0). Il a
disparu dans Linux 2.5.16. Si bien que le noyau ignorait silencieusement le
bit s'il était indiqué dans le masque flags. Bien plus tard, le même bit
a été recyclé pour être utilisé comme attribut de CLONE_PIDFD.
- CLONE_PIDFD (depuis Linux 5.2)
-
Si cet attribut est indiqué, un descripteur de fichier PID renvoyant au
processus enfant est alloué et placé à un endroit donné dans la mémoire du
parent. L'attribut close-on-exec est positionné sur ce nouveau descripteur
de fichier. Les descripteurs de fichier PID peuvent être utilisés pour des
objectifs décrits dans pidfd_open(2).
-
- •
-
Quand on utilise clone3(), le descripteur de fichier PID est placé à un
endroit vers lequel pointe cl_args.pidfd.
- •
-
Quand on utilise clone(), le descripteur de fichier PID est placé à un
endroit vers lequel pointe parent_tid. Comme le paramètre parent_tid
est utilisé pour renvoyer le descripteur de fichier PID, CLONE_PIDFD ne
peut pas être utilisé avec CLONE_PARENT_SETTID lors d'un appel
clone().
-
Il n'est pas possible actuellement d'utiliser cet attribut avec
CLONE_THREAD. Cela veut dire que le processus identifié par le
descripteur de fichier PID sera toujours un leader dans le groupe de
threads.
-
Si l'attribut obsolète CLONE_DETACHED est indiqué avec CLONE_PIDFD
lors d'un appel à clone(), une erreur est renvoyée. Une erreur se produit
aussi si CLONE_DETACHED est spécifié lors d'un appel à clone3(). Ce
comportement garantit que le bit qui correspond à CLONE_DETACHED pourra
être utilisé à l'avenir pour des fonctionnalités supplémentaires du
descripteur de fichier PID.
- CLONE_PTRACE (depuis Linux 2.2)
-
Si l'attribut CLONE_PTRACE est positionné et si l'appelant est suivi par
un débogueur, alors l'enfant sera également suivi (consultez ptrace(2)).
- CLONE_SETTLS (depuis Linux 2.5.32)
-
Le descripteur TLS (Thread Local Storage) est positionné sur tls.
-
L'interprétation de tls et les effets qui en découlent dépendent de
l'architecture. Sur x86, tls est interprété comme une struct user_desc~* (voir set_thread_area(2)). Sur x86-64, il s'agit de la
nouvelle valeur à positionner pour le registre de base %fs (voir le
paramètre ARCH_SET_FS de arch_prctl(2)). Sur les architectures ayant
un registre TLS dédié, il s'agit de la nouvelle valeur de ce registre.
-
L'utilisation de cet attribut exige une connaissance détaillée et n'est
généralement pas souhaitable, sauf dans l'implémentation de bibliothèques de
gestion des threads.
- CLONE_SIGHAND (depuis Linux 2.0)
-
Si l'attribut CLONE_SIGHAND est positionné, le processus appelant et le
processus enfant partagent la même table de gestionnaires de signaux. Si
l'appelant, ou l'enfant, appelle sigaction(2) pour modifier le
comportement associé à un signal, ce comportement est également changé pour
l'autre processus. Néanmoins, l'appelant et l'enfant ont toujours des
masques de signaux distincts, et leurs ensembles de signaux bloqués sont
indépendants. L'un des processus peut donc bloquer ou débloquer un signal en
utilisant sigprocmask(2) sans affecter l'autre processus.
-
Si CLONE_SIGHAND n'est pas utilisé, le processus enfant hérite d'une
copie des gestionnaires de signaux de l'appelant lors de l'invocation de
clone(). Les appels à sigaction(2) effectués ensuite depuis l'un des
processus n'ont pas d'effets sur l'autre processus.
-
Depuis Linux 2.6.0, le masque flags doit aussi inclure CLONE_VM si
CLONE_SIGHAND est spécifié
- CLONE_STOPPED (depuis Linux 2.6.0)
-
Si l'attribut CLONE_STOPPED est positionné, l'enfant est initialement
stoppé (comme s'il avait reçu le signal SIGSTOP), et doit être relancé en
lui envoyant le signal SIGCONT.
-
Cet attribut a été rendu obsolète par Linux 2.6.25, puis il a été
supprimé dans Linux 2.6.38. Depuis lors, le noyau l'ignore
silencieusement sans erreur. À partir de Linux 4.6, le même bit a été
réutilisé comme attribut de CLONE_NEWCGROUP.
- CLONE_SYSVSEM (depuis Linux 2.5.10)
-
Si CLONE_SYSVSEM est positionné, l'enfant et le processus appelant
partagent une même liste de valeurs d’ajustement de sémaphores System V
(consultez semop(2)). Dans ce cas, cette liste regroupe toutes les
valeurs semadj des processus partageant cette liste, et les modifications
des sémaphores sont effectuées seulement lorsque le dernier processus de la
liste se termine (ou cesse de partager la liste en invoquant
unshare(2)). Si cet attribut n'est pas utilisé, l'enfant a une liste
semadj séparée, initialement vide.
- CLONE_THREAD (depuis Linux 2.4.0)
-
Si CLONE_THREAD est présent, l'enfant est placé dans le même groupe de
threads que le processus appelant. Afin de rendre l'explication de
CLONE_THREAD plus lisible, le terme « thread » est utilisé pour parler
des processus dans un même groupe de threads.
-
Les groupes de threads sont une fonctionnalité ajoutée dans Linux 2.4 pour
gérer la notion POSIX d'ensemble de threads partageant un même PID. En
interne, ce PID partagé est appelé identifiant de groupe de threads
(TGID). Depuis Linux 2.4, l'appel getpid(2) renvoie l'identifiant du
groupe de threads de l'appelant.
-
Les threads dans un groupe peuvent être distingués par leur identifiant de
thread (TID, unique sur le système). Le TID d'un nouveau thread est
disponible sous la forme du résultat d'une fonction renvoyé à l'appelant et
un thread peut obtenir son propre TID en utilisant gettid(2).
-
Quand clone est appelé sans positionner CLONE_THREAD, le nouveau thread
est placé dans un nouveau groupe de threads dont le TGID est identique au
TID du nouveau thread. Ce thread est le leader du nouveau groupe.
-
Un nouveau thread créé en utilisant CLONE_THREAD a le même processus
parent que le processus réalisant l'appel clone (de même qu'avec
CLONE_PARENT), ainsi les appels à getppid(2) renvoient la même valeur
à tous les threads dans un même groupe. Lorsqu'un thread créé avec
CLONE_THREAD termine, le thread qui l’a créé ne reçoit pas le signal
SIGCHLD (ou autre notification de terminaison) ; de même, l'état d'un
tel thread ne peut pas être obtenu par wait(2). Le thread est dit
détaché.
-
Lorsque tous les threads d'un groupe de threads terminent, le processus
parent du groupe reçoit un signal SIGCHLD (ou un autre indicateur de
terminaison).
-
Si l'un des threads dans un groupe de threads appelle execve(2), tous les
threads sauf le leader sont tués, et le nouveau programme est exécuté dans
le leader du groupe de threads.
-
Si l'un des threads dans un groupe crée un enfant avec fork(2), n'importe
lequel des threads du groupe peut utiliser wait(2) sur cet enfant.
-
Depuis Linux 2.5.35, le masque flags doit aussi inclure CLONE_SIGHAND
si CLONE_THREAD est spécifié (et remarquez que depuis Linux 2.6.0,
CLONE_SIGHAND a également besoin de CLONE_VM).
-
Les gestions de signaux sont définies au niveau des processus : si un
signal sans gestionnaire est reçu par un thread, il affectera (tuera,
stoppera, relancera, ou sera ignoré par) tous les membres du groupe de
threads.
-
Chaque thread a son propre masque de signal, tel que défini par
sigprocmask(2).
-
Un signal peut être adressé à un processus ou à un thread. S'il s'adresse à
un processus, il cible un groupe de threads (c'est-à-dire un TGID), et il
est envoyé à un thread choisi arbitrairement parmi ceux ne bloquant pas les
signaux. Un signal peut s'adresser à un processus car il est généré par le
noyau pour d'autres raisons qu'une exception matérielle, ou parce qu'il a
été envoyé en utilisant kill(2) ou sigqueue(3). Si un signal s'adresse
à un thread, il cible (donc est envoyé) à un thread spécifique. Un signal
peut s'adresser à un thread du fait d'un envoi par tgkill(2) ou
pthread_sigqueue(3), ou parce que le thread a exécuté une instruction en
langage machine qui a provoqué une exception matérielle (comme un accès non
valable en mémoire, provoquant SIGSEGV, ou une exception de virgule
flottante provoquant un SIGFPE).
-
Un appel à sigpending(2) renvoie un jeu de signaux qui réunit les signaux
en attente adressés au processus et ceux en attente pour le thread appelant.
-
Si un signal adressé à un processus est envoyé à un groupe de threads, et si
le groupe a installé un gestionnaire pour ce signal, alors le gestionnaire
sera exécuté exactement dans un des membres du groupe de threads, choisi de
façon arbitraire parmi ceux qui n'ont pas bloqué ce signal. Si plusieurs
threads dans un groupe attendent le même signal en utilisant
sigwaitinfo(2), le noyau choisira arbitrairement l'un d'entre eux pour
recevoir le signal.
- CLONE_UNTRACED (depuis Linux 2.5.46)
-
Si l'attribut CLONE_UNTRACED est positionné, alors un processus traçant
le parent ne peut pas forcer CLONE_PTRACE pour cet enfant.
- CLONE_VFORK (depuis Linux 2.2)
-
Si le bit CLONE_VFORK est actif, l'exécution du processus appelant est
suspendue jusqu'à ce que l'enfant libère ses ressources de mémoire virtuelle
par un appel execve(2) ou _exit(2) (comme avec vfork(2)).
-
Si CLONE_VFORK n'est pas indiqué, alors les deux processus sont
ordonnancés à partir de la fin de l'appel, et l'application ne devrait pas
considérer que l'ordre d'exécution est déterminé dans un ordre particulier.
- CLONE_VM (depuis Linux 2.0)
-
Si le bit CLONE_VM est actif, le processus appelant et le processus
enfant s'exécutent dans le même espace mémoire. En particulier, les
écritures en mémoire effectuées par l'un des processus sont visibles par
l'autre. De même toute projection en mémoire, ou toute suppression de
projection, effectuée avec mmap(2) ou munmap(2) par l'un des processus
affectera également l'autre processus.
-
Si CLONE_VM n'est pas actif, le processus enfant utilisera une copie
distincte de l'espace mémoire de l'appelant au moment de l'appel clone. Les
écritures ou les associations/désassociations de fichiers en mémoire
effectuées par un processus n'affectent pas l'autre processus, comme cela se
passe avec fork(2).
-
Si l'attribut CLONE_VM est indiqué et si l'attribut CLONE_VFORK ne
l'est pas, toute autre pile de signal mise en place par sigaltstack(2)
sera vidée dans le processus enfant.
VALEUR RENVOYÉE
En cas de réussite, le TID du processus enfant est renvoyé dans le thread
d'exécution de l'appelant. En cas d'échec, -1 est renvoyé dans le
contexte de l'appelant, aucun enfant n'est créé, et errno sera positionné
pour indiquer l'erreur.
ERREURS
- EACCES (clone3() seulement)
-
CLONE_INTO_CGROUP était indiqué dans cl_args.flags, mais les
restrictions à la mise en place d'un processus enfant dans un
cgroup version 2 auquel se rapporte cl_args.cgroup (décrites dans
cgroups(7)) ne sont pas respectées.
- EAGAIN
-
Trop de processus en cours d'exécution. Consultez fork(2).
- EBUSY (clone3() seulement)
-
CLONE_INTO_CGROUP était indiqué dans cl_args.flags, mais le
descripteur de fichier indiqué dans cl_args.cgroup se rapporte à un
cgroup version 2 où un contrôleur de domaine est activé.
- EEXIST (clone3() seulement)
-
Un (ou plusieurs) PID indiqué dans le set_tid existe déjà dans l'espace
de noms PID correspondant.
- EINVAL
-
Tant CLONE_SIGHAND que CLONE_CLEAR_SIGHAND ont été indiqués dans le
masque flags.
- EINVAL
-
CLONE_SIGHAND a été spécifié dans le masque flags, mais pas
CLONE_VM (depuis Linux 2.6.0).
- EINVAL
-
CLONE_THREAD a été spécifié dans le masque flags, mais pas
CLONE_SIGHAND (depuis Linux 2.5.35).
- EINVAL
-
CLONE_THREAD a été indiqué dans le masque flags mais le processus
actuel avait appelé unshare(2) avec l'attribut CLONE_NEWPID ou il
utilisait setns(2) pour se réassocier à l'espace de noms PID.
- EINVAL
-
Tant CLONE_FS que CLONE_NEWNS ont été indiqués dans le masque
flags.
- EINVAL (depuis Linux 3.9)
-
Tant CLONE_NEWUSER que CLONE_FS ont été indiqués dans le masque
flags.
- EINVAL
-
Tant CLONE_NEWIPC que CLONE_SYSVSEM ont été indiqués dans le masque
flags.
- EINVAL
-
CLONE_NEWPID ou CLONE_NEWUSER, et CLONE_THREAD ou CLONE_PARENT,
ont été indiqués, seuls ou ensemble, dans le masque flags.
- EINVAL (depuis Linux 2.6.32)
-
CLONE_PARENT a été spécifié et l'appelant est un processus
d'initialisation.
- EINVAL
-
Renvoyée par l'enveloppe glibc de clone() quand fn ou stack valent
NULL.
- EINVAL
-
CLONE_NEWIPC a été spécifié dans le masque flags, mais le noyau n'a
pas été configuré avec les options CONFIG_SYSVIPC et CONFIG_IPC_NS.
- EINVAL
-
CLONE_NEWNET a été spécifié dans le masque flags, mais le noyau n'a
pas été configuré avec l'option CONFIG_NET_NS.
- EINVAL
-
CLONE_NEWPID a été spécifié dans le masque flags, mais le noyau n'a
pas été configuré avec l'option CONFIG_PID_NS.
- EINVAL
-
CLONE_NEWUSER a été spécifié dans le masque flags, mais le noyau n'a
pas été configuré avec l'option CONFIG_USER_NS.
- EINVAL
-
CLONE_NEWUTS a été spécifié dans le masque flags, mais le noyau n'a
pas été configuré avec l'option CONFIG_UTS_NS.
- EINVAL
-
stack n'est pas alignée sur une limite adaptée à cette architecture. Par
exemple, sur aarch64, stack doit être un multiple de 16.
- EINVAL (clone3() seulement)
-
CLONE_DETACHED a été spécifié dans le masque flags.
- EINVAL (clone() seulement)
-
CLONE_PIDFD a été indiqué avec CLONE_DETACHED dans le masque flags.
- EINVAL
-
CLONE_PIDFD a été indiqué avec CLONE_THREAD dans le masque flags.
- EINVAL (clone() seulement)
-
CLONE_PIDFD a été indiqué avec CLONE_PARENT_SETTID dans le masque
flags.
- EINVAL (clone3() seulement)
-
set_tid_size est supérieur au nombre de niveaux dans l'espace de noms
PID.
- EINVAL (clone3() seulement)
-
Un des PID indiqué dans set_tid n'était pas valable.
- EINVAL (AArch64 seulement, Linux 4.6 et antérieur)
-
stack n'était pas aligné sur une limite de 128 bits.
- ENOMEM
-
Pas assez de mémoire pour copier les parties du contexte du processus
appelant qui doivent être dupliquées, ou pour allouer une structure de tâche
pour le processus enfant.
- ENOSPC (depuis Linux 3.7)
-
CLONE_NEWPID a été spécifié dans le masque flags, et l'appel
provoquerait un dépassement de la limite du nombre maximal d'espaces de noms
utilisateur imbriqués. Consultez pid_namespaces(7).
- ENOSPC (depuis Linux 4.9 ; auparavant EUSERS)
-
CLONE_NEWUSER a été spécifié dans le masque flags, et l'appel
provoquerait un dépassement de la limite du nombre maximal d'espaces de noms
utilisateur imbriqués. Consultez user_namespaces(7).
-
De Linux 3.11 à Linux 4.8, l'erreur indiquée dans ce cas était EUSERS.
- ENOSPC (depuis Linux 4.9)
-
Une des valeurs dans le masque flags indiquait de créer un nouvel espace
de noms utilisateur, mais cela aurait provoqué un dépassement de la limite
définie par le fichier correspondant dans /proc/sys/user. Pour plus de
détails, voir namespaces(7).
- EOPNOTSUPP (clone3() seulement)
-
CLONE_INTO_CGROUP était indiqué dans cl_args.flags, mais le
descripteur de fichier indiqué dans cl_args.cgroup se rapporte à un
cgroup version 2 dont l'état est domain invalid.
- EPERM
-
CLONE_NEWCGROUP, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS,
CLONE_NEWPID ou CLONE_NEWUTS a été spécifié par un processus non
privilégié (processus sans CAP_SYS_ADMIN).
- EPERM
-
CLONE_PID a été spécifié par un processus autre que le processus 0 (cette
erreur n'arrive que sur Linux 2.5.15 et antérieurs).
- EPERM
-
CLONE_NEWUSER a été spécifié dans le masque flags, mais l'identifiant
utilisateur effectif ou l'identifiant de groupe effectif de l'appelant n'a
pas de correspondance dans l'espace de noms parent (consultez
user_namespaces(7)).
- EPERM (depuis Linux 3.9)
-
CLONE_NEWUSER a été spécifié dans le masque flags et l'appelant se
trouve dans un environnement chroot (c'est-à-dire que le répertoire racine
de l'appelant ne correspond pas au répertoire racine de l'espace de noms de
montage dans lequel il se trouve).
- EPERM (clone3() seulement)
-
set_tid_size était supérieur à zéro et l'appelant n'a pas la capacité
CAP_SYS_ADMIN dans un ou plusieurs des espaces de noms utilisateur qui
possèdent les espaces de noms PID correspondants.
- ERESTARTNOINTR (depuis Linux 2.6.17)
-
L'appel système a été interrompu par un signal et va être redémarré (cela
n'est visible qu'à l'occasion d'un trace()).
- EUSERS (Linux 3.11 à Linux 4.8)
-
CLONE_NEWUSER a été spécifié dans le masque flags, et l'appel
provoquerait un dépassement de la limite du nombre maximal d'espaces de noms
utilisateur imbriqués. Voir le point sur l'erreur ENOSPC ci-dessus.
VERSIONS
L'appel système clone3() est apparu pour la première fois dans Linux 5.3.
STANDARDS
Ces appels système sont spécifiques à Linux et ne doivent pas être utilisés
dans des programmes conçus pour être portables.
NOTES
Une utilisation de ces appels système consiste à implémenter des threads :
un programme est scindé en plusieurs lignes de contrôle, s'exécutant
simultanément dans un espace mémoire partagée.
Remarquez que la fonction enveloppe clone() de la glibc effectue des
changements dans la mémoire vers laquelle pointe stack (ce sont des
changements nécessaires pour positionner correctement la pile pour l'enfant)
avant de recourir à l'appel système clone(). Dès lors, lorsque
clone() est utilisé pour créer des enfants de manière récursive,
n'utilisez pas le tampon servant à la pile du parent en tant que pile de
l'enfant.
L'appel système kcmp(2) peut être utilisé pour vérifier si deux
processus partagent des ressources, telles qu'une table de descripteurs de
fichier, des opérations Annuler le sémaphore sur System V, ou un espace
d'adressage virtuel.
Les gestionnaires enregistrés en utilisant pthread_atfork(3) ne sont pas
exécutés pendant un appel clone.
Dans les séries 2.4.x de Linux, CLONE_THREAD ne fait en général pas du
processus parent du nouveau thread un processus identique au parent du
processus appelant. Cependant, de Linux 2.4.7 à Linux 2.4.18, l'attribut
CLONE_THREAD impliquait CLONE_PARENT (de même que dans Linux 2.6.0 et
supérieurs).
Sur i386, clone() ne devrait pas être appelé à l’aide de vsyscall, mais
directement en utilisant int $0x80.
différences entre bibliothèque C et noyau
L'appel système clone brut ressemble plus à fork(2), en ceci que
l'exécution dans le processus enfant continue à partir du point d'appel. À
ce titre, les arguments fn et arg de la fonction enveloppe de
clone() sont omis.
Contrairement à l'enveloppe de la glibc, l'appel système brut clone()
accepte NULL en paramètre de stack (et de même, clone3() permet à
cl_args.stack d'être NULL). Dans ce cas l'enfant utilise une copie de la
pile du parent (la sémantique de copie-en-écriture assure que l'enfant
recevra une copie indépendante des pages de la pile dès qu'un des deux
processus la modifiera). Pour que cela fonctionne, il faut naturellement que
CLONE_VM ne soit pas présent (si l'enfant partage la mémoire du parent
du fait d'une utilisation de CLONE_VM, aucune duplication à l’aide de la
copie-en-écriture ne se produit et il peut s'ensuivre probablement un grand
chaos).
L'ordre des paramètres change aussi dans l'appel système brut et des
variations existent dans les paramètres en fonction des architectures, comme
indiqué dans les paragraphes suivants.
L'interface de l'appel système brut sur des architectures x86-64 et quelques
autres (dont sh, tile et alpha), est :
long clone(unsigned long flags, void *stack,
int *parent_tid, int *child_tid,
unsigned long tls);
Sur x86-32 et d'autres architectures classiques (dont score, ARM, ARM 64,
PA-RISC, arc, Power PC, xtensa et MIPS), l'ordre des deux derniers
paramètres est inversé :
long clone(unsigned long flags, void *stack,
int *parent_tid, unsigned long tls,
int *child_tid);
Sur les architectures cris et s390, l'ordre des deux premiers paramètres est
inversé :
long clone(void *stack, unsigned long flags,
int *parent_tid, int *child_tid,
unsigned long tls);
Sur l'architecture microblaze, il existe un paramètre supplémentaire :
long clone(unsigned long flags, void *stack,
int stack_size, /* Taille de la pile */
int *parent_tid, int *child_tid,
unsigned long tls);
blackfin, m68k, et sparc
Les conventions de passage des arguments sur blackfin, m68k et sparc sont
différentes de celles décrites précédemment. Pour plus de détails, se
référer aux sources du noyau (et de la glibc).
ia64
Sur ia64, une interface différente est utilisée :
int __clone2(int (*fn)(void *),
void *stack_base, size_t stack_size,
int flags, void *arg, ...
/* pid_t *parent_tid, struct user_desc *tls,
pid_t *child_tid */ );
Le prototype présenté ci-dessus vaut pour la fonction enveloppe de la
glibc ; pour l'appel système lui-même, il peut être décrit comme suit (il
est identique au prototype clone() sur microblaze) :
long clone2(unsigned long flags, void *stack_base,
int stack_size, /* Taille de la pile */
int *parent_tid, int *child_tid,
unsigned long tls);
__clone2() fonctionne comme clone(), sauf que stack_base pointe sur
la plus petite adresse de la pile de l'enfant et que stack_size indique
la taille de la pile sur laquelle pointe stack_base.
Linux 2.4 et antérieurs
Sous Linux 2.4 et plus anciens, clone() ne prend pas les paramètres
parent_tid, tls, et child_tid.
BOGUES
Les versions de la bibliothèque C GNU jusqu'à la 2.24 comprise contenaient
une fonction enveloppe pour getpid(2) qui effectuait un cache des PID. Ce
cache nécessitait une prise en charge par l'enveloppe de clone() de la
glibc, mais des limites dans l'implémentation faisaient que le cache pouvait
ne pas être à jour sous certaines circonstances. En particulier, si un
signal était distribué à un enfant juste après l'appel à clone(), alors
un appel à getpid(2) dans le gestionnaire de signaux du signal pouvait
renvoyer le PID du processus appelant (le parent), si l'enveloppe de clone
n'avait toujours pas eu le temps de mettre le cache de PID à jour pour
l'enfant. (Ce point ignore le cas où l'enfant a été créé en utilisant
CLONE_THREAD, quand getpid(2) doit renvoyer la même valeur pour
l'enfant et pour le processus qui a appelé clone(), puisque l'appelant et
l'enfant se trouvent dans le même groupe de threads. Ce problème de cache
n'apparaît pas non plus si le paramètre flags contient CLONE_VM.) Pour
obtenir la véritable valeur, il peut être nécessaire d'utiliser quelque
chose comme ceci :
#include <syscall.h>
pid_t mypid;
mypid = syscall(SYS_getpid);
Suite à un problème de cache ancien, ainsi qu'à d'autres problèmes traités
dans getpid(2), la fonctionnalité de mise en cache du PID a été supprimée
de la glibc 2.25.
EXEMPLES
Le programme suivant décrit l'usage de clone() dans le but de créer un
processus enfant qui s'exécute dans un espace de noms UTS distinct. Le
processus enfant change le nom d'hôte (hostname) dans son propre espace
UTS. Les processus parent et enfant affichent chacun le nom d'hôte qui leur
correspond, permettant ainsi de constater la différence des noms d'hôtes
dans leurs espaces de noms UTS respectifs. Pour un exemple d’utilisation de
ce programme, consultez setns(2).
Dans le programme d'exemple, nous allouons la mémoire qui doit être utilisée
pour la pile de l'enfant en utilisant mmap(2) au lieu de malloc(3)
pour les raisons suivantes :
- •
-
mmap(2) alloue un bloc de mémoire commençant à la limite d'une page et
qui est un multiple de la taille de la page. Cela est utile si on veut
établir une page de protection (avec PROT_NONE) à la fin de la pile en
utilisant mprotect(2).
- •
-
On peut indiquer l'attribut MAP_STACK pour demander une association
adaptée à une pile. Pour le moment, cet attribut n'est pas opérationnel sur
Linux, mais il existe et a des effets sur d'autres systèmes, donc on doit
l'inclure pour la portabilité.
Source du programme
#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
static int /* Commencer la fonction pour l'enfant cloné */
childFunc(void *arg)
{
struct utsname uts;
/* Modifier le nom d'hôte dans l'espace de noms UTS de l'enfant. */
if (sethostname(arg, strlen(arg)) == -1)
err(EXIT_FAILURE, "sethostname");
/* Récupérer et afficher le nom d'hôte. */
if (uname(&uts) == -1)
err(EXIT_FAILURE, "uname");
printf("uts.nodename dans l'enfant : %s\n", uts.nodename);
/* Rester en sommeil (fonction sleep) pour conserver l'espace
de noms ouvert pendant un moment. Cela permet de réaliser
quelques expérimentations — par exemple, un autre processus
pourrait rejoindre l'espace de noms. */
sleep(200);
return 0; /* Le processus enfant se termine à ce moment */
}
#define STACK_SIZE (1024 * 1024) /* Taille de la pile pour
l'enfant cloné */
int
main(int argc, char *argv[])
{
char *stack; /* Début du tampon de la pile */
char *stackTop; /* Fin du tampon de la pile */
pid_t pid;
struct utsname uts;
if (argc < 2) {
fprintf(stderr, "Utilisation : %s <nom_d_hôte-enfant>\n", argv[0]);
exit(EXIT_SUCCESS);
}
/* Allouer la mémoire à utiliser pour la pile du processus enfant. */
stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED)
err(EXIT_FAILURE, "mmap");
stackTop = stack + STACK_SIZE; /* On suppose que la pile grandit vers
le bas */
/* Créer un processus enfant disposant de son propre
espace de noms UTS ; le processus enfant débute
son exécution dans childFunc(). */
pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);
if (pid == -1)
err(EXIT_FAILURE, "clone");
printf("clone() a renvoyé %jd\n", (intmax_t) pid);
/* Le parent se retrouve ici */
sleep(1); /* Laisser le temps au processus enfant de
changer son nom d'hôte */
/* Afficher le nom d'hôte pour l'espace de noms UTS du processus parent.
Celui-ci sera différent du nom d'hôte pour l'espace de noms UTS du
processus enfant. */
if (uname(&uts) == -1)
err(EXIT_FAILURE, "uname");
printf("uts.nodename dans le parent : %s\n", uts.nodename);
if (waitpid(pid, NULL, 0) == -1) /* Attendre le processus enfant */
err(EXIT_FAILURE, "waitpid");
printf("Fin du processus enfant\n");
exit(EXIT_SUCCESS);
}
VOIR AUSSI
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)
TRADUCTION
La traduction française de cette page de manuel a été créée par
Christophe Blaess <https://www.blaess.fr/christophe/>,
Stéphan Rafin <stephan.rafin@laposte.net>,
Thierry Vignaud <tvignaud@mandriva.com>,
François Micaux,
Alain Portal <aportal@univ-montp2.fr>,
Jean-Philippe Guérard <fevrier@tigreraye.org>,
Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>,
Julien Cristau <jcristau@debian.org>,
Thomas Huriaux <thomas.huriaux@gmail.com>,
Nicolas François <nicolas.francois@centraliens.net>,
Florentin Duneau <fduneau@gmail.com>,
Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,
Denis Barbier <barbier@debian.org>,
David Prévot <david@tilapin.org>,
Cédric Boutillier <cedric.boutillier@gmail.com>,
Frédéric Hantrais <fhantrais@gmail.com>
et
Jean-Philippe MENGUAL <jpmengual@debian.org>
Cette traduction est une documentation libre ; veuillez vous reporter à la
GNU General Public License version 3
concernant les conditions de copie et
de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
Index
- NOM
-
- BIBLIOTHÈQUE
-
- SYNOPSIS
-
- DESCRIPTION
-
- La fonction enveloppe clone()
-
- clone3()
-
- Équivalence entre les paramètres de clone() et de clone3()
-
- Signal de fin de l'enfant
-
- Le tableau set_tid
-
- Le masque flags
-
- VALEUR RENVOYÉE
-
- ERREURS
-
- VERSIONS
-
- STANDARDS
-
- NOTES
-
- différences entre bibliothèque C et noyau
-
- blackfin, m68k, et sparc
-
- ia64
-
- Linux 2.4 et antérieurs
-
- BOGUES
-
- EXEMPLES
-
- Source du programme
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 19:28:26 GMT, May 22, 2024