Gérer les processus


Lancer un nouveau processus (remplace le processus courant !)

La fonction exec que je vous présente permet de lancer un nouveau processus, mais ...

Image non trouvée !Cette fonction va transformer le processus appelant en un nouveau processus. L’appel exec écrase le programme par les nouvelles instructions. Ce nouveau programme sera toujours affilié au père (En fait, se sont les segments qui seront redirigés sur le nouveau programme).

Image non trouvée !Pour ne pas écraser le processus courant, il faudra utiliser l'instruction fork qui permet de faire un double en mémoire du processus courant. Ce double devenant un processus fils de celui d'origine et héritant d'informations, ... du père.

Après un exec, le nombre de processus n’est pas modifié. Les signaux positionnés pour être interceptés mettront fin aux programmes appelés.
Les données de l'ancien programme sont accessibles seulement pour la copie des arguments.
Certaines caractéristiques du processus écrasé sont conservées:
- priorité du processus.
- GPID.
- les fichiers restent ouverts.
- sémaphores.
- identificateur du groupe tty.
- drapeau de traçage.
- temps restant jusqu'à un signal d'alarme.
- répertoire de travail et répertoire racine.
- masque de création des droits d'accès aux fichiers.
- limite de taille fichier.
- les temps du processus.
- les verrous sur fichiers.

La commande exec se décline en plusieurs fonctions. L'ensemble de ces fonctions exec autorisent le remplacement du code exécutable courant par un programme et des arguments qui seront précisés en paramêtres.

int execl (char *path , char *arg0,... ,argn-1, (char *)NULL)
int execlp (char *file, char *arg0, ..., argn-1,
(char *)NULL)
int execle (char *path, char *arg0,..., argn-1,
(char *)NULL,char ** envp)
int execv (char *path , char **argv)
int execvp (char *file, char **argv)
int execve (char *path, char **argv, char **envp)

En entrée:

path pointe sur le chemin complet du fichier exécutable (y compris le nom du fichier exécutable).

file pointe sur le nom du fichier exécutable recherché grâce à PATH.

arg0 pointe sur le chemin ou le fichier exécutable.

arg1..n-1 pointe sur des arguments passés au programme

argn Un pointeur NULL termine la liste des arguments. Il est conseillé de mettre aujourd'hui: (char *)NULL comme dernier argument plutôt que 0 ou (void*) 0.
argv est un tableau de pointeurs dont le premier pointe sur le chemin ou le fichier exécutable. 1 à n-1 sur des arguments passés au programme, et le nième qui est un pointeur NULL pour terminer la liste des arguments.
envp est un tableau de pointeurs sur une liste de variables d'environnement. Un pointeur NULL termine la liste des variables d'environnement.

En sortie:

En cas d'erreur exec, retourne - 1 et l'erreur est indiquée dans errno.


Créer un processus fils

La commande fork() crée un double du programme en cours d’exécution. Ce programme aura son propre handle et sera l’image exacte du père (identique à 100% ) avant l’exécution du fork.
Le programme fils ne s’exécutera pas au début du processus, mais juste après la commande fork. Les fichiers ouverts dans le programme père avant la commande fork seront connus et accessibles par le fils (héritage).

Remarque : seul le processus 0, qui est un processus créé lors du boot n’est pas généré par un fork.

Le noyau lors d’un fork :
- Alloue 1 élément de la table des processus au nouveau processus.
- Affecte un numéro identificateur unique au fils
- Copie logique du contexte du père
- Le niveau de filiation n’est pas limité
- Il incrémente les compteurs pour tous les fichiers associer à la table des fichiers et la table des inodes. (cf. La table des fichiers).
- Retourne le numéro d’identificateur au père et 0 au fils (pas d’erreur).#include <unistd.h>

pid_t fork(void);

En sortie:

fork retourne le handle d’un processus fils dans le programme père et 0 dans le programme fils. C’est ce qui permettra de différencier les deux programmes.

En cas d'échec -1 est renvoyé dans le contexte du parent, aucun processus fils n'est créé, et errno contient le code d'erreur ENOMEM
ou EAGAIN.

NoteLe père est censé être à l'écoute (wait()) des signaux de son fils, dont celui qui indique la mort de ce fils. Sans cette écoute, le fils passe et reste dans un état zombie. Càd qu'il a bien libéré toutes ses ressources, mais il reste mappé jusqu'à ce que son père traite le signal ou meurt.

 

Terminaison d’un processus

La fonction exit() permet la terminaison d'un processus et le passage du processus en mode zombie.


- Les fichiers sont fermés.
- La mémoire partagée est détachée.
- Les sémaphores sont détachés et eventuellement corrigés.
- Les verrous sur processus sont levés.
- Le processus est enregistré dans le fichier d'audit (acct).
- Si PPID=PID=PPID du tty alors un signal SIGHUP est envoyé aux autres processus ayant le même PPID.
- Un signal SIGCLD est envoyé au processus pêre.(mort d'un fils)
- La zone u du processus est libérée.
- Le processus est zombie (defunct) si le pêre n'a pas pris en compte la mort du fils ou si le pêre ignore le signal SIGCLD.

void exit ( int status)

En entrée:

status dont la valeur sera renvoyée au processus pêre qui le récupère avec wait() (voir chapitre sur les signaux).

 

Consultation et modification des caractéristisques d’un processus

int getpid() permet d'obtenir l'identifiant du processus courant.
int getppid() retourne l'identifiant du processus père du processus courant.
int getpgrp() retourne l'identifiant du groupe du processus courant.
int setpgrp() l'identifiant du groupe du processus courant est initialisé à l'identifiant du processus. (création d'un groupe)
int getuid() retourne le numéro de propriétaire réel du processus.
int geteuid() retourne le numéro du propriétaire effectif du processus.

int getgid() retourne le numéro de groupe propriétaire réel du processus.
int getegid() retourne le numéro de groupe propriétaire effectif du processus.

L'identificateur d'utilisateur réel identifie l'utilisateur responsable du processus en exécution. L'identificateur d'utilisateur effectif permet la vérification des permissions pour les accès aux fichiers, et pour l'émission de signaux.
Si le setuid bit d'un fichier est positionné l'utilisateur effectif est le propriétaire du fichier, l'opération peut être obtenu aussi avec la fonction setuid(int uid) où uid est le propriétaire du fichier ou l'utilisateur réel.

Dans le cas où le fichier appartient au super utilisateur, uid est utilisateur réel et effectif.

Exemples de programme en C

But : Vérifier qu'une commande exec remplace bien le processus. La commande execlp() va lancer "ls -la". Un message placé après la commande execlp() ne s'affichera jamais !

Image non trouvée !

But : Utilisation de la commande fork(). Les processus vont alors déterminer qui est le programme père et le programme fils. Chacun retournant des informations: Le père retourne le n° PID du fils. Le fils affichera son PID et aussi le PID du père.

Image non trouvée !

But: Retour sur le premier programme, mais en utilisant la commande fork(). Le fils, ainsi créé, va lancer un execlp sur "ls -la". Le processus père attendra la fin du fils pour afficher un message.

Image non trouvée !

 

Un autre exemple est disponible dans le chapitre tube anonyme pour synchroniser des processus avec la commande wait().