0% ont trouvé ce document utile (0 vote)
34 vues50 pages

Tindo

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1/ 50

SYSTEMES D’EXPLOITATION II

par
Gilbert TINDO

Objectifs du cours :
- présenter les principaux concepts sur lesquels s’appuient les systèmes
d’exploitation multiprogrammés, ainsi que les éléments de leur mise en œuvre
- illustrer les concepts à l’aide d’un système : le système unix
- présenter les principes des systèmes d’exploitation distribués

Partie I: Structure d’un système d’exploitation


1-1 Organisation architecturale d’un ordinateur
1-2 Définition d’un système d’exploitation
1-3 Evolution des systèmes d’exploitation
- Le traitement par lots
- La multiprogrammation
- Le temps partagé
- Système d’exploitation réseau
- Système d’exploitation distribué
1-4 Structure et Organisation interne d’un système d’exploitation
- Gestion des processus
- Gestion de la mémoire
- Gestion des fichiers
- Gestion des entrées/sorties
- Gestion des périphériques
- Gestion du réseau
- Protection des ressources
- Interpréteur des commandes
1-5 Différents types de noyaux
- les noyaux monolithiques
- les systèmes en couches
- les machines virtuelles
- les exonoyaux
- les micronoyaux

Partie II: Gestion des Processus


2-1Définitions
2-2 Les processus séquentiels
2-3 Ordonnancement des processus
2-4 Synchronisation entre processus
2-5 Outils de synchronisation
2-6 Les processus légers
2-7 Implémentation des processus: le cas d'Unix
2-8 les interblocages

Partie III: Gestion des ressources


3-1 Gestion de la mémoire
3-1-1 la monoprogrammation sans va-et-vient ni pagination
3-1-2 la multiprogrammation avec des partitions fixes
3-1-3 le va-et-vient
3-1-4 la pagination
3-1-5 la segmentation

1
3-2 Gestion des fichiers
3-2-1 Définitions
3-2-2 Les répertoires
3-2-3 Implantation d'un système de fichiers
3-2-4 Exemple de systèmes de fichiers: FAT32 & Unix V
3-3 Les entrées/sorties de bases
3-3-1 Les matériels d'E/S
3-3-2 Les logiciels d'E/S
3-3-3 Les disques
3-3-4 Les horloges

Partie IV: Introduction aux systèmes d’exploitation distribués


4-1 Définitions et caractéristiques des systèmes distribués
4-2 Les systèmes de fichiers distribués
4-3 La coordination distribuée

Travaux Dirigés et Pratiques :


b) Opérations sur les processus en C et Java (création, destruction, manipulation, …etc)
c) Les processus légers en C et Java
d) La communication inter processus en C et Java
e) Etude de NFS : Systèmes de fichiers distribués ou réseau ?
f) Conception d’un noyau de synchronisation

Bibliographie :
1) Andrew Tanenbaum : « Systèmes d’exploitation : Système centralisés, Systèmes
distribués », InterEditions

2) Silberschatz & Galvin : « Operating Systems concepts », John Wiley


3) Sacha Krakowiak : « Principes des systèmes d’exploitation des ordinateurs », Dunod
Informatique

2
Chapitre 1 : Introduction
1.0 Introduction
Un système informatique est un ensemble de matériels et de logiciels destinés à résoudre les
problèmes d’un ensemble d’utilisateurs. Le matériel sans le logiciel n’est qu’un amas métallique
inutile. Le logiciel d’un système informatique peut se subdiviser en deux grandes classes :
- les logiciels d’application
- les logiciels système
Les logiciels d’application servent à résoudre des problèmes spécifiques d'un utilisateur Ils
peuvent être écrits par l’utilisateur lui même: il suffit que l'utilisateur sache programmer dans un
langage de programmation quelconque (C,C++, pascal, java, ...etc) et maîtrise les techniques du génie
logiciel. Les logiciels d'application peuvent aussi être trouvés sur le marché prêts à l'emploi: c’est
souvent le cas pour les logiciels de traitement de texte, les tableurs, les logiciels de gestion et
comptabilité, les didacticiels, ...etc.
Les logiciels systèmes sont plus complexes et servent en général d'interface entre les logiciels
d'application et le matériel. Sans ces logiciels systèmes, chaque programmeur devrait écrire des
programmes qui interfèrent directement avec le matériel, ce qui rendrait le travail du programmeur très
complexe. Les logiciels systèmes peuvent être regroupés en deux sous-classes : les utilitaires et le
système d’exploitation. Les utilitaires aident à développer des applications : ce sont les compilateurs,
les assembleurs, les éditeurs de liens, les chargeurs, les débogueurs, ...etc. Le système d’exploitation
quant à lui, a pour but de simplifier la tâche des utilisateurs en leur présentant une machine virtuelle
plus simple à exploiter que la machine réelle. Il permet aussi d’assurer l’exploitation efficace et
économique des différentes ressources de la machine.

1.1 organisation architecturale d’un ordinateur


Structure d’un ordinateur moderne

Un ordinateur est composé d’un ensemble d’organes qui communiquent au moyen d’une ligne
de communication appelée bus . Le bus,à un instant donné est alloué à un et un seul des organes qui se
le partagent. L'allocation du bus est assurée par un organe appelé arbitre du bus. Toutes les unités
attachées au bus , le sont à travers d’autres unités appelées contrôleurs. On distingue ainsi : des
contrôleur de disques , des contrôleurs d’imprimantes , ... etc.

Quand l’ordinateur est mis sous tension, un programme spécial chargé en mémoire morte
s’exécute. Son rôle est de localiser sur le disque dur un secteur d’amorçage (premier secteur de tout
disque, appelé aussi MBR (master boot record)), de charger son contenu en mémoire centrale et de
lancer son exécution. Ce programme d'amorce sait où trouver le système d’exploitation, comment le

3
charger en mémoire et à partir de quelle adresse commencer son exécution. La partie du système
d’exploitation qui est ainsi chargée en mémoire par le programme d'amorce est généralement appelée
noyau . Ce dernier après être chargé en mémoire commence à s’exécuter et attend qu’un événement se
réalise. Un événement peut être une interruption logicielle ou matérielle. Une interruption est un signal
généré par une organe de l'ordinateur (interruption matérielle) ou par le programme en cours
d'exécution (interruption logicielle).
Pour chaque type d’interruption, un service est fourni par le noyau et est responsable de
l’action à entreprendre lorsque cette interruption survient.
Le système d’exploitation utilise une table de statut des différentes unités. Chaque entrée de
cette table indique :
(7) le type de l’unité
(8) l’adresse où l’on peut communiquer avec l’unité
(9) le statut de l’unité (si l’unité est occupée , est inoccupée ou inopérante.)
(10) une file d’attente sur l’unité

Le système d’exploitation coordonne le fonctionnement de toutes les unités tout en cachant la


complexité de leur fonctionnement à l’utilisateur.

1. 2 Définition d’un système d’exploitation


Un système d’exploitation est un ensemble de logiciels qui assurent deux grandes fonctions :
1- présenter à l’utilisateur une machine virtuelle plus facile à utiliser. Il est donc une interface
entre l’utilisateur et la machine physique et permet de masquer la complexité de
l’utilisation de la machine.
2- Gérer de façon efficace et économique les différentes ressources de la machine telles
que : la mémoire centrale ou les mémoires de masses, le processeur, les unités
périphériques. C’est le système d’exploitation qui alloue les différentes ressources de la
machine aux différents processus. Il met en place une politique permettant de gérer les
différentes ressources de façon à augmenter le rendement de la machine.

Parmi les systèmes d’exploitation modernes, nous pouvons citer :


(11) MSDOS
(12) UNIX/LINUX/SOLARIS
(13) OS/2
(14) WINDOWS (3.x/95/98/Millennium)
(15) WINDOWS NT(4.0/2000/XP/2003/VISTA)
(16) MacOs

1.3 Organisation interne d’un système d’exploitation


Un système d’exploitation est un logiciel très complexe. A ce titre, lors de sa conception, il est
souvent décomposé en module pour faciliter le travail. Chaque module a une fonction bien
précise , des entrées et des sorties bien définies. On distingue en général :

a) la gestion des processus


Un processus est un programme en cours d’exécution. Le système d’exploitation est responsable
de :
(17) la création et la destruction des processus utilisateur ou système
(18) la suspension et le réveil des processus
(19) la synchronisation entre processus
(20) la communication entre processus
(21) le traitement des interblocages

b) la gestion de la mémoire
A un moment donné plusieurs programmes peuvent se trouver en mémoire centrale et doivent
s'exécuter simultanément. Dans ce cas, chaque programme a une zone de mémoire qui lui est propre.
Le système d’exploitation est responsable de :

4
(22) allouer et libérer une zone mémoire
(23) charger des processus en mémoire
(24) retirer des processus de la mémoire
(25) garder la trace des zones de mémoire occupées par les différents processus
(26) gérer les espaces libres en mémoire
(27) assurer le transfert des données de ou vers la mémoire centrale
Le système d’exploitation assure ces fonctions à l’aide des appels système

c) la gestion des fichiers


Un ordinateur peut garder ses données sur différents types de support tels que les bandes
magnétiques, les disques magnétiques, les Cdrom, …etc. Chaque support de stockage a ses propres
caractéristiques et son organisation physique. Chaque support est géré par un dispositif appelé
contrôleur qui a ses propres caractéristiques telles que la vitesses, le taux de transfert, la capacité, la
méthode d’accès. Le système d’exploitation fournit une vue logique uniforme du stockage des données
en fournissant une unité logique de stockage appelée fichier . Il est ainsi donc, responsable :
(28) de la création et de la destruction des fichiers
(29) de la création et de la destruction des répertoires
(30) de fournir des primitives pour manipuler les fichiers et les répertoires
(31) de faire la correspondance entre les fichiers logiques et les unités de stockage physique
L'utilisateur a donc besoin uniquement de manipuler des fichiers. Il ne se soucie pas de la façon par
laquelle les fichiers sont créés et implantés sur unités de masse. Ce travail est laissé au système
d'exploitation.

d) la gestion des entrées/sorties


Son but est de cacher aux utilisateurs les spécificités de chaque unité périphérique. Le système
d'exploitation offre pour chaque unité périphérique un logiciel appelé pilote de péréphérique. Il
sert d'interface entre le système d'exploitation et le contrôleur du périphérique. Le pilote de
périphérique connaît toutes les spécificités du périphériques qu'il pilote et sait exactement ce qu'il
faut faire pour :
(32) lire des données
(33) écrire des données
Le système d'exploitation permet aussi l'utilisation des tampons ou des spoules pour faciliter certaines
entrées/sorties.

e) La gestion des mémoires secondaires


Un contrôleur de périphérique sait lire et écrire un secteur donc le numéro lui est indiqué en
paramètre. Le problème de savoir si un secteur est libre ou occupé, à qui est alloué un secteur ne le
concerne pas. Ces problèmes sont confiés au systèmes d'exploitation.
Le système d’exploitation est donc responsable de :
(34) la gestion des espaces libres
(35) l'allocation des espaces libres
(36) l'ordonnancement des requêtes d’accès au disque

f) gestion du réseau
Le système d’exploitation considère les accès au réseau comme une sorte d’accès au fichier.
Les détails de traitement d’accès réseau sont confinés dans le pilote de l’interface réseau

g) La protection du système
Le système d’exploitation fournit un moyen permettant de distinguer les utilisations autorisée
ou non d’une. ressource. La protection pour le système d’exploitation consiste à fournir un
mécanisme de contrôle des accès aux ressources par les processus des utilisateurs.
h) L’interpréteur de commandes
C’est l’interface entre l’utilisateur et le système d’exploitation. Certains systèmes
d’exploitation tels que MSDOS, UNIX n’intègre pas l’interpréteur dans le noyau. Pour eux il

5
s’agit d’un programme qui s’exécute en premier quand un utilisateur se connecte. Le but de
l’interpréteur est d’obtenir la prochaine commande et de l’exécuter.

En résumé un système d’exploitation offre les services suivants :


(37) la gestion des processus
(38) la gestion des entrées / sorties
(39) la gestion des fichiers
(40) la gestion de la mémoire
(41) la détection des erreurs
(42) l’allocation des ressources
(43) la comptabilité sur l’utilisation des différents ressources par les utilisateurs
(44) la protection

Le noyau d’un système d’exploitation est la partie de ce système qui ne peut pas être
remplacée par un programme de l’utilisateur. Il contient les fonctions essentielles du système. On
distingue deux types de noyau :
(45) le noyau monolithique : il est composée d’un ensemble de procédures indépendantes
pouvant s’appeler les unes les autres . Il n’y a pas une organisation en module
(46) le micronoyau : c’est un noyau où tout ce qui n’est pas essentiel n’a pas été implémenté.
Un tel noyau implémente juste les fonctions essentielles. Les autres sont implémentées à un
niveau supérieure au dessus du noyau soit dans des bibliothèque soit même au niveau des
processus utilisateur.

1-4 Evolution des systèmes d’exploitation.


Tout comme le matériel les systèmes d’exploitation ont connu une série de changements
révolutionnaires . Cette évolution des systèmes d’exploitation est intimement liée à l’évolution du
matériel. Sur le plan matériel, on observe en passant d’une génération à une autre :
- une diminution des coûts, de la taille, de la chaleur dissipée et de l’énergie consommée
- une augmentation de la vitesse des composants, et des capacités de stockages
Cette évolution du matériel exige la mise sur pied à chaque nouvelle génération des systèmes
d’exploitation capables de tirer profit des avantages du nouveau matériel.
Génération 0: Absence de système d'exploitation ou la porte ouverte
Les premiers ordinateurs fabriqués à partir de 1945, n’avaient pas de système d’exploitation.
Les programmes étaient réalisés sous forme de cartes enfichables au début de l’informatique. Seuls
des spécialistes pouvaient programmer. Un utilisateur réserve la machine pendant une certaine tranche
horaire et vient muni de sa carte enfichable. Les programmes sont conçus en langage machine absolu.

Génération 1: Le traitement par lots


Par la suite, il devint possible d’enregistrer les programmes sur des cartes perforées. La
machine étaient réservée complètement à un utilisateur pendant un certain temps au cours duquel il
devait charger ses cartes, lancer l’exécution de son programme et lister les résultats sur imprimantes.
L’utilisateur fait tout ce travail à partir du pupitre.
Trop de temps était perdu entre un job et le suivant. Le premier système d’exploitation a eu
pour but de combler cette lacune en assurant la transition automatique entre un job et le suivant
préparés d’avance: c’est le moniteur d’enchaînement. Avec ce moniteur d’enchaînement, considéré
comme l’ancêtre des systèmes d’exploitation, le traitement par lot (batch processing) voit le jour. Dans
ce mode de fonctionnement, chaque utilisateur saisit son travail sur des cartes. Parmi ces cartes, on a
des cartes de contrôle qui indiquent le début et la fin du job, et le compilateur qu’il faut charger pour la
compilation du programme. Un opérateur est chargé de collecter les travaux sur cartes et de former un
lot de jobs qu’il soumettra à l’ordinateur. Le moniteur d’enchaînement permet au processeur central de
passer d’un job à un autre. Les jobs sont exécutés un à un et les résultats envoyés sur imprimantes.
Tout le processus de traitement (exécution des travaux et gestion des entrées sorties) est fait par le
processeur.
Les premiers systèmes d’exploitation qui ont utilisés cette techniques sont par exemple : le
FMS (Fortran System Monitor) et IBSYS d’IBM.

6
Le bon fonctionnement d’un système de traitement par lot suppose :
- la limitation du temps d’occupation du processeur pour éviter qu’une boucle infinie dans un
programme ne bloque tout le système.
- la supervision des entrées/sorties pour éviter des boucles sur l’utilisation des périphériques
- la protection de la zone mémoire réservée au moniteur
Le rendement du système est ainsi amélioré. Mais un inconvénient demeure: le processeur
central s’occupe entièrement des entrées/sorties qui sont pénalisantes en temps.
Une amélioration est apportée en introduisant un processeur moins puissant spécialisé dans les
entrées/sorties. Les jobs collectés sur cartes sont transcrites sur une bande magnétique par le
processeur d’entrées/sorties. Dès que la bande est pleine, elle est envoyée au processeur central qui va
lire les programmes un à un et les exécuter. Les résultats de chaque programme sont envoyés en sortie
sur une autre bande magnétique. Dès que tous les jobs ont été exécutés, la bande contenant les
résultats est retirée et envoyée au processeur d’entrées/sorties qui se chargera de copier les résultats
sur imprimantes.
Du fait de l’introduction du processeur spécialisé dans les entrées/sorties, le processeur central
n’a plus accès aux périphériques lents que sont l’imprimante et les lecteurs de cartes. Le gain en temps
est donc considérable.

Génération 2: La multiprogrammation
La génération 2 commence avec l’introduction des tambours et disques magnétiques pour
stocker les données. Ces supports de données sont adressables et à accès plus rapide que les bandes
magnétiques. Les programmes sont lus sur les cartes perforées et enregistrés sur disques. Du fait que
les disques sont à accès aléatoire, le moniteur peut choisir d’exécuter un job quelconque parmi les jobs
enregistrés sur disques. Un nouveau module est ajouté au système d’exploitation, le planificateur dont
le rôle est entre autres, d’affecter une priorité à chaque programme; cette technique qui permet au
processeur d’aller chercher les programmes sur disques suivant une certaine priorité et de les exécuter
est appelée SPOULE (traduction de Spool : Simultaneous Peripheral Opération On Line).
L’évolution du spoule va conduire à l’introduction de la multiprogrammation. Dans un tel système
plusieurs programmes sont chargés en mémoire centrale et se partagent le processeur. A tout moment
le processeur est alloué à un seul programme, mais dès que celui-ci a besoin de faire des
entrées/sorties le processeur initialise celles-ci et les fait exécuter par les unités d’échanges.
L’exécution du programme est donc suspendue et le processeur commence l’exécution du programme
le plus prioritaire dans la liste des programmes en attente. Le système d’exploitation s’enrichit d’un
nouveau module: l’allocateur (dispatcher). L’allocateur peut aussi interrompre l’exécution d’un
programme qui dure trop longtemps même si ce dernier ne demande pas à faire des entrées/sorties :
c’est ce qu’on appelle la préemption.
Une amélioration des systèmes d’exploitation multiprogrammés conduit aux systèmes à temps
partagés caractérisés par :
- un mode d’exploitation interactif et conversationnel
- un quantum de temps accordé à chaque programme pour son exécution. Au delà de ce
quantum, le programme est interrompu même s’il ne demande pas des entrées/sorties. Ce type de
système donne l’illusion à chaque utilisateur qu’il a à sa disposition toutes les ressources de la
machine.

Génération 3: Système à but général


Elle a été introduit avec le système IBM360. Un tel système est à but général et est supposé
tout faire. Il supporte à la fois le traitement par lot, le temps partagé et le traitement en temps réel. Les
systèmes temps réel sont caractérisés par des réponses immédiates aux requêtes. Les systèmes de la
troisième génération sont très grands et très cher.

Génération 4: Système pour ordinateurs personnels


La quatrième génération est celle qui commencent avec l’introduction des ordinateurs
individuelles. Elle est carctérisée par l'introduction de L'IHM. On peut citer parmi eux MSDOS,
windows 3.x., Windows NT, Unix, Linux

7
Génération 5:
La cinquième génération est celle des systèmes en réseau et des systèmes distribués. Un réseau
d’ordinateurs est un ensemble d’ordinateurs connectés à travers des liens de communication( fibre
optique, câble coaxial, ondes hertzienne, à etc) et qui peuvent s’échanger des informations. Un
système d’exploitation réseau permet de gérer un ordinateur relié à un réseau d’ordinateurs; chaque
utilisateur du réseau sait sur quelle machine il est connecté et peut envoyer un message ou transférer
des données à une autre machine en indiquant clairement son adresse. Dans un système distribué, il
peut il y avoir un ou plusieurs processeurs qui se partagent des mémoires communes, il peut même y
avoir plusieurs ordinateurs interconnectés, mais tout ceci est transparent à l’utilisateur. Tout se passe
pour l’utilisateur comme s’il a un seul processeur à sa disposition. Son programme peut être exécuté
sur un autre site que celui où il est connecté; ses données peuvent être sur le disque dur d’une autre
machine que celle sur laquelle il est connecté.

I-5 Résumé
Un ordinateur moderne comporte un ou plusieurs processeurs, une mémoire centrale, des
horloges, des terminaux, des disques, des interfaces de connexion à des réseaux, des imprimantes,
...etc. Ecrire des programmes qui prennent en compte tous ces éléments et les gèrent correctement est
un travail très difficile : la programmation dans ce cas serait l’apanage d’une très faible communauté
de spécialistes. Les systèmes d’exploitation libèrent le programmeur de la complexité du matériel en
offrant à ce dernier une machine virtuelle plus facile à utiliser et en gérant efficacement et économique
les différentes ressources de la machine.
Le système d’exploitation est donc un gestionnaire des ressources de la machine et une
machine étendue.

8
Partie I : Gestion des Processus
I – 1 Définitions
Système d’exploitation : C’est un programme qui joue le rôle d’intermédiaire entre
l’utilisateur et l’architecture matérielle de la machine. Il a pour but de fournir un
environnement dans lequel un utilisateur peut exécuter de façon commode et efficace des
programmes. Il peut être vu comme un gestionnaire des ressources de la machine ou comme
une machine virtuelle présentant une interface plus facile à utiliser.

Action atomique : C’est une action indivisible. Les états observables précèdent ou suivent
l’action. Il n’y a pas d’état intermédiaire.

Point d’observation : instant où on peut observer l’état du processeur (contenu des registres)
et de la mémoire. Il se situe entre deux instructions, ou à des endroits où la machine est
interruptible.
Etat observable : état de la machine à un point observable
Trace d’exécution : suite d’états observables produite par l’exécution d’un programme. Ils
sont datés et ordonnés.
Processus : Il correspond à l’exécution d’une tâche. Il est une entité active possédant un
contexte composé de :
- un programme
- un compteur de programme
- des registres
- un segment de code
- un segment de mémoire
- un segment de pile
- la liste des fichiers ouverts
- les informations d’ordonnancement
- les informations pour la comptabilité du temps
Contexte d’un processus : Ensemble des informations accessibles au cours du cycle de vie
du processus. On distingue un contexte processeur et un contexte en mémoire. Le contexte
processeur est formé du contenu de l’ensemble des registres de la machine. Le contexte en
mémoire est l’ensemble des informations stockés en mémoire et qui sont manipulées par le
processus.

Commutation de contexte : c’est l’opération qui consiste à sauvegarder le contexte du


processus courant afin de pouvoir exécuter un autre processus, après avoir restauré le contexte
de ce dernier.

Processus coopérants : ensemble de processus dont les contextes sont non disjoints.
L’exécution de l’un affecte l’exécution de l’autre.

Synchronisation : le fait d’imposer un ordre de précédence entre l’exécution de certaines


actions de différents processus coopérants.

Mécanismes de synchronisation : ensemble d’outils permettant de réaliser la


synchronisation entre processus coopérants.

Noyau de synchronisation : c’est la mise en œuvre des mécanismes de synchronisation dans


un système d’exploitation . On l’appelle aussi noyau de gestion des processus.

9
Noyau d’un système d’exploitation : c’est la partie du système d’exploitation correspondant
à:
- la gestion des processus
- la gestion de la mémoire
- la gestion des entrées / sorties de bas niveau.
- La gestion de bas niveau des fichiers

Le noyau d’un système d’exploitation ne peut pas être remplacé par du code appartenant à un
utilisateur.
I-2 Processus séquentiels
Un processus séquentiel (ou processus) correspond à l’exécution d’une tâche. Un
processus a un contexte et s’exécute soit en mode maître, soit en mode esclave. La plupart du
temps, le processus s’exécute en mode esclave, mais dès qu’un appel système est effectué, le
processus entre en mode maître. Un processus n’est donc jamais simultanément en mode
maître et en mode esclave.
L’exécution d’un processus utilise deux piles :
- une pile noyau du processus
- une pile utilisateur du processus
La pile noyau suit immédiatement la pile utilisateur en mémoire et les deux constitue la pile
du processus. En mode maître, le processus utilise la pile noyau , et en mode esclave, il utilise
la pile utilisateur.
NB : le noyau du système d’exploitation a sa propre pile pour son exécution.

Plusieurs processus séquentiels peuvent partager le même programme. Plusieurs


processus ne partageant pas le même code peuvent aussi coexister dans un système
multitâche. Mais en général dans un système informatique, il n’est pas toujours possible
d’avoir autant de processeur que de processus. Le système d’exploitation doit donc utiliser un
pseudo-parallélisme pour exécuter différentes tâches. Au lancement du système
d’exploitation, il n’y a en général qu’un seul processus. Mais un processus peut créer d’autres
processus. On a donc en fin de compte une arborescence des processus.

Un processus spécial appelé ordonnanceur fonctionnant en mode maître permet de


réaliser la commutation de contexte. L’ordonnanceur est activé par une interruption horloge à
la fin de chaque quantum de temps.

Différents états d’un processus :


- nouveau
- prêt
- actif
- bloqué
- terminé

Diagramme de transition :
- nouveau / prêt : fin des initialisations
- prêt / actif : choisi par l’ordonnanceur
- actif / prêt : fin du quantum (une interruption)
- actif / bloqué : attente d’entrée/sortie ou d’un événement
- bloqué / prêt : fin des entrée / sortie ou réalisation de l’événement
- actif / terminé : fin du processus

10
I-3 Synchronisation entre processus
On peut ressentir la nécessité de synchroniser des processus coopérants, s’ils sont en
compétition pour une ressource critique. La ressource critique peut être :
- un fichier partagé
- une zone de mémoire
- une imprimante
- un table d’une base de données
- … etc

On peut aussi faire coopérer des processus pour essayer d’optimiser le temps d’exécution :
décomposer une tâche en plusieurs sous tâches et allouer les sous tâches à différents
processus. Assembler les solutions partielles pour avoir une solution globale.
Enfin, pour sa convenance un utilisateur peut choisir de travailler sur plusieurs tâches
partageant une même ressource à la fois. Par exemple :
- éditer un fichier
- compiler le fichier
- imprimer le fichier

. Problème de la section critique :


Considérer n processus coopérants P0,P1,…,Pn-1. Chaque processus de l’ensemble a un
bout de code appelé section critique dans lequel il accède aux données partagées. Quand un
processus entre dans sa section critique, aucun autre processus ne doit être dans la sienne.
L’exécution des sections critiques se fait en exclusion mutuelle. Le problème de la section
critique consiste à développer un protocole permettant à un ensemble de processus
coopérants de traverser leurs sections critiques sans problème

Code d’un processus coopérant :


<section non critique>
<section critique >
<section non critique >
< reste code >

Conditions pour une bonne coopération entre processus :


- Exclusion mutuelle : un seul processus en section critique
- Un processus qui ne se trouve pas en section critique ne doit pas empêcher un
autre d’entrer en section critique
- Aucune hypothèse ne doit être faite sur la vitesse relative des processus et sur
le nombre des processus
- Un processus qui désire entrer en section critique ne doit pas attendre
indéfiniment
I-4 Outils de synchronisation
I-4-1 Solutions algorithmiques
Leur validité est basée sur le fait qu’à un instant donné, un seul processus peut accéder
à la mémoire centrale, le processus actif.
a) variable de verrouillage .
verrou= variable partagée. 0  ressource libre. 1  ressource occupée

while (verrou !=0) /*attendre */


verrou=1 ;
<section critique >

11
verrou=0 ;

Inconvénient : Processus interrompu avant d’avoir mis le verrou à 1.

b) alternance .
Utilise une variable tour. Un processus entre en section critique si c’est son tour, c’est-à-dire
que la variable tour porte son numéro.

P0 P1
While (1) { While (1) {
While (tour!=0) /* attendre */ ; While (tour!=1) /* attendre */ ;
<section critique > <section critique >
tour=1 ; tour=0 ;
<section non critique> <section non critique>
} }

Inconvénient :
- Si l’un des processus est plus rapide  Un processus non en section critique
empêche un autre d’entrée en section critique.
- Si l’un des processus se termine l’autre ne peut plus entrer en section critique.

c) solution de peterson.
#define False 0
#define True 1
#define N 2
int interesse[N] ;
int tour;
void entrer_region(int process)
{ int autre;
autre=1-process ;
interesse[process]=True ;
tour=process ;
while (tour==process && interesse[autre]==True) /*attendre */ ;
}

void quitter_region(int process)


{ interesse[process]=False ;}

Code d’un processus devient :


<section non critique >
entrer_region(n° processus) ;
<section critique>
quitter_region(n° processus) ;
<section non critique>

NB : l’attente active n’exclut pas en général les interblocages. Il suffit de prendre l’exemple
de deux processus dont l’un est prioritaire. Le moins prioritaire est en section critique.

I-4-2 Solutions matérielles

12
a) le masquage d’interruption.
On autorise un processus à masquer les interruptions et à les démasquer à un instant donné. Le
code d’un processus devient :
<section non critique>
<masquer les interruptions >
<section critique>
<démasquer les interruptions>
Dès qu’un processus a masqué les interruptions, aucun autre processus ne peut devenir actif
puisque l’ordonnanceur utilise justement le mécanisme d’interruption pour réaliser allouer le
proceseur.

Inconvénient : Si un processus oublie de démasquer les interruptions, c’est la fin du système.

b) l’instruction TSL.
Cette instruction charge le contenu d’un mot mémoire dans un registre, puis met une valeur
non nulle à cette adresse mémoire, et tout cela de façon indivisible. Le processeur qui effectue
TSL verrouille le bus de données pour empêcher les autres d’accéder à la mémoire pendant la
durée de l’opération.

I-4-3 Les appels systèmes de synchronisation


a) SLEEP et WAKEUP
Ici le système d’exploitation offre deux appels système WAKEUP et SLEEP. Un
processus qui exécute SLEEP() s’endort. Un processus exécute WAKEUP(&adr) pour
réveiller le processus référencé par adr.
Exemple :

Producteur Consommateur
While (1) { While (1) {
Produire_objet() ; if (compteur==0) sleep() ;
if (compteur==N) sleep() ; retirer_objet() ;
compteur++ ; compteur-- ;
déposer_objet() ; If (compteur==(N-1))
If (compteur==1) wakeup(&producteur) ;
wakeup(&consommateur) ; }
}

NB : Si au moment où le signal wakeup arrive à un processus, ce dernier n’est pas endormi,


alors le signal est perdu. Un bit de réveil permet de mémoriser un tel signal. Si un processus
qui veut dormir trouve le bit de réveil à 1, il ne s’endort pas mais poursuit son exécution après
avoir positionné le bit de réveil à 0.

NB : On peut cependant trouver des situations où un seul bit de réveil ne suffit pas. Multiplier
les bits de réveil ne résout pas le problème.

i) les sémaphores
Un sémaphore est une variable entière initialisée généralement à une valeur supérieure ou
égale à zéro, et qui ne peut être manipulée que par l’intermédiaire de deux appels systèmes
DOWN (ou P) et UP (ou V) dont l’exécution est atomique.

13
Le système gère une file d’attente (f) qui permet de garder les processus bloqué sur le
sémaphore, et c’est de cette file qu’un processus est réveillé par le sémaphore. Les primitives
Down et Up peuvent se présenter ainsi :

Void Down(int s,file f,int tP[], int nP) Void Up(int s,file f,int tP[],int *nP)
{ s--; { s++;
if (s<0) { if (s<=0) {
tP[nP]=”bloqué”; defiler(f,nP);
enfile(f,nP) ; tP[*nP]=”actif”;
} }
} }

Le code d’un processus utilisant un sémaphore pour se synchroniser avec d’autres processus
est :
<section non critique >
Down(s,f,tP,nP) ;
<section critique >
Up(s,f,tP,&nP);
<section non critique>
Montrons que la solution utilisant les sémaphores est correcte :

Soit s un sémaphore, notons :


- np(s) le nombre total d’appel de Down
- nv(s) le nombre total d’appel de Up
- nf(s) le nombre de franchissements de Down, c’est-à-dire le nombre de
processus ayant exécuté Down sans se bloquer
- nbloc(s) le nombre de processus bloqué dans la file associée au sémaphore
- nc(s) le nombre de processus en section critique
Les propriétés suivantes peuvent être vérifiées simplement :
S =S0 - np(s) + nv(s), où S0 est la valeur initiale du sémaphore
Le nombre de franchissements est :
nf(s) = min(np(s),s0+nv(s))
nbloc(s)= np(s) – nf(s)
nc(s)=nf(s)-nv(s)
exclusion mutuelle :
nf(s)≤s0+nv(s)  nc(s) ≤ s0
absence de blocage :
si nc(s)=0 , alors nf(s)=nv(s)  np(s)=nf(s)  nbloc(s)=0 ;

Problèmes des sémaphores :


1) sections critiques imbriquées  interblocage
P0 P1
…. ….
(1) Down(S1) (1’) Down(S2)
(2) …. (2’) ….
(3) Down(S2) (3’) Down(S1)
(4) …. (4’) ….
(5) Up(S2) (5’) Up(S1)
(6) ….. (6’) …..

14
(7) Up(S1) (7’) Up(S2)

Si les instructions des deux processus sont exécutées dans l’ordre (i), (I’), il y aura
interblocage.
2) attente indéfinie en section critique
Si un processus reste trop longtemps en section critique, il empêche les autres d’y
entrer. Les solutions adoptées sont les suivantes :
- un processus qui entre en section critique devient très prioritaire, et donc en
sort très vite
- une horloge de garde est armée dès qu’un processus entre en section critique.
S’il n’en sort pas après un certain temps, le système d’exploitation l’interrompt
et libère la section critique

3) privation
Il y a risque de privation. Tout dépend de la politique de gestion de la file d’attente, où on
stocke les processus bloqués.

j) les moniteurs
Un moniteur est un outil de plus haut niveau que les sémaphores, permettant d’écrire des
noyaux de synchronisation. Un moniteur est une sorte de classe définie par le langage utilisé.
Il est constitué :
- d’un ensemble de variables d’état inaccessibles directement aux utilisateurs du
moniteur
- d’un ensemble de primitives manipulant ces variables et accessibles aux
utilisateurs du moniteur. Les procédures du moniteur s’exécutent toujours en
exclusion mutuelle.
- Parmi les variables d’état il y en a appelée condition (c), sur lesquelles on peut
réaliser les opérations suivantes :
i. c.attendre bloque le processus qui s’exécute sur la condition c
ii. c.vide retourne vrai si aucun processus n’est bloqué
iii. c.signaler réveille un des processus bloqué sur c si non (c.vide).
Si aucun processus n’est bloqué, cette opération n’a aucun effet.

Un seul processus peut être actif dans un moniteur à un instant donné. Par conséquent,
signaler doit toujours être la dernière instruction d’une procédure du moniteur.

Comment assurer qu’un seul processus est actif dans le moniteur à un instant donné ? En
utilisant un sémaphore binaire pour assurer l’accès exclusif au moniteur.

NB : Parmi les procédures du moniteur, il y en a une qui permet d’initialiser les variables
d’état.

k) les compteurs d’événement.


Cette utilise une variable particulière appelée compteur d’événement.. Trois événements sont
définis pour un compteur d’événements E :
- READ(E), donne la valeur du compteur E
- ADVANCE(E), incrémente d’une unité la valeur du compteur E
- AWAIT(E,V), attend que E atteigne ou dépasse V, attend jusqu’à ce que E ≥
V.
Exemple : Producteur / Consommateur avec les compteurs d’événement.

15
#define N 100
typedef int compteur_evt ;
compteur_evt in=0 ; /* nombre objets dans tampon */
compteur_evt out=0 ; /* nombre objets retirés du tampon */

void producteur()
{ int objet,sequence=0 ;
while (1) {
produire_objet(&objet) ;
sequence++ ;
AWAIT(out,sequence-N) ;
Mettre_objet(objet);
ADVANCE(&in) ;
}
}

void consommateur()
{ int objet,sequence=0 ;
while (1) {
sequence++ ;
AWAIT(in,sequence) ;
Retirer_objet(&objet);
ADVANCE(&out) ;
Utiliser_objet(objet) ;
}
}

g) L’Echange de message
Les outils étudiés jusqu’ici ne permettent de synchroniser des processus que s’ils sont sur la
même machine. Si les processus à synchroniser tournent sur des machines différentes, aucune
des procédures précédentes ne peut marcher. L’échange de message offre une solution à ce
problème. On utilise deux primitives pour l’échange de messages :
Send(destination,message) ;
Receive(source,&message) ;
L’émetteur et le récepteur créent des boîtes aux lettres. Chaque processus communicants lit
les messages dans sa boîte aux lettres à l’aide de la primitive receive. Il dépose des messages
dans la boîte aux lettres de l’autre processus à l’aide de la primitive send. Les adresses source
et destination sont en fait des adresses permettant de repérer des boîtes aux lettres. Par
exemple une adresee IP suivi d’un numéro de port permet de repérer la boîte aux lettres d’un
processus en ce qui concerne le web (protocole http).
Si source est ANY, le récepteur attend des messages de n’importe quel émetteur. Le récepteur
peut se bloquer s’il n’y a pas de message. Les messages transitent à travers un réseau pour
arriver à destination. On peut donc être confronté à l’un des problèmes suivants :
- le problème de l’acquittement
- le problème de numérotation des messages
- la numérotation des processus. A quel processus délivrer un message entrant ?
- Faut-il utiliser ou non des boîtes aux lettres ?

16
Exemple : Producteur / Consommateur avec les messages
#define N 100
#define Taille 4
typedef int message[Taille] ;

void producteur()
{ int objet ;
message m ;
while (1) {
produire_objet(&objet);
receive(consommateur,&m) ;
faire_message(&m,objet) ;
send(consommateur,m) ;
}
}

void consommateur()
{ int i,objet ;
message m ;
for (i=0 ;i<N ;i++) send(producteur,m) ; /* expédie N messages vides */
while (1) {
receive(producteur, &m) ;
retirer_objet(&m,&objet) ;
send(producteur,m) ;
utiliser_objet(objet) ;
}
}

Ce système repose sur l’utilisation des boîtes aux lettres. Chaque processus a sa boîte aux
lettres.. Dans la zone de données du système d’exploitation, il y a un tampon pour le stockage
temporaire des messages sortants ou entrants. Le receive est bloquant si la boîte aux lettres du
récepteur est vide. Le send est aussi bloquant si la boîte aux lettres du récepteur est pleine.
NB : Des processus communicants utilisant des messages peuvent ne pas avoir des boîtes aux
lettres. On parle dans ce cas de rendez-vous. Un processus récepteur doit être au rendez-vous
quand un message arrive, si non il est perdu.

Quelques solutions :
- envoyer un message d’acquittement à la réception d’un message
- si le message est perdu, il n’y a pas d’acquittement. Dans ce cas, on retransmet
le message
- Si acquittement perdu, on retransmet aussi le message. Le message doit avoir un
numéro pour éviter les duplications à la réception.

Pour distinguer les processus, il faut les nommer :


- Adresse de la machine si un seul processus par machine
- associer un numéro à chaque processus
- numéro de machine + numéro de processus

I -5 Les processus légers


Un processus léger est un chemin d’exécution d’un processus. Il possède :

17
- un compteur de programme
- un ensemble de registres
- une pile
Il partage avec tous les autres processus légers du même processus :
- le segment de code
- le segment de données
- les ressources du système d’exploitation telles que la table des descripteurs de
fichiers, et la table des signaux
Un processus poids lourd est tout simplement un processus ayant un seul processus léger. Un
processus ne peut rien faire s’il n’a pas de processus léger.
NB : Chaque processus léger a sa propre copie de certaines variables globales telles que
errno.
Les processus légers partagent le processeur de la même façon que les processus poids
lourds. Un processus léger peut créer des processus légers fils. A un instant donné, un
processus léger peut être dans l’un des états étudiés pour les processus poids lourds.
Pour éviter les conflits d’accès, les processus légers utilisent les mécanismes de
synchronisation étudiés pour les processus pour accéder aux ressources partagées.
L’intérêt des processus légers est de permettre une exécution parallèle à l’intérieur
d’un même processus grâce au mécanisme de pseudo-parallélisme où à un parallélisme réel si
en présence de multiprocesseurs. Il existe plusieurs modèles pour l’implémentation des
processus légers :
- le modèle répartiteur / travailleurs. Un processus répartiteur confie les requêtes à
traiter à un ensemble de processus légers travailleurs. Seul le répartiteur a accès
aux boîtes à lettres pour récupérer les requêtes
- le modèle de groupe : chaque processus léger accède à la boîte aux lettres pour
récupérer une requête et la traiter
- le modèle pipeline

I – 6 Implémentation des processus sous UNIX.


I – 6-1 Structure d’un système d’exploitation Unix
Programmes d’application
Shells, commandes, compilateurs et interpréteurs,bibliothèques, utilitaires
Interface (appels système / noyau)
Gestionnaire des signaux des Système de fichiers
terminaux, Gestionnaires des signaux des Ordonnanceur
Pilotes des périphériques périphériques blocs Remplacement des pages en
d’entrée/sortie caractères Pilotes des périphériques mémoire
d’entrée / sortie blocs Pagination à la demande
(gestionnaire de mémoire
virtuelle)
Interface (noyau / matériel)
Contrôleurs des terminaux Contrôleurs d’autres Contrôleurs de mémoire
périphériques (disques,
bandes, … etc)

Unix peut être vu comme un ensemble de couches superposées les unes au dessus des
autres. Le noyau (quatrième ligne) interagit directement avec le matériel. Les programmes
d’application sont en général indépendants du matériel, ce qui permet leur portabilité. Les
applications au dessus du noyau interagissent avec ce dernier en invoquant les appels système.
Un appel système demande au noyau de réaliser un certain service au profit du programme

18
appelant. Le système unix autorise un périphérique à interrompre le processeur de façon
asynchrone.
A la réception d’une interruption, le noyau sauvegarde le contexte du processus
actif, détermine la cause de l’interruption et exécute le traitant d’interruption approprié. A la
fin de l’exécution du traitant, le noyau restaure le contexte du processus actif et reprend son
exécution comme s’il ne s’était rien passé. Les périphériques sont en général organisés en
niveaux de priorité :

Erreur machine
Horloge
Disques
Périphériques réseaux
Terminaux
Logiciels
La première représente la priorité la plus haute, alors que la sixième ligne représente la
priorité la plus basse.
L’exécution d’un processus se déroule suivant deux modes : le mode esclave (ou
programme, ou utilisateur) et le mode maître (ou noyau, ou superviseur). Les différences entre
les deux modes sont :
- en mode esclave, un processus a accès à ses propres instructions et ses données,
mais pas aux instructions et aux données du noyau. Par contre un processus en
mode maître peut accéder aux données des zones utilisateur et noyau.
- Certaines instructions du jeu d’instruction d’une machine sont privilégiées et ne
peuvent être invoquées qu’en mode maître. Par exemple, l’instruction qui
masque les interruptions, l’instruction qui manipule le mot d’état du processeur.

Unix a été conçu pour être un système multiprogrammé et à temps partagé.


L’interface utilisateur (shell) est simple et peut être remplacé par un autre programme de
l’utilisateur.
Le noyau du système représenté par la quatrième ligne de ce tableau. Il comporte un
certain nombre de structures de données.

1-6-2 le noyau Unix


Il comprend les modules suivants :
- le système de fichiers
- les pilotes de périphériques blocs et caractères
- le gestionnaire de la mémoire
- l’ordonnanceur (scheduler) et le distributeur (dispatcher)
- le noyau de synchronisation
- les traitants des interruptions
- gestionnaire des caches

les structures de données du noyau


- la table des processus : une entrée de cette table décrit un processus. Elle n’est
jamais sauvegardée en mémoire virtuelle. Dans chaque entrée on a
i. la taille du processus (zone mémoire nécessaire)
ii. uid (identificateur du propriétaire du processus)
iii.pid (l’identificateur du processus)

19
iv.le temps passé en mode noyau
v. le temps passé en mode utilisateur
vi.le temps passé uc consommé
vii. le temps passé en sommeil récemment
viii. une liste des signaux pendants
ix.un pointeur sur la zone utilisateur du processus
x. la priorité du processus
xi.les registres du processeur (CO,SS,CS,DS,…)
xii. l’état du processus

- la zone utilisateur du processus : Elle contient les informations du contexte d’un


processus qui peuvent être sauvegardées en mémoire virtuelle :
i. uid réel (
ii. euid (uid effectif)
iii.la table des signaux
iv.l’identificateur du terminal associé au processus
v. champ erreur (enregistre les erreurs durant un appel système)
vi.un champ pour les valeurs de retour des appels système
vii. la table des descripteurs de fichiers
viii. le répertoire courant
NB : la table des processus et la zone utilisateur constituent le contexte du processus.

- la table de description des fichiers ouverts


- la table des inodes
- la pile du noyau (utilisée par le noyau pour sa propre exécution)
- une table des niveaux de priorité dont chaque entrée est un pointeur sur une file
d’attente des processus ayant la priorité associée. Les entrées de cette table sont
indicées par des entiers variant entre –n à +m. Les plus hautes priorités sont
négatives et représentent les processus du noyau et les plus faibles sont positives
et représentent les processus utilisateur.

3 Processus utilisateur de priorité 3


2 Processus utilisateur de priorité 2
1 Processus utilisateur de priorité 1
0 Processus utilisateur de priorité 0
-1 Attente fin d’un fils
-2 Attente sortie terminal
-3 Attente entrée terminal
-4 Attente tampon disque
-5 Attente entrée/sortie disque

- un vecteur d’interruption : Chaque entrée de vecteur contient un pointeur sur un


traitant d’interruption. Les interruptions sont numérotées de 0 à un certain
maximum. 0 est l’interruption la plus prioritaire.
- La carte mémoire qui contient l’information sur l’occupation de la mémoire.

Les états d’un processus :


a. actif en mode utilisateur
b. actif en mode noyau

20
c. prêt en mémoire
d. bloqué en mémoire
e. prêt en mémoire virtuelle
f. bloqué en mémoire virtuelle
g. suspendu (suite par exemple au traitement d’un interblocage)
h. En création
i. zombi (terminé)
les transitions sont :
(a,b) : un appel system, une interruption
(b,a) : retour après un appel système ou fin d’un traitant d’interruption
(b,b) : étant en mode noyau, le processus fait un appel system ou reçoit une
interruption
(b,d) : processus bloqué car attente d’un événement (entrée/sortie)
(c,b) : le processeur est alloué au processus
(b,g) : le processus est suspendu (pour résoudre un problème d’interblocage)
(d,c) : l’événement attendu s’est réalisé
(d,f) : il n’y a pas assez de place en mémoire. Le processus est mappé sur disque
(c,e) : pas de place en mémoire : swap out
(e,c) ; place en mémoire : swap in
(f,e) : l’événement attendu s’est réalisé, mais il n’y a pas assez de place en mémoire
(h,e) : processus vient d’être créé, mais il n’y a pas assez de place en mémoire
(h,c) : processus vient d’être créé et il y a de la place en mémoire
(b,i) : le processus s’est terminé mais a encore une entrée dans la table des processus

L’accès d’un processus aux ressources :


Les droits d’accès d’un processus à une ressource dépendent du propriétaire du
programme associé au processus et de l’utilisateur qui a lancé le processus. Le noyau associe
deux identificateurs d’utilisateurs à un processus :
- le UID qui l’identificateur d’utilisateur réel
- le EUID qui est l’identificateur d’utilisateur effectif
Le UID identifie l’utilisateur ayant lancé le processus. Le EUID est utilisé pour assigner les
droits aux fichiers crées par le processus, pour vérifier les droits d’accès aux ressources par le
processus, ou pour vérifier les droits d’envoi de signaux à d’autres processus. Par défaut le
UID est égal au EUID. Mais si le programme a son bit SUID fixé à 1, alors le processus prend
pour EUID le UID du propriétaire du programme. En général un processus prend son UID et
son EUID du processus qui l’a créé.
Un programme peut aussi changer explicitement son EUID en appelant l’appel
système setuid :
- si le EUID est celui du super utilisateur, le noyau change le UID et et EUID en
celui fournit par setuid.
- Si le EUID n’est pas celui du super utilisateur, alors le noyau change EUID en
celui passé en paramètre si valeur fournie est égale à UID réel, ou si la valeur
fournie est égale à celle présente dans la table des processus.
- Dans tous les autres cas, il y a erreur.
1-6-3 Processus et amorçage d’unix
Pour mettre une machine en marche, on appuie généralement sur un bouton de mise
sous tension. Un petit programme de quelques instructions du bios en ROM est chargé en
mémoire centrale. Ce bout de programme a pour tâche de lire et de charger en mémoire le
secteur d’amorçage de la machine. Sous Unix, le secteur d’amorçage est le bloc zéro du
disque. Le code contenu dans ce secteur d’amorçage permet au cours de son exécution de

21
charger le noyau en mémoire et de lancer son exécution. Le noyau initialise les structures de
données internes, c’est-à-dire :
- construit la liste chaînée des tampons libres
- construit la liste chaînée des inodes libres
- initialise la tables des processus
- initialise la tables des inodes
- initialise la tables de description des fichiers ouverts
- monte les systèmes de fichiers
L’exécution du noyau constitue le processus numéro zéro. Quand le noyau a créé et initialisé
toutes les structures de données internes, il crée le processus init qui porte le numéro
d’identification 1. Il est la racine de l’arborescence des processus dans un système Unix. Son
code exécutable est le fichier /sbin/init. Après quelques initialisations en mode maître, il lit le
fichier /etc/inittab et traite les lignes de ce fichier les unes après les autres. Au cours du
traitement de /etc/inittab, init crée des processus qui vont scruter les terminaux à la recherche
des demandes de connexion.

1-6-4 Ordonnancement des processus


Il se fait suivant le mécanisme des priorités. C’est toujours le processus le plus
prioritaire à un moment donné qui a le processeur. Le mécanisme de priorité ici est à plusieurs
niveaux :
Le permuteur (swapper)
Processus en attente d’E/S disque
Processus en attente d’informations du tampon
Processus en attente d’inodes
Processus en attente d’entrées sur un terminal
Processus en attente de sorties sur un terminal
Processus en attente de fin d’un processus fils
Base des priorités
Processus de niveau utilisateur 0
Processus de niveau utilisateur 1
--------
Processus de niveau utilisateur n

Les niveaux de priorités au dessus de la base des priorités correspondent aux processus en
mode noyau. Les trois derniers niveaux du mode noyau sont interruptibles. Les priorités des
processus utilisateurs sont recalculées périodiquement suivant un algorithme du genre :
Priorité = (Temps CPU récent)/2 + (base des priorités).
NB : Les priorités les moins importantes sont positives.

1- 7 Les interblocages
conditions nécessaires :
j. exclusion mutuelle
k. détention et attente
l. absence de réquisition
m. attente circulaire
Toutes ces quatre conditions doivent être réunies pour qu’il y ait interblocage. Des processus
sont dits en interblocage quand chacun de ces processus attend un événement qui ne peut
provenir que de l’un des processus de l’ensemble.

22
Résolution des interblocages :
Trois approches peuvent être utilisées pour gérer le problème des interblocage :
n. prévention des interblocages : Utiliser une méthode assurant qu’au
moins l’une des conditions citées ci-dessus n’est pas remplie
i. ne pas partager les ressources en exclusion mutuelle.
ii. Un processus qui détient une ressource ne doit pas demander
une autre sans au préalable avoir libérer celle qu’il détient déjà
iii. Si une ressource demandée ne peut pas être allouée à un
processus, celles qu’il détient déjà sont requisitionnées
iv.Imposer un ordre sur les ressources en les numérotant. Un
processus qui détient une ressource de numéro i, ne peut
demander qu’une ressource de numéro supérieure.
o. évitement dynamique des interblocages : Avant d’allouer une ressource à
un processus, s’assurer que cette allocation ne peut pas créer une
situation d’attente circulaire. On peut déterminer pour chaque processus
à l’avance le nombre d’exemplaire de ressources de chaque type dont il
aura besoin et les lui allouer dès le début de son exécution. On alloue
une ressource que si après cette allocation, le système reste dans un état
sûr. Vérifier si l’allocation d’une ressource ne conduit pas à un cycle
dans le graphe d’allocation des ressources du système.
p. Détection des interblocages :Il faut fournir :
i. Un algorithme qui permet de détecter s’il y a interblocage. Si un
seul exemplaire de chaque ressource, on peut utiliser le graphe
d’attente entre processus (qui attend une ressource de qui). Un
cycle implique l’existence d’un interblocage, sinon utiliser un
algorithme du banquier à plusieurs exemplaires de ressources
pour voir si on n’est dans un état sûr ou pas.
ii. Un algorithme permettant de remédier à la situation
d’interblocage. Indiquer le problème à l’opérateur. Il peut alors
tuer des processus ou alors retirer des ressources à certains
processus.
q. la politique de l’autruche : On choisit de ne rien faire, car le prix à payer
pour éviter les interblocages est très élevé .

23
Partie II : Gestion des Informations : Le Cas d’Unix
2-1 Gestion élémentaire de la mémoire
Le gestionnaire de la mémoire est la partie du système d’exploitation qui gère la
hiérarchie de mémoire installée sur un ordinateur. Les adresses manipulées par un
programme en cours d’exécution sont des adresses logiques. L’ensemble des adresses
logiques manipulées par un programme constituent son espace d’adressage logique.
L’ensemble des adresses physiques (ou réelle) constituent l’espace d’adressage physique. Les
compilateurs supposent que le processus aura toute la mémoire physique a sa disposition et
affecte les adresses logiques de zéro à un certain maximum.
2 – 1 – 1 La Monoprogrammation sans va-et-vient ni pagination
Ici le rôle du gestionnaire est de partager la mémoire entre un seul programme
utilisateur et le système d’exploitation. Trois organisations possibles sont souvent
rencontrées :
a) le système d’exploitation se trouve aux adresses basses de la mémoire (RAM). Le
programme utilisateur se trouve juste au dessus. (Ex. dans les premiers
ordinateurs)
b) Les gestionnaires des périphériques sont en mémoire morte (ROM) et le leste du
système d’exploitation se trouve aux adresses basses de la mémoire. Le
programme utilisateur se trouve au dessus de la partie du système en RAM. (Ex :
Les ordinateurs personnels tournant sous ms-dos)
c) Le système d’exploitation se trouve en mémoire morte (ROM) et le programme
utilisateur en RAM. (Ex : les systèmes embarqués et ordinateurs de poche).
Le comportement du système peut être donné par l’algorithme simple suivant :
Tant que (vrai) faire
- Afficher le prompt
- Lire une requête
- Exécuter la reqûte
Ftantque

Dans un tel système, la gestion de la mémoire est assez simple. Un processus obtient toute la
mémoire qu’il demande. La seule protection à faire est de s’assurer que le processus
utilisateur n’écrase pas le système d’exploitation. Dans MSDOS, une telle protection n’était
même pas assurée.

La technique de recouvrement :
C’est une technique qui consiste à découper le programme à exécuter en plusieurs
morceaux de telle sorte que chaque morceau puisse tenir en mémoire centrale. Les morceaux
doivent être indépendants, c’est-à-dire qu’aucun morceau ne doit faire appel à un autre. La
décomposition en morceaux indépendants est faite par le programmeur en incluant à certains
points du code, certaines instructions spéciales. A la compilation, le compilateur prépare les
différents modules indépendants et les stocke sur le disque. Une instruction placée à la fin de
chaque module par le programmeur permet de rechercher le prochain bloc sur disque et de le
placer en mémoire à la place qu’occupait le module précédent.
Cette technique était utilisait dans les vieux systèmes à une époque où la technologie
ne permettait pas de réaliser des mémoires centrales de très grande capacité. Pour exécuter des
gros programmes sous MSDOS, on était obligé de recourir à cette technique. Aujourd’hui elle
est devenue obsolète.

2 – 1 – 2 Multiprogrammation

24
Ici on autorise l’exécution de plusieurs processus utilisateurs. Lorsqu’un processus est
bloqué en attente des entrées/sorties, un autre processus prêt peut devenir actif. On augmente
ainsi le taux d’utilisation du processeur. Ceci exige que plusieurs programmes soient chargés
en mémoire à un instant donné. La mémoire est donc divisée en partitions, chacune contenant
un seul processus. Les partitions sont de taille fixe. La mémoire est divisée en n partitions de
tailles si possible inégales. Le partitionnement est fait au démarrage du système. La taille
d’une partition ne change pas au cours de la session. A chaque partition est associée une file
d’attente. Un processus est toujours chargé en mémoire dans la file d’attente de la plus petite
partition pouvant le contenir.

Inconvénients : On peut avoir les files de petites partitions pleines tandis que les files des
grandes partitions sont vides. Dans ce cas les petits travaux doivent attendre pour accéder à la
mémoire alors qu’elle contient des partitions inutilisées.
Une autre organisation consiste à utiliser une seule file d’attente. Dès qu’une partition
est libre, tout processus pouvant y tenir et se trouvant en tête de file est chargé.
Allouer une grande partition à un petit processus crée un gaspillage de la mémoire.
Pour éviter ce gaspillage, dès qu’une partition devient libre, on parcourt l’unique file d’attente
pour rechercher le plus grand processus pouvant y tenir. Ceci peut une fois de plus pénaliser
les petits processus. On évite cela en associant à chaque petit processus un compteur initialisé
à zéro. Chaque fois qu’il est ignoré, son compteur est incrémenté d’une unité. Un processus
ne pourra pas être ignoré k fois, où k est un paramètre système.

Problèmes :
- La réallocation ou translation d’adresse. Les compilateurs supposent que les
adresses manipulées par les programmes commencent toutes à zéro. Il faut donc
au cours du chargement en mémoire d’un processus, recalculer les adresses
manipulées en ajoutant à chaque adresse l’adresse de début de la partition.
- La protection. Les partitions doivent être protégées pour éviter qu’un processus
chargé dans une partition donnée n’accède à une autre partition.
Une solution est d’utiliser un registre de base et un registre de limite. Le registre de
base est chargé avec l’adresse de début de la partition et le registre de limite avec la
longueur de la partition.

2 - 2 Le va-et-vient
Le va-et-vient apporte une solution au problème posé par la multiprogrammation qui
consiste à exécuter un grand nombre de processus que de partitions disponibles pouvant les
contenir. Un processus qui libère sa partition est envoyé intégralement sur disque. Ici les
partitions ne sont plus de taille fixe. Leur nombre et leurs tailles sont variables. L’opération de
va-et-vient peut créer des trous dans la mémoire.

2 – 2 – 1 Gestion de la mémoire avec des tables de bits.


Le système d’exploitation utilise une table appelée table des bits pour gérer
l’occupation de la mémoire. La mémoire est divisée en unités d’allocation. Chaque unité
d’allocation a un bit dans la table des bits. Un bit à 1 signifie que l’unité d’allocation est
allouée à un processus tandis qu’un bit à 0 signifie qu’elle est libre. Le système alloue à un
processus un espace qui est un multiple d’une unité d’allocation et dont la taille est la plus
petite pouvant le contenir.
La libération de la mémoire peut créer des trous libres. On peut les compacter en
déplaçant les processus vers le début de la mémoire.

25
Pour charger un processus de k unités d’allocation, il faut trouver k trous libres
consécutifs en mémoire. Il peut être nécessaire de parcourir toute la mémoire pour trouver un
tel espace.

2 – 2 – 2 Gestion de la mémoire avec les listes chaînées


On peut représenter l’occupation de la mémoire avec une liste chaînée dont chaque
élément est une structure comportant les éléments suivants :
- Un caractère qui contient ‘P’ pour processus ou ‘T’ pour trou libre
- L’adresse de début de la zone
- Un pointeur sur le nœud suivant.
La liste est triée par adresse de début croissante, ce qui permet de combiner facilement des
zones adjacentes pour n’en faire qu’une seule zone, suite par exemple à la fin d’un processus.
Les algorithmes permettant de gérer la mémoire, dès qu’ils trouvent une zone libre
pouvant contenir le processus, l’éclaté en deux nœuds dont le premier est libre et le second est
occupé. Ces algorithmes sont :
- Algorithme de la première zone libre. On parcourt la liste à partir de la tête de
liste jusqu’à trouver un nœud suffisamment grand pour contenir le processus.
- Algorithme de la zone libre suivante. La prochaine de trou libre commence où
s’était arrêtée la recherche précédente. Les expérimentations montrent que cet
algorithme est légèrement meilleur que le premier.
- Algorithme du meilleur ajustement. On recherche le plus petit nœud libre
pouvant contenir le processus. Il est plus mauvais que les deux premiers.
- Algorithme du plus grand résidu. On recherche le plus grand trou libre pouvant
contenir le processus. L’objectif est que le trou libre obtenu après une allocation
soit assez grand pour pouvoir être alloué à un autre processus.
- Algorithme du placement rapide. On gère une table des tailles le plus
fréquemment rencontrées. La recherche se fait toujours sur une entrée de la
table.
- Algorithme par subdivisions. C’est une variante de l’algorithme précédent dans
lequel le nombre d’entrée dans la table des listes chaînée est n, si la mémoire a
pour taille 2n mots.

2 – 3 La mémoire virtuelle
Elle permet de résoudre un certain nombre de problèmes :
a) Exécuter un programme dont la taille est supérieure à la mémoire disponible
b) Exécuter un ensemble de programme dont la taille totale est supérieure à la mémoire
disponible.
Les programmes sont stockés en mémoire virtuelle qui est en réalité une partie du disque.
Sous LINUX par exemple, la mémoire virtuelle peut être une partition du disque ou un fichier
spécial. Les parties du programme ou le programme tout entier font des va-et-vient entre la
mémoire virtuelle sur disque et la mémoire centrale. L’espace d’adressage réel d’un
processus est partie de la mémoire centrale qui peut être contigüe ou non. La correspondance
adresse virtuelle  adresse physique est faite pendant l’exécution par une unité spéciale de la
machine appelée MMU (Memory Management Unit).

2 - 3 - 1 la pagination
En général chaque programme considère que la mémoire qu’il utilise est numérotée de
0 à un certain maximum. Le nombre d’adresses logiques utilisées peut être très supérieur à la
taille de la mémoire physique. L’espace virtuel contigu occupé par le processus est divisé en
pages de même taille. La mémoire centrale est divisée en cadres de page de taille égale à celle

26
des pages. Chaque processus a dans son contexte une table des pages qui permet de faire la
correspondance entre les adresses virtuelles et les adresses physiques. Chaque adresse
virtuelle comporte deux parties. Un numéro de page et un déplacement dans la page. Le
numéro de page sert d’index dans la table des pages. Il y a autant d’entrées dans la table des
pages qu’il y a de pages dans la mémoire virtuelle. Chaque entrée de la table des pages est une
structure comportant :
- un bit de présence. Ce bit vaut 1 si la page correspondante est effectivement
mappée en mémoire centrale. Il vaut 0 dans le cas contraire.
- Un numéro de cadre de page. Ce numéro indique dans quelle page physique la
page virtuelle a été réellement mappée.
- Un bit de protection : 0 indique un accès en lecture/écriture, et 1 indique un
accès en lecture seule. La protection peut aussi très bien être codée sur trois
bits : un bit pour l’accès en lecture (1=oui, 0=non), un bit pour l’accès en
écriture, un bit pour l’exécution.
- Les bits de modification : permet de savoir si la page a été modifiée depuis sa
dernière sauvegarde. Si ce bit est positionné à 1, la page doit être enregistrée sur
disque en cas de son remplacement par l’algorithme de remplacement des pages.
- Le bit de référence : ce bit est positionné chaque fois qu’une page est accédée en
lecture ou en écriture.

Quand le processeur veut accéder à une zone mémoire, il passe l’adresse virtuelle au
MMU. Le MMU transforme cette adresse virtuelle en adresse physique, en se servant de la
table des pages du processus. Deux situations peuvent se produire quand le MMU accède à
l’entrée correspondante de la table des pages:
- La page recherchée se trouve en mémoire. Il suffit alors d’accéder à
l’information recherchée.
- La page recherchée ne se trouve pas en mémoire. Il se produit alors un
déroutement appelé défaut de page. Le traitement du défaut de page peut être
simple ou complexe. Il est simple s’il y a un cadre de page libre. Il suffit alors
de charger la page virtuelle dans ce cadre de page. Il est complexe s’il n’y a pas
de cadre de page libre. Il faut alors à l’aide d’un algorithme de remplacement
des pages libérer un cadre de page, y stocker la mémoire virtuelle
correspondante avant d’accéder à l’information recherchée.

Le système d’exploitation gère dans ses structures internes une table des cadres de pages.
Chaque entrée de cette table est une structure qui contient comme informations :
- indication si le cadre de page est libre
- identification du processus à qui le cadre de page est alloué
- adresse de début du cadre de page.

Implémentation de la table des pages :


- Support matériel : On peut représenter la table des pages d’un processus en
utilisant des registres dédiés à cet effet. L’accès est rapide, mais la taille de la
table est réduite. Les registres doivent être chargés chaque fois qu’on change de
processus, ce qui peut être une source de perte de temps si la table des pages est
grande.
- Loger la table des pages en mémoire centrale. Le contexte du processus a besoin
seulement d’un registre qui pointe sur le début de la table des pages : On peut
ainsi avoir une table très grande. Mais deux accès mémoire sont nécessaires
pour obtenir une donnée en mémoire. Le système est donc lent.

27
- Utilisation d’une mémoire associative : L’accès est rapide, mais il faudra
nettoyer la mémoire associative chaque fois qu’on change de processus. En effet
on remarque que certaines pages sont en général utilisées plus fréquemment que
d’autres. On peut donc garder les tables de pages en mémoire centrale et stocker
une petite table de page en mémoire associative contenant les pages les plus
fréquemment. Une entrée de cette table en mémoire associative contient les
informations suivantes :
i. Le numéro de page virtuelle
ii. Un bit de modification
iii.Un bit de protection rwx
iv.Le numéro du cadre de page
v. Un bit de validité qui indique si l’entrée est utilisée ou non.
NB : La recherche d’une page virtuelle se fait en comparant simultanément son numéro à
toutes les entrées valide de la mémoire associative. Si trouvé, alors on récupère l’adresse
physique. Si non trouvé, on charge la page en mémoire associative à partir de la table des
pages en mémoire.

NB : Tables des pages à plusieurs niveaux


La table des pages peut devenir très grande si la mémoire virtuelle a une grande
capacité. En réalité on n’a pas besoin à un instant donné d’avoir toute la table de pages en
mémoire. En effet, si n est la taille en bits d’une adresse virtuelle, il est évident que chaque
processus ne manipule pas 2n adresses. Pour résoudre le problème de l’espace occupé par la
table des pages, on utilise une table des pages à plusieurs niveaux. Par exemple :
- un premier niveau peut permettre de décrire le type de page (x1 bits) :
i. la première entrée pointe sur la table de second niveau dont les entrées
pointent sur les pages de code
ii. la deuxième entrée pointe sur la table de second niveau dont les entrées
pointent sur les pages de données
iii.la dernière entrée pointe sur la table de second niveau dont les entrées
pointent sur les pages de pile.
iv.Les autres entrées ne sont pas utilisées.
- un second niveau permet de retrouver les références des pages physiques
contenant les données, la pile et le code.
On peut étendre ce système à plus de deux niveaux pour obtenir plus de flexibilité.

2 – 3 – 2 La table de pages inversée


Avec les machines 64 bits, l’espace d’adressage potentiel d’un processus de vient 2 64
mots. Il est impensable d’avoir pour chaque processus une table de pages de 2 64 entrées. On
utilise dans ce cas les tables de pages inversées. La table de pages inversée contient plutôt les
informations sur les cadres de pages et non sur les pages virtuelles. Une entrée de la table de
pages inversée a comme information :
- le numéro du processus à qui l’entrée est associée (n)
- le numéro de la page virtuelle associée (p)
Cette table a autant d’entrée qu’il y a de cadres de pages. Quand le processus numéro n
demande l’accès à la page virtuelle p, on parcourt la table de pages inversée à la recherche
d’une entrée contenant la paire (n,p). Si une telle entrée (i) est trouvée, alors la page virtuelle
p se trouve dans le cadre de pages numéro i. On peut donc former l’adresse physique. Une
fois de plus on peut utiliser une mémoire associative pour accélérer les recherches. Pour éviter
de parcourir toute la table de page inversée, on peut utiliser une fonction de hachage qui

28
permet d’indiquer toujours l’unique entrée de la table de pages inversée où on trouvera un
pointeur sur une liste chaînée dont chaque nœud indique :
- un numéro de page virtuelle
- un numéro de cadre de page.

2 – 3 – 3 Algorithmes de remplacement des pages


a) algorithme optimal : Chaque page est indexée par le nombre d’instructions qui vont
être exécutées avant une référence à la page. La page ayant le plus grand index est la
moins prioritaire. Elle peut être sortie de la mémoire. Difficile à mettre en œuvre.
b) Algorithme de la page non récemment utilisée (NRU): Chaque page a un bit de
référence et un bit de modification. Au démarrage de chaque processus, les R et M de
ses pages sont mis à zéro. Périodiquement, par exemple à chaque interruption horloge,
le bit de référence est mis à 0. Quand un défaut de page survient et nécessite un
remplacement de pages, le système d’exploitation sépare les pages en quatre classe :
a. Classe 0 : Les pages qui ont les bits R et M à 0. Ces pages n’ont pas été
référencée
b. Classe 1 : les pages qui ont le bit R à 0 et le bit M à 1
c. Classe 2 : les pages qui ont le bit R à 1 et le bit M à 0
d. Classe 3 : Les pages qui ont le bit R 1 et le bit M à 1
On enlève une page au hasard dans la classe de plus bas numéro.
c) Algorithme premier arrivé, premier servi
d) Algorithme de la seconde chance :
C’est une amélioration de l’algorithme fifo. La page la plus ancienne n’est
enlevée de la mémoire que si son bit de référence est à 0. Si R est à 1, on le met à zéro,
met à jour sa date d’entrée en mémoire et la place en fin de liste. L’algorithme finit
toujours par trouver une page avec un bit R à 0.
e) Algorithme de l’horloge : Les pages sont placées dans une liste circulaire et seront
parcourues dans le sens des aiguilles d’une montre. Initialement l’aiguille est placée
sur la page la plus ancienne. Suite à un défaut de page, la page sur laquelle pointe
l’aiguille est consultée. Si son bit de référence est 0, elle est remplacée et la nouvelle
page prend sa place. Si le bit de référence est à 1, il est mis à 0 et l’aiguille avance sur
le nœud suivant de la liste. Le parcours se poursuit jusqu’à ce qu’une page soit
trouvée. NB : On peut construire une version à deux aiguilles.
f) Algorithme de remplacement de page la moins récemment utilisée : Le principe de la
localité des références, nous fait affirmer qu’une page accéder récemment a beaucoup
de chance d’être référencée de nouveau dans un proche avenir, tandis que les pages
qui n’ont pas été référencées depuis vont rester non référencées. C’est donc la page qui
n’a pas été utilisée depuis le plus de temps qui est retirée. Pour l’implémenter, on
utilise une liste chaînée de toutes les pages en mémoires. La page la plus utilisée est en
tête de liste. Chaque fois qu’une page est utilisée, elle est placée en tête de liste.

2 – 4 la segmentation
Elle permet de séparer les programmes et les données dans des espaces logiquement
indépendants, et facilite le partage et la protection des données. L’idée de la segmentation est
d’utilisé pour chaque processus un espace d’adressage qui ne soit pas forcément contigu.
L’espace d’adressage logique est donc une collection de segments. Un segment est une zone
contiguë de la mémoire de taille variant de 0 à un certain maximum. Un segment peut
contenir des données, la pile ou le code du processus. Il ne contient jamais un mélange
d’objets de types différents. L’adresse logique spécifie le segment et le déplacement à

29
l’intérieur du segment. Chaque adresse manipulée comporte les deux parties. Un processus a
une table des segments. Une entrée de la table des segments a :
- une adresse de base du segment, qui est l’adresse physique de début du segment
- la taille du segment
Les registres de la machine peuvent être utilisés pour sauvegarder la table des segments. On
peut aussi la stocker en mémoire. Un registre de la machine pointe sur la table des segments.
Un autre registre indique la taille de la table des segments. L’utilisation des segments facilite
la gestion du partage des zones mémoire par les processus. Au niveau du système
d’exploitation des tables permettent de garder les informations sur les segments. Les segments
peuvent devenir très grands et devenir encombrant en mémoire, d’où la nécessité de les
paginer.

Exemple d’implémentation de la segmentation : le 80386 d’intel


Ce microprocesseur a inauguré l’ère des machines 32 bits chez Intel. La liste de
registres est :
Les registres généraux (32 bits) :
EAX accumulateur (poids faible AX (AH,AL)).
EBX registre de base(BX(BH,BL))
ECX registre de comptage (CX (CH,CL))
EDX registre de données(DX (DH,DL))
ESP pointeur de pile (sommet de pile ) (SP)
EBP pointeur de pile (registre de base) (BP)
ESI index source (registre d’index )
EDI index destination (registre d’index)
Les registres d’état (ou de contrôle) (32 bits):
EIP pointeur d’instruction (IP)
EFLAGS registre d’états (FLAGS)
Les registres de segment (16 bits):
CS registre de segment de code
DS registre de segment de données
ES registre de segment de données supplémentaire
SS registre de segment de pile
FS facilite certains accès mémoire
GS facilite certains accès mémoire
Les registres de commande (32 bits):
CR0,CR1,CR2,CR3 registres de commande
GDTR pointeur sur table globale des descripteurs des segments
IDTR pointeur sur une table des descripteurs de segment
TR registre de tâche (16 bits)
LDTR pointeur sur table locale des descripteurs de segments (16 bits)
Les registres Debug :
DR0,DR1,DR2,DR3,DR4,DR5,DR6 et DR7.

Chaque processus a sa propre table locale des descripteurs de segment (LDT),


cependant il n’existe qu’une seule table globale des descripteurs de segments (GDT). La LDT
décrit les segment locaux à chaque processus, tandis que la GDT décrit les segments du
système y compris ceux du système d’exploitation.
Les bits d’un registre de segment n’indiquent plus un emplacement physique en
mémoire, mais ont plutôt les significations suivantes :
- les 2 bits de poids faibles indiquent le niveau de privilège

30
- le bit suivant indique le type de sélecteur (0=GDT, 1=LDT)
- le reste des bits représente un index dans la table des descripteurs de segments
appropriée. (13 bits  8K descripteurs différents)

Une entrée dans une table des descripteurs de segment est une structure dont la taille totale est
de huit octets :
- 2 octets pour la taille d’un segment (la taille varie de 1 à 64ko)
- 3 octets suivants donne l’adresse de début du segment en mémoire centrale (24 bits
pour une adresse au lieu des 20 bits du mode réel)
- 1 octet de contrôle, appelé registre des indicateurs. Il indique le type du segment
(segment de données, segment de code ou segment système), le bit de protection
contre l’écriture, bit indiquant si le segment peut être lu, le bit de présence, le bit
d’accès, le niveau de privilège qui est codé sur deux bits : le niveau 0 est le
privilège maximal, le niveau 1 est celui des fonctions systèmes appelées par les
applications et les utilitaires, le niveau 2 est celui des extensions du systèmes
(serveur SQL, gestionnaire de réseau), le niveau 3 est celui des applications qui se
déroulent sous le contrôle du système
- les deux derniers octets sont réservés pour un usage future
La table des descripteurs globaux contient des entrées pour :
- les segments de codes du systèmes d’exploitation
- les segments de données du système d’exploitation
- les descripteurs des segments de mémoire qui contiennent les tables locales des
descripteurs
- les descripteurs de segments spéciaux appelés porte d’appel (CALL GATE). Ils ne
définissent pas un segment mémoire mais un point d’entrée dans une routine dont
le segment de code peut avoir un privilège de plus haut rang que l’appelant.
L’entrée indique aussi clairement l’offset dans le segment. On évite ainsi
d’autoriser l’accès à tout un segment du système. Une porte d’appel se comporte
comme un segment de données. Le système d’exploitation met leur privilège au
niveau 3, pour permettre qu’elles soient appelée par toutes les applications.
- Descripteur TSS ( Task State Segment) : Zone mémoire ou le contenu de tous les
registres est sauvegardé ou permettant de restaurer le contenu des registres.

Parmi les 16 bits d’un sélecteur de segment on a un bit indiquant si le segment est une table
de segments globale (0) ou une table de segments locale (1), et qui précède les deux derniers
bits qui eux indiquent le niveau de privilège du sélecteur (RPL :requested privilege level). Le
descripteur d’un segment de code a un niveau de privilège (DPL :Descriptor Privilege level).
Pour l’accès aux données et aux instructions, on doit avoir RPL=DPL et pour l’accès aux
données seulement, on doit avoir RPL<=DPL.

Le mode protégé permet de gérer jusqu’à 8193 tables de descripteur, dont une table
globale et 8192 tables locales. A un moment donné, deux tables seulement peuvent être
actives : la table des descripteurs globaux (GDT) et une table des descripteurs locaux
(LDT :local descriptor table). Les deux registres GDTR et LDTR contiennent les références
de ces deux tables. Le registre GDTR contient l’adresse physique des tables globales et LDTR
contient la référence d’une LDT dans la table des descripteurs globale.
La table globale contient les segments de code et de données du système, les segments
contenant les tables des descripteurs locaux. Pour faire une commutation, il suffit de changer
le contenu de LDTR.

31
Avec les 80386, 80486, et les pentium, le mécanisme est presque le même. Seulement
les registres sont plus grands, et l’architecture plus sophistiquée permettent :
- d’améliorer l’efficacité dans le processus de communication de contexte.
- D’accéder à plus de mémoire

Ordonnancement des processus


Les PC sont des machines monoprocesseurs. A un moment donné, une seule tâche
peut donc être entrain de s’exécuter. Pour donner une impression de parallélisme, la
commutation de tâches est faite très rapidement. Le processeur se sert :
- du registre des tâches : TR (Task Register)
- et du segment d’état des tâches : TSS (Task State Segments)
Un TSS est une zone mémoire de 44 octets qui au moment de l’interruption d’une tâche,
reçoit le contenu de tous les registres du processeur. Le registre de tâche contient la référence
au TSS, et est sauvegardé en cas d’interruption d’une tâche dans la GDT. Pour faire la
commutation de contexte :
- repérer à l’aide de TR l’entrée de GDT correspondant à la TSS de la tâche à
interrompre
- sauvegarder les registres du processeur dans la zone correspondant à TSS.
- Dans la zone des données du système, choisir une nouvelle tâche et obtenir la
référence de sa TSS
- Charger les registres à partir de cette nouvelle TSS
- Le nouveau processus est actif
Les interruptions :
Tout comme en mode réel le processeur reconnaît 256 interruptions différentes. Une
table des descripteur d’interruption mémorise les références sur les descripteurs des segments
des routines d’interruption. L’adresse où débute cette table en mémoire est indiquée par le
registre IDTR. Seul le système d’exploitation a accès à ce registre. Une application n’est plus
en mesure d’influencer le déroulement d’une interruption.

2 - 3 Gestion de mémoire sous unix


L’espace d’adressage d’un processus Unix comprend trois parties :
- le code
- les données
- la pile
Au début de l’exécution d’un programme, sa pile n’est pas vide, elle contient toutes les
variables d’environnement ainsi que la ligne de commande utilisée pour appeler ce
programme. Quand la pile est pleine, il se produit une interruption matérielle dont le
traitement augmente la taille de la pile d’environ 1 ko.
2 – 3 –1 le va et vient
Certaines versions d’unix utilisaient au début, le principe du va et vient. Quand il n’y a
plus assez de place en mémoire pour contenir tous les processus à un moment donné suite par
exemple :
- à un fork pour créer un nouveau processus
- une tentative d’augmentation de la taille de la pile
- une tentative d’augmentation de la taille du segment des données
- chargement d’un processus très long à partir du disque
un des processus se trouvant en mémoire est envoyé sur disque. Le démon qui se charge de se
transfert est le permuteur (swapper).

32
Choix du processus à enlever de la mémoire
a) Il se fait parmi les processus bloqués en attente d’un événement.
b) Il se fait parmi les processus prêts si aucun processus n’est bloqué.
S’il y en a plusieurs, celui dont la somme du temps de résidence en mémoire et de la priorité
est la plus grande est enlevé

Choix du processus à envoyer en mémoire


Après un temps fixe (quelques secondes), le permuteur examine les processus sur disque pour
voir si l’un d’eux est près à s’exécuter :
- le processus le plus ancien sur disque est choisi et envoyé sur disque
- répéter jusqu’à ce qu’il n’y ait plus de processus prêt sur disque ou jusqu’à ce que
tous les processus en mémoire soient ceux qui y ont fait moins d’un certain temps
(≈ 2s)
NB : le transfert peut être simple ou complexe. Il est simple s’il y a assez de places en
mémoire pour recevoir les nouveaux processus. Il est complexe si les processus entrant en
mémoire doivent remplacer d’autres processus se trouvant en mémoire. Le noyau utilise une
liste de trous en mémoire et une liste de trous sur disque pour les transferts. Le choix d’un
trou se fait suivant l’algorithme du premier trou libre.

2 – 3 – 2 La pagination
La mémoire centrale est organisée en trois parties :
- le noyau
- la carte mémoire
- le reste de la mémoire divisé en cadre de pages (page frame), chacun pouvant
contenir une page de texte, de données, de piles, de la table des pages ou de la liste
des pages libres.
Le noyau et la carte mémoire ne sont jamais envoyé sur disque. La carte mémoire contient des
informations décrivant le contenu des cadres de pages. L’entrée i de la carte mémoire décrit
le cadre de pages numéro i et contient les informations suivantes :
- référence de l’entrée suivante
- référence de l’entrée précédente
Ces deux entrées sont utilisées lorsque le cadre de page est dans la liste des cadres libres.
- le type de périphérique de la mémoire virtuelle
- numéro du périphérique
- code de hachage du bloc
Si le cadre de page contient une page, ces trois informations permettent de localiser
l’emplacement réservé à la page sur le périphérique.
- référence dans la table des processus
- indication si la page contient du texte, des données ou une partie de la pile.
- Décalage dans le segment
- Indicateurs utilisés par l’algorithme de pagination :
- Bit indiquant si la page est libre
- Bit de verrouillage
- Bit indiquant si la page est demandée
- …etc
Lorsqu’un processus demande une page, le système ôte le premier cadre libre de la liste des
cadres libres et y place la page. Si la liste des cadres de pages libres est vide, le processus est
suspendu en attendant que le voleur de pages (ou démon de pages) libère des cadres de pages.
Le démon de pages a pour pid 2. Le permuteur a pour numéro 0 et init est le numéro 1.

33
Algorithme de remplacement des pages.
Le démon de pages se réveille toutes les 250ms pour exécuter cet algorithme.
1) Le démon de pages vérifie si le nombre de cadres de pages libres
est au moins égal à un paramètre système appelé lotsfree (~1/4 de
la mémoire). Si le démon constate qu’il y a plus de lotsfree
cadres de pages libres il s’endort. Si au contraire il y a moins de
lotsfree cadres de pages libres, il libère des pages de la mémoire
jusqu’à ce qu’il y ait au moins lotsfree cadres de pages libres.
2) On utilise deux paramètres min et max. Le démon de page
s ‘exécute lorsqu’il y a moins de min cadres de pages libres et
continu son exécution jusqu’à ce qu’il y ait au moins max cadres
de pages libres.
Dans tous les cas le choix des pages à libérer se fait suivant l’algorithme de l’horloge :
Les pages sont disposées dans une liste circulaire. Un pointeur permet de référencer la
page la plus ancienne. On parcourt la liste dans le sens des aiguilles d’une montre. Au premier
passage, on met les bits de référence à zéro. Au second passage, les pages dont les bits de
référence sont toujours à zéro n’ont pas été référencé depuis. On les libère en les recopiant sur
le disque.
NB : On peut utiliser une horloge à deux aiguilles.

34
2 – 4 Gestion des fichiers
Le système de fichiers désigne l’ensemble de l’organisation utilisée par un système
d’exploitation pour représenter les fichiers. Le système de fichiers est lié en général aux
périphériques utilisés. Il propose une organisation à utiliser par les unités de stockage de
masse pour permettre de:
- Organiser les unités de masse pour leur permettre d’accueillir les fichiers
- Stocker les différents blocs de données d’un fichier
En général un système d’exploitation implémente plusieurs systèmes de fichiers, ce qui lui
permet d’utiliser différents types de périphériques.
Le gestionnaire des fichiers est la partie du système d’exploitation qui implémente les
différents systèmes de fichiers de ce système. Il offre des services permettant :
- de stocker les fichiers sur les périphériques de masse en assurant leur sécurité
- de fournir une interface permettant aux utilisateurs de manipuler les fichiers (les
structurer, les nommer, les modifier, …etc)
- d’assurer l’indépendance vis-à-vis des périphériques, c’est-à-dire permettre
d’accéder aux fichiers de la même façon quel que soit le périphérique de
stockage
- de retrouver efficacement les différents blocs d’un fichier
L’utilisateur ne cherche pas à savoir quel est la taille des blocs d’un disque, sur quels blocs
ses fichiers sont stockés, quel est le nombre de secteurs d’un bloc logique, comment les blocs
libres ou occupés du disque sont repérés ? Ce qui est important pour l’utilisateur c’est que le
système lui présente une interface permettant de créer et d’accéder à ses fichiers. Le système
de fichiers cache donc la complexité liée à la gestion des fichiers dans un système
informatique.

2.4.1 Structure d’un système de fichiers UNIX


La première tâche du système d’exploitation liée à la gestion des fichiers consiste à
préparer les périphériques à recevoir les fichiers. Dans un système unix, cette tâche peut
consister à diviser le disque en plusieurs partitions. Chaque partition est à son tour divisée en
quatre zones :
- la zone de boot qui correspond au premier secteur de la partition (bloc 0). Il
contient le programme d’initialisation dont la tâche principale consiste à
localiser et à charger le noyau du système en mémoire
- le zone dite « super bloc ». Elle décrit la structure du système de fichiers.
- La zone réservé aux inodes. Les inodes sont numérotées de 1 à un certain
maximum. Chaque inode fait environ 64 octets et décrit un seul fichier. Il
contient les informations de gestion du fichier et celles permettant de localiser
les blocs du fichier sur disque.
- La zone des données : les fichiers et catalogues sont stockés dans ces blocs.
Structure du super bloc :
- la taille du système de fichiers
- le nombre de blocs libres dans le système de fichiers
- la liste des blocs libres dans le système de fichiers
- l’index du premier bloc libre
- la taille de la liste des inodes
- le nombre de inodes libres
- la liste des inodes libres
- l’index du premier inode libre
- champ de verrouillage des blocs libres
- champ de verrouillage des inodes libres

35
Structure d’un inode :
- identificateur de l’utilisateur (UID)
- type de fichier (catalogue, ordinaire, spécial bloc, spécial caractère,fifo).
Type=0  inode libre
- droits d’accès aux fichiers
- date création,
- date dernier accès
- date dernière modification du fichier
- date dernière modification du inode
- nombre de liens du fichier
- pointeurs sans indirection sur des blocs de données
- pointeurs simple indirection sur les blocs de données
- pointeurs double indirection sur les blocs de données
- pointeurs triple indirection sur les blocs de données
- taille du fichier en octets
NB : l’inode n’indique aucun chemin d’accès au fichier. Le inode numéro 1 est réservé à la
gestion des blocs défectueux, le inode numéro 2 est réservé à répertoire racine.

2-4-3 les répertoires


Un répertoire est un type particulier de fichiers, dont les données sont organisées en
enregistrements appelés entrées de répertoire. Une entrée de répertoire est une structure de
deux champs :
- le premier champ est le nom du fichier. Dans les systèmes unix modernes, la
taille du nom de fichier peut varier jusqu’à 256 caractères
- le numéro du inode.

2-4-4 Organisation interne


Chaque processus a dans sa structure utilisateur une table de descripteurs de fichiers.
Cette table peut avoir jusqu’à 20 entrées environ (3 qui sont reservées : stdin stdout stderr).
Chaque entrée est indexée par un entier appelé descripteur de fichiers. Le contenu de l’entrée
est un pointeur sur une table du noyau appelée table de description des fichiers ouverts.
Chaque entrée de cette table contient comme informations :
- un bit indiquant si le fichier est ouvert en lecture
- un bit indiquant si le fichier est ouvert en écriture
- un pointeur de position indiquant le prochain octet à lire
- un pointeur sur une entrée de la table des inodes
- …etc
Un fichier physique peut avoir plusieurs entrées dans la table de description des fichiers
ouverts. En effet chaque ouverture d’un fichier crée une entrée dans cette table.
Une dernière table du noyau est la table des inodes. Une entrée de cette table contient
le inode d’un fichier permettant de le localiser rapidement sur le périphérique. Chaque fichier
a une seule entrée dans cette table.

Exercices : Ecrire des algorithmes pour :


- l’ouverture d’un fichier
- la création d’un fichier
- retrouver le inode d’un fichier à partir d’un chemin absolu ou d’un chemin
relatif

2 - 5 Les entrées/sorties de bases

36
La gestion des entrées/sorties sous unix est intégrée dans le système de fichiers. En
effet les périphériques sont considérés comme des fichiers spéciaux. A chaque périphérique
est associé un chemin à partir du répertoire /dev, par exemple /dev/lp pour l’imprimante,
/dev/net pour le réseau , /dev/hda pour le premier disque dur. Ces fichiers sont accessibles
exactement comme on accède aux autres fichiers. On a besoin, ni de commandes spéciales, ni
d’appels système spécifiques. Les programmes peuvent ouvrir et lire les fichiers spéciaux
comme s’il s’agissait de fichiers ordinaires. Les mécanismes de protection sont utilisés pour
limiter les accès aux périphériques. On distingue deux types de fichiers spéciaux :
- les fichiers spéciaux blocs
- les spéciaux caractères
A chaque périphérique est associé un pilote qui est la partie du système qui tient compte des
spécificités du périphérique. Il présente au reste du système une interface qui permet
d’accéder au périphérique en masquant le matériel.

2-5-1 les périphériques blocs


L’objectif de la gestion des périphériques ici est de diminuer le nombre de transferts
entre le périphérique et l’unité centrale. Pour cela unix place un cache faisant partie du noyau
entre le pilote du périphérique et le système de fichiers. Le cache peut contenir jusqu’à
plusieurs centaines de blocs. Toute recherche d’un bloc commence toujours par le
cache. C’est en cas d’échec que la recherche se poursuit sur le périphérique.
Gestion du cache
Les blocs du cache sont organisés en liste chaînée. Quand on accède à un bloc en lecture ou
en écriture, on le place en tête de liste. Quand un bloc doit être retiré du cache pour faire de la
place pour un nouveau bloc, on choisit toujours le bloc en fin de liste :c’est le bloc le moins
récemment utilisé. L’écriture d’un bloc est faite sur le cache et non sur le disque. Quand un
bloc est plein ou quand il faut libérer de la place en mémoire pour un nouveau bloc, c’est alors
qu’il est recopié sur disque et enlevé de la liste. Par ailleurs pour éviter que les blocs modifiés
restent trop longtemps dans le cache sans être copiés sur disque, on recopie périodiquement
sur disque tous les blocs qui ont été modifiés (environ toutes les 30 secondes).

2 – 5 – 2 les périphériques caractères


Ils utilisent des structures de données appelées C-listes. Chacune d’elle correspond à
un bloc de 64 caractères. Les caractères qui proviennent des périphériques sont stockés dans
une liste chaînée de C-listes. Ils sont ensuite traités par un gestionnaire de ligne avant d’être
passés au processus qui a fait la demande. Le gestionnaire traite les caractères spéciaux
(retour chariot, caractère effacement, supprime les fin de ligne, …etc). Les sorties se font de
la même manière. Les données sont d’abord stockées dans la C-liste. Le gestionnaire de ligne
les transforme avant de les passer au périphérique.

NB : Dans certains cas, le gestionnaire de ligne peut être court –circuiter et les données
brutes sont transférées. C’est par exemple le cas quand il faut transférer les données entre
deux ordinateurs en utilisant une ligne série.

37
Partie IV : Introduction aux systèmes d’exploitation distribués
3-1 Définitions et caractéristiques des systèmes distribués
Un système distribué est un ensemble d’unités centrales autonomes reliées par des
voies de communication haut débit. Sur le plan physique, il s’agit d’un réseau d’unités
centrales. Mais au niveau logiciels, l’ensemble est géré comme un tout de façon transparente
aux utilisateurs. Un système d’exploitation distribué est un système d’exploitation capable de
piloter ce genre de système de sorte que chaque utilisateur ait l’illusion de travailler sur une
unique machine très puissante.

3-1-1 Avantages des systèmes distribués


Les systèmes distribués présentent un certain nombre d’avantages sur les systèmes
centralisés et sur les ordinateurs personnels :
- meilleur rapport coûts/performances
- la puissance de calcul obtenue peut être telle qu’aucune grosse machine ne
puisse fournir une puissance équivalente
- la fiabilité est plus grande : le système peut continuer à fonctionner même si une
machine de l’ensemble tombe en panne
- certaines applications sont nécessairement distribuées (réservation de place dans
un avion)
- la puissance de calcul du système peut augmenter de façon modulaire
- le partage de certains équipement chers qu’il serait impossible d’offrir un
exemplaire à chaque usager (imprimante couleur, photocomposeuse, …etc)
- permettre des communications à faible coûts (courrier électronique)
- partage des données
- souplesse d’utilisation : exécuter une application sur la machine la plus
disponible
3-1-2 les différents types de systèmes à plusieurs unités centrales
Pour mieux comprendre ce qu’est un système distribué, nous allons comparer les
systèmes d’exploitation qui gère un tel système à ceux qui gèrent un système multiprocesseurs
à mémoire partagée ou un réseau d’ordinateurs classiques. Le tableau suivant résume la
situation.
Question Système Système Système
d’exploitation d’exploitation multiprocesseurs
réseau distribué à mémoire
partagée
A-t-on l’impression de travailler sur un non oui Oui
monoprocesseur virtuel ?
Doit-on avoir le même système non oui Oui
d’exploitation sur toutes les machines ?
Combien y-a-t-il de copies du système N N 1
d’exploitation ?
Comment les communications inter- Fichiers messages Mémoires
processus sont-elles assurées ? partagées partagées
Faut-il utiliser des protocoles réseau oui oui Non
unifiées
Existe-t-il une seule file d’attente des non non Oui
exécutables ?
Le partage des fichiers a-t-il une non oui Oui
sémantique bien définie ?

38
Un système d’exploitation distribué est un système qui s’exécute sur un ensemble de
machines sans mémoire partagée, mais que pourtant l’utilisateur voit comme une seule et
unique machine.

3-1-3 Caractéristiques des vrais systèmes distribués


a) la transparence
L’utilisateur d’un système distribué doit avoir l’illusion que l’ensemble des machines est
identique à un monoprocesseur classique, mais avec une amélioration des performances. On
doit accéder de la même façon aux ressources locales qu’aux ressources distantes. En
particulier :
- les utilisateurs ne savent pas où se trouvent les ressources matérielles et
logicielles : on parle de transparence à l’emplacement
- les ressources peuvent être déplacées d’un endroit vers un autre sans changer de
nom : on parle de transparence à la migration
- les utilisateurs ne connaissent pas le nombre de copies d’une ressource telle que
les fichiers : on parle de transparence à la duplication
- plusieurs utilisateurs peuvent partager sans le savoir une ou plusieurs
ressources : on parle de transparence à la concurrence
- les tâches peuvent se dérouler en parallèle sans que l’utilisateur le sache : on
parle de transparence au parallélisme.

b) la souplesse
La structure du système doit faciliter son évolution. Pour cela, le noyau doit être le
plus petit possible et assurer quatre services minimum :
- les mécanismes de communication inter processus
- la gestion de la mémoire
- la gestion et l’ordonnancement des processus
- la gestion des entrées / sorties de bas niveau
Le noyau ne fournit ni système de fichiers, ni les répertoires. Les services que le noyau ne
fournit pas sont implantés par des serveurs de niveau utilisateurs. Pour obtenir un service, un
processus envoie un message au serveur approprié. Il existe une interface bien définie pour
chaque service. On peut implémenter et installer des nouveaux services sans avoir à arrêter le
système ou le réinitialiser avec un nouveau noyau. Le système est donc très souple.

c) la fiabilité
Le système doit rester opérationnel en cas de panne, voire de plusieurs serveurs. Les
fichiers et autres ressources doivent être protégés contre une utilisation abusive. Il faut assurer
une tolérance aux pannes au niveau de l’utilisation des fichiers en introduisant par exemple
des serveurs de fichiers sans état.

d) les performances
L’exécution des programmes devrait être plus rapide que sur un système
monoprocesseur. Les performances peuvent être mesurées par :
- le temps de réponse
- le débit
- le taux d’utilisation du système
- le pourcentage utilisé de la bande passante du réseau

3-2 Les communications dans les systèmes distribués


3-2-1 le modèle client/serveur

39
Le système d’exploitation est structuré en un ensemble de processus. Certains sont des
serveurs et fournissent des services à d’autres appelés clients. Les serveurs et les clients
tournent sous le même micro-noyau et sont des processus utilisateur. Sur la même machine,
on peut avoir des clients, des serveurs ou des clients et des serveurs. Les clients et les serveurs
utilisent un protocole simple pour communiquer de type question / réponse. Le client
demande un service au serveur. Ce dernier lui retourne une réponse. Le protocole sous jacent
a trois couches :
- la couche physique
- la couche liaison de données
- la couche question / réponse . Cette couche définit l’ensemble des questions et
des réponses.
Les services de communications fournis par le micro-noyau se limitent à deux appels système
qui peuvent être implémenter par deux procédures de la bibliothèque :
Send (destination, &mptr)
Receive (addr, &mptr)
Send envoie le message pointé par mptr à un processus identifié par destination.
Il existe plusieurs variantes de ces primitives.

3-2-1-1 L’adressage
Le client doit connaître l’adresse du serveur à qui il envoie un message. Plusieurs
méthodes peuvent être utilisées pour réaliser cet adressage :
1) un seul processus tourne sur la machine. Dans ce cas, on peut utiliser le
numéro de la machine. Le noyau sait alors qu’il y a un seul processus
utilisateur, et donc c’est à lui que le message est destiné.
2) Plusieurs processus tournent sur la machine. Dans ce cas le numéro de la
machine n’est pas suffisant.
i. Numéro de machine + numéro de processus : Chaque machine peut
numéroter ses processus à partir de zéro. L’adresse est donc composée
de deux parties : La première partie indique le numéro du processus et
la deuxième le numéro de la machine (pid@machine)
ii. Numéro de machine + un numéro d’identification : chaque
processus serveur à son lancement choisi un numéro aléatoire (sur 32
bits par exemple). ( un port d’écoute) . l’adresse est numéro machine +
numéro d’identification.
iii. Choix aléatoire de l’identificateur de processus. Chaque serveur
choisir son numéro dans un espace d’adressage (sur 64 bits par
exemple). Le processus émetteur diffuse un message sur le réseau local
contenant le numéro de processus. La machine qui reçoit ce message
répond à l’expéditeur (Cette adresse est gardée dans le cache).
iv. Utiliser un serveur de noms : L’expéditeur demande à un serveur
de noms où se trouve le serveur en utilisant une chaîne de caractères.
Le serveur de noms reçoit ce message et répond au client.
NB : Inconvénients
iii : il n’y a pas de transparence. Le client doit connaître la machine du serveur.
iii : la diffusion des messages sur le réseau peut surcharger le réseau
iv : le serveur de noms peut tomber en panne

3-2-1-2 Les primitives de communication


Elles peuvent être synchrones (bloquantes) ou asynchrones (non bloquantes), utiliser
ou non des tampons, être fiables ou non fiables.

40
Les primitives synchrones : Le processus qui fait un send est bloqué jusqu’à la fin de la
transmission du message. De la même façon, le processus qui fait receive est bloqué jusqu’à
la réception totale du message. La primitive receive peut indiquer de quel client viendra le
message. Dans ce cas l’appelant sera bloqué jusqu’à ce que ce client particulier lui envoie un
message.

Primitives asynchrones : Le processus qui exécute l’appel système send ou receive n’est pas
bloqué. Il continue son exécution après l’instruction qui suit send ou receive. L’inconv énient
est que le processus qui appelle send ne doit pas modifier son tampon jusqu’à transfert
complet du message et ne sait pas quand le tampon est complètement transféré.
Solutions :
a) le noyau recopie le tampon dans un de ses tampons internes, et plus tard dans un de
ses tampons de transmission.  il y a une copie de trop, ce qui implique un gaspillage
b) interrompre l’expéditeur pour lui dire que son message est parti, et donc que son
tampon est à nouveau disponible.  le client et le serveur sont des processus
utilisateurs, donc la programmation des interruptions est difficiles.

Primitives avec tampon : Généralement elle utilisent des boîtes aux lettres. Le serveur
demande à son noyau de lui créer une boîte aux lettre et lui communique son adresse à
rechercher dans les messages. Le destinataire se contente de lire sa boîte aux lettres.
Malheureusement la taille des boîtes aux lettres est limitée. Quand elle sont saturées, le noyau
peut :
- détruire le message
- armer un temporisateur qui lui permet de détruire le message après un certain
temps.

Primitives sans tampons : le processus à l’autre bout de la communication doit être au rendez-
vous. Le noyau peut garder le message pendant un certain dans un tampon interne. Au bout de
ce temps si le processus n’est pas toujours au rendez-vous, il détruit le message.

Primitives non fiables : L’expéditeur n’a aucune garantie sur la réception du message. Le
problème de savoir si le message est arrivé est laissé à la charge des utilisateurs.

Primitives fiables : L’expéditeur attend un accusé de réception pour savoir si le message a été
reçu. Les accusé de réception sont traités au niveau des noyaux. Deux formes possibles :
a) demande (client au serveur) – Ack (noyau à noyau) – réponse (serveur au client) –
Ack (noyau à noyau).
b) Demande (client au serveur) – réponse (serveur au client) – ack (noyau à noyau)

NB : Avec le modèle client / serveur les communications ressemblent aux entrées / sorties. On
voudrait qu’elles ressemblent aux communications dans les systèmes centralisés.

3-2-2 Les RPC (remote procedure call)


Il s’agit d’un mécanisme permettant à un processus tournant sur une machine
d’exécuter une procédure à distance sur une autre machine. La première machine envoie un
bloc de données correspondant aux paramètres et à l’identification de la procédure à exécuter
à la seconde machine. Cette dernière retourne à la première un bloc correspondant aux
résultats du traitement de la procédure. Les RPC font qu’un appel à distance ressemble à un
appel local, ce qui implique la transparence. La procédure appelante n’a pas besoin de savoir
où se trouve la procédure appelée. Par exemple pour un serveur de fichiers, le processus client

41
utilise les fonctions classiques de la bibliothèque, mais elles seront exécutées de façon
transparente sur le serveur. En résumé tout se passe de la manière suivante :
- la procédure du client appelle le subrogé client de façon classique
- le subrogé client construit un message et fait un déroutement vers le noyau
- le noyau envoie le message au noyau distant
- le noyau distant donne le message au subrogé serveur
- le subrogé serveur récupère les paramètres et appelle le serveur
- le serveur effectue le travail et envoie les résultats au subrogé serveur
- le subrogé serveur met les résultats dans un message et fait un déroutement vers
le noyau
- le noyau distant envoie le message au noyau du client
- le noyau du client donne le message au subrogé client
- le subrogé client en extrait le résultat et le donne au client
NB : Après l’appel send, le subrogé client fait un un appel à receive et se bloque jusqu’à ce
que la réponse arrive. Quand le message arrive au niveau du serveur, le noyau le donne au
subrogé serveur. Ce dernier a normalement fait un receive et est bloqué en attente de
messages. Il désassemble le message et en extrait :
- l’identification de la procédure à exécuter
- les paramètres de la procédure
et passe ces informations au serveur qui appelle la procédure de façon classique. Au niveau du
serveur, les références aux variables sont en fait des références à des emplacement du tampon
du subrogé serveur.

3-2-2-1 Le passage des paramètres


Au niveau du client les paramètres de la procédure à exécuter, ainsi qu’un numéro
identifiant la procédure sont rassemblés pour former un message, par le subrogé client. Le
désassemblage est effectué au niveau du subrogé serveur, qui identifie ainsi la procédure à
appelée. A l’appel de la procédure par le subrogé serveur, les paramètres sont des variables
initialisées à partir du message et non des constantes. Aucun problème ne se pose si le client
et le serveur sont des machines de même type. Mais dans la pratique un système distribué est
composé de machines de types différents qui ont chacune leur propre représentation des
nombres, des caractères , …etc.
Les gros systèmes IBM par exemple utilisent le code EBCDIC pour représenter les
caractères alors que les ordinateurs personnels IBM utilisent l’ASCII. Certains processeurs
tels que ceux de la famille intel numérotent les octets de la droite vers la gauche alors que
d’autres comme le sparc les numérotent de la gauche vers la droite. Le format intel et le
format petit boutiste (little endian) tandis que le format du sparc est le format gros boutiste
(big endian). La représentation des entiers peut aussi poser des problèmes : complément à un
ou complément à deux. Implicitement le client et le serveur connaissent le type des
paramètres de chaque procédure.

Solutions aux problèmes de la représentation :


a) imposer un standard réseau pour les entiers, les caractères, les booléens, les réels,
…etc et exiger que tous les expéditeurs convertissent leurs représentations internes
sous cette forme avant de rassembler les paramètres.
b) Chaque machine garde sa représentation interne et indique dans le message la
représentation qu’il utilise. La machine qui reçoit le message fait les
conversions nécessaires.

3-2-2-2 Création des procédures des subrogés

42
Elles sont en général automatiquement générées. Un compilateur approprié lit la
spécification du serveur qui indique :
- le nom du serveur
- la version du serveur
- les procédures du serveur
- les paramètres de chaque procédure
- le type de chaque paramètre
- indication pour chaque paramètre si entrée ou sortie
- le type du résultat renvoyé par chaque procédure
et génère les procédures des subrogés.

3-2-2-3 Nommage dynamique


Chaque serveur dispose d’une spécification formelle qui contient les informations
indiquées au paragraphe précédent. A l’initialisation du serveur, il fait appel à une fonction
d’initialisation qui exporte l’interface du serveur : ceci indique que le serveur envoie un
message au serveur des noms pour être connu de l’extérieur. Cette opération est appelée
enregistrement du serveur. Le serveur donne son nom, son numéro de version, un
identificateur unique sur 32 bits en général, et une adresse nécessaire pour le joindre.
L’adresse peut être une adresse IP, Ethernet ou un identificateur de processus. Le serveur peut
aussi fournir au gestionnaire des noms d’autres informations concernant l’authentification
tels que la liste des clients autorisés.
Un serveur peut aussi supprimer son enregistrement auprès du gestionnaire des noms.
Quand un client appelle une procédure àn distance pour la première fois, le subrogé client fait
appel au gestionnaire de noms pour importer la version qu’il indique de l’interface serveur. Le
gestionnaire de noms vérifie si ou plusieurs serveurs ont exporté une interface de ce nom avec
le numéro de version indiqué. Si oui le gestionnaire envoie au subrogé client les informations
nécessaires pour joindre l’un de ces serveurs.

Inconvénients :
L’importation et l’exportation des interfaces fait perdre beaucoup de temps, car les
processus clients sont généralement brefs.

Quelques problèmes :
- le client est incapable de localiser le serveur
- la demande du client au serveur est perdue
- la réponse du serveur au client est perdue
- le serveur tombe en panne après avoir reçu une demande
- le client tombe en panne après avoir émis une demande

3-3 La synchronisation dans les systèmes distribués.


Les méthodes utilisées dans les systèmes centralisés (sémaphore,moniteur, …etc) ne
sont plus utilisables car elles supposent l’existence d’une mémoire partagée par les processus.
Les algorithmes à utiliser doivent être distribués. De tels algorithmes ont les propriétés
suivantes :
- les informations manipulées sont disséminées sur plusieurs machines
- les processus prennent des décisions fondées uniquement sur l’information
disponible localement
- on doit éviter d’avoir un tendon d’achille
- il n’existe pas d’horloge commune ni de source de temps universelle
3-3-1 Horloge logique

43
Dans la synchronisation des processus, le plus important n’est pas de savoir à quelle
heure réelle un événement a eu lieu. Très souvent l’ordre de précédence entre deux événement
est largement suffisant. Soient a et b deux événement on les date de la façon suivante :
- si a précède b dans le même processus, alors t(a)<t(b)
- si a et b sont l’émission ou la réception d’un message alors t(a)<t(b)
où t(x) est le temps logique associé à l’événement x. Chaque machine a son horloge locale qui
avance à son rythme ; si ab (a précède b) alors t(a)<t(b). En outre on suppose que :
- entre deux événements sur une machine l’horloge doit avancer d’au moins une
unité.
- Si une machine reçoit un message dont le temps associé est supérieur au temps
de son horloge locale, il avance le temps de son horloge locale au temps reçu
plus une unité.
Algorithmes de synchronisation d’horloge :
a) algorithme de cristian
on suppose que l’une des machine a un receveur du temps universel (Tuc). Cette machine est
le serveur du temps. Toutes les autres machines s’adressent à ce serveur pour avoir le temps.
Soit To le temps de la demande et T1 le temps de la réponse, sur la machine locale. Le temps
de transfert est en moyenne (T1-To)/2. Le compteur de temps de la machine locale est
réinitialisé à Tuc+(T1-To)/2.

b) algorithme de berkeley
On a encore un serveur de temps. Mais c’est ce dernier qui scrute chaque machine pour lui
demander l’heure. A partir des différentes réponse, il calcule l’heure moyenne et demande à
chaque machine d’avancer son horloge ou de la retarder (le serveur aussi).
Ici le serveur n’a pas besoin d’avoir un récepteur de temps universel. Son heure peut
être régulièrement ajuster par un opérateur.

3-3-2 Exclusion mutuelle dans les SD


3-3-2-1 Algorithme centralisé
Cet algorithme simule la réalisation des exclusions mutuelle sur un système centralisé.
Un processus particulier est élu coordinateur de la ressource par exemple celui quin s’exécute
sur la machine ayant la plus grande adresse réseau. Un processus qui veut entrer en section
critique envoie un message au coordinateur. Si la ressource est libre le coordinateur envoie un
message d’autorisation au demandeur. Si la ressource n’est pas libre, le coordinateur peut
envoyer un message de refus. Il peut aussi s’abstenir de répondre  le demandeur reste
bloqué. Quand un processus n’a plus besoin de la ressource, il envoie un message de
libération au coordonnateur. Ce dernier prend alors un processus qui attend dans sa file et lui
donne l’autorisation.
Inconvénients :
- le coordinateur tombe en panne
- le coordinateur peut devenir un goulet d’étranglement

3-3-2-2 Algorithme distribué


Cet algorithme exige l’existence d’un ordre total sur tous les événement du système,
c’est-à-dire que pour toute paire d’événement, aucune ambiguïté ne doit exister sur celui
survenu le premier. Un algorithme de synchronisation d’horloge peut fournir les estampiles
nécessaires à l’exclusion mutuelle.
Un processus qui veut entrer en section critique fabrique un message contenant :
- le nom de la section critique
- le numéro de processus

44
- l’heure courante (estampille)
Ce message est envoyé à tous les autres processus y compris à l’émetteur. On utilise un
système de communication fiable. A la réception d’un message un processus peut réagir de
l’une des façons suivantes :
- le récepteur n’est pas dans la section critique et ne veut pas y entrer. Il retourne
OK à l’émetteur.
- Le récepteur est déjà dans la section critique, il ne répond pas et mémorise le
message dans sa file d’attente
- Le récepteur veut entrer en section critique, mais ne l’a pas encore fait. Il
compare l’estampille du message qu’il vient de recevoir avec celle des messages
qu’il a fabriqué lui-même et fait parvenir aux autres processus. La plus ancienne
estampille remporte. Si le récepteur a une estampille plus récente, il répond par
OK à l’émetteur. Si le récepteur a la plus vieille estampille, il ne répond pas et
mémorise le message.
Après avoir envoyé ses demandes d’entrée en section critique, un processus se met en attente
jusqu’à ce que tous les autres lui donne leur autorisation. Après avoir reçu toutes les
autorisations, un processus peut entrer en section critique. Quand il en sort, il envoie un OK à
tous les processus présents dans sa file d’attente.
Inconvénients : Chaque processus participe à la coordination. Si un processus se plante, il ne
répondra plus aux requêtes. Le silence sera interprété comme un refus. La probabilité que l’un
des coordinateurs se plante est plus élevée. On a fait pire que l’algorithme centralisé. Le trafic
a augmenté dans le réseau.
Une amélioration : Un processus doit toujours envoyé un message de refus s’il ne veut pas
donner de OK. Sans réponse après un certain temps, on peut conclure que le destinataire est
en panne.

3-3-2-3 Un algorithme de type anneau à jeton


Les processus sont numérotés sous forme d’un anneau logique. A l’initialisation le
jeton est donné au processus 0. Du processus k, le jeton va au processus k+1. Un processus ne
peut entrer en section critique que s’il détient le jeton. A sa sortie de la section critique, il
passe le jeton à son suivant.
Problèmes :
- Le jeton peut se perdre et il n’est pas facile de détecter sa perte.
- Un processus peut se planter et il n’y a plus d’anneau
Solution : Un processus qui reçoit le jeton doit envoyer un message de confirmation à
l’émetteur. Ceci permet de détecter les processus qui ne répondent pas et de les éliminer de
l’anneau. Le jeton est passé au suivant du processus mort. Mais ceci suppose que chaque
processus doit connaître la configuration courante de l’anneau.

3-3-2-4 Comparaison des trois algorithmes.


Algorithme Nombre de messages par Temps avant entrée Problèmes
E/S en section critique en section critique
Centralisé 3 2 Plantage du
coordinateur
Distribué 2(n-1) 2(n-1) Plantage d’un
processus
Anneau à jeton 1 à +∞ 0 à +∞ Perte du jeton,
plantage d’un
processus

45
3-3-3 Exclusion mutuelle à l’aide des algorithmes à Election
On suppose que chaque processus a un numéro unique permettant de l’identifier. On
suppose aussi que chaque processus connaît les numéros de tous les autres processus.

3-3-3-1 L’algorithme du plus fort


c’est toujours le processus actif qui a le plus grand numéro qui joue le rôle de
coordinateur. Quand un processus p s’aperçoit que le coordinateur ne répond plus aux
requêtes, il organise une élection :
- p envoie un message élection à tous les processus dont le numéro est supérieur
au sien
- si personne ne répond, p gagne l’élection et dévient le coordinateur
- si un processus de numéro plus élevé répond, alors p a perdu l’élection et son
rôle est terminé. Le processus qui a répondu organise aussi une élection, à moins
qu’il y en ait une en cours.
- A un moment donné un seul processus est en compétition. Ce dernier devient le
coordinateur. Il prend le pouvoir et annonce sa victoire à tous les autres.

NB : Si un processus qui était inactif se réveille, il déclenche immédiatement une élection.

3-3-3-2 Un algorithme pour anneau sans jeton


Les processus sont ordonnés physiquement ou logiquement et chacun connaît son
successeur. Dès qu’un processus s’aperçoit que le coordinateur est en panne, il organise une
élection. Pour cela, il fabrique une liste Election dans laquelle il place son numéro en tête. Le
message est passé au processus actif suivant. Chaque fois qu’un processus reçoit la liste
Election, il y ajoute son propre numéro. Dès que cette liste retrouve le processus qui l’a
initiée, ce dernier remplace Election par Coordinateur et la liste continue son chemin. Cette
fois le processus qui reçoit la liste lit dans celle-ci le nouveau numéro du coordinateur. Quand
la liste revient au processus qui l’a initiée, celui-ci la détruit.

3-4 Les systèmes de fichiers distribués


Dans un système de fichiers, on distingue :
- le service de fichiers qui est la spécification de ce que le système de fichiers
fournit aux utilisateurs. Il décrit les primitives disponibles, leurs paramètres et
les actions correspondantes. Il précise ce que l’utilisateur peut attendre du
système de fichiers mais ne donne aucune précision sur la façon dont ce service
est réalisé.
- Le service de gestion des fichiers est la partie du système de fichiers qui
implémente les services décrits par le service de fichiers. Il permet par exemple
de :
i. Créer des répertoires
ii. Ajouter ou supprimer les fichiers des répertoires
iii.Déplacer des fichiers d’un répertoire à un autre
iv. … etc

Dans un système de fichiers distribué, le service de gestion des fichiers fait appel à des unités
de stockage situées sur différentes machines interconnectées à travers des liens de
communication. Le système de gestion de fichier est réalisé sur chaque machine par un
processus appelé « serveur de fichiers ». Un serveur de fichiers s’exécute sur une machine
pour rendre les services définies par le service de fichiers. Les différents serveurs de fichiers
d’un système distribué peuvent :

46
- jouer le même rôle
- être chacun spécialisé dans certaines tâches (service unix, service windows, …
etc)
Les utilisateurs n’ont pas à savoir où sont les serveurs de fichiers. Ils appellent tout
simplement les services indiqués et ceux-ci sont réalisés de façon transparente.

3-4-1 les différents modèles de serveurs de fichiers


3-4-1-1 le modèle de copie/recopie
Dans ce modèle, le serveur de fichiers ne réalise que deux opérations :
- lire un fichier
- écrire un fichier
La lecture d’un fichier transfère l’intégralité de celui-ci du serveur vers le client, et l’écriture
du fichier réalise l’opération inverse.
Avantages :
- l’interface est simple
- le transfert d’un fichier complet augmente l’efficacité des accès suivants
Inconvénients :
- le client doit disposer d’un volume de stockage suffisant
- le client peut n’avoir besoin que d’une partie d’un fichier  transfert inutile

3-4-1-2 le modèle d’accès distant


Le fichier reste sur le serveur. Le service de fichiers fournit de nombreuses primitives
pour :
- ouvrir le fichier
- fermer le fichier
- lire une partie du fichier
- écrire une partie du fichier
- se déplacer dans le fichier
- lire et modifier les attributs du fichiers
Avantages :
- pas besoin de gros espaces de stockage chez le client
- pas de manipulation de fichier dans son intégralité
inconvénients :
- interface plus complexe
- conception difficile

3-4-2 La transparence des noms


Un nom de fichier transparent doit être indépendant de la localisation du fichier. Par
exemple, un nom du genre /rep1/rep2/fich, n’est pas un nom transparent, car on n’est obligé
de savoir sur quelle machine se trouvent les répertoires rep1 et rep2. Par contre, un nom du
genre /serveur1/rep1/rep2/fich est transparent, car bien que l’on sache que fich appartienne au
serveur1, on a aucune idée de la localisation de serveur1. On dit qu’il y a transparence à la
localisation des fichiers. Un système dans lequel on peut déplacer un fichier sans changer son
nom est dit indépendant à la localisation. Ceci n’est pas facile à réaliser, mais est très
souhaitable. Trois approches peuvent être utilisées pour nommer les fichiers :
a) nom serveur + chemin dans l’arborescence du serveur
b) monter les systèmes de fichiers distants dans la hiérarchie locale
c) avoir un espace de noms unique vu de la même façon par chaque machine.

3-4-3 Sémantique de partage de fichiers

47
Méthode commentaires
Sémantique unix Chaque opération sur un fichier est instantanément visible par
les autres processus
Sémantique de session Aucun changement n’est visible avant la fermeture du fichier
Fichiers immuables Pas de mise à jour possible ; simplification du partage et de la
duplication
transactions Tous les changements se font en tout ou rien

3-4-4 Structure d’un système de fichiers distribué


Les clients et les serveurs sont-ils différents ?
a) Pas de différence : Toutes les machines exécutent le même logiciel. Rendre un service
de fichiers revient à exporter les noms de certains répertoires, pour que d’autres
machines puissent y accéder
b) Le serveur de fichiers et le gestionnaire de fichiers sont de simples programmes
utilisateurs. Ils permettent de configurer une machine pour exécuter ou non les
logiciels client ou serveur
c) Clients et serveurs sont des machines fondamentalement différentes , sur le plan du
matériel et sur le plan du logiciel. Ils peuvent même exécuter des versions différentes
du système d’exploitation.

La différence entre les systèmes se situe souvent au niveau de la structuration des services de
fichiers et de gestion. Très souvent on sépare le service de fichiers et le service de gestion des
fichiers. Dans ce cas l’accès à un fichier implique l’accès préalable au service de gestion pour
transformer le nom symbolique en nom interne que le serveur utilisera. La hiérarchie de
répertoire est souvent répartie sur plusieurs serveurs. L’arborescence est la même sur tous les
serveurs ; cependant le nom de certains fichiers sur certains serveurs ne sont en réalité que des
pointeurs vers les fichiers réels. Un serveur peut être avec ou sans état .

Serveur sans état Serveur avec état


Tolérance aux pannes Messages de demande plus petits
Pas besoin d’ouvrir ou de fermer un fichier Meilleures performances
Pas d’espace du serveur pour les tables Lecture anticipé possible
Nombre de fichiers ouverts illimité Idempotence plus simple
Pas de problème en cas de panne d’un client Possibilité e verrouiller un fichier

48
Travaux Dirigés et Pratiques :
h) Opérations sur les processus en C et Java (création, destruction, manipulation, …etc)
i) Les processus légers en C et Java
j) La communication inter processus en C et Java
k) Etude de NFS : Systèmes de fichiers distribués ou réseau ?
l) Conception d’un noyau de synchronisation

49
TRAVAUX PRATIQUES EN LANGAGE C

A – Les processus sous UNIX


r. Création des processus
s. Création des processus légers
t. Affecter du code à exécuter par un processus ou par un processus léger
u. Récupérer la valeur de retour d’un processus fils
B – les outils de synchronisation
v. les variables de verrouillage (fichiers partagés)
w. les sémaphores
C – Communication inter processus
x. les fichiers partagés
y. les tubes nommés
z. les tubes non nommés
aa. les signaux
bb. la mémoire partagée
cc. les files de messages

50

Vous aimerez peut-être aussi