Interior Decor et son Micro-Noyau
par Jean Bellec
Une des originalités des systèmes
GCOS7 est l'inclusion dans l'architecture du code d'instructions de fonctions
habituellement incluses dans le système d'exploitation proprement dit: les
fonctions de gestion de processus (dispatching), de gestion et de protection de
l'espace d'adressage (segmentation) et de synchronisation des threads visibles du programmeur entre
elles et avec les opérations d'entrées-sorties.
Ces fonctions
étaient bien identifiées par les théoriciens des systèmes d'exploitation dans la
seconde moitié des années 1960, mais un accord sur leur systématisation et leur
"architecturisation" semblait
éloigné. Multics avait introduit une gestion de l'espace d'adressage commune aux
processus (vus comme le travail du programmeur individuel) et au système de
fichiers. IBM avait réalisé une gestion uniforme des entrées-sorties mais avait
laissé la gestion des espaces d'adresses aux initiatives des créateurs de
systèmes d'exploitation. Les mini-ordinateurs se caractérisaient davantage par
la possibilité de réaliser des systèmes d'exploitation différents que par la
continuité et l'efficacité de ceux-ci.
Ce qu'était l'APL OS en 1968 et qui deviendra GCOS64 à l'annonce et GCOS7 plus tard, c'était un système d'exploitation universel capable d'assurer les fonctions de traitements par lots (batch processing) que les clients héritaient de leurs années 1960, de permettre une utilisation efficace de ressources matériel encore très coûteuses, et de permettre la réalisation de systèmes interactifs transactionnels qui émergeaient à l'époque sur des systèmes beaucoup plus onéreux mais dont nous prévoyions la généralisation dans les années 1970.
Une autre caractéristique un peu contingente, la technologie, influença la décision de développer hors du système d'exploitation ces fonctions de micro-kernel. Les mémoires centrales (tout d'abord envisagées à tores magnétiques puis réalisées en DRAM) étaient relativement lentes par rapport à la technologie bipolaire utilisées pour les circuits et les mémoires mortes dédiées à l'interprétation du code d'instructions. De plus, la vitesse d'exécution du logiciel était un peu pénalisée par la rigueur du système de protection des accès à la mémoire principale. C'est ainsi que l'implémentation en PROM du code du dispatcher de tâches permettait de diviser par trois l'overhead d'une fonction sollicitée en permanence dans un système de gestion transactionnelle.
Le système d'adressage de la NPL était segmenté,
c'est à dire que les adresses indiquées dans les instructions comprenaient un
numéro de segment et un déplacement à l'intérieur du segment. La table de
segments était comme dans Multics spécifique de chaque thread. Cependant, sur
NPL, les segments sont classés en plusieurs catégories suivant leurs
caractéristiques de partage: les segments communs à tout le système (type 0),
les segments privés de la thread
(type 3) les segments communs aux threads partageant un même espace
d'adresse (type 2) et les segments alloués dynamiquement (type
1).
Deux catégories de taille de segments furent retenues :
celle de 64 K octets et celle de 4 M octets. Chaque catégorie était disponible
dans les différents types de segments.
Le dispatcher de threads connaît pour chaque thread son état (y compris les registres
de travail et l'espace d'adresse. Il effectue la commutation de threads sur des critères de priorité et
de disponibilité. Ce dispatcher est bien entendu
multi-processeurs.
Le nombre de threads actives dans le système était
limité à 256 groupes (process groups)
de 256 threads (appelées process dans le jargon NPL). Ce nombre
pouvait s'avérer insuffisant dans des systèmes transactionnels où un
multiplexage par logiciel s'avérait nécessaire entre une thread active et une transaction
multi-échanges.
Le mécanisme de synchronisation de threads fait lui aussi partie de
l'architecture et est basé sur des sémaphores (introduits en 1965 par
Dijkstra) utilisés par des primitives de signalisation (V-op) et de mise conditionnelle en
attente (P-op). En plus du compteur
associé à ces opérations, les sémaphores peuvent comporter une liste de
messages. Un mécanisme supplémentaire de test de l'état du sémaphore permet la
réalisation de wait
multiples.
Le mécanisme de sémaphore est non seulement utilisé
pour la synchronisation de threads du
logiciel s'exécutant dans la mémoire du (ou des) processeurs, mais également
pour synchroniser ces threads avec
les entrées-sorties (plus exactement avec les pseudo-threads exécutant des programmes
canaux).
Une autre fonction du micro-kernel est la gestion du système de protection inter-procédural
au cours de l'exécution d'une thread.
Les segments correspondant au code d'une procédure sont associées à un des
quatre anneaux de protection (rings)
du système. Une thread est exécutée
dans l'un de ces anneaux selon le type associé au segment procédure. Une
procédure peut appeler une procédure de rang plus privilégié mais ne peut
accéder à ses données tandis qu'une procédure privilégiée accède aux données de
son appelant (mais à l'intérieur de l'espace d'adresse de la thread). Les paramètres sont passés par
l'intermédiaire d'une pile (avec une pile par anneau). Le micro-kernel reporte les violations de
protections à des procédures privilégiées.
De plus, seules
des procédures de ring 0 peuvent
exécuter des instructions privilégiées touchant au matériel (entrées-sorties,
manipulation des adresses absolues).
Ce mécanisme est complètement applicable à tous les éléments du logiciel, y compris les émulateurs de modes non natifs.
Le micro-kernel se présente sous la forme de code non modifiable dynamiquement (initialement en PROM), de données de travail en registres ou en mémoire cachée sous BAR et de tables accessibles au logiciel uniquement en mode privilégié. Il est écrit en une version simplifiée des instructions de base de l'interior decor (by-passant en particulier les contrôles d'adressage et d'intégrité). Sur le DPS-7 Leo, les micro-programmes de l'unité centrale seront exécutés depuis une mémoire de contrôle en SRAM et chargés depuis un fichier spécial sur le disque système. Le code du micro-kernel a subi quelques modifications sur les différentes architectures de processeurs, mais l'interface avec le système d'exploitation est resté strictement compatible.
Au total, cette innovation de GCOS7
a recueilli la désapprobation des promoteurs (italiens) de petits systèmes qui
ont argué du coût des mécanismes d'adressage (mémoire virtuelle et segmentation)
pour obtenir le droit de définir une architecture indépendante (vaguement
compatible au niveau source assembleur) et donc la réalisation d'une ligne de
produits propre. Elle a recueilli le scepticisme des défenseurs (Phoeniciens) de
l'architecture des systèmes GE-600 qui estimaient que la définition d'un micro-kernel (et son figeage dans le
hardware) limiterait les ambitions et les innovations chez les utilisateurs
avancés.
Elle a cependant servi d'argumentaire commercial en
attendant que le logiciel soit complètement réalisé: les promoteurs vendaient
les sémaphores en 1974-1975, mais ensuite ils ont cessé de les mentionner,
surtout que cela pouvait concurrencer des lignes qui n'avaient pas la même
rigueur architecturale.
Au bout du compte, cette architecture s'est avérée solide, adaptée à la plupart des besoins des logiciels qui contrairement à beaucoup de systèmes ont su évoluer sans révolution coûteuse pendant plusieurs décennies.