• Aucun résultat trouvé

Créer des processus

Dans le document Programmation Avancée sous Linux (Page 57-62)

Avec l’option -o de la commandeps, vous indiquez les informations sur les processus que vous voulez voir s’afficher sous forme d’une liste de valeurs séparées par des virgules. Par exemple,ps -o pid,user,start_time,command affiche l’identifiant de processus, le nom de l’utilisateur propriétaire du processus, l’heure de démarrage du processus et la commande s’exécutant au sein du processus. Consultez la page de manuel de ps pour une liste complète des codes. Vous pouvez utiliser les options-f (full listing, listing complet),-l (long listing) ou-j (jobs listing) pour obtenir trois formats de listing prédéfinis.

% ps -e -o pid,ppid,command PID PPID COMMAND

1 0 init [5]

2 1 [kflushd]

3 1 [kupdate]

...

21725 21693 xterm 21727 21725 bash

21728 21727 ps -e -o pid,ppid,command

Notez que l’identifiant du processus parent de la commande ps, 21727, est l’identifiant du processus de bash, le shell depuis lequel j’ai invoqué ps. L’identifiant du processus parent de bash est 21725, l’identifiant du processus du programmexterm dans lequel le shell s’exécute.

3.1.3 Tuer un processus

Vous pouvez tuer un processus en cours d’exécution grâce à la commande kill. Spécifiez simplement sur la ligne de commande l’identifiant du processus à tuer.

La commande kill envoie un signal1 SIGTERM, ou de terminaison au processus. Cela termine le processus, à moins que le programme en cours d’exécution ne gère ou ne masque le signal SIGTERM. Les signaux sont décrits dans la Section 3.3, « Signaux ».

3.2 Créer des processus

Deux techniques courantes sont utilisées pour créer de nouveaux processus. La première est relativement simple mais doit être utilisée avec modération car elle est peu performante et présente des risques de sécurité considérables. La seconde technique est plus complexe mais offre une flexibilité, une rapidité et une sécurité plus grandes.

3.2.1 Utiliser system

La fonction system de la bibliothèque standard propose une manière simple d’exécuter une commande depuis un programme, comme si la commande avait été tapée dans un shell. En fait,

1Vous pouvez également utiliser la commandekillpour envoyer d’autres signaux à un processus. Reportez-vous à la Section 3.4, « Fin de processus ».

systemcrée un sous-processus dans lequel s’exécute le shell Bourne standard (/bin/sh) et passe la commande à ce shell pour qu’il l’exécute. Par exemple, le programme du Listing 3.2 invoque la commande ls pour afficher le contenu du répertoire racine, comme si vous aviez saisi ls -l /dans un shell.

Listing 3.2 – (system.c) – Utiliser la Fonction system

1 i n t m a i n ()

2 {

3 i n t r e t u r n _ v a l u e ;

4 r e t u r n _ v a l u e = s y s t e m ( " ls - l / " ) ;

5 r e t u r n r e t u r n _ v a l u e ;

6 }

La fonction system renvoie le code de sortie de la commande shell. Si le shell lui-même ne peut pas être lancé,system renvoie 127; si une autre erreur survient, system renvoie -1.

Comme la fonctionsystem utilise un shell pour invoquer votre commande elle est soumises aux fonctionnalités, limitations et failles de sécurité du shell système. Vous ne pouvez pas vous reposer sur la disponibilité d’une version spécifique du shell Bourne. Sur beaucoup de systèmes UNIX,/bin/shest en fait un lien symbolique vers un autre shell. Par exemple, sur la plupart des systèmes GNU/Linux, /bin/sh pointe vers bash (le Bourne-Again SHell) et des distributions différentes de GNU/Linux utilisent différentes version de bash. Invoquer un programme avec les privilèges root via la fonction system peut donner des résultats différents selon le système GNU/Linux. Il est donc préférable d’utiliser la méthode deforketexecpour créer des processus.

3.2.2 Utiliser fork et exec

Les API DOS et Windows proposent la famille de fonctions spawn. Ces fonctions prennent en argument le nom du programme à exécuter et créent une nouvelle instance de processus pour ce programme. Linux ne dispose pas de fonction effectuant tout cela en une seule fois. Au lieu de cela, Linux offre une fonction, fork, qui produit un processus fils qui est l’exacte copie de son processus parent. Linux fournit un autre jeu de fonctions, la famille exec, qui fait en sorte qu’un processus cesse d’être une instance d’un certain programme et devienne une instance d’un autre. Pour créer un nouveau processus, vous utilisez tout d’abord forkpour créer une copie du processus courant. Puis vous utilisez execpour transformer un de ces processus en une instance du programme que vous voulez créer.

Appeler fork et exec

Lorsqu’un programme appellefork, une copie du processus, appeléeprocessus fils, est créée.

Le processus parent continue d’exécuter le programme à partir de l’endroit oùforka été appelé.

Le processus fils exécute lui aussi le même programme à partir du même endroit.

Qu’est-ce qui différencie les deux processus alors ? Tout d’abord, le processus fils est un nouveau processus et dispose donc d’un nouvel identifiant de processus, distinct de celui de l’identifiant de son processus parent. Un moyen pour un programme de savoir s’il fait partie du processus père ou du processus fils est d’appeler la méthode getpid. Cependant, la fonction fork renvoie des valeurs différentes aux processus parent et enfant – un processus « rentre »

3.2. CRÉER DES PROCESSUS 45 dans le fork et deux en « ressortent » avec des valeurs de retour différentes. La valeur de retour dans le processus père est l’identifiant du processus fils. La valeur de retour dans le processus fils est zéro. Comme aucun processus n’a l’identifiant zéro, il est facile pour le programme de déterminer s’il s’exécute au sein du processus père ou du processus fils.

Le Listing 3.3 est un exemple d’utilisation defork pour dupliquer un processus. Notez que le premier bloc de la structureifn’est exécuté que dans le processus parent alors que la clause else est exécutée dans le processus fils.

Listing 3.3 – (fork.c) – Utiliserfork pour Dupliquer un Processus

1 i n t m a i n ()

2 {

3 p i d _ t c h i l d _ p i d ;

4 p r i n t f ( " ID de p r o c e s s u s du p r o g r a m m e p r i n c i p a l : % d \ n " ,(i n t) g e t p i d () ) ;

5 c h i l d _ p i d = f o r k () ;

6 if ( c h i l d _ p i d != 0) {

7 p r i n t f ( " je s u i s le p r o c e s s u s parent , ID : % d \ n " , (i n t) g e t p i d () ) ;

8 p r i n t f ( " I d e n t i f i a n t du p r o c e s s u s f i l s : % d \ n " , (i n t) c h i l d _ p i d ) ;

9 }

10 e l s e

11 p r i n t f ( " je s u i s le p r o c e s s u s fils , ID : % d \ n " , (i n t) g e t p i d () ) ;

12 r e t u r n 0;

13 }

Utiliser la famille de exec

Les fonctions exec remplacent le programme en cours d’exécution dans un processus par un autre programme. Lorsqu’un programme appelle la fonction exec, le processus cesse immé-diatement d’exécuter ce programme et commence l’exécution d’un autre depuis le début, en supposant que l’appel à exec se déroule correctement.

Au sein de la famille deexec existent plusieurs fonctions qui varient légèrement quant aux possibilités qu’elles proposent et à la façon de les appeler.

– Les fonctions qui contiennent la lettre p dans leur nom (execvp et execlp) reçoivent un nom de programme qu’elles recherchent dans le path courant ; il est nécessaire de passer le chemin d’accès complet du programme aux fonctions qui ne contiennent pas dep. – Les fonctions contenant la lettre vdans leur nom (execv,execvp etexecve) reçoivent une

liste d’arguments à passer au nouveau programme sous forme d’un tableau de pointeurs vers des chaînes terminé par NULL. Les fonctions contenant la lettre l (execl, execlp et execle) reçoivent la liste d’arguments via le mécanisme du nombre d’arguments variables du langage C.

– Les fonctions qui contiennent la lettre e dans leur nom (execve et execle) prennent un argument supplémentaire, un tableau de variables d’environnement. L’argument doit être un tableau de pointeurs vers des chaînes terminé parNULL. Chaque chaîne doit être de la forme"VARIABLE=valeur".

Dans la mesure où exec remplace le programme appelant par un autre, on n’en sort jamais à moins que quelque chose ne se déroule mal.

Les arguments passés à un programme sont analogues aux arguments de ligne de commande que vous transmettez à un programme lorsque vous le lancez depuis un shell. Ils sont accessibles

par le biais des paramètres argc et argv de main. Souvenez-vous que lorsqu’un programme est invoqué depuis le shell, celui-ci place dans le premier élément de la liste d’arguments (argv[0]) le nom du programme, dans le second (argv[1]) le premier paramètre en ligne de commande, etc. Lorsque vous utilisez une fonction exec dans votre programme, vous devriez, vous aussi, passer le nom du programme comme premier élément de la liste d’arguments.

Utiliser fork et exec

Un idiome courant pour l’exécution de sous-programme au sein d’un programme est d’effec-tuer un forkpuis d’appeler execpour le sous-programme. Cela permet au programme appelant de continuer à s’exécuter au sein du processus parent alors qu’il est remplacé par le sous-programme dans le processus fils.

Le programme du Listing 3.4, comme celui du Listing 3.2, liste le contenu du répertoire racine en utilisant la commande ls. Contrairement à l’exemple précédent, cependant, il utilise la commande ls directement, en lui passant les arguments -l et / plutôt que de l’invoquer depuis un shell.

Listing 3.4 – (fork-exec.c) – Utiliser fork et exec

1 # i n c l u d e < s t d i o . h >

3.2. CRÉER DES PROCESSUS 47

38 p r i n t f ( " Fin du p r o g r a m m e p r i n c i p a l \ n " ) ;

39 r e t u r n 0;

40 }

3.2.3 Ordonnancement de processus

Linux ordonnance le processus père indépendamment du processus fils ; il n’y a aucune garantie sur celui qui sera exécuté en premier ou sur la durée pendant laquelle le premier s’exécutera avant que Linux ne l’interrompe et ne passe la main à l’autre processus (ou à unprocessus quelconque s’exécutant sur le système). Dans notre cas, lorsque le processus parent se termine, la commande ls peut s’être exécutée entièrement, partiellement ou pas du tout2. Linux garantit que chaque processus finira par s’exécuter – aucun processus ne sera à cours de ressources.

Vous pouvez indiquer qu’un processus est moins important – et devrait avoir une priorité inférieure – en lui assignant une valeur depriorité d’ordonnancement3 plus grande. Par défaut, chaque processus a une priorité d’ordonnancement de zéro. Une valeur plus élevée signifie que le processus a une priorité d’exécution plus faible ; inversement un processus avec une priorité d’ordonnancement plus faible (c’est-à-dire, négative) obtient plus de temps d’exécution.

Pour lancer un programme avec une priorité d’ordonnancement différente de zéro, utilisez la commande nice, en spécifiant la valeur de la priorité d’ordonnancement avec l’option -n. Par exemple, voici comment vous pourriez invoquer la commande sort input.txt > output.txt, une opération de tri longue, avec une priorité réduite afin qu’elle ne ralentisse pas trop le système :

% nice -n 10 sort input.txt > output.txt

Vous pouvez utiliser la commanderenice pour changer la priorité d’ordonnancement d’un processus en cours d’exécution depuis la ligne de commande.

Pour changer la priorité d’ordonnancement d’un processus en cours d’exécution par pro-grammation, utilisez la fonctionnice. Son argument est une valeur d’ajustement qui est ajoutée à la valeur de la priorité d’ordonnancement du processus qui l’appelle. Souvenez-vous qu’une valeur positive augmente la priorité d’ordonnancement du processus et donc réduit la priorité d’exécution du processus.

Notez que seuls les processus disposant des privilèges root peuvent lancer un processus avec une priorité d’ordonnancement négative ou réduire la valeur de la priorité d’ordonnancement d’un processus en cours d’exécution. Cela signifie que vous ne pouvez passer des valeurs négatives aux commandes nice et renice que lorsque vous êtes connecté en tant que root et seul un processus s’exécutant avec les privilèges root peut passer une valeur négative à la fonction nice. Cela évite que des utilisateurs ordinaires puissent s’approprier tout le temps d’exécution.

2Une méthode visant à exécuter les deux processus de manière séquentielle est présentée dans la Section 3.4.1,

« Attendre la fin d’un processus ».

3NdT. le terme original estniceness(gentillesse), ce qui explique que plus la valeur est grande, plus le processus est « gentil » et donc moins il est prioritaire.

Dans le document Programmation Avancée sous Linux (Page 57-62)