INTRODUCTION AU SYSTEME UNIX

Chapître 7

7 Processus
7.1 Caractéristiques des Processus
7.2 Gestion de Processus par le Système Unix
7.3 Appels Systèmes Opérant sur les Processus
7.3.1 Création de Processus
7.3.2 Fin d'un Processus
7.3.3 Attente de la Fin d'un Fils
7.3.4 Substitution
7.3.5 Quelques Primitives
7.4 Les Signaux
7.4.1 Caractéristiques des Signaux
7.4.2 Principaux Signaux
7.4.3 Appels Systèmes Associés aux Signaux

7 Processus

7.1 Caractéristiques des Processus

Un processus est une exécution d'un programme à un instant donné. Le programme lui-même est un objet inerte rangé sur disque sous forme d'un fichier ordinaire exécutable. Plusieurs caractéristiques sont associées à un processus, dont :

une identification ou Process IDentifier ou PID (entier) ;
un propriétaire réel ou Real User IDentifier (entier) ;
un propriétaire effectif ou Effective User IDentifier (entier) ;
un groupe propriétaire réel ou Real Group IDentfifier (entier) ;
un groupe propriétaire effectif ou Effective Group ID (entier)
un terminal d'attachement (le terminal du login).

Lors du lancement d'un processus, le programme qu'il doit exécuter est chargé en mémoire centrale en vue de son exécution.

suite

Différents types de processus :

Un processus système est un processus créé lors du lancement du système pour exécuter des tâches à l'intérieur du noyau :

Gestion des pages de mémoire,
Transferts des processus suspendus sur disque ...
créé lors du démarrage .

Un démon est un processus chargé d'une tâche d'intérêt général :

Gestion d'impression, gestion réseau, gestion du courrier ...
Il n'est pas attaché à un terminal.
créés au démarrage ou par l'administrateur
interrompus que par l'administrateur ou lors de l'arrêt du système .

Un processus utilisateur est lancé par un utilisateur particulier depuis un terminal donné. Lors du login sur un terminal, un processus est lancé (shell en général , mais ce peut être un autre programme).

suite

7.2 Gestion de Processus par le Système Unix

La mémoire allouée à un processus (ou image mémoire) est constitué à partir du fichier qui contient le programme.

C'est un espace d'adresses virtuelles (0 à 232 ) propre à chaque processus

Seules les parties utilisées correspondent a des zones de la mémoire physique. Des zones physiques peuvent être partagées.

suite

la zone utilisateur : en zone système, contient les données de gestion du processus : tables des fichiers ouverts, paramètres des E/S ...
le segment de texte contient la séquence d'instructions exécutée;
la zone des données statiques (variables globales du programme, ...);
la zone de données dynamique pour les objets non permanents.
un tas pour les variables accédées par pointeurs.
une pile pour les variables locales, les paramètres de fonctions, ...);

Remarques

Programmes généralement partageables :

si plusieurs utilisateurs demandent l'exécution d'un même programme, une seule copie du segment de texte du programme est placée en mémoire centrale, puis elle est partagée par les différents processus correspondants.
programmes partageable généralement réentrants :
le système affecte des zones mémoire propres pour les données de chacun d'eux => pas d'interférences entre les différentes exécutions d'un même programme.

table des processus avec une entrée par processus

.

contient toutes les informations nécessaires pour que le système puisse gérer le processus lorsqu'il n'est pas actif.
allouée lors de la création du proc. et libérée lorsqu'il se termine.

suite

Création de processus

Création par clonage d'un processus père qui utilise l'appel système fork().
Le processus fils est une copie exacte du processus père avec :
le même programme mais
des copies des données du père.

Mécanisme de substitution :

on remplace l'image mémoire d'un processus par une nouvelle image construite à partir d'un fichier exécutable :
nouveau programme et
nouvelles données
L'exécution du processus se poursuit au début du nouveau programme.

Mécanisme de suspension : permet d'attendre (la terminaison d'un fils).

7.3 Appels Systèmes Opérant sur les Processus

De nombreuses primitives de gestion de processus peuvent être utilisées dans des programmes écrits en C sous UNIX.

7.3.1 Création de Processus

int fork();

Crée un processus, le "fils", copie du processus appelant, le "père".

Le processus fils :

- exécute le même programme que le processus père;
- utilise des copies des données du père;
- mêmes fichiers ouverts que le père et mêmes pointeurs de position;
- mêmes propriétaires réel et effectif que le père;
- mêmes réactions aux signaux que le processus père;
- même répertoire de travail que le père;
- attaché au même terminal que le père;
- identificateur de processus (PID) différent de celui du père.

En cas de succès l'appel système fork renvoie 0 au processus fils, et renvoie le numéro du processus fils nouvellement créé au processus père.

Exécution du processus fils

Le processus fils commence son exécution en terminant la fonction fork

=> un seul processus (le père) commence l'exécution de fork,

=> deux processus (le père et le fils) terminent l'exécution de fork.

main (){
int pid;
printf("au nom du père\n"); /* 1 */
pid = fork(); /* 2 */
if (pid == 0) /* 3 */
printf("au nom du fils\n"); /* 4 */
if (pid != 0) /* 5 */
printf("au nom du père\n"); /* 6 */
printf("au nom du père et du fils\n"); /* 7 */
}

7.3.4 Substitution de programme par un processus

Une famille de primitives exec permettent le lancement de l'exécution par le processus appelant d'un nouveau programme

Le texte du nouveau programme recouvre et efface celui de l'ancien programme exécuté.

=> pas de retour d'un exec réussi. Les appels à ces fonctions n'entraînent pas de création de processus mais seulement une modification de l'image exécutée.

execl(char *ref, char *arg0, ..., char *argn, 0).

Permet de lancer l'exécution du fichier dont la référence est ref avec les paramètres arg1, ..., argn. Le paramètre arg0 est obligatoire et doit être la même chaîne de caractères que ref.

.

7.3.2 Fin d'un Processus

exit (int n);

Termine le processus qui l'appelle. La valeur de n est disponible pour le processus père du processus appelant et il peut l'obtenir par la fonction wait (voir plus loin). La fonction exit provoque la fermeture de tous les fichiers ouverts par le processus et la libération de toutes les ressources détenues par le processus (mémoire, etc). Les processus fils du processus qui se termine sont orphelins mais sont adoptés par le processus "init" (processus 1). L'entrée correspondant au processus dans la table des processus est libérée. L'identificateur de processus ne sera pas réutilisé avant un certain temps pour éviter des confusions.

Il n'y a pas de retour pour cet appel système.

.

7.3.3 Attente de la Fin d'un Fils

int wait(int *n);

Permet de suspendre un processus jusqu'à la réception d'un signal ou qu'un de ses processus fils se termine ou s'arrête.

Renvoie le numéro du processus qui s'est terminé.

Si n est un pointeur non nul, la valeur de l'entier *n contient des informations sur l'arrêt du processus fils.

S'il n'y a pas de processus fils, la primitive wait retourne immédiatement la valeur -1.

.

.

Exemple d'utilisation des mécanismes processus par le shell
suite

7.3.5 Quelques Primitives

sleep(int n) : met le processus en sommeil pour n secondes.

getpid() : fournit le numéro du processus.

getppid() : fournit le numéro du processus père.

getuid() : donne le propriétaire.

getgid() : donne le groupe du processus.

setuid(int id) : change le propriétaire.

setgid(int gid) : change le groupe du processus.

.

7.4 Les Signaux

7.4.1 Caractéristiques des Signaux

Avertir un processus qu'un événement important s'est produit

=> un processus peut réagir à cet événement sans être obligé de le tester

Mécanisme utilisé par le système pour informer les processus d'erreurs lors des appels systèmes ou d'une erreur d'instruction : overflow, adresse illégale, etc.
Le signal est envoyé par la routine de traitement de l'exception causée par l'erreur.
utilisés pour avertir un processus que l'utilisateur a frappé une touche du clavier du terminal auquel il est attaché.
Tout processus peut envoyer un signal à un autre processus (moyennant certaines autorisations) par la fonction système kill.
La réception d'un signal provoque le plus souvent la fin du processus qui le reçoit, sauf si installation préalable dune fonction de traitement par signal.

7.4.2 Principaux Signaux

nom numéro signification

SIGHUP 1 (hang up) émis à tous les processus associés à un terminal lorsque celui-ci se déconnecte.

SIGINT 2 (interrupt) signal d'interruption émis à tous les processusassociés à un terminal lorsque le caractère d'interruption (en général <CTRL-C>) est tapé.

SIGQUIT 3 (quit) signal d'interruption émis à tous les processus associés à un terminal lorsque le caractère pour quitter une application (en général <CTRL-\>) est tapé.

SIGILL 4 (illegal) émis en cas d'instruction illégale.

SIGTRAP 5 (trap) émis après chaque instruction en cas de traçage de processus.

Principaux signaux (suite)

SIGIOT 6 (input/output trap) émis en cas d'erreur matérielle.

SIGKILL 9 (kill) tue un processus, quel que soit son état.

SIGSEGV 11 (segmentation violation) émis en cas de violation de la segmentation mémoire.

SIGSYS 12 (system) émis en cas d'erreur de paramètre dans un appel système.

SIGPIPE 13 (pipe) émis en cas d'écriture sur un tube sans lecteur.

SIGALRM 14 (alarm) signal associé à une horloge.

SIGTERM 15 (termination) terminaison normale d'un processus.

7.4.3 Appels Systèmes Associés aux Signaux

* int kill(int pid, int sig);

Émet le signalsig au processus pid, à condition que les proc. émetteur et destinataire soient du même propriétaire, ou que le premier soit le super-utilisateur.

Renvoie 0 en cas de succès et -1 sinon.

* int (*signal())(int sig, int *() fonction);

Permet d'installer fonction comme fonction de traitement lors de la réception du signalsig. La fonction de traitement peut être remplacée par une des constantes SIGIGN et SIGDFL . Le signal SIGKILL ne peut être ignoré.

Renvoie l'adresse de la fonction de traitement précédemment utilisée en cas de succès et -1 en cas d'échec.

Exemple :

Le programme suivant met en place un traitement pour les signaux SIGINT et SIGQUIT, puis se suspend pendant 120s avant de se terminer. Il réagit aux signaux SIGINT et SIGQUIT mais ne meurt pas .

#include <signal.h>
void trait_sigint(){
printf("bien recu SIGINT, mais je m'en moque\n");
}
void trait_sigquit() {
printf("bien recu SIGQUIT,mais je m'en moque\n");
}
main(){
signal(SIGINT, trait_sigint);
signal(SIGQUIT, trait_sigquit);
sleep(120);
print("je meurs de ma belle mort\n");
}

Autres appels systèmes associés aux signaux

* int pause();

Suspend le processus jusqu'à réception d'un signal. Suivant la nature du signal et les traitements de signaux mis en place, il reprend son exécution ou traite le signal puis reprend son exécution, ou bien se termine directement.


* int alarm (int sec);

Programme l'envoi par le système du signal SIGALRM au processus appelant dans sec secondes.

FIN