Systèmes d'exploitation (SYE) Gestion des processus (v2.2) Daniel Rossier daniel.rossier@heig-vd.ch
Plan Processus File System Network Manager Changement de contexte Scheduler Memory Manager Threads IPC Init IPC (Inter-Process Communication) Algorithmes d'ordonnancement 2
Processus - Introduction Un processus est caractérisé par: Une image binaire Un fichier exécutable pouvant être chargé en mémoire. Un contexte d'exécution Code Valeurs de registres, caches processeur Un espace mémoire Données (variables globales, locales, constantes) Espace mémoire virtuel Un ensemble de ressources Fichiers ouverts Ressources de communications interprocessus Ressources matériels Alertes/signaux en attente Espace d'adressage e Espace mémoire Kernel (OS, data, etc.) Stack Heap BSS Data Code 3
Processus - PCB Un processus possède une fiche signalétique permettant au système d'exploitation de disposer des informations liées à ce processus. Cette fiche signalétique est le Process Control Block (PCB) Le PCB permet de gérer les ressources système de manière virtuelle. La virtualisation des ressources permet aux processus de faire "comme s'il disposait chacun d'une machine complète". Mémoire Registres Matériel Fichiers 4
PCB - Détails Le PCB est composé des éléments fondamentaux suivants: U ét t State ID PTBR/STBR (Cf. gestion mémoire) PC Stack Heap Un état Un espace d'adressage Tas (Heap) Des processus fils Table de fichiers ouverts Un ou plusieurs contexte(s) d'éxécution Un compteur ordinal (PC) Des registres de données Une pile Linux task_struct Registres List of open files... List of process children... PTBR/STBR... 5
Processus Exécution concurrente Un processus lâche le processeur de manière: Volontaire multi-tâche coopératif L'ordonnancement dépend de l'application Possibilité de monopoliser le système Forcé multi-tâche préemptif Protection de l'os Permet d'assurer un équilibre entre les processus. Typiquement, un processus est interrompu (préempté) Après un certain temps (time slice) En cas de terminaison d'une entrée/sortie Si un autre processus a une plus haute priorité. 6
Processus - Processeur Processus 1 Processus 2 Processus 3 Processus 4 Stack Stack Stack Stack Heap Heap Heap Heap BSS BSS BSS BSS Data Data Data Data Equilibre de charge (load-balancing) Code Code Code Code BUS PARTAGE Mémoire Principale Entrées/Sorties Dans une architecture SMP, chaque processeur gère une liste de processus qui s'exécutent tour à tour. Processeur 7
Processus Changement de contexte Le basculement d'un processus à l'autre est géré par le noyau. Suspendre le processus P 0 Mettre à jour le PCB du processus s P 0 Restaurer le PCB du processus P 1 Reconfigurer l'espace mémoire Reconfiguration du Memory Management Unit (MMU) Démarrer processus P 1 Cette opération est généralement décidée et réalisée par l'ordonnanceur. C'est une opération très coûteuse! O(ms) 8
Création de processus fork() L'appel système fork() permet de créer un nouveau processus. Le nouveau processus devient un processus fils du processus qui exécute fork(). Le processus fils hérite des ressources du processus parent. L'espace mémoire est dupliqué (inclut les descripteurs de fichiers et d'autres ressources) L'espace mémoire est copiée dans son intégralité (code, données, etc.) Au niveau du code, il faudra différencier celui du parent et celui du fils. Processus parent (original) Pile Processus fils (nouveau) Pile Tas Données Tas Données pid = fork(); pid = fork(); (pid!= 0) (pid = 0) 9
Exercice Soit le code ci-dessous: int main () { int pid; } printf(" message0 \n "); pid = fork(); if (pid < 0) exit(-1); if (pid) { printf(" message1 \n "); pid = fork(); if (pid < 0) exit(-1); if (pid) printf(" message2\n "); } else printf("message3\n "); Combien y a-t-il de processus au maximum? Donnez, sous forme d un dun arbre, les différents ordres possibles d affichage des messages (chaque chemin de l arbre devrait correspondre à un ordre possible). 10
Processus Etats et transitions New Processus créé et initialisé (prêt à être ordonnancé) Processus relancé par l'utilisateur Stopped Ready Processus préempté (par l'ordonnanceur) Processus réveillé (fin I/O, ressource disponible) Processus élu/activé Processus stoppé par l'utilisateur Waiting Processus suspendu (requête I/O, mise en attente) Running Processus terminé Zombie 11
Threads - Introduction (1) Décomposition d'une application en plusieurs tâches indépendantes. Ces tâches peuvent s'exécuter en parallèle. L'application peut s'exécuter sur plusieurs processeurs. Deux approches Multi-processus Multi-thread Multi-processus Les changement de contexte t sont coûteux. Chaque processus dispose de ses propres ressources. La communication inter-processus est coûteuse (cf IPC). 12
Threads - Introduction (2) Multi-thread Un thread est un processus léger (lightweight process) Les ressources sont partagées Création rapide (env. 10-100 fois plus rapide que pour un processus) Changements de contexte simplifiés et rapides La communication entre les threads est "directe". Très bonne performance Notion d'hyperthreading Gestion multi-threads au niveau du processeur 13
Threads Caractéristiques Un thread a un contexte réduit Un compteur ordinal (PC) Des registres Une pile Un état Une priorité Par conséquent, un processus multi-thread a plusieurs piles! Le modèle de programmation multi-thread peut être soit coopératif, soitpréemptif 14
Threads Ressources Le thread utilise l'espace d'adressage du processus ainsi que toutes les ressources gérées par le processus. Tous les threads se partagent les ressources du processus (code, variables globales, fichiers ouverts, ) La protection entre les threads n'est pas garantie! Les threads s'exécutent dans une même machine virtuelle. 15
Threads Implantation OS Niveau applicatif (threads utilisateur) Structure t et contrôle du thread dans le processus. Chaque processus peut contenir des threads de types différents (différentes classes). Niveau système (threads noyau) Structure et contrôle au niveau du noyau Les threads ont la même structure/gestion pour tous les processus (une seule classe de thread). Les threads sont visibles durant les appels systèmes. 16
Threads - Relations La gestion des threads se fait au niveau utilisateur. Thread utilisateur Modèle "many-to-one" Un seul contexte d'exécution pour le processus Thread noyau La gestion des threads se fait au niveau noyau. Modèle "one-to-one" 17
Threads - POSIX Il existe une spécification POSIX (IEEE 1003.1c) 1 pour la gestion des threads et leur synchronisation via mutex. POSIX est très couramment utilisé sous UNIX/Linux. pthread_create(), pthread_join(), pthread_mutex(), etc. Supporté par Windows XP (sous-système POSIX) 18
IPC - Introduction Inter-Process Communication Ensemble de mécanismes permettant la communication et la synchronisation entre processus. Les IPCs ont des interfaces standardisées. Standard POSIX 19
IPC - Communication Les tubes Permettent l'échange de message (ou de données) entre des processus Flux de données entre deux processus Les signaux Envoi asynchrone d'un dun signal ou événement àunouplusieurs processus Les fichiers mappés Projection en mémoire du contenu d'un fichier Les files de message (message queue) Permet l'envoi de plusieurs messages simultanément Utiliser par RPC (invocation de méthodes) distantes, par exemple Les sockets Communication via le réseau Lent (dépend de la bande passante) Les segments de mémoire partagée 20
Tubes - Définition Les tubes sont des canaux de communication entre processus dans une même machine. C'est un mécanisme de communication qui interagit fortement avec le système de fichiers. Un tube est un fichier d'un type spécial (type pipe). Un tube possède donc deux descripteurs de fichier. Il est possible d'utiliser les primitives read() et write() puisqu'il est possible d'acquérir un descripteur La communication est (de préférence) unidirectionnelle. Une communication bidirectionnelle nécessite deux tubes. La lecture est destructive, c'est-à-dire qu'elle ne s'effectue qu'une une seule fois. Gestion de type FIFO Le tube a une capacité limitée (généralement de 4Ko) Un tube peut être plein ou vide. 21
Tubes Exemple d'un client/serveur C est un client/serveur non réparti. Le client fournit le nom du fichier. Le serveur envoie le contenu de ce fichier. nom de fichier données Processus 1 Client nom de fichier PIPE 1 PIPE 2 données Processus 2 Serveur fichier 22
Utilisation de fork() - Exemple Squelette du programme client-serveur int main() { int pipe1[2], pipe2[2], id; char buff[100]; if (pipe(pipe1) < 0) { perror(""); exit(-1); } if (pipe(pipe2) < 0) { perror(""); exit(-1); } } id = fork(); if (id < 0) { perror(""); exit(-1); } if (id > 0) { /* Client */ close(pipe1[0]); close(pipe2[1]); client(pipe2[0], pipe1[1]); waitpid(id, NULL, 0); close(pipe1[1]); close(pipe2[0]); exit(0); } else { /* Serveur */ close(pipe1[1]); close(pipe2[0]); serveur(pipe1[0], pipe2[1]); close(pipe1[0]); close(pipe2[1]); exit(0); } 23
Signaux - Définition Les signaux jouent le rôle de sonnette d'alarme, ils permettent de communiquer des informations à un processus afin qu'il prenne une action immédiate. (Exemple: la sonnerie du téléphone) Le signal peut-être envoyé par l'usager SIGINT (CTRL/C), SIGQUIT ou SIGTSTP Il peut aussi être envoyé par le système. SIGSEGV est généré en cas de débordement de la mémoire. Le signal provoque l'exécution d'un dun traitant (callback ou handler) dans l'espace utilisateur. Le traitant peut être considéré comme une routine de service implémenté par l'utilisateur (dans l'espace utilisateur). 24
Signaux - Traitement Le signal est dans l'état... si... Pendant Le signal transmis à un processus n'a pas encore été pris en compte. Un seul exemplaire d'un même type de signal peut être pendant. Pris en compte ou délivré Le signal est pris en compte par le processus lorsque celui-ci s'exécute, dans le mode utilisateur. À la délivrance du signal, une fonction "handler" (callback) est appelée; le signal est alors "délivré". Un processus dans l'état waiting ou stopped peut capter un signal; il sera ordonnancé afin de le prendre en compte, puis retournera dans l'état original. Bloqué ou masqué Mécanisme permettant de différer volontairement la délivrance du signal. Utilisé afin de permettre l'exécution du handler. 25
Signaux - Types Nom du signal Evénement associé SIGHUP Terminaison du processus leader de session SIGINT Frappe du caractère intr sur le clavier du terminal de contrôle SIGQUIT Frappe du caractère quit sur le clavier du terminal de contrôle SIGILL Détection d'une instruction illégale SIGABRT Terminaison anormale provoquée par l'exécution de la fonction abort SIGFPE Erreur arithmétique ih éi (diii (division par zéro) SIGKILL Signal de terminaison SIGSEGV Violation mémoire (segmentation fault) SIGPIPE Ecriture dans un tube sans lecteur SIGALRM Fin de temporisation (fonction alarm) SIGTERM Signal de terminaison SIGUSR1 Signal émis par un processus utilisateur SIGUSR2 Signal émis par un processus utilisateur SIGCHLD Terminaison d'un fils SIGSTOP Signal de suspension SIGTSTP Frappe du caractère susp sur le clavier du terminal de contrôle SIGCONT Signal de continuation d'un processus stoppé SIGTTIN lecture par un processus en arrière-plan SIGTTOU Ecriture par un processus en arrière-plan (terminal en mode tostop) La commande "kill -l" permet de lister tous les signaux. 26
Programmation des signaux (1/2) La commande signal(signal, action) permet de recevoir un signal donné et de spécifier l'action qui lui est associée (SIG_IGNIGN ignore le signal, SIG_DFL implémente le comportement par défaut). L'exemple suivant permet d'ignorer les interruptions du clavier et restitution du comportement par défaut: void fonctiondusignal(int sig) { if (sig == SIGTSTP) printf("suspension impossible\n"); } int main(int argc, char **argv) { signal(sigtstp, fonctiondusignal); } for ( ; ; ); 27
Programmation des signaux (2/2) L'exemple suivant permet d'ignorer les interruptions du clavier et restitution du comportement par défaut: int main(int argc, char **argv) { signal(sigint,sig_ign); signal(sigquit,sig_ign); _ signal(sigint,sig_dfl); signal(sigquit,sig_dfl); } Le programme suivant boucle indéfiniment: int main(int argc, char **argv) { signal(sigint,sig_ign); signal(sigquit,sig_ign); for( ; ; ); } On peut le tuer avec kill -9 PID 28
Fichier mappé L'appel système mmap() permet de projeter le contenu d'un dun fichier en mémoire. Le contenu en mémoire est synchronisé automatiquement avec le contenu du fichier, et vice-versa. Il y a un mappage du contenu. L'option MAP_SHARED est requise pour garantir la synchronisation. Un fichier mappé (en mémoire) peut être partagé par plusieurs processus. addr = mmap(null, size, PROT_READ PROT_WRITE, MAP_SHARED, fd, 0); Espace mémoire du processus 29
Socket - Aperçu Architecture client-serveur Appels systèmes accept() pour se mettre en attente d'une connexion client. connect() pour se connecter à un serveur. send() pour envoyer un flux de données. Appel atomique non bloquant pour autant que la capacité ne dépasse pas celle du buffer interne. /proc/sys/net/core/optmem_max Utiliser le flag MSG_NOSIGNAL pour éviter le signal SIGPIPE en cas de déconnexion soudaine de l'extrémité. recv() pour recevoir un flux. Appel bloquant jusqu'à ce qu'il y ait quelque chose de disponible. 30
IPC - Synchronisation Le système d'exploitation fournit les mécanismes pour contrôler l'accès concurrent par différents processus. cf cours "Programmation concurrente (PCO/PCE)" Le noyau est réentrant t Nécessité de gérer les accès concurrents sur les structures du noyau. Mutex Mécanismes de verrou utilisable au niveau des threads. Sémaphore Utilisation d'un compteur, d'une liste de processus, méthodes P() et V(). Processus 1 Processus 2 Standard: POSIX, System V 31
Processus - Ordonnancement Il faut déterminer quel processus va occuper le processeur. Les processus dans l'état ready sont examinés. Cette opération peut s'effectuer à différents instants, durant l'exécution du code noyau. Ces instants s'appellent points de préemption. Typiquement, un point de préemption peut survenir à la fin du traitement d'une routine de service (ISR). 32
Ordonnancement et points de préemption 1 Transition running waiting Peut préempter 2 Transition running ready 3 4 Transition waiting ready Transition running zombie Interruption par un timer unlock/ wakeup mutex/semaphore/signal queue lock/wait Dans le cas et il y a ordonnancement de processus et l'ordonnancement est dit non-préemptif Dans le cas et il peut y avoir ordonnancement de processus et l'ordonnancement est dit préemptif 33
Ordonnancement - Critères Taux d'utilisation du CPU Rapport temps CPU / temps écoulé Il faut tenir compte des entrées/sorties. Lié au degré de multiprogrammation Délai de rotation (turnaround) Temps écoulé entre la soumission du processus jusqu'à sa terminaison Intéressant lorsque l'on considère les I/Os Capacité de traitement (throughput) Une bonne capacité de traitement ne garantit pas un délai de rotation minimale. Temps d'attente (waiting time) Temps écoulé dans l'état ready 34
Ordonnancement - Burst Normalement, un processus effectue une alternance de cycle d'activité et de cycle d'entrée-sortie. Pour l'étude d'algorithmes d'ordonnancement, on considère uniquement des processus effectuant un cycle d'activité (sans entrée-sortie), que l'on appellera burst (rafale). Pour l'étude des performances, un processus effectuant des I/Os peut être décomposé en plusieurs processus sans I/Os. Le burst a une certaine durée. 35
Algorithmes d'ordonnancement FCFS First Come First Served SJF Shortest Job First RR Round-Robin Ordonnancement par priorité avec/sans files d'attente multiples 36
Ordonnancement - FCFS FCFS - First Come First Served (Premier arrivé, Premier servi) Gestion des processus à l'aide d'un FIFO Ordonnancement non-préemptif Facile à implémenter Sous-optimal Processus Durée P1 24 P2 3 P3 3 Cas 1 (P1, P2, P3) P 1 P 2 P 3 24 27 Cas 2 (P2, P3, P1) P 2 P 3 P 1 0 3 6 30 37
Ordonnancement SJF (1/2) SJF - Shortest Job First (Job le plus court d'abord) Processus Durée Arrivée Sélection du processus nécessitant le moins de temps d'exécution (le prochain burst le plus court) Ordonnancement non-préemptif ou préemptif Difficile à implémenter Optimal P1 7 0.0 P2 4 2.0 P3 1 4.0 P4 4 5.0 Cas non-préemptif 0 P 1 P 3 P 2 P 4 7 8 12 16 Cas préemptif P 1 P 2 P 3 P 2 P 4 P 1 0 2 4 5 7 11 16 38
Ordonnancement SJF (2/2) SJF est impossible à implémenter en tant que tel. Impossible de connaître la longueur du prochain burst. On peut faire une approximation. La longueur du prochain burst peut être estimé au moyen d'une estimation basée sur les durées précédentes. Ordonnancement à long terme Nécessite l'observation des durées d'exécution. Possibilité de pondérer la dernière observation avec la dernière estimation. 39
Ordonnancement - RR RR - Round Robin (Tourniquet) Il s'agit d'un FCFS avec l'introduction d'une tranche ou quantum de temps (time slice) Ordonnancement préemptif Processuss Durée P1 24 P2 3 P3 5 Très utilisé Quantum = 4 ms P 1 P 2 P 3 P 1 P 3 P 1 P 1 P 1 24 28 P 1 0 4 7 11 15 16 20 32 40
Ordonnancement - Priorité (1/3) Ordonnancement par priorité Un processus ne peut s'exécuter que si aucun processus de priorité supérieure n'est dans l'état ready. Si tous les processus ont la même priorité, c'est la politique FIFO qui est appliquée. SCHED_FIFO Priorité dynamique Augmentation graduelle de la priorité des processus en basse priorité Evite la famine des processus. Ordonnancement non-préemptif ou préemptif Processus Durée Priorité P1 10 3 P2 1 1 P3 2 4 P4 1 5 P5 5 2 P 2 P 5 P 1 P 3 P 4 0 1 6 16 18 19 41
Ordonnancement - Priorité (2/3) Files d'attente multiples Chaque file d'attente à sa propre politique d'ordonnancement File haute priorité: RR File basse priorité: FCFS 42
Ordonnancement - Priorité (3/3) Files multiples avec rétroaction Un processus peut être amené à changer de file au cours de son exécution. Il reste à définir une bonne stratégie de changement. RR, quantum = 8 Priorité dynamique RR, quantum = 16 FCFS 43
Références & Figures A. Silberschatz et al.: "Operating Systems Concepts", 6 th edition, Wiley Andrew Tanenbaum, "Systèmes d'exploitation", 2ème édition 44