Précédent Remonter Suivant
Page d'accueil de ce livre

Chapitre 10  Machines virtuelles et micro-noyaux


10.1  Notion de machine virtuelle

Les chapitres qui précèdent ont montré à plusieurs reprises que la conception d'une architecture informatique consistait le plus souvent en grande partie à organiser des niveaux d'abstraction différents afin de donner une intelligibilité supérieure à un mécanisme, ou au contraire pour le dissimuler aux yeux de l'utilisateur. Nous pouvons subsumer certains de ces artefacts sous la notion de machine virtuelle.

L'exemple le plus simple de machine virtuelle est donné par certains langages de programmation interprétés, qui fonctionnent finalement comme des calculettes : l'utilisateur entre au clavier une phrase du langage, l'interpréteur évalue la phrase et donne la réponse. L'interpréteur se présente à son utilisateur comme un ordinateur dont le langage machine serait le langage qu'en fait il traduit à la volée. Il est une machine virtuelle du langage considéré. Basic, Scheme, Python, le shell Unix sont des langages interprétés, par opposition aux langages compilés comme C, Scheme (oui, il peut être les deux), Ada, pour lesquels il faut d'abord écrire le texte du programme jusqu'au bout, puis le soumettre à un traducteur appelé compilateur qui le traduit en langage machine.

Le système d'exploitation présente une métaphore de l'ordinateur qu'il anime à l'utilisateur : celui-ci, en soumettant des phrases du langage de commande (ou en agissant sur les objets de l'interface graphique), agit symboliquement sur des abstractions, et déclenche ainsi des actions réelles d'objets matériels. On peut dire que le système d'exploitation exhibe une machine virtuelle qui représente de façon stylisée et elliptique la machine réelle, dont les aspects les plus sordides sont ainsi dissimulés.

10.1.1  Émulation et machines virtuelles

Assez tôt l'idée s'est fait jour qu'une telle possibilité pourrait être mieux exploitée : puisqu'un système d'exploitation est capable de donner une métaphore de la machine sous-jacente, pourquoi ne pourrait-il pas représenter une autre machine, qu'il simulerait ? Un tel programme est appelé un émulateur, dont on dit qu'il émule la machine simulée. Ainsi aux temps préhistoriques IBM fournissait un émulateur 7090 pour le système 360 qui permettait d'exploiter sur ce dernier les programmes écrits pour le premier. Des émulateurs d'Unix sur VAX sous VMS ont existé, ainsi que des émulateurs de VMS sous Unix. Apple et d'autres sociétés ont produit des logiciels qui émulent un PC sous Windows sur un Macintosh. L'inverse existe aussi d'ailleurs. Bref, il est ainsi possible d'utiliser le système et les logiciels destinés à un ordinateur que l'on ne possède pas, c'est pratique mais souvent les performances sont assez médiocres parce qu'il faut exécuter en fait le code de trois systèmes : le vrai système de la vraie machine, l'émulateur et le système émulé. Mais au fil des ans les techniques d'émulation ont atteint une perfection diabolique, et il est même possible d'exécuter sous Linux ou MacOS des logiciels de jeux destinés à Windows, exercice particulièrement délicat puisqu'il faut actionner des interfaces graphiques complexes, des manettes de pilotage, joysticks, manches à balai1 etc.

La société VMware Inc. de Palo Alto en Californie a développé une technologie très élaborée d'émulation généralisée : son logiciel de machine virtuelle fonctionne sur un PC à processeur Intel sous Linux, et il accueille un système hôte, par exemple Windows. Tous les accès de Windows au matériel sont interceptés de telle sorte que le système hôte ne puisse pas faire la distinction entre un périphérique réel et l'abstraction présentée par la machine virtuelle. L'émulateur peut d'ailleurs accueillir simultanément plusieurs machines virtuelles tournant sous des systèmes différents. C'est particulièrement utile pour un développeur qui veut tester ses programmes sur plusieurs types de plateformes.

10.1.2  De CP/67 à VM/CMS

La technologie mise en oeuvre par VMware remonte en fait à 1967, date de lancement d'une machine dont nous avons déjà parlé à la section 4.4.8, l'IBM 360/67, doté de l'« hyperviseur » CP/67 capable de supporter plusieurs machines virtuelles 360/65 tournant sous des versions de système différentes. On voit bien que ce type de méta-système a été inventé par les développeurs de systèmes (en l'occurrence ceux du Cambridge Research Lab. d'IBM) pour se faciliter la tâche en disposant de systèmes de test sans avoir à réclamer à leur management des machines supplémentaires, dont le prix à l'époque se comptait en millions de dollars. CP/67 a engendré VM/CMS, qu'IBM a commercialisé pendant les années 1970-1980. L'idée de CP/67 et de VM/CMS était un micro-système très dépouillé, fournissant des fonctions très élémentaires d'accès au matériel, et laissant la complexité au système des machines virtuelles accueillies. Ce dépouillement avait d'ailleurs des avantages, à tel point que certains clients utilisaient VM/CMS tout seul, sans machine virtuelle : ils disposaient ainsi d'une machine temps partagé simple et bon marché. C'est peut-être pour cette raison qu'IBM a laissé mourir VM/CMS, qui révélait que la complexité et la lourdeur de ses autres systèmes était peut-être inutile...

10.1.3  Java

La notion de machine virtuelle allait connaître un nouvel avatar avec le lancement par Sun Microsystems du langage Java en 1995, dont le concepteur principal était James Gosling. Rarement langage aura suscité un tel engouement, justifié non pas par sa syntaxe, assez banalement héritée de C débarassé de ses traits de bas niveau tels que les pointeurs et augmenté d'une couche simple de gestion des objets (ce qu'aurait dû être C++), ni par ses performances en termes de vitesse de calcul, assez déplorables, mais justement par sa machine virtuelle. Signalons deux autres traits novateurs de Java : il comporte un système de gestion des activités (threads) dans le langage ; les activités (threads) font l'objet de la section suivante, mais disons qu'il s'agit d'un moyen de faire de la multi-programmation à l'intérieur d'un processus utilisateur. Le jeu de caractères standard de Java est Unicode, ce qui autorise des identifiants en écriture coréenne Hangul, par exemple.

L'exécution d'un programme Java obéit à un enchaînement d'opérations inhabituel. Le texte du programme source est d'abord soumis à un compilateur, qui produit un résultat dans un langage intermédiaire appelé bytecode. Ce langage intermédiaire est le langage d'une machine virtuelle Java (JVM), et il suffit de soumettre le bytecode à l'interpréteur de la JVM pour que le programme s'exécute2.

Tout l'intérêt de la démarche réside dans le fait que la JVM est normalisée, c'est-à-dire qu'un programme Java compilé peut être exécuté tel quel sur n'importe quelle plate-forme (compile once, run anywhere), à la différence d'un programme en langage classique qui doit subir une compilation spécifique pour chaque architecture de machine cible et chaque système. La JVM est conçue pour être peu encombrante et sécurisée. Votre navigateur WWW comporte une JVM embarquée. Ainsi, un serveur WWW peut envoyer un petit programme Java (en anglais applet, soit en français appliquette, ou aplète) à votre navigateur WWW et celui-ci saura l'exécuter sur votre machine. Cela s'appelle du code mobile et c'est quand même assez révolutionnaire.

Cette possibilité pour un serveur d'exécuter du code sur une machine distante pose certes des problèmes de sécurité. Pour éviter les malveillances les plus évidentes la JVM exécute les aplètes dans un « bac à sable » (sandbox) qui les isole de l'environnement local. En fait Java a causé moins d'incidents de sécurité que de plantages de navigateurs ou de systèmes un peu fragiles ou que de chargements interminables de pages HTML passionnantes. La technologie est certes perfectible. En fait la principale cause du désenchantement relatif que subit Java aujourd'hui réside dans la politique assez opaque du propriétaire de la technologie qui modifie arbitrairement les règles du langage et de son implémentation, ce qui décourage les développeurs. Et le premier charme épuisé on redécouvre cette chose déplorablement banale : réaliser les calculs sur un serveur central correctement administré a quand même beaucoup d'avantages.

Quoi qu'il en soit, Java et sa JVM semblent promis à un bel avenir parce que ce système est assez facile à installer dans toutes sortes de petits processeurs qui peuplent les téléphones portables, les machines à laver, les routeurs d'appartement, les voitures, les caméscopes, les cartes à puce, etc., et cela renouvelle entièrement la programmation de ce genre d'objets, qui était auparavant de la magie noire. Les activités permettent même la réalisation de mini-systèmes d'exploitation en Java. Signalons aussi l'apparition de compilateurs pour d'autres langages que Java vers le bytecode, ce qui diversifie les moyens de créer des aplètes. Ainsi le compilateur Bigloo permet d'écrire ses aplètes en Scheme.




10.2  Les activités (threads)

10.2.1  Séparer le fil d'exécution des ressources allouées

Le chapitre 3 a défini la notion de processus et décrit le comportement de tels objets ; le chapitre 4 a expliqué la gestion de la mémoire : en fait le processus et son espace-adresse, que nous avons séparés pour la commodité de l'exposé, sont indissociables. Le processus, disions-nous, est une entité active constituée d'un programme en cours d'exécution et des ressources qui lui sont nécessaires : temps de processeur, fichiers ouverts, espace de mémoire. Nous pouvons isoler conceptuellement l'aspect « programme en cours d'exécution » en le désignant comme un fil, au sens de « fil de la conversation » (en anglais thread). Le terme français « fil » n'est pas très commode pour traduire thread parce que son pluriel a une graphie ambiguë. L'équipe du projet Chorus a lancé le mot « activité », qui convient bien, et c'est celui que nous utiliserons. Les attributs qui relèvent de l'activité (thread), par opposition aux ressources, sont les suivants : Le processus possède en outre les ressources suivantes : Il résulte de cette définition que le processus est une entité complexe, décrite par des tables nombreuses et encombrantes : table des pages à plusieurs niveaux, table des fichiers ouverts, etc. Une commutation de contexte entre processus implique notamment la commutation d'espace adresse, donc la remise à zéro du TLB, ce qui a un impact négatif lourd sur les performances de la pagination.

10.2.2  Définition de l'activité (thread)

De ces considérations naquit l'idée qu'il serait bien d'avoir des processus avec plusieurs fils d'exécution, ou, si l'on voit la question sous l'angle opposé, d'avoir des « processus légers » qui n'auraient pas besoin de recevoir toutes ces ressources neuves à leur lancement et qui se contenteraient de celles déjà possédées par leur processus père, qu'ils partageraient avec leurs frères3. Bref, cette démarche conduit à la naissance d'une entité spéciale, l'activité (thread) :

10.2.3  Avantages procurés par les activités

Les activités ainsi définies offrent de nombreux avantages : par exemple les navigateurs WWW font de la multi-activité (multithreading), ce qui permet d'avoir plusieurs fenêtres ouvertes dans lesquelles se chargent simultanément plusieurs pages de données, sans encourir le prix de lancement de multiples processus ; on observe bien que la première fenêtre s'ouvre beaucoup plus laborieusement que les suivantes. Et des processus distincts ne feraient pas l'affaire, parce qu'ils ne pourraient pas partager de façon simple le cache mémoire et le cache disque, ni les fichiers de signets. En outre, comme chaque activité dispose de sa propre pile et de son propre état, si elle émet des demandes d'entrée-sortie bloquantes (qui la mettent en attente), une autre activité pourra prendre le contrôle sans que le programme ait à prévoir quoi que ce soit de particulier, et la pseudo-simultanéité sera assurée « naturellement »4.

Le principal avantage reste la performance : créer et démarrer une activité demande jusqu'à cent fois moins de temps que la création d'un processus.

10.2.4  Implémentation des activités

Pour réaliser les activités, le concepteur de système a le choix entre deux possibilités : en mode utilisateur ou en mode noyau.

Activités en mode utilisateur

Les activités sont des objets purement internes au processus, dont le noyau n'a pas à être informé. Le processus gère totalement le partage des ressources et la pseudo-simultanéité entre les activités. Le système procure au processus une bibliothèque d'outils pour assurer cette gestion, notamment pour implanter les piles et les tables d'état des activités.


Figure 10.1 : Activités en mode noyau.


Activités en mode noyau

Le noyau gère les activités : création, ordonnancement, arrêt. Cela consomme plus de ressources que les activités en mode utilisateur, mais seule la gestion des activités en mode noyau permet le traitement correct des appels système bloquants dans une activité (par exemple une demande d'entrée-sortie), cas où il faut pouvoir ordonnancer une autre activité.

10.2.5  Inconvénients des activités

Les activités permettent une amélioration des performances de certains logiciels, au prix d'une complexité plus grande pour le développeur. Le principal problème soulevé est celui des variables globales. Un programme d'une certaine taille, nous l'avons signalé à la section 3.5, est subdivisé en sous-programmes. Nous avons évoqué les variables à la section 4.7. Les variables locales d'un sous-programme sont affectées sur la pile si elles sont petites (elles tiennent dans un mot), sinon elles sont affectées sur le tas mais repérées par un pointeur maintenu sur la pile. Comme nous avons dit que chaque activité disposait de sa propre pile, il n'y a en principe pas de risque qu'une activité accède à une variable locale appartenant à une autre. Mais le problème est plus difficile à résoudre pour les variables globales, visibles de tous les sous-programmes. Le problème est le même pour les accès aux fichiers. Dans ces deux cas, les précautions à prendre sont à la charge du développeur.

D'autres soucis incombent à l'auteur du système : certains sous-programmes de bibliothèque peuvent ne pas être réentrants, c'est-à-dire que leur comportement sera erroné s'ils sont appelés par un programme alors que le précédent appel par un autre programme n'est pas terminé. La cause la plus courante de ce type de problème vient de ce que le sous-programme a des variables réservées « en dur » dans son texte (au lieu d'être allouées dynamiquement sur le tas) et que ces variables reflètent l'état du calcul du premier appel, ce qui sème la confusion lors du second. Pour être réentrant, c'est-à-dire apte à être utilisé en une copie unique par deux appels concomitants, un programme doit posséder un texte invariant, c'est-à-dire non susceptible d'être modifié lors de son exécution. La désignation des objets externes qu'il manipule doit être extérieure à son texte. En bref, tout ce qui est variable doit être dans les registres, sur la pile, ou atteint au moyen d'une indirection passant par la pile ou par un registre (incidemment, sous Unix par exemple, les arguments qu'il reçoit du programme appelant sont sur la pile).

Ainsi, le sous-programme de bibliothèque qui exécute un appel système pour allouer une zone de mémoire sur le tas (malloc sous Unix) peut, lorsqu'il travaille dans un univers à fil d'exécution unique, laisser temporairement des tables de pointeurs dans un état incohérent, puisque s'il est interrompu ce sera par un autre processus, avec un autre espace adresse. Cette assertion cesse de tenir dans un univers à activités multiples... La solution consiste bien sûr à n'écrire que du code réentrant pour les sous-programmes de bibliothèque, mais le monde ne saurait être parfait...

En fait les difficultés d'implémentation des activités sont telles que l'on assiste à une relative désaffection pour cette technique dans le monde des développeurs au profit de techniques telles que la programmation par événements.




10.3  Micro-noyaux

Dans les systèmes tels que ceux que nous avons évoqués jusqu'à présent, le noyau désigne la partie du système d'exploitation dont la présence en mémoire réelle est indispensable et qui est commune à tous les autres logiciels. Dans un système tel qu'Unix, cet ensemble est monolithique (même si des Unix modernes tels que Linux ont introduit des modules chargeables dynamiquement en cours de fonctionnement) et il est devenu assez encombrant parce qu'y ont été incorporées par commodité des fonctions assez variées.

L'idée de micro-noyau est née dans les années 1980 ; il s'agit de réduire au minimum le contenu du noyau, et de placer en dehors, c'est-à-dire dans l'espace utilisateur, tout ce qui peut l'être. Les avantages de cette démarche semblent évidents : l'interface du micro-noyau sera plus simple que celle d'un macro-noyau, et permettra de ce fait la construction d'un système plus modulaire ; il est possible d'implanter au-dessus du micro-noyau des serveurs qui utilisent ses services pour exhiber le comportement, les caractéristiques et la sémantique de systèmes divers, comme Unix, Windows, MacOS etc., ce qui rejoint la notion de machine virtuelle et en facilite la réalisation ; en cas de panne d'un des serveurs, le système continue à fonctionner, ce qui facilite grandement tous les travaux de développement et de mise au point de système tout en augmentant la tolérance aux pannes et la capacité de redémarrage à chaud.

L'idée était aussi que tout cela fonctionne en réseau : chaque machine physique serait animée par un micro-noyau, et les serveurs en mode utilisateur seraient répartis au gré des opportunités, ce qui ouvre la voie à la construction d'architectures distribuées souples et modifiables dynamiquement.

Un peu comme l'hyperviseur de VM/CMS, un micro-noyau typique fournit des services minimum d'accès au matériel : création d'activités (threads), gestion minimale des interruptions, commutation de contexte, verrouillage élémentaire de sections critiques, accès brut à la mémoire et aux entrées-sorties, protection réciproque des activités. Les fonctions plus raffinées (ordonnancement de processus, gestion de mémoire virtuelle, système de fichiers, protocole de réseau...) sont déléguées à des serveurs en espace utilisateur.

Les communications entre le micro-noyau et les serveurs sont réalisées classiquement par passage de message, une technique qui a l'avantage de pouvoir fonctionner aussi bien par le réseau que localement. Le message contient les informations nécessaires au traitement d'un événement tel qu'une interruption, et il est déposé dans une zone de mémoire connue comme boîte à lettres, où le serveur concerné peut le récupérer. Ce mécanisme a l'avantage de fournir un bon moyen d'abstraction et de séparation des fonctions, il a aussi deux inconvénients : jusqu'à des développements récents ses performances étaient médiocres, et dès lors que le système est réparti sur plusieurs sites en réseau il est difficile de restituer ainsi la sémantique d'un noyau Unix.

Les premiers micro-noyaux célèbres furent Mach, développé à l'Université Carnegie-Mellon à Pittsburgh, Chorus, créé en France en 1979 par une équipe de l'INRIA avec notamment Hubert Zimmerman et Michel Gien, Amoeba créé à l'Université Libre d'Amsterdam par Andrew Tanenbaum.

10.3.1  Chorus

Chorus est né en 1979 comme projet de recherche à l'INRIA près de Paris. La société Chorus Systèmes a été créée en 1986 pour commercialiser une nouvelle version de ce noyau (version 3), et elle a été rachetée par Sun Microsystems en septembre 1997. Entre temps le système Chorus a connu un succès assez modéré dans le monde informatique proprement dit, mais beaucoup plus significatif dans celui des constructeurs de matériel téléphonique, dont les autocommutateurs sont en fait de vastes systèmes informatiques distribués qui semblent faits pour les micro-noyaux.

Le noyau Chorus décompose la notion de processus selon les deux axes que nous avions déjà mis en évidence à la section 10.2 : Chorus présente ses abstractions avec une terminologie qui témoigne, au moins dans les articles rédigés en français tels que « UNIX et la répartition : retour à la simplicité originelle ? » [5] dont les lignes qui suivent sont largement inspirées, d'un réel souci d'énonciation des concepts dans un langage précis et expressif :


Figure 10.2 : Abstractions du micro-noyau Chorus




Figure 10.3 : Serveur UNIX sur un groupe de sites Chorus


Au-dessus du noyau les créateurs de Chorus ont développé un ensemble de serveurs destinés à constituer un sous-système Unix, tel que représenté par la figure 10.3. Chaque type de ressource du système (processus, fichier...) est géré par un serveur système dédié. Les serveurs peuvent résider sur des sites différents : on voit que Chorus, encore plus que Mach, a été conçu dans la perspective de construction de systèmes répartis. Ce découpage du noyau Unix en serveurs modulaires était très intéressant tant du point de vue du génie logiciel (l'art de construire de grands systèmes informatiques) que de celui de l'architecture. L'entreprise a (partielllement) achopé sur la difficulté à restituer la sémantique du noyau Unix dans un contexte non monolithique, ainsi que sur des problèmes de performances. Tant que l'on en reste à un site unique, Chorus implémente des appels de procédures à distance (RPC, pour Remote Procedure Call) légers, mais cette solution n'est disponible que si l'on renonce à la répartition, et pour des processus en mode superviseur. La réalisation efficace de communications inter-processus par passage de messages ne viendra qu'après le rachat de Chorus par Sun, et ce sera une autre équipe qui s'en acquittera.



10.3.2  Mach

Mach est né en 1983 comme un projet de recherche de l'Université Carnegie Mellon dont les idées majeures sont exprimées dans une communication à la conférence USENIX de 1986, Mach: A New Kernel Foundation for UNIX Development [2]. Ce projet a suscité de grands espoirs, au point que la DARPA a à cette époque réorienté vers lui une part importante des financements qui allaient auparavant au Computer Systems Research Group (CSRG) de l'Université de Californie à Berkeley. Les objectifs de Mach sont les suivants : Le noyau Mach ignore la notion classique de processus, qu'il désarticule selon les deux axes que nous avions déjà mis en évidence à la section 10.2 : Les abstractions de base du noyau Mach sont les suivantes (figure 10.4 :


Figure 10.4 : Abstractions du micro-noyau Mach


Le projet Mach à l'Université Carnegie-Mellon s'est arrêté en 1994, mais il a une postérité réelle. L'Université d'Utah a repris le flambeau pendant quelques années. Le projet GNU Hurd vise à remplacer le noyau Unix par une collection de serveurs implantés au-dessus d'un noyau Mach. Le système MacOS-X d'Apple, et dans une certaine mesure le noyau de Tru64 Unix de Compaq (ex-Digital) sont des descendants plus ou moins légitimes du micro-noyau Mach au-dessus duquel Apple et Compaq ont implanté des systèmes Unix de sensibilité plutôt BSD.

10.3.3  Eumel, L3, L4

La série des systèmes Eumel, L3 et L4, développés à partir de 1977 par Jochen Liedtke à l' Université de Bielefeld, puis à partir de 1984 au GMD (Gesellschaft für Mathematik und Datenverarbeitung), à partir de 1996 au centre de recherche Thomas J. Watson d'IBM et à partir de 1999 à l'Université de Karlsruhe, représente un des efforts les plus notables à la fois dans le domaine des micro-noyaux et dans celui des domaines persistants (cf. section 5.4). Espérons que la disparition prématurée de Jochen Liedtke n'en marquera pas la fin.

Dans son article de 1995 On µ-Kernel Construction [38] Liedtke pose les fondations de la « seconde génération » des micro-noyaux. Il part de la constatation que certains pionniers ont été conduits à réintégrer au noyau des fonctions qui en avaient été extraites vers le mode utilisateur, essentiellement pour des raisons de performances. Il examine donc les différents problèmes de performances rencontrés et entreprend de leur trouver des solutions qui respectent le programme initial des micro-noyaux : une architecture de système modulaire, des serveurs en mode utilisateur pour toutes les fonctions dont l'appartenance au noyau n'est pas conceptuellement indispensable, la possibilité d'implanter des stratégies variées de gestion du système en mode utilisateur.

Le premier problème de performance examiné concerne le coût de la commutation mode noyau -- mode utilisateur, qui avec un noyau Mach 3 sur un antique processeur Intel 486 à 50 MHz consomme 900 cycles de processeur. Avec le noyau L3 Liedtke abaisse ce coût à 180 cycles dans le cas le plus défavorable (3 adresses non résolues par le TLB, 10 fautes de cache). L3 implémente les activités (threads) en mode noyau et les processus persistants, ceci pour dire que c'est un noyau complet et non pas une simple maquette dont la rapidité aurait pour contrepartie des fonctions rudimentaires.

Liedtke examine ensuite la question de la commutation des espaces adresses. Comme nous l'avions noté à la section 4.4.5, cette opération est beaucoup plus rapide sur les processeurs qui utilisent un TLB étiqueté (tagged TLB) comme le MIPS R4000 ou l'Alpha, que sur les processeurs comme le Pentium ou le Motorola PowerPC qui doivent réinitialiser le TLB à chaque commutation d'espace adresse. Pour les processeurs de cette dernière catégorie, Liedtke propose d'utiliser les registres de segment, inutilisés par la plupart des systèmes d'exploitation contemporains, pour simuler un TLB étiqueté et éviter ainsi la réinitialisation du TLB. Le coût de la commutation d'espace adresse descend ainsi à moins de 50 cycles, ce qui autorise 100 000 commutations par seconde sans baisse de performance insupportable.

Le passage de messages, et de façon générale les communications interprocessus, souvent incriminées, peuvent être accélérées par la réaffectation de cadres de pages d'un espace-adresse à un autre, ce qui évite la recopie physique de zones mémoire, un grande source de gaspillage de cycles et de saturation du cache. Incidemment cette technique est aussi de nature à améliorer les performances de l'accès au réseau. Ces opérations doivent bien sûr être effectuées sous le contrôle exclusif du noyau, ne serait-ce que pour des raisons de sécurité.

Une des conclusions tirées par Liedtke de ses expériences, c'est qu'un micro-noyau, pour être efficace, ne doit pas être conçu pour être indépendant du matériel, mais doit au contraire exploiter au mieux les caractéristiques du processeur auquel il est destiné. Ainsi, le passage en mode noyau coûte un minimum de 156 cycles sur Intel 486, contre 20 cycles sur MIPS R2000, qui profite de son TLB étiqueté et d'une zone mémoire réservée au noyau non affectée à l'espace adresse de l'utilisateur : il est clair que la conception d'un noyau pour ces deux processeurs aura à tenir compte de cette différence. Pour le 486, Liedtke a été amené à organiser l'espace adresse de manière à réduire le nombre d'accès au TLB par tous les moyens, par exemple concentrer les données les plus cruciales du noyau en une page.

10.3.4  Conclusion sur les micro-noyaux

Jusqu'au milieu des années 1990, aucune conférence informatique peu ou prou orientée vers les systèmes ne pouvait avoir lieu sans plusieurs communications consacrées aux micro-noyaux. Il semblait évident à tout le monde que c'était la technologie du lendemain. Aujourd'hui on n'en parle plus guère.

Les qualités intrinsèques du modèle du micro-noyau, son adaptation à des systèmes distribués et flexibles, sa capacité à fonctionner sur des plateformes de toutes dimensions, ainsi que les améliorations apportées par les travaux de la seconde génération, ceci combiné avec les attraits des systèmes persistants (cf. section 5.4), me donnent à penser que cette technologie réapparaîtra, sans doute combinée avec celle du code mobile à la Java.




1
Il faut savoir qu'aujourd'hui ce sont les logiciels de jeux électroniques qui sont le moteur de l'industrie du microprocesseur. Les processeurs actuels sont en effet très suffisants pour satisfaire tout usage professionnel raisonnable en dehors de certains domaines scientifiques assez spécialisés tels que la mécanique des fluides, la sismographie, la météorologie, l'analyse génomique, etc. Mais l'avidité des jeux est sans limite, et le marché des jeux est plus vaste que celui de l'océanographie ou des souffleries numériques.
2
Cette technique de production d'un langage intermédiaire interprété n'est pas inédite, elle a été utilisée par Pascal UCSD, LeLisp, Emacs Lisp, CAML...
3
Incidemment, cette idée n'est pas entièrement inédite. À une époque reculée (1968) IBM avait lancé un moniteur transactionnel nommé CICS (Customer Information Control System) ; le travail d'un tel logiciel consistait à recevoir des requêtes en provenance de milliers de terminaux, par exemple dans une banque, à interroger ou mettre à jour la base de données, à donner la réponse au terminal. Bien sûr il faut éviter que les mises à jour concomitantes ne se télescopent et veiller à ce que les temps de réponse ne soient pas trop catastrophiques. Pour des raisons de simplicité de portage sur des systèmes différents, CICS était réalisé comme un unique gros processus (task dans le language d'IBM) qui réalisait lui-même (avec une efficacité modeste) le partage du temps et des ressources entre les différents travaux attachés aux terminaux. Aux dernières nouvelles CICS est toujours au catalogue d'IBM, des milliers de sociétés sont spécialisées en CICS, 30 millions de personnes sont assises derrière des terminaux CICS, et cela continue à croître. CICS avait été conçu dans les années 1960 comme une solution temporaire en attendant que soit terminée la réalisation d'un SGBD plus ambitieux (IMS, Information Management System), aujourd'hui largement délaissé et oublié même si toujours au catalogue...
4
Dans son livre de système[8] Samia Bouzefrane observe que les activités ou processus légers lancés dans le contexte d'un processus représentent une bonne réalisation des moniteurs de Hoare[29].
© copyright Éditions Vuibert et Laurent Bloch 2003
Page d'accueil de ce livre
Précédent Remonter Suivant