Processus et threads: Programme et Processus Remarque 1: Un processus est une instance d'un programme qui est entrain de s'exécuter en mémoire Hard Disk Memory Program1_instance_1 Remarque 2: On peut avoir en mémoire (en cours d'exécution) aucune, une ou plusieurs instances du même programme (du même fichier sur le disque dur). Ex, si vous lancez plusieurs fois votre navigateur alors on aura autant de processus créés à partir du même programme (fichier) navigateur Program1 Program1_instance_2 …. Remarque 3: Le noyau linux assigne à chaque processus un identifiant unique qu'on appele le PID (Process ID) Program1_instance_n ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Processus, Stack (pille) et Appel d'une fonction Remarque 1: La stack est une zone mémoire d'une taille dynamique réservée à chaque processus. Elle sert a manipuler les appels et retours des fonctions. A chaque fois qu'une fonction est appelée par une autre fonction une nouvelle frame est rajoutée à la stack pour stocker le contexte de cette fonction. STACK Remarque 2: Le contexte d'une fonction contient ses variables locales ainsi que l'adresse de la frame précédente (adresse du contexte de la fonction appelante) Remarque 3: Le registre RSP (Stack Pointer Register) du microprocesseur donne l'adresse mémoire où il faudra empiler une nouvelle frame pour le cas d'un appel de fonction STACK Remarque 4: Le registre RBP (Base Pointer Register) du microprocesseur donne l'adresse mémoire de la frame précédente pour le cas d'un retour de fonction ( restitution du contexte de la fonction appelante) Remarque 5: L'empilement dans la stack se fait dans le sens des adresses décroissantes. ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Sections d'un processus en mémoire Remarque 1: Les tailles des sections Code et Static sont constantes (elles sont déterminés par le compilateur) Remarque 2: La taille de la stack (pille) augmente (sont pointeur adresse diminue) d'une frame à chaque appelle de fonction. La taille de cette frame dépend des variables locales à cette fonction Remarque 3: La taille de la heap augmente (sont pointeur adresse augment) à chaque fois que la fonction malloc est appellé et diminue à chaque fois que la fonction free est appellé. Donc l'allocation dynamique se fait sur la heap Remarque 4: Un processus n'utilise qu'une partie de tout l'espace d'adressage. Le reste ne lui est pas accessible (Le noyau le fera crasher s'il essaye de le faire car il peut dans ce cas corrompre les data d'un autre processus) Problème: Comment faire pour que les adresses des différents processus ne se chevauchent pas en mémoire physique (sur la RAM) ? ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Adresse virtuelle et adresse physique Solution: Chaque adresse mémoire dans un processus, ou adresse CPU, est une adresse virtuelle. Elle est convertie en une adresse physique via un mécanisme géré par le noyau linux et le sous-module matériel TLB (Translation Lookaside Buffer) qui se trouve dans le contrôleur matériel MMU (Memory Management Unit) De ce fait même si deux processus utilise deux adresses virtuelles identiques l'adresse physique de cette adresse virtuelle n'est pas la même suivant le processus en cours d'exécution ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Mémoire Virtuelle et Pagination L'espace mémoire d'un processus est subdivisé en pages de 4K octets chacune. Le noyau linux via la MMU gère le mapping (correspondance) entre pages virtuelle et pages physique ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Processus et Mémoire Virtuelle Chaque processus à l'illusion de pouvoir utiliser tout l'espace d'adressage mais le noyau linux via la MMU optimise l'utilisation de l'espace d'adressage physique (la RAM) en assignant des pages physiques à un processus à chaque fois qu'il en a besoin ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Linux startup (boot) BIOS: motherboard firmware inside ROM Load bootloader getty (User dialog consol) fork() GRUB/U-boot (bootloader) inside master boot record (MBR) on HD (Disc): Load kernel Login: Authentification fork() Kernel: Low level initialization: cpu, clk, ram… Hardware probe: drivers loading and devices initialization File systems loading Create init process bash, sh (terminal) fork() ls cd Grep … prog1 … Prog-n init ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Création d'un processus Mémoire Physique Mémoire Physique Mémoire Physique Code data stack P1: père Code data stack P1: père Code data stack P1: père Solution: Utiliser les appels système fork et exec fournis par le noyau linux Remarque: Fork permet de créer un processus fils à partir d'un processus père en dupliquant l'espace mémoire du père. P1 et P2 sont indépendants fork() Stack data P2: fils Remarque: Exec permet de remplacer l'espace mémoire d'un processus en cours d'exécution par un autre processus (dont le programme est stocké sur le disque ou ailleurs) P2: exec(prog) Stack data P2: fils Code ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: fork() et exit() Remarque 1: Chaque processus est identifié dans le système par un entier unique qui est le PID (Process ID) Remarque 2: La fonction getpid() permet de récupérer le PID du processus courant Remarque 2: L'appel fork() retourne 0 au processus père et un ID (son PID) au processus fils Remarque 3: L'appel exit() permet de terminer l'exécution du programme courant en retournant un code d'erreur Remarque 4: EXIT_SUCCESS, EXIT_FAILURE,… sont des code de retour prédéfinis ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: fork() et execv ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: fork() et wait() ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Les signaux Définition: Les signaux sont des mécanismes permettant de manipuler et de communiquer avec des processus sous Linux. Ils sont en général utilisé pour contrôler les processus. Un signal est un message spécial envoyé à un processus. Les signaux sont asynchrones; lorsqu'un processus reçoit un signal, il le traite immédiatement dès que le noyau lui donne le CPU, sans même terminer la fonction ou la ligne de code en cours. Il y a plusieurs douzaines de signaux différents, chacun ayant une signification différente. Chaque type de signal est caractérisé par son numéro de signal, mais au sein des programmes, on y fait souvent référence par un nom. Sous Linux, ils sont définis dans /usr/include/bits/signum.h (vous ne devriez pas inclure ce fichier directement dans vos programmes, utilisez plutôt <signal.h>). Comportement: Lorsqu'un processus reçoit un signal, il peut agir de différentes façons, selon l'action enregistrée pour le signal. Pour chaque signal, il existe une action par défaut (en général un exit), qui détermine ce qui arrive au processus si le programme ne spécifie pas d'autre comportement. Pour la plupart des signaux, le programme peut indiquer un autre comportement -- soit ignorer le signal, soit appeler un gestionnaire de signal, fonction chargée de traiter le signal. Si un gestionnaire de signal est utilisé, le programme en cours d'exécution est suspendu, le gestionnaire est exécuté, puis, une fois celui-ci terminé, le programme reprend. Génération: – Exception au cours de l'exécution du processus (ex: division par 0) – D'origine matérielle : erreur d'adressage, virgule flottante (en général SIGSEGV est le signal utilisé pour cet événement) – D'origine logicielle : CTRL-C, SIGCHLD, sur commande Les signaux ne sont pas des interruptions: Lors d'une interruption, la routine associée est exécutée immédiatement. Lors de la réception d'un signal, le code associé sera exécuté lorsque le processus aura du temps d'exécution disponible sur un CPU. Une interruption peut provoquer l'envoie d'un signal à un processus. Les signaux ne sont pas temps réels ! ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Liste de signaux #define SIGHUP 1 /* Hangup (POSIX). */ #define SIGINT 2 /* Interrupt (ANSI). */ #define SIGQUIT 3 /* Quit (POSIX). */ #define SIGILL 4 /* Illegal instruction (ANSI). */ #define SIGTRAP 5 /* Trace trap (POSIX). */ #define SIGABRT 6 /* Abort (ANSI). */ #define SIGIOT 6 /* IOT trap (4.2 BSD). */ #define SIGBUS 7 /* BUS error (4.2 BSD). */ #define SIGFPE 8 /* Floatingpoint exception (ANSI). */ #define SIGKILL 9 /* Kill, unblockable (POSIX). */ #define SIGUSR1 10 /* Userdefined signal 1 (POSIX). */ #define SIGSEGV 11 /* Segmentation violation (ANSI). */ #define SIGUSR2 12 /* Userdefined signal 2 (POSIX). */ #define SIGPIPE 13 /* Broken pipe (POSIX). */ #define SIGALRM 14 /* Alarm clock (POSIX). */ #define SIGTERM 15 /* Termination (ANSI). */ #define SIGSTKFLT 16 /* Stack fault. */ #define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ #define SIGCHLD 17 /* Child status has changed (POSIX). */ #define SIGCONT 18 /* Continue (POSIX). */ #define SIGSTOP 19 /* Stop, unblockable (POSIX). */ #define SIGTSTP 20 /* Keyboard stop (POSIX). */ #define SIGTTIN 21 /* Background read from tty (POSIX). */ #define SIGTTOU 22 /* Background write to tty (POSIX). */ #define SIGURG 23 /* Urgent condition on socket (4.2 BSD). #define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ #define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ #define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ #define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ #define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ #define SIGPOLL SIGIO /* Pollable event occurred (System V). */ #define SIGIO 29 /* I/O now possible (4.2 BSD). */ #define SIGPWR 30 /* Power failure restart (System V) #define SIGSYS 31 /* Bad system call. */ ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: signal() et kill() Remarque 1: On peut envoyer un signal à un processus depuis le shell avec la commande : kill –sig_num pid Remarque 2: Dans le shell, la combinaison de touche Ctrl+c permet d'envoyer un signal SIGKILL au processus courant ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Les threads (taches) Définition: Un thread est un processus léger (un "sous-processus") qui s'exécute en parallèle avec les autres threads ainsi que le processus père lui-même. Dans la figure ci-contre, la fonction routine1 et routine2 sont remplacées par les thread qui exécutent les mêmes instructions que ces fonctions. Les threads sont communément appelés des taches ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Les threads (taches) Exemple : Contrôle de trajectoire d'un robot mobile avec une caméra embarquée La tache routine1 effectue l'acquisition des images de la caméra (30 images par secondes) puis exécute un algorithme de traitement d'image pour fournir la position courante du robot La tache routine2 effectue l'acquisition des données des autres capteur (gyro, accéléro, courants moteurs…) toutes les 5ms et en utilisant la position du robot fournie par la tache1 exécute un algorithme de correction de trajectoire puis applique les consignes sur les actionneurs Les deux taches s'exécutent en parallèle chacune à son rythme sans se soucier de l'autre. Le développement de ce système devient de ce fait moins compliqué que de le faire en une seul tache ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Les threads et espace mémoire du processus Question: Dans l'exemple du robot, pourquoi ne pas utiliser deux processus en parallèles au lieu de deux taches Réponse: La variable position (x,y) peut être une variable C global de ce fait elle peut être utilisée par les deux taches. Or si on avait deux processus à la place de deux taches alors il faudrait trouver un moyen pour communiquer la variable position du processus caméra vers le processus contrôle/commande (donc plus de développement => plus de bug pour moins de performance…) Remarques: Les taches du même processus partagent les section data, heap (malloc) et text du processus père. eIles partagent aussi les descripteurs de fichiers et d'autre infos relatifs au processus père. Il y a une stack par tache ainsi que le stack main Les taches sont ordonnancées par le scheduler de la même manière que les processus (Le scheduler ne voit par de différence entre thread et processus) ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Les threads, avantages et inconvénients Avantages des threads par rapport au processus: Communication facile entre threads (par l'intermédiaire de variables globale) Temps d'ordonnancement (context switch) d'un thread vers un autre thread du même processus est très inférieur au switch entre un processus et un autre Inconvénient des threads par rapport au processus: Si un thread crashe à cause d'un bug alors c'est tout le processus qui crashe (donc toutes ses autres thread sont arrêtés) ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: Création d'un thread ESME - Programmation Système sous Linux - A.TALBI
Processus et threads: attente de la fin des thread ESME - Programmation Système sous Linux - A.TALBI