État de l art associé au projet tuteuré Réalisation d un OS 32 bits pour PC(x86) Maxime Chéramy <mcheramy@etud.insa-toulouse.fr> Benjamin Hautbois <bhautboi@etud.insa-toulouse.fr> Nicolas Floquet <nfloquet@etud.insa-toulouse.fr> Simon Vernhes <vernhes@etud.insa-toulouse.fr> 4ème année Informatique Résumé du projet Les systèmes d exploitations sont au coeur du fonctionnement des ordinateurs. Cette partie logicielle fait le lien entre le matériel et les applications que nous utilisons au quotidien. Un non initié, ne se doute probablement pas de la complexité et de l importance des mécanismes mis en place pour le bon fonctionnement du système. Nous verrons à travers ce rapport, que les systèmes d exploitations sont activement développés et que les différents mécanismes utilisés font l objet de nombreuses recherches à l heure actuelle. L aboutissement de nos recherches nous permettra l écriture d un système d exploitation 32 bits pour architecture Intel x86 dans le cadre des projets tutorés de 4ème année Informatique à l INSA de Toulouse. Nous avons décidé d axer nos recherches sur l étude des différents types de noyaux de système d exploitation dans un premier temps, puis nous nous concentrerons sur le cas des micro-noyaux qui constituent selon nous un type de noyau très intéressant et prometteur. Dans cette seconde partie, nous détaillerons les principaux éléments mis en jeu même s ils ne sont pas toujours spécifiques à ce type de noyau. L objectif de notre projet tutoré est de réaliser un système d exploitation utilisant un micro-noyau. Celui-ci sera capable de lancer plusieurs processus simultanément. Cela implique donc l écriture d un ordonnanceur, d une gestion de la mémoire de manière sécurisée et du chargement en mémoire d un programme. D un point de vue utilisateur, notre système fournira une Interface Homme-Machine très rudimentaire. État de l art associé au projet tuteuré Page 1
Table des matières 1 Introduction à la notion de système d exploitation 3 1.1 Présentation.................................................. 3 1.2 Les différents types de systèmes d exploitation............................... 3 1.3 Évolution................................................... 3 2 Noyaux de systèmes d exploitations 4 2.1 Introduction.................................................. 4 2.2 Types de noyaux existants.......................................... 4 2.2.1 Noyaux monolithiques non modulaires............................... 4 2.2.2 Noyaux monolithiques modulaires................................. 4 2.2.3 Micro-Noyaux............................................. 4 2.2.4 Noyaux hybrides........................................... 5 2.2.5 Exo-noyaux.............................................. 5 2.3 Les micro-noyaux............................................... 5 3 Les différents éléments qui constituent un micro-noyau 6 3.1 Ordonnanceur................................................. 6 3.1.1 Rôle d un ordonnanceur et principales caractéristiques...................... 6 3.1.2 Algorithmes.............................................. 6 3.1.3 Vocabulaire.............................................. 9 3.2 Communication Inter-Processus (IPC)................................... 9 3.2.1 Fichier................................................. 9 3.2.2 Signaux................................................ 9 3.2.3 Socket................................................. 10 3.2.4 Message queue............................................ 10 3.2.5 Sémaphore.............................................. 10 3.2.6 Mémoire partagé........................................... 10 3.2.7 Message passing........................................... 10 3.3 Mémoire.................................................... 11 3.3.1 Unité de gestion de mémoire.................................... 11 3.3.2 Mémoire segmentée......................................... 11 3.3.3 Mémoire paginée........................................... 11 3.3.4 Mémoire virtuelle paginée...................................... 12 3.3.5 Algorithmes de pagination...................................... 13 3.3.6 Protection de la mémoire...................................... 14 3.3.7 Vocabulaire.............................................. 14 3.4 Pilotes..................................................... 14 3.5 Système de fichiers.............................................. 14 4 Conclusion 16 5 Bibliographie 17 État de l art associé au projet tuteuré Page 2
1 Introduction à la notion de système d exploitation 1.1 Présentation Un système d exploitation est la couche logicielle qui s exécute entre le matériel et les applications. Cette couche peut avoir plusieurs rôles, parmi les plus importants on trouvera : fournir une interface de programmation simplifiée, grâce aux appels système. Notamment pour fournir une abstraction par rapport au matériel. Mais aussi permettre aux différentes applications de communiquer entres elles (communication inter-processus). gérer l exécution des tâches : on parlera de système d exploitation mono-tâche si celui si ne peut en exécuter qu une à la fois, et de système d exploitation multi-tâche si celui-ci peut gérer plusieurs tâches en même temps. Dans ce cas, il se chargera alors d allouer à chaque tâche un temps d utilisation du processeur, on parlera d ordonnancement. protéger le système des erreurs que pourraient provoquer les applications. 1.2 Les différents types de systèmes d exploitation Dans l absolu, il pourrait exister un type de système d exploitation pour chaque utilisation que l on voudrait en faire. Dans la réalité il se trouve que les systèmes d exploitations les plus courants peuvent rentrer dans certaines catégories. On distinguera dans un premier temps les systèmes mono-tâche des systèmes multi-tâche. Ensuite, selon si le système d exploitation permet une gestion de différents utilisateurs avec des droits attribués, ou ne gère qu un seul utilisateur, on parlera de système multi-utilisateur, ou de système mono-utilisateur. Ces deux distinctions sont, à l heure actuelle, un peu désuètes, étant donné qu il existe de moins en moins de systèmes d exploitation ne permettant pas la gestion de plusieurs tâches et de plusieurs utilisateurs. Il existe cependant une dernière catégorie de systèmes d exploitation qui gagne de l importance de nos jours. En effet, si la plupart des systèmes peuvent convenir au grand public dans un usage qui n est pas critique, certaines applications comme l aéronautique réclament d importantes contraintes sur le temps d exécution des taches. On appellera systèmes d exploitation temps-réel les systèmes d exploitation permettant de répondre rigoureusement à ces contraintes. Les systèmes d exploitation les plus connus (Windows, MacOS, Linux) sont multi-tâches et multi-utilisateurs, Windows et Linux offrent cependant des déclinaisons orientées temps-réel (telles que Windows CE et RTLinux). 1.3 Évolution Au cours de l histoire de l informatique le rôle des systèmes d exploitations a grandement évolué. [1] 1940 - Premiers ordinateurs chers et rares, la programmation se faisait à bas niveau et on exécutait un seul programme à la fois. Pas de véritables besoin de recourir à une couche telle qu un système d exploitation. 1960 - Apparition de la multiprogrammation. On se rend compte que les programmes sont fortement ralentis par les entrées/sorties. L idée émerge donc d exécuter plusieurs applications en même temps (afin de profiter du temps de calcul autrement perdu lorsque le premier programme attend les E/S). Ceci entraine le besoin d avoir un dispositif pour gérer la répartition des ressources en puissance calcul, c est la naissance des premiers systèmes d exploitation basiques. 1975 - Apparition de la micro-informatique. La démocratisation de l informatique apporte de nouveaux enjeux tels que la possibilité d avoir plusieurs utilisateurs sur la même machine. Il s agit également de l arrivée des interfaces graphiques. 2005 - On commence à voir apparaitre des systèmes d exploitation là où on ne se attendait pas à les voir. Désormais il n est pas rare que nos téléphones portables voire même nos téléviseurs tournent sur ce qui a tout d un système d exploitation. Dans les années à venir les systèmes d exploitation tels que nous les connaissons seront surement amenés à changer. Les services tels que le mail et la bureautique migrant de plus en plus vers Internet, il est probable que nous rencontrions bientôt des systèmes d exploitation minimalistes à l instar de ChromeOS, conçus pour s appuyer sur cette tendance dite du Cloud Computing. État de l art associé au projet tuteuré Page 3
2 Noyaux de systèmes d exploitations 2.1 Introduction La plupart des systèmes d exploitation respectent une organisation en couches. Chaque couche apporte un niveau d abstraction supplémentaire sur lequel la couche suivante peut s appuyer [2]. Dans l ensemble on identifie (de la couche d abstraction la plus élevée jusqu au matériel lui-même) : L espace utilisateur (user space) : il s agit du niveau dans lequel s exécutent les applications, si le système d exploitation offre une interface de communication avec l utilisateur (qu elle soit graphique ou non) elle s exécute à ce niveau. Cette interface est appelée le Shell. L espace noyau (kernel space) : il s agit du niveau dans lequel s exécutent les composants du système d exploitation (le noyau), ce niveau peut être lui aussi découpé en couches, l organisation de ces couches dépend du type de noyau. Les applications qui tournent dans l espace noyau n ont aucune restriction et il est donc important de tester de manière intensive ces applications pour ne pas compromettre la stabilité du système tout entier. Le matériel : il ne fait pas parti du système d exploitation, le noyau est responsable de fournir une couche d abstraction pour celui-ci, grâce aux pilotes. Chaque différent type de noyau définit où les différentes fonctionnalités du système d exploitation doivent se trouver (dualité entre espace noyau et espace utilisateur). 2.2 Types de noyaux existants 2.2.1 Noyaux monolithiques non modulaires Dans un noyau monolithique, les fonctions du système et les pilotes sont regroupés dans le kernel space généré à la compilation. L avantage d avoir les drivers dans le noyau est de limiter le nombre d appels système qui sont lents. Les inconvénients sont un kernel énorme et donc difficile à maintenir. De plus, il faut charger un noyau avec tous les drivers même ceux qui ne sont que rarement utilisés. Un autre problème des noyaux monolithiques est la sécurité et la stabilité du système : une erreur dans un module met en danger la stabilité de tout le système. Exemples : MS-DOS et Linux avant la version 1.2. 2.2.2 Noyaux monolithiques modulaires Pour palier le problème de noyau trop gros, seules les fonctions fondamentales du noyau sont gardés dans un bloc monolithique. Les pilotes de périphériques sont séparés sous la forme de module qui pourront être chargés à chaud. Le problème de stabilité n est pas résolu par les modules puisqu ils sont toujours dans le kernel space contrairement aux Micro-Noyaux. Exemples : Linux et BSD. 2.2.3 Micro-Noyaux Pour obtenir un noyau plus facilement maintenable mais aussi beaucoup plus stable, les micro-noyaux déplacent la plupart des fonctionnalités dans l user-space. Ces fonctionnalités sont alors regroupés sous forme de petits serveurs indépendants. La section 2.3 expose plus en détails les différents aspects des micro-noyaux. Exemples : Le noyau L4 (utilisé par Hurd depuis 2004) et Singularity (projet expérimental de Microsoft). État de l art associé au projet tuteuré Page 4
2.2.4 Noyaux hybrides Les noyaux hybrides combinent les avantages des noyaux monolithiques et des micro-noyaux. En effet, la première génération de micro-noyaux était certes intéressant mais avait pour défaut d être beaucoup trop lente à cause des nombreux appels systèmes. L idée des noyaux hybrides est donc de prendre les avantages et l idée de base des micro-noyaux mais de faire revenir dans le kernel certaines fonctions non essentielles mais gourmandes en appels système. Exemples : Les noyaux de la famille Windows NT (2000, XP, Vista, 7) 2.2.5 Exo-noyaux Un Exo-noyau reprend l idée d un micro-noyau mais en la poussant un peu plus à l extrême. La théorie part du principe que le noyau qui est placé entre la couche hardware et l user-space va trop ralentir la machine (notamment à cause des nombreux appels systèmes, des changements de contexte). L idée des exo-noyaux est donc d avoir un noyau vraiment minimaliste laissant les applications accéder aux ressources hardware directement en leur offrant seulement une protection lors de ces accès. Chaque application pourrait lier une bibliothèque de type libos qui gérerait par exemple les fichiers, les ipc, la communication réseau, etc. Ces bibliothèques remplaceraient les différentes fonctionnalités offertes généralement par le noyau. 2.3 Les micro-noyaux Un micro-noyau n implémente que des mécanismes basiques comme la gestion de la mémoire virtuelle, un ordonnanceur et la communication inter-processus. Tous les mécanismes plus évolués (tel que la gestion des systèmes de fichiers, les drivers, accès au réseau...) sont séparés dans différents serveurs (assimilable aux daemons UNIX) et sont exécutés dans l espace utilisateur. Dans un telle configuration, on voit bien que la gestion de la communication entre les processus va être primordial. En effet, toutes les actions qui habituellement nécessitent un appel système va maintenant nécessiter le dialogue avec le serveur responsable de l action que le processus désire accomplir. Prenons l exemple de l écriture sur le disque dur : il va donc falloir communiquer avec le serveur capable d écrire sur le disque dur, tout ceci en réalisant de nombreux appels systèmes pour la communication inter-processus. Il est donc très important de veiller à obtenir de très bonnes performances pour les IPC [3]. Avantages Stabilité : un maximum de services tournent en user space et bénéficient de la protection de la mémoire [4]. Sécurité : Limitation des accès matériels. Simplicité : Faible dépendance entre les modules, protection mémoire. Portabilité : Grace à une meilleure séparation des modules et un nombre de ligne réduit. (Minix, un microkernel écrit par Tanenbaum possède seulement 5000 lignes de codes). Inconvénients Lent : nombreux appels système couteux en temps. Contestation de la simplicité : définition de nombreuses API [5]. État de l art associé au projet tuteuré Page 5
3 Les différents éléments qui constituent un micro-noyau 3.1 Ordonnanceur 3.1.1 Rôle d un ordonnanceur et principales caractéristiques Le rôle de l ordonnanceur dans un système d exploitation multi-tâche est de choisir le processus à exécuter sur le ou les processeurs de l ordinateur. Il existe de nombreuses stratégies différentes pour ordonnancer les processus et le choix d un algorithme d ordonnancement va avoir un grand impact sur le comportement du système en terme de performances et de réactivité. Ce choix peut varier en fonction des contraintes que nous imposons à notre système, ainsi, par exemple, un système temps réel impose des contraintes supplémentaires sur les temps d exécution alors que pour un système d exploitation grand public, on souhaite avant tout un système réactif. Dans cette partie, nous allons étudier différents algorithmes en mettant en avant leurs qualités et leurs défauts. Avant de lister ces algorithmes, il est important de lister les critères d évaluation d un ordonnanceur : Utilisation du processeur au maximum Capacité de traitement : quantité de processus terminés par unité de temps Temps de restitution : temps entre la soumission d un job et date de terminaison Temps d attente : somme des temps d attente des processus Temps de réponse : temps entre la soumission d une requête et la réponse Nous verrons que certains algorithmes sont dit à temps partagé, cela signifie que plusieurs processus peuvent être exécutés en même temps par alternance afin d éviter qu un processus très long puisse bloquer les autres processus. Pour cela, l ordonnanceur va arrêter l exécution d un processus pour en relancer un autre et ainsi de suite. Cela a pour conséquence d apporter une sensation de réactivité au système mais de perdre en performance brut à cause de ces changements de contexte. Ce temps perdu est appelé overhead. Parmi les ordonnanceurs à temps partagés, on peut faire la distinction entre ceux qui sont préemptifs et ceux qui ne le sont pas. Un ordonnanceur préemptif est un ordonnanceur capable d interrompre l exécution d un processus pour placer sur le processeur un processus prioritaire. Dans ce dernier cas, il faut veiller à ne pas créer de famines, c est à dire des processus à qui on ne donne jamais de temps d exécution car ils ne sont pas assez prioritaires. 3.1.2 Algorithmes FIFO / FCFS L algorithme FIFO (First In First Out) ou FCFS (First Come First Served) est l un des algorithmes les plus simple qu il soit. L idée est d ajouter chaque processus dans une file et d exécuter chaque processus par ordre d arrivée. Avantages : Minimisation de l overhead dû aux changements de contextes. Très simple à implémenter. Inconvénients : Problème du temps partagé avec les gros processus. Pas de priorités. Shortest job first (SJF) / Plus court d abord L algorithme SJF ressemble au FIFO mais au lieu d exécuter les processus par ordre d arrivée, on choisi d exécuter celui qui sera le plus court. Mais le problème est de déterminer le temps d exécution d un processus avant de l exécuter et pour cela il faut se baser sur une estimation. Avantages : On favorise les processus courts ce qui augmente le débit de processus traités et donc la réactivité Faible overhead État de l art associé au projet tuteuré Page 6
Inconvénients : Problème du temps partagé si un gros processus trouvé l opportunité de se lancer. Risques de famine (un processus trop long pourrait ne jamais être exécuté s il y a toujours un plus court) Pour réduire le problème de temps partagé avec de gros processus, il existe une variante appelée Shortest remaining time qui apporte la notion de préemption. Ainsi, si un processus très long est lancé à un moment, il ne pourra pas bloquer l arrivée de nouveaux processus rapides d exécution. Augmentant ainsi la réactivité du système mais en augmentant l overhead en particulier s il y a beaucoup de création de processus. Earliest deadline first scheduling (EDF) Dans le même ordre d idée, on peut décider d exécuter en premier le processus qui nécessite d être fini le plus rapidement. Cet algorithme est utilisé pour les systèmes temps réel. C est un ordonnancement préemptif avec priorité dynamique : le processus le plus prioritaire est celui dont la date de fin et la plus proche. C est à dire que plus le travail doit être réalisé rapidement, plus il est prioritaire. Cependant, il est assez complexe à mettre en œuvre et il se comporte mal en cas de surcharge du système ce qui fait qu il est finalement peu utilisé [6]. L algorithme Brain Fuck Scheduler (BFS) qui est disponible sous Linux et qui a fait parler de lui en 2009 pour ses performances parfois meilleures que l ordonnanceur par défaut (CFS) est en partie basé sur une estimation de la date de fin. Round-Robin / Tourniquet L algorithme Round-Robin est très intéressant dans la mesure où il est à la base de plusieurs algorithmes plus sophistiqués. C est un système à temps partagé et bien qu il ne soit pas préemptif, certains algorithmes ont rajouté la notion de priorité au Round-Robin et l ont rendu préemptif. L idée générale est la suivante : Lorsque le processus est créé, il se met en fin de la liste. Lorsque le processus a accès au processeur, il ne peut l utiliser que pendant un certain Quantum de temps q. À l expiration de ce quantum de temps, ou s il a fini avant (ou s il est bloqué en entrée/sortie), il laisse automatiquement sa place pour le processus suivant. S il y a n processus dans la file d attente avant la création, on sait que le processus aura accès au processeur dans moins de n q. Le choix du quantum q va permettre de choisir le comportement de notre système. En effet, si q = 4 ms et si changer de processus prend 1 ms, on perd 20% du temps en changement de contexte! En pratique, le choix du quantum se fait entre 10 et 100ms. Pour résumer : Un quantum trop court implique beaucoup de changements de contexte (overhead), Un quantum trop long fait tendre le système vers un algorithme de type FIFO (FIFO si q est supérieur au temps d exécution des processus). Fixed priority pre-emptive scheduling Les concepts utilisés par cet algorithme sont : Chaque processus possède une priorité fixe. L ordonnanceur exécute toujours le processus de plus haute priorité et peut interrompre l exécution d un processus pour accepter un processus de plus haute priorité (préemption). De manière optionnelle, l ordonnanceur peut interrompre l exécution d un processus au bout d un certain temps pour éviter qu un processus s accapare tout le CPU. Ce type d algorithme est utilisé dans les systèmes temps réel mais son principal inconvénient est le risque de famine. Une solution à ce problème serait d augmenter la priorité d un processus avec le temps (vieillissement) mais ce ne serait alors plus le même ordonnanceur! État de l art associé au projet tuteuré Page 7
Files multi-niveaux à retour / Multilevel feedback queue Un ordonnanceur de type files multi-niveaux à retour est un ordonnanceur qui va faire tourner en temps partagé plusieurs ordonnanceurs différents. Pour mieux comprendre le principe commençons par le cas le plus simple d un système à deux niveaux : On classe les processus en 2 catégories : premier plan (interactif, court) arrière plan (calculs longs) Chaque catégorie possède sa file avec un ordonnancement différent : premier plan : Round Robin arrière plan : FIFO Puis nous allons ordonnancer ces deux files par tranches de temps : Nous allons par exemple donner 80% du temps à la file en arrière plan et 20% du temps à la file au premier plan. Si un processus au premier plan semble être trop long, il peut être changé de file. Ce choix de tranches de temps au lieu d un système basé sur des priorités est fait pour éviter les risques de famines. En effet, s il y a toujours un processus interactif à exécuter, les processus en arrière plan ne seraient jamais exécutés. Il est tout à fait possible d étendre le système à n files : Ainsi, de manière générale un ordonnanceur de files multi-niveaux à retour est défini selon les paramètres suivants : Nombre de files Politique d ordonnancement pour chaque file Méthode déterminant la promotion d un processus vers une file d attente plus prioritaire Méthode déterminant la destitution d un processus dans une file moins prioritaire Méthode déterminant dans quelle file placer un nouveau processus On peut alors avoir une file avec les processus qui ont besoin d un très bon temps de réponse avec un quantum faible, une file pour les processus classiques avec un quantum moyen, ainsi qu une file pour les taches de fond avec un quantum très grand ou encore en FIFO. Et nous pourrions choisir comme politique de changement de file : On place le nouveau processus dans la file la plus réactive et prioritaire et si à la fin du quantum le processus n est pas terminé, on le déplace dans la file moins prioritaire, etc. Enfin, si le processus passe à l état bloqué (attente d une entrée-sortie par exemple), il est alors promu à la file plus prioritaire. Autres Ordonnanceurs Lottery scheduling : on donne un certain nombre de tickets de loterie aux processus en fonction de leur priorité puis on tire au hasard un ticket pour élire le processus qui pourra utiliser le CPU. Il n y a théoriquement pas de risque de famine car la probabilité de tirer un ticket n est jamais nulle. Rate-Monotonic Scheduling : Il attribue la priorité la plus forte à la tâche qui possède la plus petite période. C est destiné aux systèmes temps réel et c est utilisé dans RTEMS. Swappable Schedulers : L idée serait d avoir un ordonnanceur par utilisateur comme ça on peut fournir la possibilité à l utilisateur de choisir son scheduler en fonction de ce qu il veut faire. L utilisateur root utiliserait toujours du round robin. O(1) scheduler : Ordonnanceur utilisé dans les noyaux linux de la version 2.6.0 à la version 2.6.22. Ordonnancement à temps constant (Gigue nulle). Repose sur un sytème de priorité dynamique calculée à partir du temps passé en attente [7]. Completely Fair Scheduler (CFS) : Ordonnanceur utilisé par le noyau Linux depuis la version 2.6.23. L ordonnanceur choisi le processus qui manque de temps d allocation au processus comparé au cas du multi-tâche idéal (ie. chaque processus est lancé en parallèle des autres et à la même vitesse.) ULE scheduler : Ordonnanceur utilisé par FreeBSD 8.0. Optimisé pour gérer au mieux les architectures à plusieurs processeurs [8]. État de l art associé au projet tuteuré Page 8
3.1.3 Vocabulaire Préemption : la préemption est la capacité d un système d exploitation multi-tâche à exécuter ou stopper une tâche planifiée en cours en faveur d une tâche de priorité supérieure. (meilleure réactivité) Famine : Les processus de plus basse priorité ne peuvent jamais s exécuter. (Solution classique : augmenter la priorité avec le temps : vieillissement) Overhead / Surcoût : Temps supplémentaire nécessaire au mécanisme utilisé. Ex : commutation de contexte pour changer de tâche active. Jitter / Gigue : dans le cas d un ordonnanceur, cela représente les variations du temps d ordonnancement en fonction du nombre de processus à traiter. 3.2 Communication Inter-Processus (IPC) La communication inter-processus regroupe un ensemble de mécanismes essentiels à un système d exploitation multi-tâche. Ces mécanismes peuvent permettre la communication et la synchronisation entre plusieurs processus concurrents du système. La communication inter-processus est un aspect qui doit être étudié avec précaution sur un système à micronoyau car c est un mécanisme qui devient fondamental pour assurer la communication entres les différents services. La communication est donc un facteur limitant à la performance du micro-noyau. Nous allons donc détailler les différents mécanismes de communication et de synchronisation et nous attacher à présenter les différents avantages et inconvénient de chacun. Ces mécanismes sont complémentaires et il convient de choisir celui qui correspond le mieux aux besoins de l application. 3.2.1 Fichier Une première solution pour partager des données entre processus est de le faire à travers un fichier. Il faut cependant généralement le coupler avec un autre mécanisme pour la synchronisation. Avantages Simple Possibilité de stocker beaucoup d informations (stockage sur disque dur) Inconvénient Lent 3.2.2 Signaux Il s agit d une méthode de notification asynchrone. Il s agit donc d un simple envoi de signal. Un mécanisme de type handler doit être implémenté par le processus receveur de signaux pour traiter ceux-ci. Un processus peut aussi choisir d ignorer le signal. Un signal peut interrompre n importe qu elle action (non atomique), même un appel système. Il peut donc résulter certaines erreurs en cas de non synchronisation entre les actions de l handler et celles du processus luimême. Avantages Très rapide Inconvénient Peu d informations véhiculées État de l art associé au projet tuteuré Page 9
3.2.3 Socket Il s agit d un système permettant la création d un canal de communication entre 2 processus de différent type : Stream : habituellement asymétrique (Client/Serveur) mais communication bidirectionnelle sous forme de flux de données. Une connexion doit être établie au préalable. Une fragmentation possible des paquets transmis. Exemple : TCP Datagram : ne demande pas qu une connexion soit établie au préalable. Déséquencement et perte de paquet possible. Sequenced : même chose que stream mais sans fragmentation raw : envoie des paquet directement au niveau liaison en évitant l encapsulation des protocoles applicatifs du système d exploitation. Avantages Polyvalent Inconvénient Lent 3.2.4 Message queue Utilisation d une file de message pour communiquer entre processus ou threads. Chaque message est associé à un type et une taille explicite. Lors de la récupération d un message dans la file, on peut choisir le type de message que l on veut. Les fonctions de lectures peuvent être bloquantes ou non bloquantes. Avantages Sélection du type de message à lire. 3.2.5 Sémaphore Un sémaphore permet de protéger l accès aux ressources critiques. 2 méthodes : P(s) / Wait(s) : mise en attente d un jeton V(s) / Signal(s) : rendre un jeton Un Sémaphore peut-être initialisé avec plusieurs jetons et peut permettre de résoudre certains problèmes, typiquement celui du dîner des philosophes mais aussi celui des lecteurs/rédacteurs. 3.2.6 Mémoire partagé Il s agit d une zone mémoire partagé entre plusieurs processus. Elle permet d éviter la redondance d informations. Avantages Accès très rapide à une donnée partageable entre plusieurs processus Inconvénient demande une synchronisation externe pour l accès à une mémoire partagée (ce qui ralentit le mécanisme) 3.2.7 Message passing Il s agit d un système très simple de communication. Un processus (p1) envoie un message à une autre processus (p2) et attend (fonction bloquante) la réception de ce message par p2, puis p1 attend la réponse de p2. C est une méthode d implémentation d un protocole de communication, utilisé par exemple par SOAP. État de l art associé au projet tuteuré Page 10
3.3 Mémoire Dans un ordinateur, il existe différents types de mémoire. Idéalement il n y aurait qu un seul type de mémoire qui serait rapide, peu onéreux, peu encombrant et possédant une grande capacité de stockage (non volatile). Malheureusement on constate que les mémoires les plus rapides ne sont pas persistantes et que plus elles sont rapides et plus elles sont chères [9]. Type de mémoire Taille typique Vitesse typique Registres 256 octets 0.5 ns Cache L1 16 Kio 1 ns Cache L2 2 Mio 2 ns Mémoire centrale 2 Gio 10 ns Disque dur 300 Gio 10 ms Tab. 1 Vitesses typiques des différents types de mémoire. En simplifiant quelques peu, cette mémoire est hiérarchisée de telle sorte que la couche de mémoire plus rapide sert de mémoire cache à la mémoire plus lente (Tab. 1). Le système d exploitation s occupe de gérer la gestion mémoire centrale et le disque dur, généralement à travers des mécanismes de mémoire virtuelle. Nous nous intéressons donc ici à la gestion de la mémoire centrale par le système d exploitation. Pour cela nous allons expliquer les différents concepts mis en place. Certains termes sont explicités en fin de partie. 3.3.1 Unité de gestion de mémoire L unité de gestion de mémoire (ou MMU de Memory Management Unit) est un composant physique de l architecture d un ordinateur. Autrefois séparée du processeur, elle est désormais intégrée. Son rôle principal consiste à faire de la translation d adresse, c est-à-dire gérer la segmentation et la pagination pour traduire une adresse virtuelle en adresse linéaire physique. La MMU remplit également un rôle important dans la sécurisation d un système d exploitation, car elle est en mesure de lever des exceptions en cas d accès non autorisés à la mémoire (menant à une erreur de segmentation par exemple). 3.3.2 Mémoire segmentée Un segment est un espace de la mémoire continue définit par l adresse du début et sa longueur. L adresse logique 0 représente la base du segment. Chaque segment est décrit par un descripteur de segment (structure à 8 octets) et est utilisé avec le sélecteur de segment pour permettre la traduction de l adresse. Le descripteur de segment contient toutes les informations nécessaires pour la traduction d adresse et le sélecteur de segment permet de récupérer le descripteur dans la table GDT 1 ou LDT. La protection de la mémoire est assurée par le flag DPL du descripteur (et le Request Privilege Level du sélecteur), chaque segment a un niveau de 0 à 3. Chaque processus dispose de sa table de descripteurs afin de savoir quels sont les zones mémoires autorisées en lecture ou écriture et ainsi interdire à un processus d écrire sur la mémoire d un autre. Les segments se chevauchent car l adresse de base du segment est codé sur 16 bits tandis que sa longueur peut aller jusqu à 32 bits. Une zone mémoire peut être adressé par plusieurs couples segment/offset. Le problème principal de la mémoire segmentée est la fragmentation externe : il est difficile de trouver un espace mémoire pour loger un segment tout en limitant les espaces non utilisables, car trop petits, entre les segments. Réordonner les segments pour réduire la fragmentation est une opération coûteuse. 3.3.3 Mémoire paginée Les pages sont des segments de petite taille ayant la particularité d être de taille fixe. Elles sont accompagnées d un mécanisme permettant un adresse linéaire. La pagination sert à palier les insuffisances de la segmentation, c est à dire : 1 Global Descriptor Table (GDT) : structure de données utilisées dans l architecture x86 pour référencer les descripteurs de segment. État de l art associé au projet tuteuré Page 11
la faible granularité (si la mémoire d un programme est mise sur un unique segment), le risque de fragmentation, le manque de transparence pour les langages de haut niveau. La mémoire physique est découpée en cadres de page qui pourront accueillir des pages. Les cadres ont bien entendu la même taille et dans le cas le plus fréquent, les cadres de page et les pages ont une taille de 4 Kio (cas des processeurs x86). Nous nous placerons dans ce cas pour la suite des explications tout en gardant en tête que cette taille n est pas imposée et qu il est tout à fait possible de trouver d autres tailles de page. Nous ferons aussi l hypothèse que les adresses mémoires son codées sur 32 bits. La distinction entre pages et cadres de page permet de mettre en place un mécanisme de mémoire virtuelle qui sera expliqué par la suite. Il peut en effet il y avoir plus de pages que de cadres de page. Chaque processus dispose d un espace d adresse de 4 Gio soit 1024 * 1024 pages. L association entre pages et cadres de page sera assurée par l unité de pagination (MMU). Si chaque processus devait posséder une table de l ensemble des pages (a priori un tableau de plus d un million d entrées en grande partie vide) cela consommerait énormément de place en mémoire. Pour le prouver il suffit d imaginer un système avec 150 processus (nombre raisonnable pour un station de travail) : Chaque processus contient une table contenant 1048576 pages. Chaque page étant définie par une adresse de 32 bits (4 octets), cela nous donne une table de 4 Mio. Soit au total 600 Mio pour l ensemble des tables de 150 processus. Pour palier ce problème, une structure à deux niveaux est mise en place. On dispose donc de : Un tableau de 1024 adresses, de niveau 1, nommé catalogue de pages, 1 à 1024 tableaux de 1024 adresses, de niveau 2, nommé table de pages. Chacun de ces tableaux tient dans un cadre de page (1024*32 bits = 4 Kio). Une adresse n est donc plus définie par un numéro de page et d un décalage à l intérieur de cette page mais est définie comme ceci : les 10 bits de poids fort de l adresse désignent une entrée du tableau de niveau 1 contenant l adresse d une table de pages, les 10 bits suivants de l adresse désignent une entrée de cette table de pages. Cette entrée donne l adresse physique de la frame associée à la page, les 12 bits de poids faible donnent le déplacement dans la page. Dans les tables de pages, les entrées font 32 bits mais seuls 20 bits sont nécessaires puisque ce sont des adresses de cadre de page or il n y a que 2 20 pages. Les 12 bits restant servent donc à placer divers indicateurs, notamment le bit de présence. En cas d accès à une page dont le bit de présence est éteint une exception de type défaut de page est levée. Ceci peut être du à : une page n ayant pas de cadre de page car stockée ailleurs (cf mémoire virtuelle) une page non allouée par le programme. Concernant les problèmes de fragmentation, la pagination remplace la fragmentation externe par une fragmentation interne (page non complète). Au final il est cependant préférable d utiliser le mécanisme de pagination. Il est aussi possible de combiner segmentation et pagination pour obtenir une mémoire paginée segmentée. Le principe repose sur une mémoire découpée en segments mais possédant un redécoupage en pages. 3.3.4 Mémoire virtuelle paginée Comme nous venons de le voir, il peut il y avoir plus de pages que de cadres de page. Pour rappel, les cadres de page constituent un découpage de la mémoire physique ce qui signifie que l on va pouvoir utiliser d autres supports pour mémoriser des informations et donc étendre la taille de la mémoire. La possibilité d utiliser le disque dur comme zone mémoire est appelée swap. Il faut bien garder en tête que le disque dur est environ 1000 fois plus lent que la mémoire vive et qu il faut donc limiter ses accès ce qui amène donc à une réflexion autour des algorithmes à mettre en place. Le principe de la mémoire virtuelle paginée est le suivant : État de l art associé au projet tuteuré Page 12
La mémoire virtuelle est découpée en pages de taille fixe La mémoire physique est découpée en cadres de page de la même taille Lors d un accès mémoire, le système d exploitation demande à la MMU de traduire l adresse virtuelle en adresse physique. Soit la MMU y arrive et dans ce cas la donnée est disponible sur le bus de donnée. Soit la MMU lève une exception qui doit être traitée par l OS : Le système d exploitation va voir si l adresse pointe vers une zone mémoire appartenant à la mémoire virtuelle tel que le swap. S il ne trouve pas, il lève une erreur (segfault). S il trouve, il va essayer de déplacer l information dans la mémoire physique ( demande paging ). S il n y a plus de place dans la mémoire physique il va ce qu on appelle swaper : il va déplacer des informations jugées moins souvent utilisées dans le swap pour faire de la place dans la mémoire physique (l algorithme qui va choisir la zone mémoire à swaper va induire des différences de performance sur le système). Remarque : Il existe aussi la mémoire virtuelle segmentée qui repose sur le même principe que la mémoire virtuelle paginée. Cependant ce mécanisme est contraignant car les segments représentent de grandes zones mémoires contigües difficiles à remplacer. 3.3.5 Algorithmes de pagination Le but des algorithmes de pagination est de gérer la mémoire de manière à accéder aux données le plus vite possible. En effet lorsqu un système utilise la mémoire virtuelle, il faut limiter au maximum les lectures et écritures sur le disque dur qui est très lent. Choisir quelles pages garder dans la mémoire vive et quelles pages déplacer vers le swap pour faire de la place est un exercice difficile car il n est pas évident de prévoir quelles données les programmes vont avoir besoin à l avenir. Ce choix repose sur l une des stratégies présentées : FIFO : La page déplacée vers le swap correspond à la page amené en mémoire il y a le plus longtemps. Cet algorithme n est pas efficace mais présente l intérêt d être extrêmement simple. Son implémentation repose sur une file (structure FIFO). Seconde chance : Une variante de FIFO est l algorithme de la seconde chance : si la page est la plus ancienne mais qu elle a été accédée alors on la repositionne au début de la file après l avoir démarquée. Si la page la plus ancienne n a pas été accédée alors elle est choisie. Autres noms de cette stratégie : FINUFO et Algorithme de l Horloge (Clock). LFU (Least Frequently Used) : La page choisie par cette stratégie est celle qui a été la moins accédée. À chaque accès à une page, un compteur propre à cette page est incrémenté. Pour choisir la page, il faut parcourir l ensemble des compteurs. Mais une zone mémoire qui aurait été utilisée de manière intensive à un certain moment ne sera pas choisie. De plus il faut gérer de nombreux compteurs qui risqueraient de dépasser leur capacité. LRU (Least Recently Used) : Cet algorithme va choisir la page qui a été accédée il y a le plus longtemps. Pour cela, l algorithme utilise une liste contenant les pages ordonnées par date d accès : à chaque utilisation d une page, celle-ci est remontée en haut de la liste. NRU (Not Recently Used) : L algorithme élimine les pages n ayant pas été utilisées recemment Pour cela il utilise le bit R des pages, ce bit est regulierement remis à 0 et passe à 1 lorsqu une page est utilisée. Lorsque l algorithme doit eliminer une page il en choisi si possible une ayant le bit à 0. On peut l ameliorer en utilisant 4 etats au lieu de 2 1. Non référencées, non modifiées. 2. Non référencées, modifiées. État de l art associé au projet tuteuré Page 13
3. Référencées, non modifiées. 4. Référencées, modifiées. On choisira alors d écarter en priorité les pages dans l etat 1 puis 2 puis 3... Cet algorithme est relativement efficace mais necessite de modifier souvent l etat des bits ce qui peut être couteux. Aléatoire : Enfin, il est tout à fait possible de choisir la page aléatoirement. Mais comme on peut s en douter, ce n est pas une stratégie très efficace. 3.3.6 Protection de la mémoire Protection de la mémoire par la MMU Il existe plusieurs façons de gérer la segmentation : Basic Flat Model, Protected Flat Model et Multi-Segment Model. La dernière offre une meilleure protection : Chaque processus possède sa table de descripteur de segments et ses propres segments (certains peuvent être partagés entre processus). Ainsi, il n est pas possible pour un processus d accéder à une zone mémoire en dehors d un de ses segments, la MMU ne fera pas la traduction! Cependant, la pagination étant souvent utilisée et proposant un mécanisme de protection similaire, il n est pas forcément nécessaire de mettre en place un mécanisme complexe pour gérer la segmentation. Ainsi, c est le Basic Flat Model qui est le plus souvent utilisé. Autres protections L architecture Intel propose plusieurs solution en hardware pour protéger la mémoire. Au delà des interruptions proposées par la MMU, il est aussi possible sur certaines architecture x86 de mettre en place le NX-bit (No execution bit, ou XD-bit chez Intel, execution Disabled) qui permet d interdire l exécution de certaines zones mémoire. Cela amène à une version plus sécurisé de la machine de von Neumann, puisque données et code sont stockés au même endroit mais ne peuvent pas être traités de la même manière. 3.3.7 Vocabulaire Adresse logique : Une adresse logique consiste en un sélecteur de segment et un offset. Le sélecteur de segment est un identifiant unique pour un segment. Ce sélecteur de segment fourni entre autre un indice dans la table de description (GDT par ex) pour indiquer une structure appelée descripteur de segment. Descripteur de segment : Chaque segment possède un descripteur de segment qui contient la taille, les droits d accès et privilèges, le type de segment et l emplacement du premier bit dans l adresse linéaire. Adresse linéaire : L adresse linéaire est identique à l adresse physique lorsque la pagination est désactivée. Sinon il y a un système de pagination (mémoire virtuelle) qui s occupe de fournir la donnée souhaitée. 3.4 Pilotes Les pilotes (drivers) servent d interface logicielle pour que les programmes du plus haut niveau puissent communiquer avec le matériel. Les pilotes fournissent également les routines de gestion des interruptions matériel. Ils peuvent être exécuté en user space ou en kernel space. Chaque mode a ses avantages et ses inconvénients. En kernel space, un pilote sera plus rapide, ceci est particulièrement nécessaire pour du matériel nécessitant une forte bande passante et/ou une faible latence. En user space, un pilote apportera par contre de la stabilité en évitant de planter tout le système s il provoque une erreur. 3.5 Système de fichiers Un système de fichier est un schéma d organisation des données/fichiers (généralement sur une mémoire secondaire). Il permet notamment à l utilisateur de faire abstraction du fait que la mémoire n est qu un grand tableau en structurant les données (grâce aux fichiers, concept bien plus simple). État de l art associé au projet tuteuré Page 14
Un système de fichier se démarque par son organisation, la plupart des systèmes de fichiers sont hiérarchisés mais il en existe des plats, sans notions de dossiers. L identification d un fichier se fait la plupart du temps à partir de son nom (et de son chemin dans le cas des systèmes hiérarchisés). Il peut exister une limite de taille à la chaine de caractères qui stocke le nom du fichier (cf, la fameuse limite 8.3 des premiers FAT). Les systèmes de fichiers gèrent également diverses informations supplémentaires (méta-data) sur les fichiers, tel que les dates de modifications, les droits sur le fichier, l auteur, etc... On identifie différents types de systèmes de fichiers qui se différencient en fonction du support sur lequel ils vont être utilisés. Par exemple les systèmes de fichiers pour disques durs mécaniques (exemples : ext, FAT, NTFS) ont une architecture qui permettent de minimiser les déplacements des têtes de lectures. Ces architectures perdent tous leurs intérêts dès lors qu elles sont utilisées sur des disques SSD. Il existe donc des systèmes de fichiers pour SSD (exemple : YAFFS, LogFS). État de l art associé au projet tuteuré Page 15
4 Conclusion Un système d exploitation repose sur un ensemble de mécanismes pouvant être complexes et dont il faut faire le choix dès la conception. Ces mécanismes doivent alors ensuite être assemblés pour former un système fonctionnel. Nous avons décidé de nous orienter vers un système reposant sur un micro-noyau. En effet, les micro-noyaux sont plus jeunes et très prometteurs. La réalisation d un noyau monolithique nous parait moins enrichissante car c est quelque chose de très répandu et donc peu original. Nous visons à faire un système multi-tâche et pour cela nous avons besoin d un ordonnanceur. Parmi les différents algorithmes présentés, l algorithme de Files Multi-niveaux à Retour nous semble intéressant. Cependant nous commencerons par des algorithmes plus simples à implémenter tels que le FCFS et le Round-Robin qui sont de toute façon utilisés par les Files Multi-niveaux à Retour. La mémoire sera paginée sur deux niveaux tel que présenté dans ce document et si nous décidons d implémenter une mémoire virtuelle, elle sera également basée sur la pagination. Nous pensons implémenter le système de fichier FAT32 pour sa simplicité mais aussi parce que c est le système de fichier le plus répandu. Enfin, afin de tester notre système d exploitation il nous faudra également prévoir le développement certaines applications basiques ce qui implique de pouvoir charger des programmes qui ne sont pas intégrés au système d exploitation. Nous n avons pas déterminé précisément quels seraient ces logiciels mais nous pourrions par exemple développer une horloge, un éditeur de texte très basique ou encore de petits jeux. État de l art associé au projet tuteuré Page 16
5 Bibliographie Références [1] Tim Bergin. History of Operating Systems. [en ligne]. (modifié le 5 mars 2001). Disponible sur <http://www.computinghistorymuseum.org/teaching/papers/research/history_of_operating_ system_moumina.pdf>. [2] Thom Holwerda. Kernel designs explained. [en ligne]. (modifié en mars 2007). Disponible sur <http://www. osnews.com/files/17537/kernel_designs_explained.pdf>. [3] Jochen Liedtke. Improving IPC by Kernel Design. [en ligne]. asheville : German national research center for computer science (gmd), 1993. Disponible sur <http://l4ka.org/publications/1993/improving-ipc.pdf>. [4] Andy Tanenbaum. Tanenbaum-Torvalds Debate : Part II. [en ligne]. (modifié le 12 mai 2006). Disponible sur <http://www.cs.vu.nl/~ast/reliable-os/>. [5] Linus Torvalds. Re : LINUX is obsolete. [en ligne]. 1992. Disponible sur <http://oreilly.com/catalog/ opensources/book/appa.html>. [6] Sanjoy K. Baruah and Jayant R. Haritsa. Scheduling for Overload in Real-Time Systems. [en ligne]. septembre 1997. Disponible sur <http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=00620484>. [7] Josh Aas. Understanding the Linux 2.6.8.1 CPU Scheduler. [en ligne]. silicon graphics, inc. février 2005. Disponible sur <http://joshaas.net/linux/linux_cpu_scheduler.pdf>. [8] Jeff Roberson. ULE : A Modern Scheduler For FreeBSD. [en ligne]. Disponible sur <http://www.usenix. org/event/bsdcon03/tech/full_papers/roberson/roberson.pdf>. [9] Gaël Le Mignot. Système d exploitation : Gestion de la mémoire. [en ligne]. lieu d édition : Insia srt, 2007, 17p. Disponible sur : <http://cours.pilotsystems.net/cours-insia/ cours-de-systemes-dexploitation-ing2-srt/memory.pdf>. État de l art associé au projet tuteuré Page 17