PROGRAMMATION SYSTÈME
SOUS UNIX/LINUX
Chapitre 1 – La gestion des Processus
Najar Yousra
2020/2021 - 2 Ing
Plan de la matière
■ La gestion des processus
■ Les signaux
■ Les tubes
■ Les IPC System V
■ Les sockets
Plan du chapitre 1
■ Introduction
■ Les arguments d’un programme
■ Les processus sous UNIX
■ La terminaison d’un processus
Introduction
■ Ce cours porte sur l’utilisation des appels système des systèmes de la famille
Unix : Linux,MacOS X, AIX, LynxOS, BeOS, QNX, OpenBSD, FreeBSD,NetBSD.
■ Le rôle d’un système d’exploitation est de :
1. Gérer le matériel
2. Fournir une interfaces pour les programmes (un ensemble d’appels système)
3. Fournir une interfaces bas niveau pour l’utilisateur (un ensemble de
commande shell)
4. Eventuellement une interface utilisateur haut niveau par un environnement
graphique(kde,gnome)...
Introduction
■ Un appel système : En informatique, un appel système (en anglais, system
call, abrégé en syscall) est une fonction primitive fournie par le noyau (kernel)
d’un système d’exploitation et utilisée par les programmes s’exécutant dans
l’espace utilisateur (en d’autres termes, tous les processus distincts du
noyau). Ce système permet de contrôler de façon sécurisée les applications
dans l’espace utilisateur.
■ La norme POSIX (Portable Operating System Interface UniX) est un ensemble
de standardsde l’IEEE (Institute of Electrical and Electronics Engineers). POSIX
définit notamment :
1. Les commandes shell de base (ksh, ls, man, ...)
2. L’API (Application Programming Interface) des appels système.
Les arguments d’un programme
■ Il s’agit du passages d’arguments et variables d’environnement qui permettent à un
shell de transmettre des informations à un programme qu’il
lance. Plus
généralement, ces techniques permettent à un programme de transmettre des
informations aux programmes qu’il lance (processus fils ou descendants).
■ Pour écrire un programme C sous Unix, il suffit d’utiliser un éditeur comme vi :
$ vi nom du fichier puis écrire le code et enregistrer avec :wq
■ Pour compiler un programme C sous Linux/Unix, on utilise GCC (GNU C Compiler).
Tout d’abord on doit s’assurer qu’il est installé sinon on doit l’installer.
Advertisement
■ gcc s'utilise en console : gcc [arguments] [fichiers à compiler] (-o fichier de sortie)
Exmple : $ gcc prog.c –o prog
$ prog4
Les arguments d’un programme
■ La fonction main d’un programme C doit retourner (return/exit) lorsqu'il se termine «
code de retour » entier. Ce code de retour permet au programme de faire savoir au
système si une erreur a été détectée : un retour 0 indique une sortie normale et un
retour négatif indique un retour avec erreur,
■ La fonction main d’un programme C peut prendre des arguments en ligne de
commande lors de l’appel :
Exemple : $ prog arg1 arg2 arg3
■ Pour récupérer les arguments dans le programme C, on utilise les paramètres argc et
argv dumain.
Les arguments d’un programme
■ L’entier argc donne le nombre d’arguments rentrés dans la ligne de
est un tableau de chaînes de
commande plus1, et le paramètre argv
caractères qui contient comme éléments :
1. Le premier élément argv[0] est une chaîne qui contient le nom du fichier
exécutable du programme
2. Les éléments suivants argv[1], argv[2], etc... sont des chaînes de caractères
qui contiennent les arguments passés en ligne de commande
int main (int argc ,char** argv )
Les arguments d’un programme
Les Processus sous UNIX
■ Tout le logiciel d’un ordinateur est organisé en un certain nombre de processus séquentiels. Un
processus est un programme qui s’exécute et possède des compteurs de son exécution, des
registres, des variables et une pile d’exécution. Son exécution est, en général, une alternance
de calculs effectués par le processeur et de requêtes d’Entrée/Sortie effectuées par les
périphériques.
Il existe une table des informations concernant tous les processus
créés. Il y a une entrée par processus dans la table, appelée le Bloc
de Contrôle de Processus (PCB).
Chaque entrée de la table PCB comporte des informations sur :
– Le pid du processus.
– L’état du processus.
– Son compteur ordinal (adresse de la prochaine instruction devant
être exécutée par ce processus).
– Son allocation mémoire.
– Les fichiers ouverts.
– Les valeurs contenues dans les registres du processeur.
–
Les Processus sous UNIX
■ Chaque processus possède un numéro de processus (PID).Sous unix, on peut voir la liste des
processus en cours d’exécution, ainsi que leur PID, parla commande ps, qui comporte
différentes options. Pour voir ses propres processus en cours d’exécution on peut utiliser le
commande
$ ps –x
Advertisement
Pour voir l’ensemble des processus du système, on peut utiliser la commande
$ ps –aux
Pour voir l’ensemble des attributs des processus, on peut utiliser la commande
$ ps –f –x
La gestion des processus sous UNIX
Le standard Posix définit un nombre relativement petit d’appels système pour la gestion
de processus.
Le type pid_t( équivalent à entier long)
#include <sys/types.h>
■ pid_t fork(): Création de processus fils.
■ int execl(), int execlp(), int execvp(), int execle(), int execv(): Les services exec()
permettent à un processus d’exécuter un programme (code) différent.
■ pid_t wait(): Attendre la terminaison d’un processus.
■ void exit(): Finir l’exécution d’un processus.
■ pid_t getpid(): Retourne l’identifiant du processus.
■ pid_t getppid(): Retourne l’identifiant du père du processus.
La création d’un processus
■ Un processus peut créer un ou plusieurs processus fils qui, à leur tour, peuvent créer des
processus fils sous une forme de structure arborescente. Le processus créateur est appelé
processus père.
■ Le père continue à s’exécuter en concurrence avec ses fils. C’est ce qu’on appelle exécution
asynchrone. Un processus fils créé peut partager certaines ressources comme la mémoire ou
les fichiers avec son processus père ou avoir ses propres ressources. Le processus père peut
contrôler l’usage des ressources partagées et peut avoir une certaine autorité sur ses
processus fils. Également, il peut suspendre ou détruire ses processus fils. Il peut également
se mettre en attente de la fin de l’exécution de ses fils. L’espace d’adressage du processus fils
est obtenu par duplication de celui du père. Il peut exécuter le même programme que son père
ou charger un autre programme.
fork() est le seul moyen de créer des processus, par duplication d’un processus existant.
L’appel système fork() crée une copie exacte du processus original. Mais maintenant il se
pose un problème, car les deux processus père et fils exécutent le même code.
La création d’un processus
Comment distinguer alors le processus père du processus fils ? Pour résoudre ce problème,
on regarde la valeur de retour de fork(), qui peut être :
- 0 pour le processus fils
- Strictement positive pour le processus père et qui correspond au pid du processus fils
- Négative si
mémoire ou si bien le nombre maximal de créations autorisées est atteint.
la création de processus a échoué, s’il n’y a pas suffisamment d’espace
La création d’un processus
L’appel système fork est fournit par la bibliothèque <unistd . h>
Exemple
$ gcc -o filsfils.c fils
$ Je suis le père avec pid 4130
$ Je suis le fils avec pid 4131
La création d’un processus
Exercice d’ application :
Ecrire un programme tfork.c qui crée
un processus fils. Le processus fils et père
modifient
Advertisement
la même variable globale a (
initialisée à 20 le fils lui ajoute 10 et le père lui
ajoute 100)
Les appels systèmes exec
Le processus fils créé peut remplacer son code de programme par un autre programme. Le
système Unix offre une famille d’appels système exec qui permettent de changer l’image d’un
processus. Tous les appels système exec remplacent le processus courant par un nouveau
processus construit à partir d’un fichier ordinaire exécutable. Les segments de texte et de
données du processus sont remplacés par ceux du fichier exécutable.
#include <unistd.h>
■ int execl(const char path, const char argv, ...);
■ int execv(const char path, const char argv[]);
■ int execlp(const char file, const char argv, ...);
■ int execvp(const char file, const char argv[]);
Les appels systèmes exec
■ execl(): permet de passer un nombre fixé de paramètres au nouveau programme.
■ execv(): permet de passer un nombre libre de paramètres au nouveau programme.
■ exelp(): Interface et action identiques à celles d’execl(), mais la différence vient du fait que si
le nom du fichier n’est pas un nom complet — par rapport à la racine — le système utilisera
le chemin de recherche des commandes — les chemins indiqués par la variable PATH— pour
trouver dans quel répertoire se trouve le programme.
■ exevp(): Interface et action identiques à celles d’execv(), mais la différence vient du fait que
si le nom de fichier n’est pas un nom complet, la commande utilise les répertoires spécifiés
dans PATH.
Les appels systèmes exec
■ Exemple de passage de paramètres :
char *arguments[4]
...
arguments[0]="/bin/ls";
arguments[1]="-l";
arguments[2]="/etc";
arguments[3]="NULL";
execv("/bin/ls", arguments);
execl("/bin/ls", "/bin/ls " ,"-l" , "/etc" , "NULL");
execvp("ls", arguments);
execlp("ls", "ls " ,"-l" , "/etc" , "NULL");
Les appels systèmes exec
Exemple soit le programme suivant :
La fonction system
■ Il y a une façon de créer sous-processus en Unix/Linux, en utilisant la commande
system(), de la bibliothèque standard de C <stdlib.h>. Comme arguments elle reçoit
le nom de la commande : system.c
Il crée un processus fils en lançant la commande : ls -l /
Pour lancer ce programme :
gcc –o system system.c
system
Il faut retenir que system() n’est pas un appel système, mais
une fonction C. Ce qui rend l’utilisation de la fonction system()
Advertisement
moins performante qu’un appel
système de création de
processus.
Les appels systèmes wait, waitpid et
exist
■ Ces appels système permettent au processus père d’attendre la fin d’un de ses
processus fils et de récupérer son statuts de fin (état de terminaison).
• void exit(int return_code ): Permet de finir volontairement l’exécution d’un processus et donne son état de
terminaison avec code return_code : ce paramètre est reçu par le père à l'aide de la primitive wait.
Wait et waitpid…..
■ wait(int *status): Permet à un processus père d’attendre jusqu’à ce qu’un processus fils
termine. Il retourne l’identifiant du processus fils et son état de terminaison dans &status s’il
n’est pas NULL.
■ waitpid(int pid, int *status): Permet à un processus père d’attendre jusqu’à ce que le
processus fils numéro pid termine. Il retourne l’identifiant du processus fils et son état
de terminaison dans &status. La valeur de pid peut être l'une des suivantes :
Wait et waitpid…
L’état de terminaison d’un processus
Le processus appelant est mis en attente jusqu’à ce que l’un de ses fils termine. Quand cela se
produit, il revient de la fonction. Si status est différent de 0, alors 16 bits d’information sont
rangés dans les 16 bits de poids faible de l’entier pointé par status. Ces informations permettent
de savoir comment s’est terminé le processus selon les conventions suivantes :
■ Si le fils est stoppé, les 8 bits de poids fort contiennent le numéro du signal qui a arrêté le
processus et les 8 bits de poids faible ont la valeur octale 0177.
■ Si le fils s’est terminé avec un exit(), les 8 bits de poids faible de status sont nuls et les 8 bits
de poids fort contiennent les 8 bits de poids faible du paramètre utilisé par le processus fils
lors de l’appel de exit().
■ Si le fils s’est terminé sur la réception d’un signal, les 8 bits de poids fort de status sont nuls
et les 7 bits de poids faible contiennent le numéro du signal qui a causé la fin du processus.
Wait et waitpid ……
■ Si status n'est pas NULL, wait() et waitpid() enregistrent les informations sur l'état dans l'entier
int sur lequel il pointe. Cet entier est analysé avec les macros suivantes (qui prennent en
argument l'entier lui-même, pas un pointeur sur lui, comme cela est fait dans wait() et
waitpid()) , exemple :
■ WIFEXITED(status) : vrai si le processus s'est terminé de façon normale.
■ WEXITSTATUS(status) : le code de sortie, c.à.d. status dans exit(status).
■ WIFSIGNALED(status): vrai si le processus s'est terminé à cause d'un signal (par exemple, un
CTRL-C)
■ WTERMSIG(status), le signal qui a provoqué la terminaison.
■ WIFSTOPPED(status) : vrai si le processus est arrêté à cause d'un signal (primitive waitpid
avec option WUNTRACED)
■ WSTOPSIG(code), le signal qui a provoqué l' arrêt.
Wait et waitpid ……
Exemple :