0% ont trouvé ce document utile (0 vote)
27 vues10 pages

Chapitre 2

Le document traite des processus dans les systèmes d'exploitation, en expliquant la différence entre programmes et processus, ainsi que l'ordonnancement et la gestion des processus sous Unix. Il aborde également les concepts de PID, UID, GID, et les états d'un processus, ainsi que les commandes de gestion et la création de nouveaux processus. Enfin, il explique comment un processus peut se terminer et comment gérer les processus fils, notamment en évitant l'état zombie.

Transféré par

l7204348
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
27 vues10 pages

Chapitre 2

Le document traite des processus dans les systèmes d'exploitation, en expliquant la différence entre programmes et processus, ainsi que l'ordonnancement et la gestion des processus sous Unix. Il aborde également les concepts de PID, UID, GID, et les états d'un processus, ainsi que les commandes de gestion et la création de nouveaux processus. Enfin, il explique comment un processus peut se terminer et comment gérer les processus fils, notamment en évitant l'état zombie.

Transféré par

l7204348
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL

Chapitre 2 : LES PROCESSUS

I. Présentation des processus


1. Parallélisme et pseudo parallélisme
Le parallélisme est la base des ordinateurs modernes ; Du point de vue matériel,
le processeur passe d'un programme à un autre en quelques millisecondes, ce qui va
donner à l'utilisateur une impression de simultanéité. C'est le pseudo parallélisme, à
différencier avec le véritable parallélisme des systèmes multiprocesseurs.

2. Programmes et processus
Il est très important de différencier un programme et processus. Un processus,
c'est un programme en cours d'exécution auquel est associé un environnement
processeur et un environnement mémoire.
Un programme, c'est une suite d'instructions (notion statique), tandis qu'un
processus, c'est l'image du contenu des registres et de la mémoire centrale (notion
dynamique).

3. Espace d’adressage des processus


Chaque processus possède un espace d'adressage, c'est à dire un ensemble
d'adresses mémoires dans lesquelles il peut lire et écrire. Cet espace est divisé en
trois parties :
• Le segment de texte (le code du programme) ;
• Le segment de données (les variables) ;
• La pile Sa particulièrement est qu’il empile les données au fur et
à mesure

4. Ordonnancement des processus


Lorsqu'un processus est lancé, le système doit gérer la mémoire et l'allocation du
processeur lui étant accordée. Il fait appel à l'ordonnanceur Organe responsable d’allouer
un un temps pour des gestions
des tâches
Un système d'exploitation est préemptif lorsqu'il peut arrêter à tout moment
n'importe quelle application pour passer à la suivante (exemple : Windows XP,

CHRISTIAN KITIO 1
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL
Windows 7 et GNU/Linux sont des systèmes préemptifs). Il peut aussi être coopératif
quand il permet à plusieurs applications de fonctionner et d'occuper la mémoire, et
leur laissant le soin de gérer cette occupation (exemple : Windows 95, 98 et Millénium
sont des systèmes coopératifs).

On distingue donc le multitâche préemptif (le système d'exploitation garde le


contrôle et se réserve le droit de fermer l'application) et le multitâche coopératif
(le système d'exploitation laisse les applications gérer).

II. Gestion des processus Unix

Une des particularités de la gestion des processus sous Unix consiste à séparer la
création d'un processus et l'exécution d'un programme. Cela permet d'avoir plusieurs
processus pour un même programme.
Autrement dit, sous les autres systèmes d'exploitation (mis à part quelques
exceptions), processus = nouveau programme, alors que sous Unix ce n'est pas
forcément le cas. La plupart des systèmes d'exploitation offrent un seul appel
système pour exécuter un nouveau programme, Unix en possède deux : fork et
exec. L’exécution du processus nécessite la création du processus et l’exécution du
processus

1. PID
Chaque processus peut être identifié par son numéro de processus, ou PID (Process
IDentifier).
Un numéro de PID est unique dans le système : il est impossible que deux
processus aient un même PID au même moment.
Lorsque l'on crée un processus (nous verrons comment faire dans la suite du
chapitre), on utilise une fonction qui permet de dupliquer le processus appelant. On
distingue alors les deux processus par leur PID. Le processus appelant est nommé
processus père et le nouveau processus, processus fils. Quand on s'occupe du
processus fils, le PID du processus père est noté PPID (Parent PID).

Par défaut, le noyau attribue un PID avec une valeur inférieure à 32768.
CHRISTIAN KITIO 2
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL
Le 32768ème processus créé reçoit la plus petite valeur de PID libéré par un
processus mort entretemps. Par ailleurs, cette valeur maximale peut être changée
par l'administrateur en modifiant la valeur du fichier /proc/sys/kernel/pid_max.
Commande modifiant la valeur maximale d’un processus

De plus, les PID sont attribués de façon linéaire. Par exemple, si 17 est le PID
le plus élevé affecté, un processus créé à cet instant aura comme PID 18. Le noyau
réutilise les PID de processus n'existant plus uniquement quand la valeur de pid_max
est atteinte.

2. UID (devoir)
Dans un système Unix chaque utilisateur possède un identifiant, sous forme
numérique, nommé UID (User IDentifier).
En conséquence, nous pouvons également distinguer les processus entre eux par
l'UID de l'utilisateur qui les a lancés.
On distingue trois identifiants d'utilisateur par processus :
• L'UID réel : il correspond à l'UID de l'utilisateur qui a lancé le processus ;
• L'UID effectif : il correspond aux privilèges accordés à cet utilisateur ;
• L'UID sauvé : c'est la copie de l'ancien UID réel quand celui-ci a été modifié par
un processus.

3. Permission Set – UID


Il existe une permission spéciale, uniquement pour les exécutables binaires,
appelée la permission Set – UID. Cette permission permet à l'utilisateur ayant les
droits d'exécution sur ce fichier d'exécuter le fichier avec les privilèges de son
propriétaire. On met les droits Set UID avec la commande chmod et l'argument +s.
On passe en second argument le nom du fichier.

4. GID
Chaque utilisateur du système appartient à un ou plusieurs groupes. Ces derniers
sont définis dans le fichier /etc/groups.
Un processus fait donc également partie des groupes de l'utilisateur qui l'a lancé.
Comme nous l'avons vu avec les UID, un processus dispose donc de plusieurs GID

CHRISTIAN KITIO 3
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL
(Group IDentifier) réel, effectif, sauvé, ainsi que de GID supplémentaires si
l'utilisateur qui a lancé le processus appartient à plusieurs groupes.

5. Organisation des processus


Les processus sont organisés en hiérarchie. Chaque processus doit être lancé par
un autre (rappelez-vous les notions sur processus père et processus fils). La racine
de cette hiérarchie est le programme initial : Le processus inactif du système
(System idle process : le processus que le noyau exécute tant qu'il n'y a pas d'autres
processus en cours d'exécution) a le PID 0. C'est celui-ci qui lance le premier
processus que le noyau exécute, le programme initial.
Généralement, sous les systèmes basés sous Unix, le programme initial se nomme
init, et il a le PID 1.

Après son chargement, le programme initial gère le reste du démarrage :


initialisation du système, lancement d'un programme de connexion... Il va également
se charger de lancer les démons. Un démon (du terme anglais daemon) est un
processus qui est constamment en activité et fournit des services au système.

6. Les états d'un processus


Un processus peut avoir plusieurs états :
• exécution (R pour running) : le processus est en cours d'exécution ;
• sommeil (S pour sleeping) : dans un multitâche coopératif, quand il rend la main
; ou dans un multitâche préemptif, quand il est interrompu au bout d'un quantum de
temps ;
• arrêt (T pour stopped) : le processus a été temporairement arrêté par un signal.
Il ne s'exécute plus et ne réagira qu'à un signal de redémarrage ;
• zombie (Z pour zombie) : le processus s'est terminé, mais son père n'a pas encore
lu son code de retour.

De plus, sous Unix, un processus peut évoluer dans deux modes différents : le
mode noyau et le mode utilisateur. Généralement, un processus utilisateur entre
dans le mode noyau quand il effectue un appel système.
CHRISTIAN KITIO 4
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL

III. Commandes de gestion des processus


Pour afficher ses propres processus en cours d'exécution, on utilise la commande :
ps. Pour afficher tous les processus en cours d'exécution, on peut utiliser l'option
aux.
Dans le résultat qui s'affiche, vous pouvez voir la liste de tous vos processus en cours
d'exécution.
• La première colonne USER correspond à l'utilisateur qui a lancé le processus.
• La deuxième colonne PID indique le numéro de PID du processus.
• La huitième colonne STAT correspond à l'état du processus.
• La neuvième colonne START correspond à l'heure du lancement du processus.
• Enfin, la dernière colonne COMMAND correspond au chemin complet de la
commande lancée par l'utilisateur (car même si vous lancez un exécutable en mode
graphique, vous avez une commande qui s'exécute).

IV. Création d'un nouveau processus


Bon nombre de fonctions utilisées avec la programmation système (notamment les
Appels système) nécessiteront l'inclusion du fichier <unistd.h>.

1. La fonction fork
Pour créer un nouveau processus à partir d'un programme, on utilise la fonction
fork (qui est un appel système). Pour rappel, le processus d'origine est nommé
processus père et le nouveau processus créé processus fils, qui possède un
nouveau PID. Les deux ont le même code source, mais la valeur retournée par
fork nous permet de savoir si l'on est dans le processus père ou dans le processus
fils. Ceci permet de faire deux choses différentes dans le processus père et le
processus fils (en utilisant une structure de condition, if ou switch).

Lors de l'exécution de l'appel système fork, le noyau effectue les opérations


suivantes :
• il alloue un bloc de contrôle (PCB : ensemble d'informations liés au processus) dans
la table des processus.
CHRISTIAN KITIO 5
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL
• il copie les informations contenues dans le bloc de contrôle du père dans celui du
fils sauf les identificateurs (PID, PPID...).
• il alloue un PID au processus fils.
• il associe au processus fils un segment de texte dans son espace d'adressage.
• l'état du processus est mis à l'état exécution.

La fonction fork retourne une valeur de type pid_t. Il s'agit généralement d’une
int ; il est déclaré dans <sys/types.h>. La valeur renvoyée par fork est de :
• 1 si il y a eu une erreur ;
• 0 si on est dans le processus fils ;
• Le PID du fils si on est dans le processus père. Cela permet ainsi au père de
connaître le PID de son fils.
Dans le cas où la fonction a renvoyé 1 et donc qu'il y a eu une erreur, le code
de l'erreur est contenue dans la variable globale errno, déclarée dans le fichier
errno.h (n'oubliez pas le #include). Ce code peut correspondre à deux constantes :
• ENOMEM : le noyau n'a plus assez de mémoire disponible pour créer un nouveau
processus ;
• EAGAIN : ce code d'erreur peut être dû à deux raisons : soit il n'y a pas
suffisamment de ressources systèmes pour créer le processus, soit l'utilisateur a déjà
trop de processus en cours d'exécution. Ainsi, que ce soit pour l'une ou pour l'autre
raison, vous pouvez rééditer votre demande tant que fork renvoie EAGAIN.

Prototype de fork
#include <unistd.h>
#include <sys/types.h>
pid_t fork(void);

Autres fonctions
La fonction getpid retourne le PID du processus appelant.
#include <unistd.h>
#include <sys/types.h>
pid_t getpid(void);

CHRISTIAN KITIO 6
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL
La fonction getppid retourne le PPID du processus appelant.
#include <unistd.h>
#include <sys/types.h>
pid_t getppid(void);

 TP1

V. Terminaison d'un programme


Un programme peut se terminer de deux façons différentes. La plus simple
consiste à laisser le processus finir le main avec l'instruction return suivie du code
de retour du programme. Une autre est de terminer le programme grâce à la fonction
exit() (déclarée dans <stdlib.h>). Celle-ci a pour avantage de quitter le programme
quelle que soit la fonction dans laquelle on se trouve.

Exemple :
#include <stdio.h>
#include <stdlib.h>
void quit(void)
{
printf(" Nous sommes dans la fonction quit().\n");
exit(0);
}

int main(void)
{
quit();
printf(" Nous sommes dans le main.\n");
return 0;
}

L'exécution montre que l'instruction printf("Nous sommes dans le main.\n");


n'est pas exécutée. Le programme s'est arrêté à la lecture de exit(0);

CHRISTIAN KITIO 7
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL

VI. Terminaison d'un processus fils


Lorsque le processus fils se termine (soit en sortant du main soit par un appel à
exit) avant le processus père, le processus fils ne disparaît pas complètement, mais
devient un zombie. Pour permettre à un processus fils à l’état de zombie de
disparaître complètement, le processus père peut appeler la fonction wait() qui se
trouve dans la bibliothèque sys/wait.h comme suit : wait(NULL) ; Son prototype
est le suivant : pid_t wait(int*status);

L’appel de wait est bloquant, c’est à dire que lorsque la fonction wait est
appelée, l’exécution du père est suspendue jusqu’à ce qu’un fils se termine.

Le paramètre status correspond au code de retour du processus. Autrement


dit, la variable que l'on y passera aura la valeur du code de retour du processus (ce
code de retour est généralement indiqué avec la fonction exit). De plus, il faut mettre
autant d’appels de wait qu’il y a de fils. La fonction wait renvoie le code d’erreur −1
en cas d'erreurs (dans le cas où le processus n’a pas de fils). Le macro
WEXITSTATUS (status) renvoie le code de retour du processus fils passé à exit ou
à return.
Si le processus père s'arrête sans avoir lu le code de retour de son fils, le
processus init (processus de PID 1) qui va le faire afin de le libérer de cet état de
zombie.
Il est possible de mettre le processus père en attente de la fin d’un processus
fils particulier par l’instruction waitpid(pid_fils, NULL, 0);

 TP2 et TP3
VII. Exécution d'un programme externe
PRÉREQUIS :

 Arguments en ligne de commandes


Argc est un entier de type int qui donne le nombre d'arguments passés en ligne de
commande plus 1. Argv est un tableau de pointeurs. Argv[0] contient de nom du
fichier exécutable du programme. Les cases suivantes argv[1], argv[2], etc.
CHRISTIAN KITIO 8
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL
contiennent les arguments passés en ligne de commande. Enfin, argv[argc] doit
obligatoirement être NULL.

 La variable PATH (export)


La variable PATH contient une série de chemin vers des répertoires qui contiennent
des exécutables ou des scripts de commande. Lorsqu'on lance une commande dans
la console, le système va chercher l'exécutable dans les chemins donnés dans le
PATH. La commande export modifie temporairement le contenu de PATH.

 L'environnement (environ, setenv, getenv)


Une application peut être exécutée dans des contextes différents : terminaux,
répertoire de travail... C'est pourquoi le programmeur système a souvent besoin
d'accéder à l'environnement. Celui-ci est définit sous la forme de variables
d'environnement. Lorsqu'un programme en C démarre, ces variables sont
automatiquement copiées dans un tableau de string. Vous pouvez y accéder en
déclarant la variable externe globale environ au début de votre fichier, comme
ceci : extern char **environ (se terminant par NULL)

Recherche une variable d'environnement : getenv char *getenv(const char


*name); Modifie une variable d'environnement : setenv int setenv(const char
*name, const char *value, int overwrite);

 TP4

VIII. La famille de fonction exec


La famille de fonction exec présente un ensemble de fonctions permettant de
lancer un programme à partir d'un autre. Concrètement ces fonctions permettent de
remplacer un programme en cours par un autre programme sans en changer le PID.
Autrement dit, on peut remplacer le code source d'un programme par celui d'un autre
programme en faisant appel à une fonction exec. n réalité, il existe six fonctions
appartenant à cette famille : execl, execle, execlp, execv, execve et execvp.
Interessons nous à execv. Son prototype est le suivant :

CHRISTIAN KITIO 9
ENSPD 2023/2024 SYSTEMES D’EXPLOITATION GIT/GL
int execv(const char *path, char *const argv[]);

Cette fonction prend en paramètre le chemin complet vers l'exécutable (commandes)


et les arguments associés à la commande. Elle renvoie 1 si erreur et 0 sinon.
 TP5 et TP6

IX. La fonction system


La fonction system (déclaré dans stdlib.h) est semblable à exec, mais elle est
beaucoup plus simple d'utilisation. En revanche, on ne peut pas passer d'arguments
pour une commande donnée. Son prototype est :

int system(const char *command);

Elle prend en paramètre le nom de la commande devant être lancé.


Exemple : programme qui lance la commande clear qui permet d'effacer le
contenu de la console.

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
system("clear");
return EXIT_SUCCESS;
}

CHRISTIAN KITIO 10

Vous aimerez peut-être aussi