Mort au Dos ! Conçu en 1981 pour des processeurs 8088, le Dos n’a plus beaucoup de raisons d’être en 1994. La version 1.0 supportait 256 KB et deux floppys de 180 KB. On comprend aisément qu’il n’a plus grand chose à voir avec les 486 ou Pentium qui envahissent nos bureaux. Mon propos d’aujourd’hui est de vous entretenir de toutes les limitations d’un Dos qui n’a plus aucune raison de trôner sur votre machine treize ans plus tard. Je ne vais pas vous faire l’insulte de rappeler la limite 8.3 des noms de fichier ou la barrière des 640 KB et du MB d’espace adressable dont 384 KB sont monopolisés par la ROM du système et les périphériques comme la carte vidéo. Le DOS n’a été pensé que pour exécuter une seule tâche à la fois. On en parle comme un environnement “ single task ” ou “ single thread ”. Comme le DOS ne fournit aucun service de multi-tâche, les programmes qui réclament du multitasking doivent le gérer eux-mêmes. C’est le cas par exemple des programmes résidants (TSR ou Terminate & Stay Resident). Les TSR sont chargés en mémoire comme d’autres applications DOS mais restent en mémoire une fois terminés ne pouvant être réactivés que par une interruption software ou hardware. Puisque ces TSR ne sont jamais certains que la mémoire nécessaire sera disponible à chaque activation, ils sont obligés d’allouer et de gaspiller cette mémoire lorsqu’ils sont chargés pour la première fois même s’ils ne sont plus réveillés par la suite. Comme le processeur 8088 ne contient aucun mécanisme de protection de la mémoire et confond allègrement la mémoire utilisée par le système et celle gérée par les applications, les plantages liés à ces TSR sont fréquents et ne peuvent se résoudre que par un méchant reset. De plus comme le Dos n’est pas “ réentrant ”, un seul programme peut utiliser un service Dos à la fois. Si une application et un TSR s’approprient en même temps un service Dos, c’est le crash assuré. Le contrôle des I/O est tout aussi inexistant. N’importe quel programme peut à tout moment lire ou écrire sur un périphérique d’entrée/sortie sans même que le Dos lui en donne la permission. La plupart des applications désireuses de faire un I/O entrent dans une boucle où elles interrogent le périphérique pour vérifier que l’opération I/O est terminée. On appelle ca du “ polling ”, une méthode qui gaspille plein d’instructions du processeur et ralentit les autres tâches. Pire encore, une application peut désactiver une interruption par une simple instruction donnée au processeur. Nombreuses sont les applications qui désactivent toutes les interruptions avant d’exécuter un loop. Votre cache disque ou votre redirecteur réseau désactive toutes les interruptions avant d’écrire un paquet de données sur votre disque et du coup, votre programme de communication en tâche de fond rate de précieux caractères ou votre gestionnaire d’impression ne reçoit pas régulièrement des ticks pour poursuivre son impression. L’apparition du 80386 et son mode Virtual Mode 8086 et son PMMU (Paged Memory Management Unit) n’a pas vraiment arrangé les choses. Desqview et Windows 3.0 sont apparus pour offrir du multitâche au dessus du Dos. Mais ils sont toujours basés sur le Dos en mode réel et le BIOS, tous deux non-réentrants, et passent le plus clair de leur temps à balancer du mode réel au mode protégé. Bien qu’il utilise le mode protégé, Windows 3.x n’exploite aucune des possibilités propres à ce mode de protéger le système d’exploitation d’une application errante ou de protéger les applications entre elles. Tel qu’il est conçu pour l’instant, Windows n’est jamais qu’un “ Dos Extender ” tournant au-dessus du Dos en mode réel et ne peut se prévaloir du titre de système d’exploitation. L’API 16 bits de Windows peut à tout moment passer un mauvais pointeur (offset correct mais segment erroné par exemple) au Dos et planter totalement la machine. Toujours basé sur l’architecture segmentée des anciens processeurs Intel, il oblige le programmeur à se battre contre la barrière du segment de 64 KB alors qu’il pourrait exploiter l’adressage linéaire 32 bits disponible depuis l’apparition du 386 repoussant la limite d’un segment à 4 GB. Trop de parties de Windows ont été écrites avec le processeur 80286 en tête, un CPU “ brain-damaged ” qui ne dispose d’aucun mécanisme pour repasser tout seul du mode protégé au mode réel. La seule façon sur un 80286 de repasser du mode protégé au mode réel est de procéder à un très long reset du processeur via le contrôleur clavier. La gestion du temps accordée à chaque tâche sous Windows n’est pas non plus très efficace. On parle de multitâche non-préemptif ou coopératif. Une fois qu’une tâche a reçu le droit de s’approprier le processeur elle dispose du droit inaliénable de le monopoliser jusqu’à ce qu’elle décide de rendre volontairement le contrôle au système d’exploitation. Une fois prévu, un processus doit s’exécuter jusqu’à la fin et n’est pas forcé de rendre le contrôle du processeur à une tâche qui le réclame avec une plus grand priorité. Cela arrive fréquemment sous Windows : une tâche se lance dans un calcul complexe et le programmeur n’a pas jugé utile de faire un “ yield ” et de suspendre brièvement son application pour permettre aux autres applications de s’exécuter concuremment. Pire encore, si sa routine est buggée et se perd dans une boucle infinie, il n’y aura plus personne pour rendre le processeur à l’Operationg System. Qui s’étonnera encore que votre bouton reset soit aussi usé ! En cas de multitâche préemptif, un processus actif peut à n’importe quel moment être remplacé par un process de priorité plus élevée. Pour obtenir cette préemption, un système d’exploitation doit gérer un “ scheduler ” qui s’active lorsqu’une priorité est modifiée. Dès qu’une tâche à forte priorité est disponible, le scheduler se charge de retirer le contrôle du CPU à la tâche en cours et le confie à une nouvelle tâche. Le mauvais comportement d’une tâche n’est plus un problème puisque l’OS est capable de lui retirer le contrôle du CPU. Le progrès en matière d’Operating Systems est tel que tous les systèmes d’exploitation 32 bits apparus après 1993 résolvent presque tous les problèmes évoqués plus haut : - La limite du 1 MB est repoussée théoriquement à 4 GB par l’adressage 32 bits (2 exposant 32) - Les noms de fichiers sous OS/2 ou NT peuvent aller jusque 255 caractères. - Dans un véritable multitâche préemptif, les TSR gloutons appartiennent définitivement au passé. - Les accès aux I/O et périphériques sont virtualisés pour éviter tout conflit. - L’horrible polling est remplacé par une gestion asynchrone des I/O. Une application réclame le droit d’opérer une opération I/O et peut déjà faire autre chose pendant que le périphérique termine de transférer les données. L’OS notifie automatiquement la tâche que l’opération I/O est terminée. - La limite des partitions disque de 512 MB imposée par le BIOS est repoussée par le recours à des file systems plus évolués comme le HPFS ou le NTFS incluant structure arborescente accélérant les recherches, restauration automatique des données après un plantage, notion de sécurité, tolérance de panne, une meilleure stratégie de gestion des clusters libres, l’utilisation de secteurs au lieu de clusters comme unité d’allocation, la présence d’attributs de fichier étendus. - Les OS 32 bits peuvent recourir à d’autres file systems installables pour gérer des CD-ROM ou des WORM par exemple. - Les portions non-réentrantes du BIOS sont inutilisées et remplacées par des fonctions 32 bits de l’Operating System. -Pour une meilleure protection, l’Operating System tourne en mode kernel (Ring 0) alors que les applications n’ont accès qu’au User mode (Ring 2 ou 3). Chaque application ou thread dispose de son propre espace mémoire adressable et n’est pas autorisée à accéder aux adresses virtuelles d’autres processes. Un mécanisme de protection par page mémoire de 4KB assigne à chaque page virtuelle une série de flags déterminant les types d’accès autorisés pour ces pages (lecture seulement, lecture-écriture etc). - Les limites de mémoire sont éliminées par le recours à un espace adressable virtuel théoriquement de 4 GB par application. - Le Memory Management Unit (MMU) du processeur permet de dissocier l’adresse réelle en mémoire de celle vue par l’application. Grâce à un mécanisme baptisé “ address translation ”, le MMU traduit les adresses virtuelles en adresses physiques au fur et à mesure que les instructions sont exécutées. Quand la mémoire physique réellement présente est pleine, le VM manager transfère (en anglais “ page ”) certains pans de la mémoire sur disque. Quand un processus ou un thread veut accéder à une adresse virtuelle “ paginée ” sur un disque, le VM manager se charge de la rappeler en mémoire. - Une application peut être découpée en de nombreux threads ( fil en français) disposant chacun de leur propre niveau de priorité, d’un jeu de registres et d’un stack. Le scheduler de l’OS détermine le thread à la plus forte priorité et lance ce thread pour une période de temps (appelée timeslice ou quantum) déterminée définie par le mode de timeslicing. A la fin du timeslice, le scheduler détermine si un autre thread est prêt à prendre le relais. C’est le mécanisme de context switching. - Pour permettre l’échange de données et la synchronisation entre tâches ou threads, les OS nouvelle cuvée disposent de mécanismes de communication interprocess (IPC ou Interprocess Communication) comme la mémoire partagée, le sémaphore ( une sorte de flag levé et abaissé en début et fin d’une section critique), le signal (méthode un peu obsolète de notification asynchrone entre process), une queue (une sorte de boîte aux lettres que peuvent se partager plusieurs threads) ou un pipe (un échange de données entre deux threads). Je n’ai qu’un conseil à vous donner : abandonner le Dos dans les six mois qui viennent. Je ne me permettrai pas d’influencer votre choix du système d’exploitation 32 bits qui le remplacera. Que vous choisissiez OS/2, NT, Linux, Unixware, NextStep, SCO Unix, Solaris m’indiffère. Mon seul propos est de vous faire sortir de l’âge de la pierre ! En 1994, vous êtes en droit d’exiger un OS prévu pour les processeurs 80386 et suivants, 32 bits, à multitâche préemptif, supportant le multithreading et offrant la meilleure émulation Dos et Windows possible.