Interior Decor et son Micro-Noyau

par Jean Bellec

 Retour

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.