Vous êtes sur la page 1sur 148

Cours Syst`eme

D.Revuz
17 fevrier 2005

ii

Table des mati`


eres
1 Introduction
1.1 Unix . . . . . . . . . . . . . . . . . . . . . . .
1.1.1 Pourquoi unix ? . . . . . . . . . . . .
1.1.2 le succ`es dUnix et de linux . . . . . .
1.1.3 Des points forts . . . . . . . . . . . .
1.1.4 Des points faibles . . . . . . . . . . . .
1.2 Structure generale des syst`emes dexploitation
1.2.1 Les couches fonctionnelles . . . . . . .
1.2.2 Larchitecture du syst`eme . . . . . . .
1.2.3 Larchitecture du noyau . . . . . . . .
1.3 historique . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

1
1
1
1
1
2
2
3
3
5
5

2 Syst`
eme de Gestion de Fichiers
2.1 Le concept de fichier . . . . . . . . . . .
2.2 Fichiers ordinaires / Fichiers speciaux.
2.3 Organisation utilisateur des Disques . .
2.4 Les inodes . . . . . . . . . . . . . . . . .
2.5 Organisation des disques System V . . .
2.6 Adressage des blocs dans les inodes . . .
2.7 Allocation des inodes dun disque . . . .
2.8 Allocation des blocs-disque . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

7
7
8
8
9
10
11
11
11

3 Le Buffer Cache
3.1 Introduction au buffer cache . . . . . . . . . . . . .
3.1.1 Avantages et desavantages du buffer cache .
3.2 Le buffer cache, structures de donnees. . . . . . . .
3.2.1 La liste doublement chanee des blocs libres
3.3 Lalgorithme de la primitive getblk . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

17
17
17
17
18
18

4 La biblioth`
eque standard
4.1 Les descripteurs de fichiers. . . . . . . . . . . . . . . . . . . . . . .
4.1.1 Ouverture dun fichier . . . . . . . . . . . . . . . . . . . . .
4.1.2 Redirection dun descripteur : freopen . . . . . . . . . . .
4.1.3 Creation de fichiers temporaires . . . . . . . . . . . . . . . .
4.1.4 Ecriture non formatee . . . . . . . . . . . . . . . . . . . . .
4.1.5 Acc`es sequentiel . . . . . . . . . . . . . . . . . . . . . . . .
4.1.6 Manipulation du pointeur de fichier . . . . . . . . . . . . .
4.1.7 Un exemple dacc`es direct sur un fichier dentiers. . . . . .
4.1.8 Les autres fonctions de deplacement du pointeur de fichier.
4.2 Les tampons de fichiers de stdlib. . . . . . . . . . . . . . . . . . . .
4.2.1 Les modes de bufferisation par defaut. . . . . . . . . . . . .
4.2.2 Manipulation des tampons de la biblioth`eque standard. . .

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

23
23
24
24
25
25
26
26
26
26
27
27
27

iii

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

`
TABLE DES MATIERES

iv
4.3
4.4
4.5
4.6
4.7

Manipulation des liens dun fichier . .


Lancement dune commande shell . . .
Terminaison dun processus . . . . . .
Gestion des erreurs . . . . . . . . . . .
Creation et destruction de repertoires

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

29
29
30
31
31

5 Appels syst`
eme du Syst`
eme de Gestion de Fichier
5.1 open . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.1.1 Deroulement interne dun appel de open . . .
5.2 creat . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3 read . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.4 write . . . . . . . . . . . . . . . . . . . . . . . . . .
5.5 lseek . . . . . . . . . . . . . . . . . . . . . . . . . .
5.6 dup et dup2 . . . . . . . . . . . . . . . . . . . . . . .
5.7 close . . . . . . . . . . . . . . . . . . . . . . . . . .
5.8 fcntl . . . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

33
33
35
36
36
36
37
37
38
38

6 Les processus
6.1 Introduction aux processus . . . . . . . . . . . . . . . . . .
6.1.1 Creation dun processus - fork() . . . . . . . . . .
6.2 Format dun fichier executable . . . . . . . . . . . . . . . .
6.3 Chargement/changement dun executable . . . . . . . . . .
6.4 zone u et table des processus . . . . . . . . . . . . . . . . .
6.5 fork et exec (revisites) . . . . . . . . . . . . . . . . . . . .
6.6 Le contexte dun processus . . . . . . . . . . . . . . . . . .
6.7 Commutation de mot detat et interruptions. . . . . . . . .
6.8 Les interruptions . . . . . . . . . . . . . . . . . . . . . . . .
6.9 Le probl`eme des cascades dinterruptions . . . . . . . . . . .
6.9.1 Etats et transitions dun processus . . . . . . . . . .
6.9.2 Listes des etats dun processus . . . . . . . . . . . .
6.10 Lecture du diagramme detat. . . . . . . . . . . . . . . . . .
6.11 Un exemple dexecution . . . . . . . . . . . . . . . . . . . .
6.12 La table des processus . . . . . . . . . . . . . . . . . . . . .
6.13 La zone u . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.14 Acc`es aux structures proc et user du processus courant . .
6.14.1 Les informations temporelles. . . . . . . . . . . . . .
6.14.2 Changement du repertoire racine pour un processus.
6.14.3 Recuperation du PID dun processus . . . . . . . . .
6.14.4 Positionement de leuid, ruid et suid . . . . . . . . .
6.15 Tailles limites dun processus . . . . . . . . . . . . . . . . .
6.15.1 Manipulation de la taille dun processus. . . . . . . .
6.15.2 Manipulation de la valeur nice . . . . . . . . . . . .
6.15.3 Manipulation de la valeur umask . . . . . . . . . . .
6.16 Lappel syst`eme fork . . . . . . . . . . . . . . . . . . . . .
6.17 Lappel syst`eme exec . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

41
41
41
42
42
43
43
45
45
46
47
47
47
48
49
49
50
50
50
51
51
51
52
52
52
52
53
53

7 Lordonnancement des processus


7.1 Le partage de lunite centrale . . .
7.1.1 Famine . . . . . . . . . . .
7.1.2 Strategie globale . . . . . .
7.1.3 Crit`eres de performance . .
7.2 Ordonnancement sans preemption.
7.3 Les algorithmes preemptifs . . . .
7.3.1 Round Robin (tourniquet) .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

55
55
56
56
57
57
57
58

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

`
TABLE DES MATIERES

7.4

7.3.2 Les algorithmes `a queues multiples


Multi-level-feedback round robin Queues .
7.4.1 Les niveaux de priorite . . . . . . .
7.4.2 Evolution de la priorite . . . . . .
7.4.3 Les classes de priorite . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

8 La m
emoire
8.0.4 les memoires . . . . . . . . . . . . . . . . . . . . . . . . .
8.0.5 La memoire centrale . . . . . . . . . . . . . . . . . . . . .
8.1 Allocation contigue . . . . . . . . . . . . . . . . . . . . . . . . . .
8.1.1 Pas de gestion de la memoire . . . . . . . . . . . . . . . .
8.1.2 Le moniteur residant . . . . . . . . . . . . . . . . . . . . .
8.1.3 Le registre barri`ere . . . . . . . . . . . . . . . . . . . . . .
8.1.4 Le registre base . . . . . . . . . . . . . . . . . . . . . . . .
8.1.5 Le swap . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.1.6 Le co
ut du swap . . . . . . . . . . . . . . . . . . . . . . .
8.1.7 Utilisation de la taille des processus . . . . . . . . . . . .
8.1.8 Swap et executions concurrentes . . . . . . . . . . . . . .
8.1.9 Contraintes . . . . . . . . . . . . . . . . . . . . . . . . . .
8.1.10 Deux solutions existent . . . . . . . . . . . . . . . . . . .
8.1.11 Les probl`emes de protection . . . . . . . . . . . . . . . . .
8.1.12 Les registres doubles . . . . . . . . . . . . . . . . . . . . .
8.2 Ordonnancement en memoire des processus . . . . . . . . . . . .
8.3 Allocation non-contigue . . . . . . . . . . . . . . . . . . . . . . .
8.3.1 Les pages et la pagination . . . . . . . . . . . . . . . . . .
8.3.2 Ordonnancement des processus dans une memoire paginee
8.3.3 Comment proteger la memoire paginee . . . . . . . . . . .
8.3.4 La memoire segmentee . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

58
58
58
59
60

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. .
. .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

61
61
61
63
63
63
63
63
65
65
65
66
66
66
66
66
67
68
68
68
69
69

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

9 La m
emoire virtuelle
9.0.5 Les overlays . . . . . . . . . . . . . . . . . . . . . . . .
9.0.6 Le chargement dynamique . . . . . . . . . . . . . . . .
9.1 Demand Paging . . . . . . . . . . . . . . . . . . . . . . . . . .
9.1.1 Efficacite . . . . . . . . . . . . . . . . . . . . . . . . .
9.2 Les algorithmes de remplacement de page . . . . . . . . . . .
9.2.1 Le remplacement optimal . . . . . . . . . . . . . . . .
9.2.2 Le remplacement peps (FIFO) . . . . . . . . . . . . .
9.2.3 Moins recemment utilisee LRU. . . . . . . . . . . . . .
9.2.4 Lalgorithme de la deuxi`eme chance . . . . . . . . . .
9.2.5 Plus frequemment utilise MFU . . . . . . . . . . . . .
9.2.6 Le bit de salete (Dirty Bit) . . . . . . . . . . . . . . .
9.3 Allocation de pages aux processus . . . . . . . . . . . . . . .
9.4 Lappel fork et la memoire virtuelle . . . . . . . . . . . . . . .
9.5 Projection de fichiers en memoire . . . . . . . . . . . . . . . .
9.6 Les conseils et politiques de chargement des zones mmappees
9.7 Chargement dynamique . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

71
71
72
72
73
75
75
75
76
76
76
77
77
78
78
80
81

10 Tubes et Tubes Nomm


es
10.1 Les tubes ordinaires (pipe) .
10.2 Creation de tubes ordinaires
10.3 Lecture dans un tube . . . .
10.4 Ecriture dans un tube . . .
10.5 Interblocage avec des tubes
10.6 Les tubes nommes . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

83
83
83
85
86
86
86

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

`
TABLE DES MATIERES

vi

10.6.1 Ouverture et synchronisation des ouvertures de tubes nommes . . . . . . .


10.6.2 Suppression dun tube nomme . . . . . . . . . . . . . . . . . . . . . . . . .
10.6.3 les appels popen et pclose . . . . . . . . . . . . . . . . . . . . . . . . . . .
11 Les signaux
11.0.4 Provenance des signaux . . . . . . . .
11.0.5 Gestion interne des signaux . . . . . .
11.0.6 Lenvoi de signaux : la primitive kill .
11.1 La gestion simplifiee avec la fonction signal
11.1.1 Un exemple . . . . . . . . . . . . . . .
11.2 Probl`emes de la gestion de signaux ATT . . .
11.2.1 Le signal SIGCHLD . . . . . . . . . .
11.3 Manipulation de la pile dexecution . . . . . .
11.4 Quelques exemples dutilisation . . . . . . . .
11.4.1 Lappel pause . . . . . . . . . . . . . .
11.5 La norme POSIX . . . . . . . . . . . . . . . .
11.5.1 Le blocage des signaux . . . . . . . . .
11.5.2 sigaction . . . . . . . . . . . . . . . . .
11.5.3 Lattente dun signal . . . . . . . . . .

87
87
87
89
89
89
90
91
91
91
93
94
95
95
96
96
97
97

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

12 Les verrous de fichiers


12.1 Caracteristiques dun verrou . . . . . . . . . . .
12.2 Le mode operatoire des verrous . . . . . . . . .
12.3 Manipulation des verrous . . . . . . . . . . . .
12.4 Utilisation de fcntl pour manipuler les verrous

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

99
. 99
. 99
. 100
. 101

13 Algorithmes Distribu
es & Interblocages
13.1 exemples . . . . . . . . . . . . . . . . . . . . . . . .
13.1.1 Les mefaits des acc`es concurrents . . . . . .
13.1.2 Exclusion mutuelle . . . . . . . . . . . . . .
13.2 Mode dutilisation des ressources par un processus.
13.3 Definition de linterblocage (deadlock) . . . . . . .
13.4 Quatre conditions necessaires `a linterblocage. . . .
13.5 Les graphes dallocation de ressources . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

103
103
103
104
105
105
105
105

14 S
ecurit
e et S
uret
e de fonctionnement
14.1 Protection des syst`emes dexploitation . . . . . . . . . . . . . . . . . .
14.2 Generalites sur le controle dacc`es . . . . . . . . . . . . . . . . . . . . .
14.2.1 Domaines de protection et matrices dacc`es . . . . . . . . . . .
14.2.2 Domaines de protection restreints . . . . . . . . . . . . . . . . .
14.2.3 Avantages des domaines de protections restreints . . . . . . . .
14.3 Le cheval de Troie . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.4 Le confinement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.5 les mecanismes de controle . . . . . . . . . . . . . . . . . . . . . . . . .
14.5.1 Application des capacites au domaines de protection restreints
14.6 Les ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.6.1 Appels systemes setacl et getacl . . . . . . . . . . . . . . . .
14.6.2 Autres pistes sur la securite . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

107
107
108
109
109
110
110
110
110
112
115
115
116

15 Multiplexer des entr


ees-sorties
15.1 Gerer plusieurs cannaux dentree sortie . . .
15.1.1 Solution avec le mode non bloquant
15.1.2 Utiliser les mecanismes asynchrones
15.2 Les outils de selection . . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

119
119
119
119
119

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

`
TABLE DES MATIERES
15.2.1 La primitive select .
15.2.2 La primitive poll . .
15.2.3 Le peripherique poll .
15.2.4 Les extensions de read
15.3 une solution multi-activites .

vii
. . . . . .
. . . . . .
. . . . . .
et write
. . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

119
121
122
123
123

16 Les threads POSIX


16.0.1 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.0.2 fork et exec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.0.3 clone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.0.4 Les noms de fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.0.5 les noms de types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.0.6 Attributs dune activite . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.0.7 Creation et terminaison des activites . . . . . . . . . . . . . . . . . . . .
16.1 Synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.1.1 Le mod`ele fork/join (Paterson) . . . . . . . . . . . . . . . . . . . . . . .
16.1.2 Le probl`eme de lexclusion mutuelle sur les variables gerees par le noyau
16.1.3 Les semaphores dexclusion mutuelle . . . . . . . . . . . . . . . . . . . .
16.1.4 Utilisation des semaphores . . . . . . . . . . . . . . . . . . . . . . . . . .
16.1.5 Les conditions (ev`enements) . . . . . . . . . . . . . . . . . . . . . . . . .
16.2 Ordonnancement des activites . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.2.1 Lordonnancement POSIX des activites . . . . . . . . . . . . . . . . . .
16.3 Les variables specifiques `a une thread . . . . . . . . . . . . . . . . . . . . . . .
16.3.1 Principe general des donnees specifiques, POSIX . . . . . . . . . . . . .
16.3.2 Creation de cles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.3.3 Lecture/ecriture dune variable specifique . . . . . . . . . . . . . . . . .
16.4 Les fonctions standardes utilisant des zones statiques . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

125
125
125
127
127
127
128
128
128
129
129
129
130
130
132
132
133
134
134
134
134

17 Clustering
135
17.1 Le clustering sous linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
18 Bibliographie
137
18.1 Webographie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

viii

`
TABLE DES MATIERES

Cours de conception de syst`emes et dutilisation dUNIX


Ce poly est `a lusage des etudiants de la fili`ere Informatique et Reseaux de lecole dingenieurs
Ingenieurs 2000 UMLV et de la trois`eme annee de lience dinformatique de Marne la Vallee comme
`
support du cours SYSTEMES
dEXPLOITATION.
Cette version du , apporte de nombreuse corrections de typo et autre, je remercie David Lecorfec
pour sa lecture attentive, et les remarques sur le fond seront prises en compte dans la prochaine
version.
Ce poly a une version HTML disponible sur le Web a ladresse suivante :
http://www-igm.univ-mlv.fr/~dr/NCS/
Ce document a de nombreux defauts en particulier son manque dhomogeneite, et une absence
dexplications dans certaines parties (explication donnees en general oralement en cours).
Au menu lessentiel dUNIX : SGF, processus, signaux, memoire, memoire virtuelle, manipulation des terminaux, tubes, IPC. Quelques detours : micro-noyaux, securite. Un chapitre important
mais un peut court : les probl`emes de programmation distribue et des interblocages (ameliorations
en cours fin 2004).
Prerequis : pour la partie conceptuelle des notions de programmation et dalgorithmique sont
necessaire pour profiter pleinement du cours, pour la partie technique une competance raisonable
en C est necessaire, en particulier les notions de pointeurs dallocation dynamique doivent etre maitrisees, les 4 methodes dallocation principale du C doivent etre maitrisees ! (text,static,auto,heap).

Evolutions
futures : dr@univ-mlv.fr (jattend vos remarques), uniformisation de la presentation,
nettoyage des points obscurs, corrections orthographiques, complement sur fcntl, ioctl, plus dexemples,
des sujets de projets , des sujets dexamen.

Chapitre 1

Introduction
Ceci est un polycopie de cours de licence informatique sur les syst`emes dexploitations en
general et plus specialement sur la famille Unix.
Ce poly est le support utilise pour les licences et pour les Apprentis ingenieurs de la fili`ere Informatique et Reseau.

1.1
1.1.1

Unix
Pourquoi unix ?

Pourquoi ce choix dunix comme sujet detude pour le cours ?

LE PRIX
la disponibilite des sources
Lintelligence des solutions mise en oeuvre
de grande ressource bibliographique
il faut mieux apprendre les conceptes fondamentaux dans un syst`eme simple et ouvert puis
passer a des syst`emes proprietaires et fermes que linverse.
parceque je ne vais pas changer mon cours tout de suite

1.1.2

le succ`
es dUnix et de linux

Le succ`es dUNIX sans doute parce que :


Ecrit dans un langage de haut niveau : C (C++, Objective C) ;
une interface simple et puissante : les shells, qui fournissent des services de haut niveau ;
Des primitives puissantes qui permettent de simplifier lecriture des programmes ;
Un syst`eme de fichier hierarchique qui permet une maintenance simple et une implementation
efficace ;
Un format generique pour les fichiers, le flot doctets qui simplifie lecriture des programmes ;
Il fournit une interface simple aux peripheriques ;
Il est multi-utilisateurs et multi-taches ;
Il cache compl`etement larchitecture de la machine `a lutilisateur.

1.1.3

Des points forts

Syst`eme ne dans le monde de la recherche


integration de concepts avances
Diffusion ouverte
acc`es aux sources
1

CHAPITRE 1. INTRODUCTION
Langage (de haut niveau )
compilation separee, conditionnelle, parametrage, precompilation
Enrichissement constant
Ouverture (parametrabilite du poste de travail)
Souplesse des entrees/sorties
uniformite
Facilites de communication inter-syst`emes
Communautes dutilisateurs (/etc/groups)
Langages de commandes (flexibles et puissants)
Aspect multi-utilisateurs
connections de tout type de terminal, biblioth`eques, etc
Parallelisme
multi-taches : scheduling par tache
communication entre taches
multiprocesseurs
Interface syst`eme/applications
appels syst`eme, biblioth`eque
le syst`eme de gestion de fichiers
hierarchie
Interfaces graphiques normees : X11.
Profusion dinterfaces graphiques sous linux Gnome et KDE en particulier

1.1.4

Des points faibles

Fragilite du S.G.F.
pertes de fichiers possible en cas de crash
regle avec les SGF journalises
Gestion et rattrapage des interruptions inadapte au temps reel
Des evolutions avec RLlinux et OS9.
Mecanisme de creation de processus lourd
de nombreuses ameliorations en particulier les threads.
Une edition de liens statique
Amelioration avec les librairies partagees.
des Modules noyau chargeables/dechargeables dynamiquement
Rattrapage derreur du compilateur C standard peu aise !
Ces bugs sont corrigees
Co
ut en ressources
reste globalement efficasse
Gestion

1.2

Structure g
en
erale des syst`
emes dexploitation

Un syst`eme dexploitation est un programme qui sert dinterface entre un utilisateur et un ordinateur.

Un syst`eme dexploitation est un ensemble de procedures manuelles et automatiques qui permet

ERALE

`
1.2. STRUCTURE GEN
DES SYSTEMES
DEXPLOITATION

`a un groupe dutilisateurs de partager efficacement un ordinateur. Brinch Hansen.

Il est plus facile de definir un syst`eme dexploitation par ce quil fait que par ce quil est. J.L.
Peterson.

Un syst`eme dexploitation est un ensemble de procedures coherentes qui a pour but de gerer la
penurie de ressources. J-l. Stehle P. Hochard.

Quelques syst`
emes :
le batch Le traitement par lot (disparus).
interactifs Pour les utilisateurs (ce cher UNIX).
temps r
eels Pour manipuler des situations physiques par des peripheriques (OS9 un petit fr`ere
fute dUNIX). Lidee est de gerer le temps vrai.En particulier de gerer des ev`enement
aleatoires qui neccessite lexecution dune action en proirite absolue.
distribu
es UNIX ?, les micros noyaux ? lavenir ?
moniteurs transactionnels Ce sont des applications qui manipulent des objets `a taches multiples comme les comptes dans une banque, des reservations, etc. Lidee est de decomposer
lactivite en actions, chacune independantes des autres,pour ce faire elle sont ecrites pour
avoir un comportement dit atomique ainsi il ny a pas de programme mais des ev`enement
et des actions associees. Il ny pas dans de changement de context pour traiter une action,
cest le syst`eme adapte pour traite de gros volumes de petites operations.
SE orient
es objets Micro Noyaux.

1.2.1

Les couches fonctionnelles

Couches fonctionnelles :
Programmes utilisateurs
Programmes dapplication editeurs/tableurs/BD/CAO
Programmes syst`eme assembleurs/compilateurs/editeurs de liens/chargeurs
syst`eme dexploitation
langage machine
microprogramme
machines physiques

1.2.2

Larchitecture du syst`
eme

Larchitecture globale dUNIX est une architecture par couches (coquilles) successsives comme
le montre la figure 1.2. Les utilisateurs ordinaire communiquent avec la couche la plus evoluee celle
des applications (en generale aujourdhui associe avec une interface graphique). Le programmeur
lui va en fonction de ses besoins utiliser des couches de plus en plus profondes, plus precises mais
plus difficiles a utiliser.
Chaque couche est construite pour pouvoir etre utilisee sans connaitre les couches inferieures (ni
leur fonctionnement, ni leur interface).
Cette hierarchie dencapsulation permet decrire des applications plus portables. En effet si elles
sont ecrites dans les couches hautes, le travaille de portage est fait par le portage des couches
inferieures. Pour des applications o`
u le temps de calcul prime devant la portabilite, les couches
basses seront utilisees.

CHAPITRE 1. INTRODUCTION

Utilisateurs
user 1

user 2

user 3

compilateur

editeur

jeux

user N

Base de ...

Applications
Systme dexploitation

Matriel

Fig. 1.1 Vue generale du syst`eme

utilisateur
utilisateur

utilisateur

SHELL
make
ls
awk
Hardware
cc
Kernel
vi
Applications

Fig. 1.2 Point de vue utilisateur

1.3. HISTORIQUE

Applications/utilisateurs


bibliotheques

Niveau Utilisateur
Niveau Noyau
Interface appels - systeme
Sous-Systeme
de
Gestion de fichiers

Sous-Systeme
Gestion des processus
communication
interprocessus
"scheduler"

cache

gestion memoire
caractere |
bloc
Controleurs

Controle Materiel
Niveau Noyau
Niveau Materiel
Materiel

Fig. 1.3 Architecture du noyau

1.2.3

Larchitecture du noyau

Lautre approche architecturale est larchitecture interne du Noyau (kernel). Cest une architecture logicielle elle permet aux developpeur de structurer le travail de developpement. Le but ici est
de simplifier la comprehension et la fabrication du syst`eme. Nous cherchons donc ici `a decomposer
le noyau en parties disjointes (qui sont concevables et programmables de facons disjointes). La
Figure 1.3 donne une idee de ce que peut etre larchitecture interne dun noyau UNIX. Noter bien
la position exterieure des biblioth`eques .

1.3

historique

Il existe un site tr`es agreable sur lhistoire des ordinateurs :


http://www.computerhistory.org/
.

CHAPITRE 1. INTRODUCTION

Chapitre 2

Syst`
eme de Gestion de Fichiers
Le syst`eme de gestion de fichiers est un outil de manipulation des fichiers et de la structure
darborescence des fichiers sur disque et a aussi le role sous UNIX de conserver toutes les informations dont la perennite est importante pour le syst`eme (et pour les utilisateurs biensur). Ainsi tous
les objets importants du syst`eme sont references dans le syst`eme de fichiers (memoire, terminaux,
peripheriques varies, etc).
Le syst`eme de gestion de fichier permet une manipulation simple des fichiers et g`ere de facon
transparente les differents probl`emes dacc`es aux supports de masse :
partage : utilisation dun meme fichier/disque par plusieurs utilisateurs
efficacite : utilisation de cache, uniformisation des acc`es
droits : protection des elements important du syst`eme et protection interutilisateurs
alignement : transtypage entre la memoire et les supports magnetiques

2.1

Le concept de fichier

Lunite logique de base de linterface du Syst`eme de Gestion de Fichiers : le fichier.


Un fichier Unix est une suite finie de bytes (octets) Mat
erialis
ee par des blocs
disques, et une inode qui contient les propri
et
es du fichier (mais pas son nom).
Le contenu est enti`erement defini par le createur, la gestion de lallocation des ressources necessaires
est a la seule responsabilite du syst`eme.
Sur Unix les fichiers ne sont pas types du point de vue utilisateur, le concept de fichier permet
de proposer un type generique (polymorphe) aux programmeurs le syst`eme gerant la multiplicite
des formats effectifs (differenttes marques et conceptions de disques dur par exemple).
Linode definit le fichier, soit principalement les informations :
la localisation sur disque,
le proprietaire et le groupe proprietaire,
les droits dacc`es des differents utilisateurs,
la taille,
la date de creation.
On trouvera sur dautre syst`emes dautres structures dinformation pour decrire les fichiers, par
exemple NT utilise des objets files records.
Un nom est lie `
a un fichier (une reference indique un fichier) mais un fichier nest pas lie `
a
une reference, un fichier peut exister sans avoir de nom dans larborescence.
7

`
CHAPITRE 2. SYSTEME
DE GESTION DE FICHIERS

2.2

Fichiers ordinaires / Fichiers sp


eciaux.

Le syst`eme est un utilisateur du syst`eme de gestion de fichier et en temps que createur il definit
quelques contenus structures ces fichiers auront de ce fait des acc`es r`eglementes.
Pour le syst`eme les fichiers sont donc organises en deux grandes familles :
les fichiers standards que sont par exemple les fichiers texte, les executables, etc. Cest-`a-dire
tout ce qui est manipule et structure par les utilisateurs.
Les fichiers sp
eciaux peripheriques, memoire, et autre fichiers physiques ou logique. Ces fichiers ont une structure interne definie (par les developpeurs du syst`eme) qui doit etre respecte cest pourquoi leur manipulation nest possible que par par lintermediaire du syst`eme
(encore un bon exemple dencapsulation).
Les catalogues sont des fichiers speciaux, il faut pour les manipuler physiquement faire appel
au syst`eme ce qui en prot`ege la structure1 .
Les fichiers physiques dans le repertoire /dev (dev comme devices dispositifs materiels, les peripheriques
et quelques dispositifs logiques )
Character devices (peripheriques ou la communication ce fait octets par octets)
les terminaux (claviers, ecrans)
les imprimantes
la memoire
etc
Block devices (peripheriques ou la communication ce fait par groupe doctet appeles blocs)
les disques
les bandes magnetiques
etc
Les fichiers `a usages logiques et non physiques

liens symboliques
pseudo-terminaux
sockets
tubes nommes
Ce dernier type de fichiers speciaux est utilise pour servir dinterface entre disques, entre
machines et simuler : des terminaux, des lignes de communication, etc.
Cette distinction entre fichier ordinaire et speciaux et tout simplement le fait que le syst`eme est
un utilisateur comme les autres des fichiers. Pour certains fichier le syst`eme utilise une structure
interne speciale (dou le nom) qui ne doit pas etre modifier sous peine de comportement indefini.
Pour se proteger le syst`eme ne permet pas lacc`es direct aux informations cest lui qui fait toutes
les entrees sortie sur les fichiers speciaux de facon a en assurer lintegrite. Ceci est independant
du syst`eme de droits dacc`es, la structure du code du noyau ne permet pas dautres acc`es que les
acc`es speciaux 2 .

2.3

Organisation utilisateur des Disques

Comment permettre aux utilisateurs didentifier les donnees sur les supports de masse ?
Le syst`eme le plus rependu aujourdhui est un syst`eme arborescent avec des fichiers utilises comme
1 les r
epertoires sont rest
e accessible longtemps en lecture comme des fichiers ordinaires mais lacc`
es en

ecriture etait contraint, pour assurer la structure arborescente acyclique. Aujourdhui tout les acc`
es au r
epertoires
ont contraint et on a un ensemble dappels syst`
eme sp
ecifiques pour r
ealiser des entr
es sortie dans les repertoires. opendir(3), closedir(3), dirfd(3), readdir(3), rewinddir(3), scandir(3),seekdir(3), telldir(3)
approche qui permet d
etre effectivement plus ind
ependant sur la structure interne des r
epertoires, avec des syst`
eme
plus efficaces que les listes utilis
ees dans les premi`
ere impl
ementations. Voire Reiser fs par exemple.
2 Pour plsu dinformation sur le sujet aller voire dans les sources les structures de sgf et dinode TODO : nom
de fichiers concern
es .

2.4. LES INODES

Fig. 2.1 larborescence MULTICS


noeud de larbre qui permette de lister les fichiers et les sous arbres quil contienti, dautres
organisations plates existe ou lon organise les fichiers en utilisans des types et des extentions
de nom de fichier pour organiser.
Les arborescences de fichiers et de catalogues, organisees comme un graphe acyclique 3 , apparaissent avec le projet MULTICS.
Cette organisation logique du disque a les avantages suivants :
Une racine, un acc`es absolu aise (`a la difference de certains syst`eme qui ont de nombreuses racines).
Une structure dynamique.
Une grande puissance dexpression.
Un graphe acyclique.
Lorganisation est arborescente avec quelques connections supplementaires (liens multiples sur un
meme fichier) qui en font un graphe. Mais ce graphe doit rester acyclique, pour les raisons suivantes :
Lensemble des algorithmes simples utilisables sur des graphe acycliques comme le parcours,
la verification des fichiers libres, etc. deviennent beaucoup plus difficiles `a ecrire pour des graphes
admettant des cycles.
Des algorithmes de ramasse-miettes doivent etre utilises pour savoir si certains objets sont
utilises on non et pour recuperer les inodes ou blocs perdus apr`es un crash.
Tous les algorithmes de detection dans un graphe quelconque ont une complexite beaucoup
plus grande que ceux qui peuvent profiter de lacyclicite du graphe.
Sous Unix nous sommes assures que le graphe est acyclique car il est interdit davoir plusieurs
references pour un meme catalogue (sauf la reference speciale .. ).
Sous UNIX cest un graphe acyclique !

2.4

Les inodes

Linode est le passage oblige de tous les echanges entre le syst`eme de fichier et la memoire.
Linode est la structure qui contient toutes les informations sur un fichier donne `a lexception de
3 Ce

nest pas un arbre car un fichier peut avoir plusieurs r


ef
erences

`
CHAPITRE 2. SYSTEME
DE GESTION DE FICHIERS

10

sa reference dans larborescence (son nom), larborescence netant quun outil de referencement
des fichiers.
Les informations stockees dans une inode disque sont :
utilisateur proprietaire
groupe proprietaire
type de fichier
- fichiers ordinaires
d repertoire (dyrectory)
b mode bloc
c mode caract`ere
l lien symbolique
p pour une fifo (named pipe)
s pour une socket
droits dacc`es (ugo*rwx)
date de dernier acc`es
date de derni`ere modification
date de derni`ere modification de linode
taille du fichier
adresses des blocs-disque contenant le fichier.
Dans une inode en memoire (fichier en cours dutilisation par un processus) on trouve dautres
informations supplementaires :
le statut de linode
{ locked,
waiting P
inode `a ecrire,
fichier `a ecrire,
le fichier est un point de montage
}
Et deux valeurs qui permettent de localiser linode sur un des disques logiques :
Numero du disque logique
Numero de linode dans le disque
cette information est inutile sur le disque (on a une bijection entre la position de linode sur disque
et le numero dinode).
On trouve aussi dautres types dinformations comme lacc`es `a la table des verrous ou bien des
informations sur les disques `a distance dans les points de montage.

2.5

Organisation des disques System V

Lorganisation disque decrite sur la figure 2.2 est la plus simple que lon peut trouver de nos
jours sous UNIX, il en existe dautres o`
u lon peut en particulier placer un meme disque logique
sur plusieurs disques physiques (dangereux), certaines o`
u les blocs sont fragmentables, etc.
Boot bloc utilise au chargement du syst`eme.
Super Bloc il contient toutes les informations generales sur le disque logique.
Inode list Table des inodes.
blocs les blocs de donnees chaines `a la creation du disque (mkfs).
Les blocs de donnees ne sont pas fragmentables sous Syst`eme V.

2.6. ADRESSAGE DES BLOCS DANS LES INODES

11

Structure du systme de fichier sur un disque logique


Boot
Bloc

Super
Bloc

Inode liste

Blocs de
donnes

Plusieurs disques logiques sur un disque physique

Super Bloc

Inode liste

Disque logique 1 Disque logique 2 Disque logique 3

Boot Bloc

Boot Bloc (vide)

Blocs de
donnes

Fig. 2.2 Organisation des blocs et des inodes (SYS V)

2.6

Adressage des blocs dans les inodes

Le syst`eme dadressage des blocs dans les inodes (syst`eme V) consiste en 13 adresses de blocs.
Les dix premi`eres adresses sont des adresses qui pointent directement sur les blocs de donnees du
fichier. Les autres sont des adresses indirectes vers des blocs de donnees contenant des adresses.
La figure 2.3 nous montre les trois niveaux dindirection. Linteret de cette representation est
deconomiser sur la taille des inodes tout en permettant un acc`es rapide au petits fichiers (la majorite des fichiers sont petits). Mais en laissant la possibilite de creer de tr`es gros fichiers :
10 + 256 + (256 256) + (256 256 256)
blocs disques.

2.7

Allocation des inodes dun disque

Lallocation des inodes est realisee en recherchant dans la zone des inodes du disque une inode
libre. Pour accelerer cette recherche : un tampon dinodes libres est gere dans le SuperBloc, de
plus lindice de la premi`ere inode libre est garde en reference dans le SuperBloc afin de redemarrer
la recherche qu`a partir de la premi`ere inode reellement libre.
Mais ce syst`eme a une faille quil faut prevoir dans lecriture dans lalgorithme ialloc dallocation
dinode, cette faille est decrite dans la Figure 2.10

2.8

Allocation des blocs-disque

Lalgorithme utilise pour gerer lallocation des inodes sappuie sur le fait que lon peut tester si
une inode est libre ou non en regardant son contenu. Ceci nest plus vrai pour les blocs. La solution
est de chaner les blocs. Ce chanage est realise par blocs dadresses pour accelerer les acc`es et
profiter au maximum du buffer cache. Il existe donc un bloc dadresses dans le super bloc qui sert
de zone de travail pour lallocateur de blocs. Lutilisation de ce bloc et le mecanisme dallocation
sont decrits dans les Figures 2.11 `a 2.16

`
CHAPITRE 2. SYSTEME
DE GESTION DE FICHIERS

12

Blocs de donnes
sur le disque

Inode
direct 0
direct 1
direct 2
direct 3
direct 4
direct 5
direct 6
direct 7
direct 8
direct 9
indirect
double
triple

Fig. 2.3 Adressage direct et indirect des inode UNIX

Liste des inodes du Super Bloc


inodes libres

83
19

18

vide

48
20
Curseur

Fig. 2.4 Inodes libres dans le SuperBloc.

Liste des inodes du Super Bloc


inodes libres

vide

83
18

19

20

Curseur

Fig. 2.5 Allocation dune inode.

2.8. ALLOCATION DES BLOCS-DISQUE

13

Liste des inodes du Super Bloc


vide

473
0
Curseur

(numro d'inode de rfrence)

Liste des inodes du Super Bloc


539

inodes libres

479

475

477

Fig. 2.6 Si le SuperBloc est vide.

Liste des inodes du Super Bloc


539

inodes libres

479

477

475

0
Curseur

Fig. 2.7 Liberation dune inode avec le SuperBloc plein.

Liste des inodes du Super Bloc


219

inodes libres

479

477

475

0
Curseur

Fig. 2.8 Le numero dinode inferieur au numero de reference.

Liste des inodes du Super Bloc


219

inodes libres

479

477

475

0
Curseur

Fig. 2.9 Le numero dinode superieur au numero de reference.

`
CHAPITRE 2. SYSTEME
DE GESTION DE FICHIERS

14

Processus B

Processus A
allocation
de l'inode I

Processus C

en sommeil pendant
la lecture de l'inode (a)
allocation
avec super bloc vide (b)
l'inode I (libre) est remise
dans le super bloc (c)
Travail sur
l'Inode I en mmoire
allocation
d'une inode (d)

allocation (d)
de l'inode I
Mais l'inode I
n'est pas libre !!
allocation (e)
d'une autre l'inode

temps
(a)

(b)
(c)

JIK

(d)

JI

(e)

temps
Fig. 2.10 Faille de lalgorithme dallocation.

2.8. ALLOCATION DES BLOCS-DISQUE

15

Super Bloc Liste


109 106 103 100

95

Bloc 109
211 208 205 202 199

112

Bloc 211
311 308 305 302 301

214

etc
Fig. 2.11 Liste chainee de blocs.

Super Bloc Liste


109

vide

211 208 205 202 199

112

Fig. 2.12 Etat initial du SuperBloc.

Super Bloc Liste


109 978

211 208 205 202 199

112

Fig. 2.13 Liberation du bloc 978.

Super Bloc Liste


109
Bloc 109
211 208 205 202 199
Fig. 2.14 Allocation du bloc 978.

112

`
CHAPITRE 2. SYSTEME
DE GESTION DE FICHIERS

16

Super Bloc Liste


211 208 205 202 199

112

Bloc 211
311 308 305 302 301

214

Fig. 2.15 Allocation du bloc 109.

Super Bloc Liste


612
Bloc 612
211 208 205 202 199
Fig. 2.16 Liberation du bloc 612.

112

Chapitre 3

Le Buffer Cache
3.1

Introduction au buffer cache

Le buffer cache est un ensemble de structures de donnees et dalgorithmes qui permettent de


minimiser le nombre des acc`es disque.
Ce qui est tr`es important car les disques sont tr`es lents relativement au CPU et un noyau qui
se chargerait de toutes les entrees/sorties serait dune grande lenteur et lunite de traitement ne
serait effectivement utilisee qu`a un faible pourcentage (voir Historique).
Deux idees pour reduire le nombre des acc`es disques :
1. bufferiser les differentes commandes decriture et de lecture de facon `a faire un acc`es disque
uniquement pour une quantite de donnees de taille raisonnable (un bloc disque).
2. Eviter des ecritures inutiles quand les donnees peuvent encore etre changees (ecriture differees).

3.1.1

Avantages et d
esavantages du buffer cache

Un acc`es uniforme au disque. Le noyau na pas `a connatre la raison de lentree-sortie. Il


copie les donnees depuis et vers des tampons (que ce soient des donnees, des inodes ou le
superbloc). Ce mecanisme est modulaire et sint`egre facilement `a lensemble du syst`eme quil
rend plus facile `a ecrire.
Rend lutilisation des entrees-sorties plus simple pour lutilisateur qui na pas `a se soucier
des probl`emes dalignement, il rend les programmes portables sur dautres UNIX 1 .
Il reduit le trafic disque et de ce fait augmente la capacite du syst`eme. Attention : le nombre
de tampons ne doit pas trop reduire la memoire centrale utilisable.
Limplementation du buffer cache prot`ege contre certaines ecritures concurrentes
Lecriture differee pose un probl`eme dans le cas dun crash du syst`eme. En effet si votre
machine sarrete (coupure de courant) et que un (ou plusieurs) blocs sont marques `a ecrire
ils nont donc pas etes sauvegardes physiquement. Lintegrite des donnees nest donc pas
assuree en cas de crash.
Le buffer cache necessite que lon effectue une recopie (interne `a la memoire, de la zone utilisateur au cache ou inversement) pour toute entree-sortie. Dans le cas de transferts nombreux
ceci ralentit les entrees-sorties .

3.2

Le buffer cache, structures de donn


ees.

Le statut dun bloc cache est une combinaison des etats suivants :
verrouill
e lacc`es est reserve `a un processus.
1 Les

probl`
emes dalignement existent toujours quand on transf`
ere des donn
ees, cf. protocoles XDR,RPC

17

18

CHAPITRE 3. LE BUFFER CACHE


Entte de Bloc
# de disque
# de bloc
statut
Suivant sur hash queue

Prcdent sur
hash queue

Suivant sur liste des libres


Prcdent sur
liste des libres

Fig. 3.1 Structure des entetes de Bloc du Buffer Cache


Liste des blocs libres

tte de liste

b1

b2

bn

allocation du tampon 1 : le moins rcemment utilis

tte de liste

b2

bn

Fig. 3.2 La liste des tampons libres.


valide (les donnees contenues dans le bloc sont valides).
`
a
ecrire les donnees du bloc doivent etre ecrites sur disque avant de reallouer le bloc ( cest
de lecriture retardee).
actif le noyau est en train decrire/lire le bloc sur le disque.
attendu un processus attend la liberation du bloc.

3.2.1

La liste doublement chan


ee des blocs libres

Les tampons libres appartiennent simultanement `a deux listes doublement chanees : la liste
des blocs libres et la hash-liste correspondant au dernier bloc ayant ete contenu dans ce tampon.
Linsertion dans la liste des tampons libres se fait en fin de liste, la suppression (allocation
du tampon `a un bloc donne) se fait en debut de liste, ainsi le tampon alloue est le plus vieux
tampon libere2 . Ceci permet une reponse immediate si le bloc correspondant est reutilise avant
que le tampon ne soit alloue `a un autre bloc.

3.3

Lalgorithme de la primitive getblk

Algorithme getblk (allocation dun tampon)


entree : # disque logique , # de block
sortie : un tampon verrouille utilisable pour manipuler bloc
{
while (tampon non trouve)
2 ordre

fifo : first in first out

3.3. LALGORITHME DE LA PRIMITIVE GETBLK

19

bloc# 0 mod 4

28

64

bloc# 1 mod 4

17

97

bloc# 2 mod 4

98

50

10

bloc# 3 mod 4

35

99

liste libres
Fig. 3.3 Etat du buffer cache avant les scenarios 1, 2 et 3.
{
if (tampon dans sa hash liste)
{
if (tampon actif )
{
[5]
sleep attente de la liberation du tampon
continuer
}
[1]
verrouiller le tampon
retirer le tampon de la liste des tampons libres
retourner le tampon
}
else /* nest pas dans la hash liste */
{
if (aucun tampon libre )
{
[4]
sleep attente de la liberation dun tampon
continuer
}
retirer le tampon de la liste libre
[3]
if (le tampon est a ecrire)
{
lancer la sauvegarde sur disque
continuer
}
[2]
retirer le buffer de son ancienne liste
de hashage, le placer sur la nouvelle
retourner le tampon
}
}
}

20

CHAPITRE 3. LE BUFFER CACHE

bloc# 0 mod 4

28

64

bloc# 1 mod 4

17

97

bloc# 2 mod 4

98

50

10

bloc# 3 mod 4

35

99

liste libres
Fig. 3.4 Scenario 1- Demande dun tampon pour le bloc-disque 4.

bloc# 0 mod 4

28

64

bloc# 1 mod 4

17

97

bloc# 2 mod 4

98

50

10

35

99

bloc# 3 mod 4

41

liste libres

Fig. 3.5 Scenario 2- Demande dun tampon pour le bloc-disque 41.

bloc# 0 mod 4

28

bloc# 1 mod 4

17

64

97

writing

bloc# 2 mod 4

98

50

10

bloc# 3 mod 4

35

99

18

writing

liste libres

Fig. 3.6 Scenario 3- Demande pour le bloc 18 (3 & 5 marques `a ecrire).

3.3. LALGORITHME DE LA PRIMITIVE GETBLK

21

bloc# 0 mod 4

28

64

bloc# 1 mod 4

17

97

bloc# 2 mod 4

98

50

10

bloc# 3 mod 4

35

99

liste libres
Fig. 3.7 Scenario 4- Plus de blocs libres.

bloc# 0 mod 4

28

64

bloc# 1 mod 4

17

97

bloc# 2 mod 4

98

50

10

bloc# 3 mod 4

35

99

liste libres
Fig. 3.8 Scenario 5- Demande pour le bloc 17 qui est dej`a utilise.

22

CHAPITRE 3. LE BUFFER CACHE

Chapitre 4

La biblioth`
eque standard
4.1

Les descripteurs de fichiers.

Le fichier dinclusion <stdio.h> contient la definition du type FILE. Ce type est une structure
contenant les informations necessaires au syst`eme pour la manipulation dun fichier ouvert. Le
contenu exact de cette structure peut varier dun syst`eme `a lautre (UNIX, VMS, autre).
Toutes les fonctions dE/S utilisent en premier argument un pointeur sur une telle structure :
FILE *. Le role de cet argument est dindiquer le flux sur lequel on doit effectuer loperation
decriture ou de lecture.
Pour pouvoir utiliser une fonction dentree-sortie il faut donc avoir une valeur pour ce premier
argument, cest le role de la fonction fopen de nous fournir ce pointeur en ouvrant le fichier.
Les deux fonctions printf et scanf sont des synonymes de
fprintf(stdout, format, ...)
et
fscanf(stdin, format, ...)
o`
u stdout et stdin sont des expressions de type FILE * definies sous forme de macro-definitions
dans le fichier <stdio.h> . Avec POSIX ce sont effectivement des fonctions.
Sur les syst`eme de la famille UNIX les fichiers ouverts par un processus le restent dans ses fils.
Par exemple le shell a en general trois flux standards :
stdin le terminal ouvert en lecture.
stdout le terminal ouvert en ecriture.
stderr le terminal ouvert en ecriture, et en mode non bufferise.
ainsi si lexecution dun programme C est realisee `a partir du shell le programme C a dej`a ces
trois descripteurs de fichiers utilisables. Cest pourquoi il est en general possible dutiliser printf
et scanf sans ouvrir prealablement de fichiers. Mais si lentree standard nest pas ouverte, scanf
echoue :
#include <stdio.h>
main()
{
int i;
if (scanf("%d", &i) == EOF)
{
printf("l\entree standard est fermee\n");
}
else
{
printf("l\entree standard est ouverte\n");
23

`
CHAPITRE 4. LA BIBLIOTHEQUE
STANDARD

24
}
}

Compile,(a.out), cela donne les deux sorties suivantes :


$ a.out
lentree standard est ouverte
$ a.out <&- # fermeture de lentree standard en ksh
lentree standard est fermee
De meme printf echoue si la sortie standard est fermee.

4.1.1

Ouverture dun fichier

La fonction de la biblioth`eque standard fopen permet douvrir un fichier ou de le creer.


#include <stdio.h>
FILE *fopen(const char *filename,
const char *type);
filename est une reference absolue ou relative du fichier `a ouvrir ; si le fichier nexiste pas alors
il est cree si et seulement si lutilisateur du processus a lautorisation decrire dans le repertoire.
type est une des chanes suivantes :
r ouverture en lecture au debut du fichier
w ouverture en ecriture au debut du fichier avec ecrasement du fichier si il existe (le fichier est
vide de son contenu `a louverture).
a ouverture en ecriture `a la fin du fichier (mode append).
r+,w+,a+ ouverture en lecture ecriture respectivement au debut du fichier, au debut
du fichier avec ecrasement, `a la fin du fichier.
FILE *f;
...
if ((f = fopen("toto", "r")) == NULL)
{
fprintf(stderr, "impossible douvrir toto\n");
exit(1);
}
...
La fonction retourne un pointeur sur un descripteur du fichier ouvert ou NULL en cas dechec,
(acc`es interdit, creation impossible, etc).

4.1.2

Redirection dun descripteur : freopen

Permet dassocier un descripteur dej`a utilise `a une autre ouverture de fichier. Ceci permet de
realiser facilement les redirections du shell.
FILE *freopen(const char *ref,
const char *mode,
FILE *f)
Par exemple les redirections de la ligne shell :
com <ref1 >>ref2
peuvent etre realisees avec

4.1. LES DESCRIPTEURS DE FICHIERS.

25

if (!freopen("ref1", "r", stdin) || !freopen("ref2", "a", stdout))


{
fprintf(stderr, "erreur sur une redirection\n");
exit(1);
}
execl("./com", "com", NULL);

4.1.3

Cr
eation de fichiers temporaires

La fonction
#include <stdio.h>
FILE *tmpfile(void);
cree et ouvre en ecriture un nouveau fichier temporaire, qui sera detruit (un unlink est realise
immediatement) `a la fin de lexecution du processus, attention le descripteur est la aussi herite
par les fils, et il faut en gerer le partage. Cette fonction utilise la fonction
int mkstemp(char *patron);
Les 6 dernier caract`ere du chemin patron doivent etre XXXXXX il seront remplace par une
chaine rendant le nom unique, ce chemin sera utilise pour ouvrir un fichier temporaire avec loption
creation et echec sur creation avec les droit 0600 ce qui permet deviter des troux de securite. La
fonction retourne le descripteur. Attention mkstemp nassure pas que le fichier sera detruit apr`es
utilisation comme cetait le cas avec tmpfile , par contre il devient tr`es difficile de realiser une
attaque sur les fichiers temporaire creer par mkstemp.

4.1.4

Ecriture non format


ee

Les deux fonctions suivantes permettent decrire et de lire des zones memoire, le contenu de
la memoire est directement ecrit sur disque sans transformation, et reciproquement le contenu du
disque est place tel quel en memoire. Linteret de ces fonctions est dobtenir des entrees sorties
plus rapides et des sauvegardes disque plus compactes mais malheureusement illisibles (binaire).
Dautre part les fonction de lecture et decriture sont exactement symetrique ce qui nest pas le
cas de scanf et printf
#include <stdio.h>
int fwrite(void *add, size_t ta, size_t nbobjets, FILE *f);
Ecrit nbobjets de taille ta qui se trouvent `a ladresse add dans le fichier de descripteur f.
#include <stdio.h>
int fread(void *add, size_t ta, size_t nbobjets, FILE *f);
Lit nbobjets de taille ta dans le fichier de descripteur f et les place `a partir de ladresse add
en memoire.
Attention : La fonction fread retourne 0 si lon essaye de lire au del`a du fichier. Pour ecrire
une boucle de lecture propre on utilise la fonction feof(FILE *) :
int n[2];
while (fread(n, sizeof(int), 2, f), !feof(f))
printf("%d %d \n", n[0], n[1]);

`
CHAPITRE 4. LA BIBLIOTHEQUE
STANDARD

26

4.1.5

Acc`
es s
equentiel

On distingue deux techniques dacc`es aux supports magnetiques :


Lacc`es sequentiel qui consiste `a traiter les informations dans lordre o`
u elle apparaissent sur
le support (bandes). Le lecteur physique avance avec la lecture, et se positionne sur le debut
de lenregistrement suivant.
Lacc`es direct qui consiste `a se placer directement sur linformation sans parcourir celles
qui la prec`edent (disques). Le lecteur physique reste sur le meme enregistrement apr`es une
lecture.
En langage C lacc`es est sequentiel mais il est possible de deplacer le pointeur de fichier cest `a
dire selectionner lindice du prochain octet `a lire ou ecrire.
Comme nous venons de le voir dans les modes douverture, le pointeur de fichier peut etre
initialement place en debut ou fin de fichier.
Les quatre fonctions dentree-sortie (fgetc, fputc, fscanf, fprintf) travaillent sequentiellement `a partir de cette origine fixee par fopen, et modifiable par fseek.

4.1.6

Manipulation du pointeur de fichier

Le pointeur de fichier est un entier long qui indique `a partir de quel octet du fichier la prochaine
fonction dentree-sortie doit seffectuer.
En debut de fichier cet entier est nul.
#include <stdio.h>
int fseek(FILE *f, long pos, int direction);
f le descripteur du fichier dans lequel ont deplace le pointeur.
direction est une des trois constantes enti`eres suivantes :
SEEK SET positionnement sur loctet pos du fichier
SEEK CUR positionnement sur le pos-i`eme octet apr`es la position courante du pointeur de
fichier. (equivalent `a SEEK SET courant+pos).
SEEK END positionnement sur le pos-i`eme octet apr`es la fin du fichier.
Remarquer que pos est un entier signe : il est possible se placer sur le 4i`eme octet avant la fin
du fichier :
fseek(f, -4L, SEEK_END);

4.1.7

Un exemple dacc`
es direct sur un fichier dentiers.

La fonction suivante lit le n-i`eme entier dun fichier dentiers prealablement ecrit grace `a
fwrite :
int lirenieme(int n, FILE *f)
{
int buf;

4.1.8

fseek(f, sizeof(int)*(n-1), SEEK_SET);


fread(&buf, sizeof(int), 1, f);
return buf;
\istd{fseek}\istd{fread}

Les autres fonctions de d


eplacement du pointeur de fichier.

La fonction ftell
long int ftell(FILE *);

4.2. LES TAMPONS DE FICHIERS DE STDLIB.

27

retourne la position courante du pointeur.


La fonction rewind
void rewind(FILE *f);
equivalent `a : (void) fseek (f, 0L, 0)

4.2

Les tampons de fichiers de stdlib.

La biblioth`eque standard utilise des tampons pour minimiser le nombre dappels syst`eme. Il est
possible de tester lefficacite de cette bufferisation en comparant la vitesse de recopie dun meme
fichier avec un tampon de taille 1 octet et un tampon adapte `a la machine, la difference devient
vite tr`es importante. Une facon simple de le percevoir est decrire un programme com qui realise
des ecritures sur la sortie standard ligne par ligne, de regarder sa vitesse puis de comparer avec la
commande suivantes :com | cat la biblioth`eque standard utilisant des buffer differents dans les
deux cas une difference de vitese dexecution est perceptible (sur une machine lente la difference
de vitesse est evidente, mais elle existe aussi sur une rapide. . .).

4.2.1

Les modes de bufferisation par d


efaut.

Le mode de bufferisation des fichiers ouverts par la biblioth`eque standard depend du type de
peripherique.
Si le fichier est un terminal la bufferisation est faite ligne `a ligne.
En ecriture le tampon est vide `a chaque ecriture dun \n , ou quand il est plein
(premi`ere des deux occurences).
En lecture le tampon est rempli apr`es chaque validation (RC), si lon tape trop de
caract`eres le terminal proteste (beep) le buffer clavier etant plein.
Si le fichier est sur un disque magn
etique
En ecriture le tampon est vide avant de deborder.
En lecture le tampon est rempli quand il est vide.
Le shell de login change le mode de bufferisation de stderr qui est un fichier terminal `a non
bufferise.
Nous avons donc `a notre disposition trois modes de bufferisation standards :
Non bufferise (sortie erreur standard),
Bufferise par ligne (lecture/ecriture sur terminal),
Bufferise par blocs (taille des tampons du buffer cache).
Un exemple de reouverture de la sortie standard, avec perte du mode de bufferisation :
#include <stdio.h>
main()
{
freopen("/dev/tty", "w", stderr);
fprintf(stderr, "texte non termine par un newline ");
sleep(12);
exit(0); /* realise fclose(stderr) qui realise fflush(stderr) */
}
Il faut attendre 12 secondes laffichage.

4.2.2

Manipulation des tampons de la biblioth`


eque standard.

Un tampon alloue automatiquement (malloc) est associe `a chaque ouverture de fichier par
fopen au moment de la premi`ere entree-sortie sur le fichier.

`
CHAPITRE 4. LA BIBLIOTHEQUE
STANDARD

28

La manipulation des tampons de la biblioth`eque standard comporte deux aspects :


1. Manipulation de la bufferisation de facon ponctuelle (vidange).
2. Positionnement du mode de bufferisation.
Manipulations ponctuelles
La fonction suivante permet de vider le tampon associe au FILE * f :
#include <stdio.h>
fflush(FILE *f);
En ecriture force la copie du tampon associe `a la structure f dans le tampon syst`eme (ne garantit
pas lecriture en cas dinterruption du syst`eme !).
En lecture detruit le contenu du tampon, si lon est en mode ligne uniquement jusquau premier
caract`ere \n.
La fonction fclose() realise un fflush() avant de fermer le fichier.
La fonction exit() appel fclose() sur tous les fichiers ouvert par fopen (freopen,tmpfile,. . .) avant
de terminer le processus.

Manipulations du mode de bufferisation et de la taille du tampon.


La primitive
int setvbuf(FILE *f,
char *adresse,
int mode,
size_t taille);
permet un changement du mode de bufferisation du fichier f avec un tampon de taille taille
fourni par lutilisateur `a ladresse adresse si elle est non nulle, avec le mode defini par les macrodefinitions suivantes (<stdio.h>) :
_IOFBF
_IONBF
_IOMYBUF
_IOLBF

bufferise
Non bufferise
Mon buffer
bufferise par ligne (ex: les terminaux)

Attention : Il ne faut pas appeler cette fonction apr`es lallocation automatique realisee par la
biblioth`eque standard apr`es le premier appel `a une fonction dentree-sortie sur le fichier.
Il est fortement conseille que la zone memoire pointee par adresse soit au moins dune taille egale
`a taille.
Seul un passage au mode bufferise en ligne ou non bufferise peut etre realise apr`es lallocation
automatique du tampon, au risque de perdre ce tampon (absence d appel de free). Ce qui permet
par exemple de changer le mode de bufferisation de la sortie standard apr`es un fork. Attention
ce peut etre dangereux, pour le contenu courant du tampon comme le montre lexemple suivant.
Avant cette fonction de norme POSIX on utilisait trois fonctions :
void setbuf(FILE *f, char *buf);
void setbuffer(FILE *f,char *adresse,size_t t);
void setlignebuf(FILE *f);

4.3. MANIPULATION DES LIENS DUN FICHIER


#include <stdio.h>
main()
{
printf("BonJour ");
switch(fork())
{
case -1 :
exit(1);
case 0 :
printf("je suis le fils");
/* version 1 sans la ligne suivante version 2 avec
setbuffer(stdout, NULL, 0);
sleep(1);
printf("Encore le fils");
break;
default :
printf("je suis le pere");
sleep(2);
}
printf("\n");
}
version 1
fork_stdlib
BonJour je suis le fils Encore le fils
BonJour je suis le pere
version 2
Encore le fils
BonJour je suis le pere

4.3

29

*/

Manipulation des liens dun fichier

Changer le nom dun fichier :


int rename(const char *de,const char *vers);
permet de renommer un fichier (ou un repertoire). Il faut que les deux references soient de
meme type (fichier ou repertoire) dans le meme syst`eme de fichiers.
Rappel : ceci na deffet que sur larborescence de fichiers.
Detruire une reference :
int remove(const char *filename);
Detruit le lien donne en argument, le syst`eme recup`ere linode et les blocs associes au fichier
si cetait le dernier lien.

4.4

Lancement dune commande shell

#include <stdlib.h>
int system(const char *chaine_de_commande);
Cree un processus /bin/posix/sh qui execute la commande ; il y a attente de la fin du shell,
(la commande peut elle etre lancee en mode detache ce qui fait que le shell retourne immediatement

`
CHAPITRE 4. LA BIBLIOTHEQUE
STANDARD

30

sans faire un wait). Ce mecanisme est tr`es co


uteux. Attention la commande system bloque les
signaux SIGINT et SIGQUIT, il faut analyser la valeur de retour de system de la meme facons
que celle de wait. Il est conseille de bloquer ces deux signaux avant lappel de system .

4.5

Terminaison dun processus

exit

La primitive de terminaison de processus de bas niveau :

#include <stdlib.h>
void _exit(int valeur);
La primitive exit est la fonction de terminaison bas niveau
elle ferme les descripteurs ouverts par open, opendir ou herites du processus p`ere.
la valeur est fournie au processus p`ere qui la recup`ere par lappel syst`eme wait. Cette valeur
est le code de retour de processus en shell.
Cette primitive est automatiquement appelee `a la fin de la fonction main (sauf en cas dappels
recursifs de main).
exit

La fonction de terminaison de processus de stdlib :

#include <stdlib.h>
void exit(int valeur);
la fonction exit :
lance les fonctions definies par atexit.
ferme lensemble des descripteurs ouverts grace `a la biblioth`eque standard (fopen).
detruit les fichiers fabriques par la primitive tmpfile
appelle exit avec valeur.
atexit La primitive atexit permet de specifier des fonctions `a appeler en fin dexecution, elle
sont lancees par exit dans lordre inverse de leur positionnement par atexit.
#include <stdlib.h>
int atexit(void (*fonction) (void ));
Exemple :
void bob(void) {printf("coucou\n");}
void bib(void) {printf("cuicui ");}
main(int argc)
{
atexit(bob);
atexit(bib);
if (argc - 1)
exit(0);
else
_exit(0);
}
$ make atexit
cc
atexit.c -o atexit
$ atexit
$ atexit unargument
cuicui coucou
$

4.6. GESTION DES ERREURS

4.6

31

Gestion des erreurs

Les fonctions de la biblioth`eque standard positionnent deux indicateurs derreur, la fonction


suivante les repositionne :
void clearerr(FILE *);
La fonction int feof(FILE *) est vraie si la fin de fichier est atteinte sur ce canal, int
ferror(FILE *) est vraie si une erreur a eu lieu pendant la derni`ere tentative de lecture ou
decriture sur ce canal.
Une description en langue naturelle de la derni`ere erreur peut etre obtenue grace `a
void perror(const char *message);
laffichage se fait sur la sortie erreur standard (stderr).

4.7

Cr
eation et destruction de r
epertoires

Creation dun repertoire vide (meme syntaxe que creat) :


#include <unistd.h>
int mkdir(char *ref, mode_t

mode);

Destruction :
int rmdir(char *ref);
avec les memes restrictions que pour les shells sur le contenu du repertoire (impossible de
detruire un repertoire non vide).

32

`
CHAPITRE 4. LA BIBLIOTHEQUE
STANDARD

Chapitre 5

Appels syst`
eme du Syst`
eme de
Gestion de Fichier
Les appels syst`eme dentrees-sorties ou entrees-sorties de bas niveau sont rudimentaires mais
polymorphes, en effet cest eux qui permettent decrire des programmes independamment des supports physiques sur lesquels se font les entrees/sorties et de pouvoir facilement changer les supports
physiques associes a une entree-sortie.
Les appels syst`eme du syst`eme de gestion de fichier sont :
open/creat ouverture/creation dun fichier
read/write lecture/ecriture sur un fichier ouvert
lseek deplacement du pointeur de fichier
dup,dup2 copie douverture de fichier
close fermeture dun fichier
mount chargement dun disque
mknode creation dun inode de fichier special
pipe creation dun tube
fcntl manipulation des caracteristiques des ouvertures de fichiers
Les appels syst`eme sont realises par le noyau et retournent -1 en cas derreur.

5.1

open

#include <fcntl.h>
int open(char *ref, int mode, int perm);
Ouverture du fichier de reference (absolue ou relative `a .) ref.
Le mode douverture est une conjonction des masques suivants :
O_RDONLY
O_WRONLY
O_RDWR
O_NDELAY
O_APPEND
O_CREAT
O_TRUNC
O_EXCL

/*
/*
/*
/*
/*
/*
/*
/*

open for reading */


open for writing */
open for read & write */
non-blocking open */
append on each write */
open with file create */
open with truncation */
error on create if file exists*/
33

table des
descripteurs
0
1

Dans chaque
processus

la table systme
des fichiers ouverts

la table des
inodes
en mmoire

Dans le noyau

Buffer
cache

donnes

inodes

Sur Disque

34
`
`
CHAPITRE 5. APPELS SYSTEME
DU SYSTEME
DE GESTION DE FICHIER

Fig. 5.1 Tables du syst`eme de fichiers.

5.1. OPEN

35

Dans le
processus

Dans le noyau
inodes en mmoire

descripteurs
0
1
2

1 rd

Dans le
processus

1 wr Dans le noyau
1 wr

descripteurs
0
1
2
fd

vers
le buffer
cache et
le disque
inodes en mmoire

1 rw

1 rd

1 wr
1 wr

vers
le buffer
cache et
le disque

fd=open("toto",O_RDWR |O_CREAT,0666);

Fig. 5.2 Avant louverture, descripteurs standard ouverts, puis apr`es louverture de toto.
Le param`etre permission na de sens qu`a la creation du fichier, il permet de positionner les
valeurs du champ mode de linode. Les droits effectivement positionnes dependent de la valeur
de umask, grace `a la formule droits = perm & ~ umask. La valeur par defaut de umask est 066
(valeur octale).
La valeur de retour de open est le numero dans la table de descripteurs du processus qui a ete
utilise par open. Ce numero est appele descripteur de louverture. Ce descripteur est utilise dans
les autres appels syst`eme pour specifier louverture de fichier sur laquelle on veut travailler1 , et -1
en cas dechec de louverture.

5.1.1

D
eroulement interne dun appel de open

1. Le syst`eme determine linode du fichier reference (namei).


2. Soit linode est dans la table des inodes en memoire.
Soit il alloue une entree et recopie linode du disque (iget).
3. Le syst`eme verifie les droits dacc`es dans le mode demande.
4. Il alloue une entree dans la table des fichiers ouverts du syst`eme, et positionne le curseur de
lecture ecriture dans le fichier (offset = 0, sauf dans le cas du mode O APPEND offset=taille
du fichier).
5. Le syst`eme alloue une place dans la table des descripteurs iob du fichier.
6. Il renvoie au processus le numero de descripteur, cest `a dire le numero de lentree quil vient
dallouer dans le tableau iob.
Si loperation a echoue dans une des etapes le syst`eme renvoie -1.

1 Un

m
eme fichier peut
etre ouvert plusieurs fois.

`
`
CHAPITRE 5. APPELS SYSTEME
DU SYSTEME
DE GESTION DE FICHIER

36

5.2

creat

Creation dun fichier et ouverture en ecriture.


int creat(char *reference, int permissions);
1. Le syst`eme determine linode du catalogue o`
u lon demande la creation du fichier.
(a) Si il existe dej`a une inode pour le fichier
Le noyau lit linode en question (allocation dans la table des inodes en memoire),
verifie que cest un fichier ordinaire autorise en ecriture par le proprietaire effectif du
processus, sinon echec.
Le syst`eme lib`ere les blocs de donnees et reduit la taille du fichier `a zero, il ne modifie
pas les droits quavait le fichier anterieurement.
(b) Si nexistait pas dinode pour le fichier
Le syst`eme teste les droits en ecriture sur le catalogue
Il alloue une nouvelle inode (ialloc)
Il alloue une nouvelle entree dans la table des inodes en memoire.
Meme suite que pour open.

5.3

read

int nbcharlus = read(int d, char *tampon, int nbalire)


descripteur entree de la table des descripteurs correspondante au fichier dans lequel doit etre
effectuee la lecture (fourni par open).
nbalire nombre de caract`eres `a lire dans le fichier.
tampon un tableau de caract`eres alloue par lutilisateur. Les caract`eres lus sont places dans ce
tampon.
nbcharlus nombre de caract`eres effectivement lus, ou -1 en cas dechec de lappel syst`eme, (droits,
...), la fin de fichier est atteinte quand le nombre de caract`eres lus est inferieur au nombre
de caract`eres demandes.
Deroulement :
1. Verification du descripteur acc`es aux tables syst`eme.
2. Droits (mode adequat)
3. Grace `a linode le syst`eme obtient les adresses du (des) bloc(s) contenant les donnees `a lire.
Le syst`eme effectue la lecture de ces blocs.
4. Le syst`eme recopie les donnees du buffer cache vers le tampon de lutilisateur.
5. Le curseur dans le fichier est remit `a jour dans lentree de la table des fichiers ouverts.
6. Le syst`eme renvoie le nombre de caract`eres effectivement lus.

5.4

write

int nbcecrits = write(int desc, char *tampon, int nbaecrire);


Meme deroulement que read mais avec une allocation eventuelle de bloc-disque dans le cas
dun ajout au-del`a de la fin du fichier.
Dans le cas o`
u lappel concerne un peripherique en mode caract`ere : le syst`eme active la fonction
write (reciproquement read pour une lecture) du peripherique qui utilise directement ladresse
du tampon utilisateur.

5.5. LSEEK

37

Remarquons ici encore le polymorphisme de ces deux appels syst`eme qui permet de lire et decrire
sur une grande variete de peripheriques en utilisant une seule syntaxe. Le code C utilisant lappel syst`eme marchera donc indifferemment sur tous les types de peripheriques qui sont definis
dans le syst`eme de fichier. Par exemple, il existe deux peripheriques logiques qui sont /dev/null
et /dev/zero (que lon ne trouve pas sur toutes les machines). Le premier est toujours vide en
lecture et les ecritures nont aucun effet (il est donc possible de deverser nimporte quoi sur ce
peripherique). Le deuxi`eme fournit en lecture une infinite de zero et naccepte pas lecriture.

5.5

lseek

#include <fcntl.h>
off_t lseek(int d, off_t offset, int direction)
lseek permet de deplacer le curseur de fichier dans la table des fichiers ouverts du syst`eme.
offset un deplacement en octets.
d le descripteur.
direction une des trois macros L SET, L INCR, L XTND.
L SET la nouvelle position est offset sauf si offset est superieur `a la taille du fichier, auquel cas
la position est egale `a la taille du fichier. Si loffset est negatif, alors la position est zero.
L INCR la position courante est incrementee de offset place (meme contrainte sur la position
maximum et la position minimum).
L XTND Deplacement par rapport `a la fin du fichier, cette option permet daugmenter la taille
du fichier (ne pas creer de fichiers virtuellement gros avec ce mecanisme, ils posent des
probl`emes de sauvegarde).
La valeur de retour de lseek est la nouvelle position du curseur dans le fichier ou -1 si lappel
a echoue.

5.6

dup et dup2

Les appels dup et dup2 permettent de dupliquer des entrees de la table des descripteurs du
processus.
int

descripteur2 = dup(int descripteur1);

1. verification que descripteur est le numero dune entree non nulle.


2. recopie dans la premi`
ere entr
ee libre du tableau des descripteurs lentree correspondant `a
descripteur1.
3. le compteur de descripteurs de lentree associee `a descripteur1 dans la table des ouvertures
de fichiers est incremente.
4. renvoi de lindice dans la table des descripteurs de lentree nouvellement allouee.
Redirection temporaire de la sortie standard dans un fichier :
tempout = open("sortie_temporaire",1);
oldout = dup(1);
close(1);
newout = dup(tempout); /* renvoie 1 */
write(1,"xxxx",4); /* ecriture dans le fichier temporaire */

`
`
CHAPITRE 5. APPELS SYSTEME
DU SYSTEME
DE GESTION DE FICHIER

38

close(tempout);
close(1);
newout = dup(oldout);
close(oldout);
Il est aussi possible de choisir le descripteur cible avec
int ok = dup2(int source, int destination);
Recopie du descripteur source dans lentree destination de la table des descripteurs. Si
destination designe le descripteur dun fichier ouvert, celui-ci est prealablement ferme avant
duplication. Si destination nest pas un numero de descripteur valide, il y a une erreur, retour
-1.

5.7

close

Fermeture dun fichier.


int ok = close(descripteur);
1. si descripteur nest pas un descripteur valide retour -1
2. lentree dindice descripteur de la table est liberee.
3. Le compteur de lentree de la table des fichiers ouvert associe `a descripteur est decremente.
Si il passe `
a Zero alors
4. lentree de la table des fichiers ouverts est liberee et le compteur des ouvertures de linode
en memoire est decremente.
Si il passe `
a Zero alors
5. lentree dans la table des inodes en memoire est liberee.
Si de plus le compteur de liens de linode est `
a 0 alors
6. le fichier est libere : recuperation de linode et des blocs.
Dans le cas dune ouverture en ecriture : le dernier bloc du buffer cache dans lequel on a ecrit
est marque a ecrire.

5.8

fcntl

Lappel syst`eme fnctl permet de manipuler les ouverture de fichier apr`es louverture, bien
sur il nest pas possible de changer le mode douverture (lecture/ecriture/lecture-ecriture) apr`es
louverture.
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int desc, int commande);
int fcntl(int desc, int commande, long arg);
int fcntl(int desc, int commande, struct flock *verrou);
Lappel syst`eme fnctl permet de positionner des verrous de fichier voire le chapitre 12. Lappel
syst`eme fnctl permet la manipulation de certains des drapeaux douverture :
O APPEND

5.8. FCNTL

39
dup2(fd,1);
descripteurs
0
1
2
fd

2 rw

1 rd

1 wr
close(fd);
0
1
2

1 rw

1 rd

1 wr

Fig. 5.3 Redirection de la sortie standard sur toto.


O NONBLOCK
O ASYNC
O DIRECT
Lappel syst`eme fnctl permet gerer les signaux associes aux entree asyncrones.

40

`
`
CHAPITRE 5. APPELS SYSTEME
DU SYSTEME
DE GESTION DE FICHIER

Chapitre 6

Les processus
6.1

Introduction aux processus

Un processus est un ensemble doctets (en langage machine) en cours dexecution, en dautres
termes, cest lexecution dun programme.
Un processus UNIX se decompose en :
1. un espace dadressage (visible par lutilisateur/programmeur)
2. Le bloc de controle du processus (BCP) lui-meme decompose en :
une entree dans la table des processus du noyau struct proc
definie dans <sys/proc.h>.
une structure struct user appelee zone u definie dans <sys/user.h>
Les processus sous Unix apportent :
La multiplicite des executions
Plusieurs processus peuvent etre lexecution dun meme programme.
La protection des executions
Un processus ne peut executer que ses instructions propres et ce de facon sequentielle ; il ne
peut pas executer des instructions appartenant `a un autre processus.
Les processus sous UNIX communiquent entre eux et avec le reste du monde grace aux
appels syst`eme.

6.1.1

Cr
eation dun processus - fork()

Sous UNIX la creation de processus est realisee par lappel syst`eme :

P1

le noyau

P5

table des processus

P1
les processus

P5

Fig. 6.1 La table des processus est interne au noyau.


41

42

CHAPITRE 6. LES PROCESSUS


int fork(void);

Tous les processus sauf le processus didentification 0, sont crees par un appel `a fork.
Le processus qui appelle le fork est appele processus p`ere.
Le nouveau processus est appele processus fils.
Tout processus a un seul processus p`ere.
Tout processus peut avoir zero ou plusieurs processus fils.
Chaque processus est identifie par un numero unique, son PID.
Le processus de PID=0 est cree manuellement au demarrage de la machine, ce processus
a toujours un role special1 pour le syst`eme, de plus pour le bon fonctionement des programmes
utilisant fork() il faut que le PID zero reste toujours utilise. Le processus zero cree, grace `a un
appel de fork, le processus init de PID=1.
Le processus de PID=1 de nom init est lancetre de tous les autres processus (le processus 0
ne realisant plus de fork()), cest lui qui accueille tous les processus orphelins de p`ere (ceci a fin
de collecter les information `a la mort de chaque processus).

6.2

Format dun fichier ex


ecutable

Les compilateurs nous permettent de creer des fichiers executables. Ces fichiers ont le format
suivant qui permet au noyau de les transformer en processus :
Une en-tete qui decrit lensemble du fichier, ses attributs et sa carte des sections.
La taille `a allouer pour les variables non initialisees.
Une section TEXT qui contient le code (en langage machine)
Une section donnees (DATA) codee en langage machine qui contient les donnees initialisees.
Eventuellement dautres sections : Table des symboles pour le debugeur, Images, ICONS,
Table des chanes, etc.
Pour plus dinformations se reporter au manuel a.out.h sur la machine.

6.3

Chargement/changement dun ex
ecutable

Lappel syst`eme execve change lexecutable du processus courant en chargeant un nouvel


executable. Les regions associee au processus sont prealablement liberees :
int execve(/* plusieurs formats */);
Pour chaque section de lexecutable une region en memoire est allouee.
Soit au moins les regions :
le code
les donn
ees initialisees
Mais aussi les regions :
des piles
du tas
La region de la pile :
Cest une pile de structures de pile qui sont empilees et depilees lors de lappel ou le retour de
fonction. Le pointeur de pile, un des registres de lunite centrale, indique la profondeur courante
de la pile.
1 swappeur,gestionnaire

de pages

6.4. ZONE U ET TABLE DES PROCESSUS

43

Adresse Haute = 0xFFFFFFFF


argc,argv,env
Tas

Pile
Donnes non-initialises
Donnes initialise
Texte

} initialise zro
par exec
lu par exec

Adresse Basse =0

Fig. 6.2 La structure interne des processus.

Le code du programme g`ere les extensions de pile (appel ou retour de fonction), cest le noyau qui
alloue lespace necessaire `a ces extensions. Sur certains syst`emes on trouve une fonction alloca()
qui permet de faire des demandes de memoire sur la pile.
Un processus UNIX pouvant sexecuter en deux modes (noyau, utilisateur), une pile privee sera
utilisee dans chaque mode.
La pile noyau sera vide quand le processus est en mode utilisateur.
Le tas est une zone o`
u est realisee lallocation dynamique avec les fonctions Xalloc().

6.4

zone u et table des processus

Tous les processus sont associes `a une entree dans la table des processus qui est interne au
noyau. De plus, le noyau alloue pour chaque processus une structure appelee zone u , qui contient
des donnees privees du processus, uniquement manipulables par le noyau.
La table des processus nous permet dacceder `a la table des regions par processus qui permet dacceder `a la table des
regions. Ce double niveau dindirection permet de faire partager des regions.
Dans lorganisation avec une memoire virtuelle, la table des regions est materialisee logiquement
dans la table de pages.
Les structures de regions de la table des regions contiennent des informations sur le type, les
droits dacc`es et la localisation (adresses en memoire ou adresses sur disque) de la region.
Seule la zone u du processus courant est manipulable par le noyau, les autres sont inaccessibles. Ladresse de la zone u est placee dans le mot detat du processus.

6.5

fork et exec (revisit


es)

Quand un processus realise un fork, le contenu de lentree de la table des regions est duplique,
chaque region est ensuite, en fonction de son type, partagee ou copiee.
Quand un processus realise un exec, il y a liberation des regions et reallocation de nouvelles
regions en fonction des valeurs definies dans le nouvel executable.

44

CHAPITRE 6. LES PROCESSUS

zone u

Table des rgions


par processus

Table des rgions

Table des processus

Mmoire Centrale

Fig. 6.3 Table des regions, table des regions par processus

zone u
zone u

Table des rgions


par processus

Table des rgions


partage
copie

copie
Table des processus

fork()
pre =
fils =

Mmoire Centrale

Fig. 6.4 Changement de regions au cours dun fork.

zone u

Table des rgions


par processus

Table des rgions

ancienne
entre

Table des processus

exec()
Mmoire Centrale

Fig. 6.5 Changement de regions au cours dun exec.

6.6. LE CONTEXTE DUN PROCESSUS

6.6

45

Le contexte dun processus

Le contexte dun processus est lensemble des donnees qui permettent de reprendre lexecution
dun processus qui a ete interrompu.
Le contexte dun processus est lensemble de
1. son etat
2. son mot detat : en particulier
La valeur des registres actifs
Le compteur ordinal
3. les valeurs des variables globales statiques ou dynamiques
4. son entree dans la table des processus
5. sa zone u
6. Les piles user et system
7. les zones de code et de donnees.
Le noyau et ses variables ne font partie du contexte daucun processus !
Lexecution dun processus se fait dans son contexte.
Quand il y a changement de processus courant, il y a realisation dune commutation de mot
d
etat et dun changement de contexte. Le noyau sexecute alors dans le nouveau contexte.

6.7

Commutation de mot d
etat et interruptions.

Ces fonctions de tr`es bas niveau sont fondamentales pour pouvoir programmer un syst`eme
dexploitation.
Pour etre execute et donner naissance `a un processus, un programme et ses donnees doivent
etre charges en memoire centrale. Les instructions du programme sont transferees une `a une de la
memoire centrale sur lunite centrale o`
u elles sont executees.
Lunite centrale :
Elle comprend des circuits logiques et arithmetiques qui effectuent les instructions mais aussi des
memoires appelees registres.
Certains de ces registres sont specialises directement par les constructeurs de lunite centrale,
dautres le sont par le programmeur du noyau. Quelques registres specialises :
Laccumulateur qui recoit le resultat dune instruction ; sur les machines `a registres multiples,
le jeu dinstructions permet souvent dutiliser nimporte lequel des registres comme accumulateur.
le registre dinstruction (qui contient linstruction en cours)
le compteur ordinal (adresse de linstruction en memoire) Ce compteur change au cours de
la realisation dune instruction pour pointer sur la prochaine instruction `a executer, la majorite des instructions ne font quincrementer ce compteur, les instructions de branchement
realisent des operations plus complexes sur ce compteur : affectation, incrementation ou
decrementation plus importantes.
le registre dadresse
les registres de donn
ees qui sont utilises pour lire ou ecrire une donnee `a une adresse specifiee
en memoire.
les registres d
etat du processeur : (actif, mode (user/system), retenue, vecteur dinterruptions,
etc)
les registres d
etat du processus droits, adresses, priorites, etc
Ces registres forment le contexte dunit
e centrale dun processus. A tout moment, un processus est caracterise par ces deux contextes : le contexte dunite centrale qui est compose des memes
donnees pour tous les processus et le contexte qui depend du code du programme execute. Pour

46

CHAPITRE 6. LES PROCESSUS


Nature de linterruption

fonction de traitement

horloge

clockintr

disques

diskintr

console

ttyintr

autres peripheriques

devintr

appel system

sottintr

autre interruption

otherintr

Fig. 6.6 Sous UNIX, on trouvera en general 6 niveaux dinterruption

pouvoir executer un nouveau processus, il faut pouvoir sauvegarder le contexte dunite centrale
du processus courant (mot detat), puis charger le nouveau mot detat du processus `a executer.
Cette operation delicate realisee de facon materielle est appelee commutation de mot d
etat.
Elle doit se faire de facon non interruptible ! Cette Super instruction utilise 2 adresses qui sont
respectivement :
ladresse de sauvegarde du mot detat
ladresse de lecture du nouveau mot detat
Le compteur ordinal faisant partie du mot detat, ce changement provoque lexecution dans le
nouveau processus.
Cest le nouveau processus qui devra realiser la sauvegarde du contexte global. En general cest
le noyau qui realise cette sauvegarde, le noyau nayant pas un contexte du meme type.
Le processus interrompu pourra ainsi reprendre exactement o`
u il avait abandonne.
Les fonctions setjmp/longjmp permettent de sauvegarder et de reinitialiser le contexte dunite
central du processus courant, en particulier le pointeur de pile.

6.8

Les interruptions

Une interruption est une commutation de mot detat provoquee par un signal produit par le
materiel.
Ce signal etant la consequence dun evenement exterieur ou interieur, il modifie letat dun indicateur qui est reguli`erement teste par lunite centrale.
Une fois que le signal est detecte, il faut determiner la cause de linterruption. Pour cela on utilise
un indicateur, pour les differentes causes, On parle alors du vecteur dinterruptions.
Trois grands types dinterruptions :
externes (independantes du processus) interventions de loperateur, pannes,etc
d
eroutements erreur interne du processeur, debordement, division par zero, page fault etc
(causes qui entraine la realisation dune sauvegarde sur disque de limage memoire core
dumped en general)
appels syst`
emes demande dentree-sortie par exemple.
Suivant les machines et les syst`emes un nombre variable de niveaux dinterruption est utilise.
Ces differentes interruptions ne realisent pas necessairement un changement de contexte complet du processus courant.
Il est possible que plusieurs niveaux dinterruption soient positionnes quand le syst`eme les
consulte. Cest le niveau des differentes interruptions qui va permettre au syst`eme de selectionner
linterruption `a traiter en priorite.
Lhorloge est linterruption la plus prioritaire sur un syst`eme Unix.

`
6.9. LE PROBLEME
DES CASCADES DINTERRUPTIONS
Systme
traitement
dinterruption

Processus 1

47
Processus 2

interruption

Sauvegarde
du contexte
du Processus 1
traitement
Chargement
du contexte
du processus 2

Acquittement

Commutations dtat

Fig. 6.7 Le traitement dune interruption.

6.9

Le probl`
eme des cascades dinterruptions

Si pendant le traitement dune interruption, une autre interruption se produit, et que ceci se
rep`ete pendant le traitement de la nouvelle interruption, le syst`eme ne fait plus progresser les
processus ni les interruptions en cours de traitement ...
Il est donc necessaire de pouvoir retarder ou annuler la prise en compte dun ou plusieurs
signaux dinterruptions. Cest le role des deux mecanismes de masquage et de d
esarmement
dun niveau dinterruption. Masquer, cest ignorer temporairement un niveau dinterruption.
Si ce masquage est fait dans le mot detat dun traitement dinterruption, `a la nouvelle commutation detat, le masquage disparat ; les interruptions peuvent de nouveau etre prises en compte.
Desarmer, cest rendre le positionnement de linterruption caduque. (Il est clair que ceci ne peut
sappliquer aux deroutements).

6.9.1

Etats et transitions dun processus

Nous nous placons dans le cas dun syst`eme qui utilise un mecanisme de swap pour gerer la
memoire ; nous etudierons ensuite le cas des syst`emes de gestion paginee de la memoire (les couples
detats 3,5 et 4,6 y sont fusionnes).

6.9.2

Listes des
etats dun processus

1. le processus sexecute en mode utilisateur


2. le processus sexecute en mode noyau
3. le processus ne sexecute pas mais est eligible (pret `a sexecuter)
4. le processus est endormi en memoire centrale
5. le processus est pret mais le swappeur doit le transferer en memoire centrale pour le rendre
eligible. (ce mode est different dans un syst`eme `a pagination).
6. le processus est endormi en zone de swap (sur disque par exemple).
7. le processus passe du mode noyau au mode utilisateur mais est preempte2 et a effectue un
changement de contexte pour elire un autre processus.
8. naissance dun processus, ce processus nest pas encore pret et nest pas endormi, cest letat
initial de tous processus sauf le swappeur.
2 Bien que le processus soit pr
et, il est retir
e de lunit
e de traitement pour que les autres processus puissent
avancer.

48

CHAPITRE 6. LES PROCESSUS


Excution
en mode utilisateur
Appel system
interruption

Retour au
mode utilisateur

Excution
en mode noyau
gestion
interruption

premption

exit

zombie
9

sleep

Prempt

ordonancement
du processus
Examiner
les signaux
3

Prt et en mmoire

wakeup
Endormi
en mmoire

Examiner
et traiter
les signaux

mmoire
suffisante

4
swapout

swapout
swapin

centrale
swap

Cration
fork
8
mmoire
insuffisante

Endormi
6
en zone de swap

wakeup
5

Prt
en zone de swap

Fig. 6.8 Diagramme detat des processus


9. zombie le processus vient de realiser un exit, il apparat uniquement dans la table des
processus o`
u il est conserve le temps pour son processus p`ere de recup`erer le code de retour
et dautres informations de gestion (co
ut de lexecution sous forme de temps, et dutilisation
des ressources ).
Letat zombie est letat final des processus, les processus restent dans cet etat jusqu`a ce que leur
p`ere lise leur valeur de retour (exit status).

6.10

Lecture du diagramme d
etat.

Le diagramme des transitions detat permet de decrire lensemble des etats possibles dun
processus. Il est clair que tout processus ne passera pas necessairement par tous ces differents
etats.
La naissance dun processus a lieu dans letat 8 apr`es lappel syst`eme fork execute par un
autre processus. Il devient au bout dun certain temps pret `a sexecuter. Il passe alors dans
letat execute en mode noyau o`
u il termine sa partie de lappel syst`eme fork. Puis le processus
termine lappel syst`eme et passe dans letat execute en mode utilisateur. Passe une certaine
periode de temps (variable dun syst`eme `a lautre), lhorloge peut interrompre le processeur. Le
processus rentre alors en mode noyau, linterruption est alors realisee avec le processus en mode
noyau.
Au retour de linterruption, le processus peut etre pr
eempt
e (etant reste tout son quantum de
temps sur le cpu), cest `a dire, il reste pret `a sexecuter mais un autre processus est elu. Cet etat
7 est logiquement equivalent `a letat 3, mais il existe pour materialiser le fait quun processus ne
peut etre preempte quau moment o`
u il retourne du mode noyau au mode utilisateur. Quand un
processus preempte est reelu, il retourne directement en mode utilisateur.
Un appel syst`eme ne peut etre preempte. On peut detecter en pratique cette r`egle, en effet


6.11. UN EXEMPLE DEXECUTION

49

on constate un ralentissement du debit de la machine pendant la realisation dun core de grande


taille.
Quand un processus execute un appel syst`eme, il passe du mode utilisateur au mode syst`eme.
Supposons que lappel syst`eme realise une entree-sortie sur le disque et que le processus doive
attendre la fin de lentree-sortie. Le processus est mis en sommeil (sleep) et passe dans letat
endormi en memoire. Quand lentree-sortie se termine, une interruption a lieu, le traitement de
linterruption consistant `a faire passer le processus dans le mode pret `a sexecuter (en memoire).

6.11

Un exemple dex
ecution

Placons-nous dans la situation suivante : lensemble de la memoire est occupe par des processus,
mais, le processus le plus prioritaire est un processus dans letat 5, soit : pret `a sexecuter en
zone de swap. Pour pouvoir executer ce processus, il faut le placer dans letat 3, soit : pret `a
sexecuter en memoire. Pour cela le syst`eme doit liberer de la memoire (faire de la place), en
faisant passer des processus des etats 3 ou 4 en zone de swap (swapout) donc les faire passer dans
les etats 5 et 6.
Cest au swappeur de realiser les deux operations :
Selectionner une victime (le processus le plus approprie), pour un transfert hors memoire
centrale (swapout).
realiser ce transfert.
une fois quune place suffisante est liberee, le processus qui a provoque le swapout est charge
en memoire (swapin).
Le processus a un controle sur un nombre reduit de transitions : il peut faire un appel syst`eme,
realiser un exit, realiser un sleep, les autres transitions lui sont dictees par les circonstances.
Lappel `a exit() fait passer dans letat zombie, il est possible de passer `a letat zombie sans
que le processus ait explicitement appele exit() (`a la reception de certains signaux par exemple).
Toutes les autres transitions detat sont selectionnees et realisees par le noyau selon des r`egles bien
precises. Une de ces r`egles est par exemple quun processus en mode noyau ne peut etre preempte3 .
Certaines de ces r`egles sont definies par lalgorithme dordonnancement utilise.

6.12

La table des processus

La table des processus est dans la memoire du noyau. Cest un tableau de structure proc
(<sys/proc.h>). Cette structure contient les informations qui doivent toujours etre accessibles
par le noyau.

etat se reporter au diagramme, ce champ permet au noyau de prendre des decisions sur les
changements detat `a effectuer sur le processus.
adresse de la zone u
adresses taille et localisation en memoire (centrale, secondaire). Ces informations permettent de
transferer un processus en ou hors memoire centrale.
UID proprietaire du processus, permet de savoir si le processus est autorise `a envoyer des signaux
et `a qui il peut les envoyer.
PID,PPID lidentificateur du processus et de son p`ere. Ces deux valeurs sont initialisees dans
letat 8, creation pendant lappel syst`eme fork.

ev`
enement un descripteur de lev`enement attendu quand le processus est dans un mode endormi.
Priorit
es Plusieurs param`etres sont utilises par lordonnanceur pour selectionner lelu parmi les
processus prets.
vecteur dinterruption du processus ensemble des signaux recus par le processus mais pas
encore traites.
3 Exercice

: Donner un exemple.

50

CHAPITRE 6. LES PROCESSUS

divers des compteurs utilises pour la comptabilite (pour faire payer le temps CPU utilise) et
que lon peut manipuler par la commande alarm, des donnees utilisees par limplementation
effective du syst`eme, etc.

6.13

La zone u

La zone u de type struct user definie dans <sys/user.h> est la zone utilisee quand un processus sexecute que ce soit en mode noyau ou mode utilisateur. Une unique zone u est accessible
`a la fois : celle de lunique processus en cours dexecution (dans un des etats 1 ou 2).
Contenu de la zone u :
pointeur sur la structure de processus de la table des processus.
uid r
eel et effectif de lutilisateur qui determine les divers privil`eges donnes au processus, tels
que les droits dacc`es `a un fichier, les changements de priorite, etc.
Compteurs des temps (users et system) consommes par le processus
Masque de signaux Sur syst`eme V sous BSD dans la structure proc
Terminal terminal de controle du processus si celui-ci existe.
erreur stockage de la derni`ere erreur rencontree pendant un appel syst`eme.
retour stockage de valeur de retour du dernier appel syst`eme.
E/S les structures associees aux entrees-sorties, les param`etres utilises par la biblioth`eque standard, adresses des buffers, tailles et adresses de zones `a copier, etc.
. et / le repertoire courant et la racine courante (c.f. chroot())
la table des descripteurs position variable dun implementation `a lautre.
limites de la taille des fichiers de la memoire utilisable etc 41 (c.f. ulimit en Bourne shell et limit
en Csh ).
umask masque de creation de fichiers.

6.14

Acc`
es aux structures proc et user du processus courant

Les informations de la table des processus peuvent etre lues grace `a la commande shell ps. Ou
par des appels syst`eme. Par contre, les informations contenues dans la zone u ne sont accessibles
que par une reponse du processus lui-meme (en progammation objet, on dit que ce sont des variables dinstances privees), do`
u les appels syst`eme suivants :
times, chroot, chdir, fchdir, getuid, getgid, ..., setuid, ..., ulimit, nice, brk,
sbrk.
Qui permettent de lire ou de changer le contenu des deux structures.

6.14.1

Les informations temporelles.

#include <sys/times.h>
clock_t times(struct tms *buffer);
times remplit la structure pointee par buffer avec des informations sur le temps machine utilise dans les etat 1 et 2.
La structure? :
struct tms {
clock_t
clock_t

tms_utime;
tms_stime;

/* user time */
/* system time */

` AUX STRUCTURES PROC ET USER DU PROCESSUS COURANT


6.14. ACCES
clock_t
clock_t
};

tms_cutime;
tms_cstime;

51

/* user time, children */


/* system time, children */

contient des temps indiques en microsecondes 10-6 secondes, la precision de lhorloge est par
defaut sur les HP9000 700/800 de 10 microsecondes.

6.14.2

Changement du r
epertoire racine pour un processus.

#include <unistd.h>
int chroot(const char *path);
permet de definir un nouveau point de depart pour les references absolues (commencant par
/). La reference .. de ce repertoire racine est associee `a lui-meme, il nest donc pas possible de
sortir du sous-arbre defini par chroot. Cet appel est utilise pour rsh et ftp, et les comptes pour
invites.
Les appels suivants permettent de changer le repertoire de travail de reference . et donc
linterpretation des references relatives :
int chdir(char *ref);
int fchdir(int descripteur);

6.14.3

R
ecup
eration du PID dun processus

#include <unistd.h>
pid_t
getpid(void);
pid_t
getpgrp(void);
pid_t
getppid(void);
pid_t
getpgrp2(pid_t pid);
Lappel getpid() retourne le PID du processus courant, getppid le PID du processus p`ere,
getpgrp le PID du groupe du processus courant, getpgrp2 le PID du groupe du processus pid (si
pid=0 alors equivalent `a getpgrp).

6.14.4

Positionement de leuid, ruid et suid

Luid dun processus est lidentification de lutilisateur executant le processus. Le syst`eme


utilise trois uid qui sont :
euid uid effective utilise pour les tests dacc`es.
ruid uid reelle, uid `a qui est facture le temps de calcul.
suid uid sauvegardee, pour pouvoir revenir en arri`ere apr`es un setuid.
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
Fonctionnement :
si euid == 0 (euid de root) les trois uid sont positionnes `a la valeur de uid
sinon si uid est egal `a ruid ou suid alors euid devient uid. ruid et suid ne changent pas. sinon rien !
pas de changements.
Syntaxe identique pour setgid et gid.
La commande setreuid() permet de changer le propietaire reel du processus, elle est utilise
pendant le login, seul le super utilisateur peut lexecuter avec succ`es.

52

CHAPITRE 6. LES PROCESSUS

6.15

Tailles limites dun processus

#include <ulimit.h>
long ulimit(int cmd,...);
La commande cmd est
UL GETFSIZE retourne le taille maximum des fichiers en blocs.
UL SETFSIZE positionne cette valeur avec le deuxi`eme argument.
UL GETMAXBRK valeur maximale pour lappel dallocation dynamique de memoire : brk.
Ces valeurs sont heritees du processus p`ere.
La valeur FSIZE (taille maximum des fichiers sur disques en blocs) peut etre changee en ksh
avec ulimit [n].

6.15.1

Manipulation de la taille dun processus.

#include <unistd.h>
int brk(const void *endds);
void *sbrk(int incr);
Les deux appels permettent de changer la taille du processus. Ladresse manipulee par les deux
appels est la premi`ere adresse qui est en dehors du processus. Ainsi on realise des augmentations
de la taille du processus avec des appels `a sbrk et on utilise les adresses retournees par sbrk pour
les appels `a brk pour reduire la taille du processus. On utilisera de preference pour les appels
`a sbrk des valeurs de incr qui sont des multiples de la taille de page. Le syst`eme realisant des
deplacement du point de rupture par nombre entier de pages (ce qui est logique dans un syst`eme de
memoire pagine). A ne pas utiliser en conjonction avec les fonctions dallocation standard malloc,
calloc, realloc, free.

6.15.2

Manipulation de la valeur nice

Permet de changer la valeur de nice utilisee par le processus. Si lon a des droits privilegies la
valeur peut etre negative. La valeur de nice est toujours comprise entre -20 et +20 sous linux. Seul
le super utilisateur pouvant utiliser une valeur negative.
#include <unistd.h>
int nice(int valeur);
La commande shell renice priorite -p pid -g pgrp -u user permet de changer le nice
dun processus actif.

6.15.3

Manipulation de la valeur umask

Lappel umask permet de specifier quels droits doivent etre interdits en cas de creation de
fichier. cf. 5.1
#include <sys/stat.h>
mode_t umask(mode_t mask);
la valeur retournee est lancienne valeur.

`
6.16. LAPPEL SYSTEME
FORK

6.16

53

Lappel syst`
eme fork

lappel syst`eme fork permet le creation dun processus clone du processus courrant.
pid_t

fork(void);

DEUX valeurs de retour en cas de succ`es :


Dans le processus p`ere valeur de retour = le PID du fils,
Dans le processus fils valeur de retour = zero.
Sinon
Dans le processus p`ere valeur de retour = -1.
Les PID et PPID sont les seules informations differentes entre les deux processus.

6.17

Lappel syst`
eme exec

#include <unistd.h>
extern char **environ;
int execl( const char *path, const char *arg0, ...,NULL);
int execv(const char *path, char * const argv[]);
int execle( const char *path, const char *arg0, ...,NULL,

char * const envp[]);

int execve(const char *file, char * const argv[], char * const envp[]);
int execlp( const char *file,const char *arg0, ... , NULL );
int execvp(const char *file, char * const argv[]);
Informations conservees par le processus : PID PPID PGID ruid suid (pour leuid cf le
setuidbit de chmod ), nice, groupe dacc`es, catalogue courant, catalogue /, terminal de
controle, utilisation et limites des ressources (temps machine, memoire, etc), umask, masques
des signaux, signaux en attente, table des descripteurs de fichiers, verrous, session.
Quand le processus execute dans le nouvel executable la fonction :
main(int argc, char **argv,char **envp)
argv et env sont ceux qui ont ete utilises dans lappel de execve.
Les differents noms des fonction exec sont des mnemoniques :
l liste darguments
v arguments sont forme dun vecteur.
p recherche du fichier avec la variable denvironnement PATH.
e transmission dun environnement en dernier param`etre, en remplacement de lenvironnement
courant.

54

CHAPITRE 6. LES PROCESSUS

Chapitre 7

Lordonnancement des processus


La selection dans le temps des processus pouvant acc`eder `a une ressource est un probl`eme dit
dordonnancement. Nous presentons ici :
le cas general
les besoins et les probl`emes
et nous decrirons des solutions que lon trouve sous UNIX pour differents probl`emes dordonnancement.
Les algorithmes dordonnancement realisent la selection parmi les processus actifs de celui
qui va obtenir lutilisation dune ressource, que ce soit lunite centrale, ou bien un peripherique
dentree-sortie.
Pour lunite centrale notre but est de maximiser debit et taux utile de lunite centrale :
le d
ebit est le nombre moyen de processus executes en un temps donne.
le taux utile est la proportion de temps reellement utilisee pour executer des processus utilisateurs.
Un exemple :
Soient 2 processus A et B de meme comportement 30 periodes de deux seconde :
1 seconde dactivite
1 seconde dinactivite
AIAIAIAIAIAIAIAIAIAIAIAIAIAIAIAIAIAIAI
Si lon execute les deux processus consecutivement on obtient un debit de 1 processus par
minute, et un taux utile de 50%. Si lon entrelace les periodes actives et inactives des deux processus
on obtient un debit de 2 processus par minute et un taux dutilisation de 100%.
Pour une autre ressource dautres crit`eres seront utilises.

7.1

Le partage de lunit
e centrale

Ce partage doit etre fait non seulement entre les processus utilisateurs mais aussi entre les
differentes taches du syst`eme, scheduler, entrees-sorties, gestion des interruptions, etc.
Nous demandons de plus `a lalgorithme dordonnancement de nous assurer lexclusion mutuelle et labsence de famine, qui sont les points-clefs de la plupart des probl`emes dordonnancement. Linvention dun algorithme dordonnancement se base en generale sur des remarques
statistique sur le comportement des processus :
Le couple UC/ES (cpu/io), les processus ont tendance `a basculer constamment entre des
phases dentrees-sorties et des phases de calcul sur lunite centrale.
Les processus consommant de longues periodes dU.C. sont proportionnellement rares.
55

56

CHAPITRE 7. LORDONNANCEMENT DES PROCESSUS

200

150

100

50

0
1

12

16

20

24

Fig. 7.1 Histogramme de repartition de la duree de la periode dutilisation de lunite centrale


A long terme

A court terme

ligibles pour lU.C.

E/S

U.C.

Files (FIFO) des


priphriques
dentres/sorties

Fig. 7.2 Strategie globale dordonnancement.

7.1.1

Famine

Notre premi`ere tache est daffecter une ressource (lUC par exemple) `a un unique processus `a
la fois (exclusion mutuelle) et sassurer de labsence de famine.
famine : un processus peut se voir refuser lacc`es `a une ressource pendant un temps indetermine,
il est dit alors que le processus est en famine.
Un syst`eme qui ne cree pas de cas de famine : fournira toujours la ressource demandee par un
processus, au bout dun temps fini.
Si on prend le cas des peripheriques (tels que les disques) lordonnancement peut se faire de
facon simple avec par exemple une file dattente (FIFO).
Pour lunite centrale on va devoir utiliser des structures de donnees plus complexes car nous
allons avoir besoin de gerer des priorites. Cest par exemple, autoriser lexistence de processus qui
evitent la file dattente. La structure de donnees utilisee peut parfaitement etre une file, une liste,
un arbre ou un tas, ceci en fonction de lelement-clef de notre algorithme de selection (age, priorite
simple, priorite `a plusieurs niveaux, etc).
Cette structure de donnees doit nous permettre dacceder `a tous les processus prets (eligibles).

7.1.2

Strat
egie globale

On peut representer lordonnancement global avec le schema 7.2


Les ordonnancements `a court terme doivent etre tr`es rapides, en effet le processus elu ne va
utiliser lunite centrale que pendant un tr`es court laps de temps ( 10 milli-secondes par exemple).


7.2. ORDONNANCEMENT SANS PREEMPTION.

57

Si on utilise trop de temps (1 milli-seconde) pour selectionner cet elu, le taux utile decrot tr`es
rapidement (ici on perd 9% du temps dunite centrale).
Par contre lordonnancement `a long terme peut etre plus long car il a lieu moins souvent (toutes
les secondes par exemple). La conception de lordonnanceur `a long terme est faite dans loptique
dobtenir un ordonnanceur `a court terme rapide.

7.1.3

Crit`
eres de performance

Les crit`
eres de performance des algorithmes dordonnancement
Taux dutilisation de lunite centrale
Debit
Temps reel dexecution
Temps dattente
Temps de reponse
Ces cinq crit`
eres sont plus ou moins mutuellement exclusifs.
Les comparaisons des differents algorithmes se fait donc sur une selection de ces crit`eres.

7.2

Ordonnancement sans pr
eemption.

FCFS : First Come First served


Facile `a ecrire et `a comprendre, peu efficace ...
SJF : Shortest Job First
le plus petit en premier.
Optimal pour le temps dattente moyen ...
A priorite :
Lutilisateur donne des priorites aux differents processus et ils sont actives en fonction de
cette priorite.
probl`eme famine possible des processus peu prioritaires
Solution faire augmenter la priorite avec le temps dattente :
plus un processus attend, plus sa priorite augmente ainsi au bout dun certain temps le
processus devient necessairement le plus prioritaire.
re-probl`eme si le processus en question (le tr`es vieux tr`es gros) est execute alors que de
nombreux utilisateurs sont en mode interactif chute catastrophique du temps de reponse et
du debit
solution preemption.
La pr
eemption est la possibilite qua le syst`eme de reprendre une ressource `a un processus sans
que celui-ci ait libere cette ressource.
Ceci est impossible sur bon nombre de ressources. Lesquelles ?

7.3

Les algorithmes pr
eemptifs

FCFS ne peut etre preemptif ...


SJF peut etre preemptif : si un processus plus court que le processus actif arrive dans la queue,
le processus actif est preempte.
Dans des syst`emes interactifs en temps partage un des crit`eres est le temps de reponse, cest `a
dire que chaque utilisateur dispose de lunite centrale reguli`erement. Heureusement, les processus
interactifs utilisent lUC pendant de tr`es courts intervalles `a chaque fois.

58

CHAPITRE 7. LORDONNANCEMENT DES PROCESSUS

7.3.1

Round Robin (tourniquet)

Cet algorithme est specialement adapte aux syst`emes en temps partage.


On definit un quantum de temps (time quantum) dutilisation de lunite centrale.
La file dattente des processus eligibles est vue comme une queue circulaire (fifo circulaire).
Tout nouveau processus est place `a la fin de la liste.
De deux choses lune, soit le processus actif rend lUnite Centrale avant la fin de sa tranche de
temps (pour cause dentree/sortie) soit il est preempte, et dans les deux cas place en fin de liste.
Un processus obtiendra le processeur au bout de (n -1)*q secondes au plus (n nombre de
processus et q longueur du quantum de temps), la famine est donc assurement evitee.
Remarquons que si le quantum de temps est trop grand, round-robin devient equivalent `a FCFS.
De lautre cote si le quantum de temps est tr`es court, nous avons theoriquement un processeur n
fois moins rapide pour chaque processus (n nombre de processus).
Malheureusement si le quantum de temps est court, le nombre de changements de contexte d
us
`a la preemption grandit, do`
u une diminution du taux utile, do`
u un processeur virtuel tr`es lent.
Une r`egle empirique est dutiliser un quantum de temps tel que 80 pourcent des processus
interrompent naturellement leur utilisation de lunite centrale avant lexpiration du quantum de
temps.

7.3.2

Les algorithmes `
a queues multiples

Nous supposons que nous avons un moyen de differencier facilement les processus en plusieurs
classes de priorite differentes (cest le cas sous UNIX o`
u nous allons differencier les taches syst`eme,
comme le swappeur, des autres taches).
Pour selectionner un processus, le scheduler parcourt successivement les queues dans lordre
decroissant des priorites.
Un exemple de queues organisees en fonction du contenu des processus :
les processus syst`emes
les processus interactifs
les processus edition
les processus gros calcul
les processus des etudiants
pour quun processus etudiant soit execute il faut que toutes les autres files dattente soient vides ...
Une autre possibilite est de partager les quantums de temps sur les differentes queues.
Il est aussi possible de realiser differents algorithmes de scheduling sur les differentes queues :
Round Robin sur les processus interactifs
FCFS sur les gros calculs en tache de fond.

7.4

Multi-level-feedback round robin Queues

Le syst`eme dordonnancement des processus sous UNIX (BSD 4.3 et system V4) utilise plusieurs files dattente qui vont materialiser des niveaux de priorite differents et `a linterieur de ces
differents niveaux de priorite, un syst`eme de tourniquet.

7.4.1

Les niveaux de priorit


e

Le scheduler parcourt les listes une par une de haut en bas jusqu`a trouver une liste contenant
un processus eligible. Ainsi tant quil y a des processus de categorie superieure `a executer les autres
processus sont en attente de lunite centrale.

interruptibles

59

swapper

non
interruptibles

Disk I/O

Attentes de :

Interne au Noyau

7.4. MULTI-LEVEL-FEEDBACK ROUND ROBIN QUEUES

Buffer
Inode
tty input
tty output
enfants

priorit limite

niveau 0

Utilisateurs

niveau 1

niveau N

Fig. 7.3 Les queues multiples en tourniquet


Dans les listes internes au noyau, de simples files dattente sont utilisees avec la possibilite de
doubler les processus endormis de la meme liste (en effet seul le processus reveille par la fin de son
entree/sortie est eligible).
Pour les processus utilisateurs, la meme r`egle est utilisee mais avec preemption et la r`egle du
tourniquet.
Cest `a dire, on calcul une priorite de base qui est utilisee pour placer le processus dans la
bonne file dattente.
Un processus qui utilise lunite centrale voit augmenter sa priorite.
Un processus qui lib`ere lunite centrale pour demander une entree/sortie ne voit pas sa priorite
changer.
Un processus qui utilise tout sont quantum de temps est preempte et place dans une nouvelle file
dattente.
Attention : plus la priorit
e est grande moins le processus est prioritaire.

7.4.2

Evolution de la priorit
e

Regardons la priorite et levolution de la priorite dun processus utilisateur au cours du temps.


Les fonctions suivantes sont utilisees dans une implementation BSD.
Pour calculer la priorite dun processus utilisateur, le scheduler utilise lequation suivante qui
est calculee tous les 4 clicks horloge (valeur pratique empirique) :
P usrpri = PUSER +

P cpu
+ 2 P nice
4

cette valeur est tronquee `a lintervalle PUSER..127. En fonction de cette valeur le processus
est place dans une des listes correspondant `a son niveau courant de priorite.
Ceci nous donne une priorite qui diminue lineairement en fonction de lutilisation de lunite
centrale (il advient donc un moment o`
u le processus devient le processus le plus prioritaire !).
P nice est une valeur specifiee par le programmeur grace `a lappel syst`eme nice. Elle varie entre
-20 et +20 et seul le super utilisateur peut specifier une valeur negative.
P cpu donne une estimation du temps passe par un processus sur lunite centrale. A chaque click
dhorloge, la variable p cpu du processus actif est incrementee. Ce qui permet de materialiser la

60

CHAPITRE 7. LORDONNANCEMENT DES PROCESSUS

consommation dunite central du processus. Pour que cette valeur ne devienne pas trop penalisante
sur le long terme (comme pour un shell) elle est attenuee toute les secondes grace `a la formule
suivante :
P cpu =

2 load
P cpu + P nice
2 load + 1

la valeur de load (la charge) est calculee sur une moyenne du nombre de processus actifs
pendant une minute.
Pour ne pas utiliser trop de ressources, les processus qui sont en sommeil (sleep) voient leur
P cpu recalcule uniquement `a la fin de leur periode de sommeil grace `a la formule :

P cpu =

2 load
2 load + 1

sleep time
P cpu

la variable sleep time etant initialisee `a zero puis incrementee une fois par seconde.

7.4.3

Les classes de priorit


e

La priorit
e des processus en mode syst`
eme d
epend de laction `
a r
ealiser.
PSWAP 0 priorite en cours de swap
PINOD 10 priorite en attendant une lecture dinformation sur le syst`eme de fichiers
PRIBIO 20 priorite en attente dune lecture/ecriture sur disque
PZERO 25 priorite limite
PWAIT 30 priorite dattente de base
PLOCK 35 priorite dattente sur un verrou
PSLEP 40 priorite dattente dun ev`enement
PUSER 50 priorite de base pour les processus en mode utilisateur
Le choix de lordre de ces priorites est tr`es important, en effet un mauvais choix peut entraner
une diminution importante des performances du syst`eme.
Il vaut mieux que les processus en attente dun disque soient plus prioritaires que les processus
en attente dun buffer, car les premiers risquent fort de liberer un buffer apr`es leur acc`es disque
(de plus il est possible que ce soit exactement le buffer attendu par le deuxi`eme processus). Si la
priorite etait inverse, il deviendrait possible davoir un interblocage ou une attente tr`es longue si
le syst`eme est bloque par ailleurs.
De la meme facons, le swappeur doit etre le plus prioritaire et non interruptible Si un
processus est plus prioritaire que le swappeur et quil doit etre swappe en memoire ...
En Demand-Paging le swappeur est aussi le processus qui realise les chargements de page, ce
processus doit etre le plus prioritaire.

Chapitre 8

La m
emoire
8.0.4

les m
emoires

La memoire dun ordinateur se decompose en plusieurs elements, dont le prix et le temps


dacc`es sont tr`es variables, cf figure 8.1. Nous developperons dans ce chapitre et le suivant les
questions et solutions relatives `a la memoire centrale.
Limportance de la gestion de la memoire centrale vient de son co
ut et du co
ut relatif des
autres formes de stockage, la figure 8.2 donne une idee des caracteristiques relatives des differents
types de stockage.

8.0.5

La m
emoire centrale

La memoire est un tableau `a une dimension de mots machines (ou doctets), chacun ayant une
adresse propre. Les echanges avec lexterieur se font en general par des lectures ou des ecritures `a
des adresses specifiques.
Le syst`eme Unix est multi-tache,ceci pour maximiser lutilisation du cpu. Cette technique
pose comme condition obligatoire que la memoire centrale soit utilisee et/ou partagee entre les
differentes taches.
Les solutions de gestion de la memoire sont tr`es dependantes du materiel et ont mis longtemps
`a evoluer vers les solutions actuelles. Nous allons voir plusieurs approches qui peuvent servir dans
des situations particuli`eres .
La memoire est le point central dans un syst`eme dexploitation, cest `a travers elle que lunite
centrale communique avec lexterieur.

Mmoire
volatile

Registres
Mmoire cache
Mmoire centrale

Cot par bit croissant


vitesse daccs croissant
capacit de stockage
dcroissante

Disques
Bandes magntiques

Mmoire
permanente

Fig. 8.1 Hierarchie de memoires


61


CHAPITRE 8. LA MEMOIRE

62

CARACTERISTIQUES DES TYPES DE MEMOIRES

TYPE DE
MEMOIRE

TAILLE
(Octets)

TEMPS DACCES
(secondes)

CACHE

103-104

10-8

10

10-7

MEMOIRE
CENTRALE

106-107

COUT RELATIF
PAR BIT

DISQUE

108-109

10-3-10-2

10-2-10-3

BANDE

108-109

10-102

10-4

Fig. 8.2 Caracteristiques relatives des memoires.

64Kilos octets
utilisateurs

FFFF

Fig. 8.3 Une memoire de 64 Kilo Octets.


8.1. ALLOCATION CONTIGUE

63
0
le noyau
(moniteur)

Registre
Barrire

un programme
utilisateur

FFFF

Fig. 8.4 Protection du moniteur par un registre barri`ere.

8.1
8.1.1

Allocation contigu
e
Pas de gestion de la m
emoire

Pas de gestion de la memoire ! Cette methode, qui a lavantage de la simplicite et de la rapidite,


permet toute liberte quand `a lutilisation de la memoire. En effet, toute adresse est accessible, et
peut etre utilisee pour nimporte quelle tache. Le desavantage : aucune fonctionnalite, tout doit
etre reprogramme, typiquement il ny pas de syst`eme dexploitation !

8.1.2

Le moniteur r
esidant

On cherche `a proteger le noyau des interferences possibles de la part des utilisateurs. Pour cela,
toute adresse dinstruction ou de donnee manipulee par un programme utilisateur est comparee `a
un registre barri`ere (fence register).
Tant que ladresse est superieure `a la barri`ere, ladresse est legale, sinon ladresse est une
reference illegale au moniteur et une interruption est emise (invalid adress).
Cette methode demande que pour tout acc`es `a la memoire une verification de la validite de
ladresse soit realisee. Ceci ralentit toute execution dun acc`es memoire. (Paterson donne comme
exemple de ralentissement des temps de 980 nanosecondes sans verification et 995 nanosecondes
avec verification). Globalement ce temps supplementaire peut etre oublie.

8.1.3

Le registre barri`
ere

Limplementation dun tel mecanisme doit etre realisee de facon materielle.


La valeur du registre barri`ere est parfois realisee de facon fixe sur une machine, ce qui pose des
probl`emes d`es que lon veut changer le noyau et/ou proteger plus de memoire (voir DOS).

8.1.4

Le registre base

Le mecanisme suivant est une notion plus utile et plus ergonomique pour decrire la zone
dadressage dun programme, et utile pour resoudre le probl`eme de deplacement des programmes
en memoire (relocation).
En effet, du fait que lon utilise un registre barri`ere, les adresses utilisables de la memoire ne
commencent plus `a 0000, alors que lutilisateur veut continuer `a utiliser des adresses logiques qui
commencent `a 0000.


CHAPITRE 8. LA MEMOIRE

64

Registre
Barrire

unit
centrale

A < Barrire

non

mmoire

oui
Intruption

Fig. 8.5 Implementation du registre Barri`ere.

Registre
Base
1400

unit
centrale

mmoire

+
0346

1746

Fig. 8.6 Implementation du registre de Base.

0
le noyau
(moniteur)

Registre
Barrire

un programme
utilisateur

FFFF

Fig. 8.7 Positionnement dun processus par un registre de Base.


8.1. ALLOCATION CONTIGUE

65

Moniteur
Barrire

1 swap out

P1

Zone
utilisateur
P2
2 swap in

Fig. 8.8 Un syst`eme de swap utilisant uniquement un registre barri`ere.


Pour continuer `a fournir cette possibilite le registre barri`ere est transforme en registre de base
(relocation) . A chaque utilisation dune adresse logique du programme, on ajoute `a cette adresse
la valeur du registre de base pour trouver ladresse physique. Lutilisateur ne connat plus les
adresses physiques. Il travaille uniquement avec des adresses logiques (xdb).
Le moniteur a evidemment une valeur nulle pour son registre de base et donc peut adresser
toute la memoire. Le changement de la valeur du registre de base se fait de facon protegee en
mode moniteur.
Ces deux syst`emes de protection de la memoire sont clairement mono-processus. Seul le moniteur peut etre protege par ces mecanismes, il nest pas possible de proteger les processus entre
eux.

8.1.5

Le swap

Il est possible avec les registres barri`ere ou les registres de base decrire des syst`emes temps
partage, en utilisant le mecanisme de swap (echange).
Swapper, cest echanger le contenu de la memoire centrale avec le contenu dune memoire
secondaire. Par extension swapper devient laction de deplacer une zone memoire de la memoire
vers le support de swap (en general un disque) ou reciproquement du peripherique de swap vers
la memoire.
Le syst`eme va realiser cet echange `a chaque changement de contexte. Les syst`emes de swap
utilisent une memoire secondaire qui est en general un disque mais on peut utiliser dautre supports
secondaires plus lents ou plus rapides comme des bandes ou memoires secondaires (non accessibles
par lunite de traitement).

8.1.6

Le co
ut du swap

Sur un tel syst`eme, le temps de commutation de taches est tr`es important. Il est donc necessaire
que chaque processus reste possesseur de lunite de traitement un temps suffisamment long pour
que le ralentissement d
u au swap ne soit pas trop sensible. Que ce passe-t-il sinon ? Le syst`eme
utilise la majeure partie de ses ressources `a deplacer des processus en et hors memoire centrale.
Lunite de traitement nest plus utilisee au maximum ...

8.1.7

Utilisation de la taille des processus

Pour ameliorer les mecanismes de swap, on remarque que le temps de swap est proportionnel `a
la taille des donnees `a deplacer. Pour ameliorer les performances, il faut donc introduire la notion


CHAPITRE 8. LA MEMOIRE

66
Bas

unit
centrale

A < Bas

Haut

non

A > Haut

oui
Interruption

non

mmoire

oui
Interruption

Fig. 8.9 Double registre barri`ere.


de taille effective dun processus, ce qui permet dameliorer le debit mais cela impose que toutes
les augmentations ou reductions de taille dun processus utilisateur soient realisee par un appel
syst`eme (sbrk) afin que le noyau connaisse `a tout moment la taille reelle de chaque processus.

8.1.8

Swap et ex
ecutions concurrentes

Une autre approche tr`es efficace est de realiser le swap pendant lexecution dun autre processus.
Mais avec le syst`eme de registres de relocation cest dangereux. En effet nous ne pouvons pas
assurer quun processus utilisateur donne ne va pas ecrire dans les adresses reservees `a un autre
processus.

8.1.9

Contraintes

Le swap introduit dautres contraintes : un processus doit etre en preempte actif pour etre
swappe, cest `a dire netre en attente daucune entree-sortie. En effet, si P1 demande une E/S et
pendant cette demande il y a echange de P1 et P2, alors la lecture demandee par P1 a lieu dans
les donnees de P2.

8.1.10

Deux solutions existent

Soit ne jamais swapper de processus en attente dentrees-sorties. Soit realiser toutes les entreessorties dans des buffers internes au noyau (solution UNIX), ce qui a pour co
ut une recopie memoire
a memoire supplementaire par E/S. Les transferts entre le noyau et le processus ayant lieu uni`
quement quand le processus est en memoire.

8.1.11

Les probl`
emes de protection

Nous venons dapercevoir des probl`emes de protection entre un processus et le noyau. Si lon
autorise plusieurs processus `a resider en memoire en meme temps, il nous faut un mecanisme de
protection inter-processus.
Deux methodes sont couramment utilisees : les extensions du registre barri`ere et du registre de
base (relocation).

8.1.12

Les registres doubles

Deux registres Barri`ere Bas et Haut


Si Adresse < Bas lever une exception erreur dadresse
Si Adresse >= Haut lever une exception erreur dadresse
Sinon adresse correcte.
Deux registres de relocation Base et Limit, on travaille avec des adresses logiques Limit donne
la valeur maximale dune adresse logique et Base donne la position en memoire de ladresse logique


8.2. ORDONNANCEMENT EN MEMOIRE
DES PROCESSUS
Base

limite

unit
centrale

67

non

A > limite

mmoire

oui
Interruption

Fig. 8.10 Base et Limite.


0

Moniteur

300k
500k
600k

p1
p2

0
300k
500k
600k
800k

1000k
1200k

Moniteur

300k
p1
p2

500k
600k

p3
p4

p3

1200k

300k
p1
p2

2100k
Initial

500k
600k

Moniteur
p1
p2

p4
1000k

p3

1200k
1500k

1500k
1900k

Moniteur

p4

p4
1900k
2100k
Dplacement :
600k

2100k

2100k

Dplacement :
400k

p3

Dplacement :
200k

Fig. 8.11 Une situation dordonnancement de processus en memoire.


zero.
Si Adresse >= Limit lever une exception erreur dadresse
sinon utiliser ladresse physique Adresse+Base.

8.2

Ordonnancement en m
emoire des processus

Les choix de limplementation des mecanismes dadressage influence enormement lordonnancement des processus.
Nous travaillons dans le cas dun syst`eme de traitement par lots cest `a dire en temps partage
mais les processus restent en memoire tout le temps de leur execution. Sil ny a plus de place le
processus est mis en attente (i.e. non charge en memoire).
Nous devons resoudre le probl`eme suivant : il nous faut un algorithme pour choisir dynamiquement, parmi les blocs libres de la memoire centrale, celui qui va recevoir le nouveau processus
(algorithme dallocation de memoire `a un processus). On reconnat en general trois methodes :
First-fit Le premier bloc suffisamment grand pour contenir notre processus est choisi.
Best-fit Le plus petit bloc suffisamment grand pour contenir notre processus est choisi.
Worst-fit Le bloc qui nous laisse le plus grand morceau de memoire libre est choisi (le plus grand
bloc).
De nombreuse experiences pratiques et des simulations ont montre que le meilleur est first-fit
puis best-fit et que ces deux algorithmes sont beaucoup plus efficaces que worst-fit. Compactage
On cherche `a ameliorer ces mecanismes en defragmentant la memoire cest `a dire en deplacant les
processus en memoire de facon `a rendre contigues les zones de memoire libre de facon `a pouvoir
les utiliser.


CHAPITRE 8. LA MEMOIRE

68
0

Moniteur

Moniteur

40k

40k

P5

P5

90k

90k
100k

P4
P4

160k
170k

P3

190k

200k

Zone contigu
de 66k

P3

230k
256k

256k

Fig. 8.12 Compactage


0

0
Moniteur

Moniteur

40k

100k

40k
P1

P1

100k

0
Moniteur

Moniteur

40k

Moniteur

40k

40k

100k

90k
100k

P5

P1

100k
P4

P4

P4

P2

200k

200k
P3

230k
256k

170k

170k

170k

200k

200k

200k

P3

230k

P3

230k

256k

256k

P3

230k

256k

P3

230k
256k

Fig. 8.13 Plusieurs deplacements possibles.

8.3

Allocation non-contigu
e

8.3.1

Les pages et la pagination

Pour accelerer ces mecanismes dallocation, la notion de page a ete introduite.


On va decouper la memoire et les processus en pages. Grace `a ce syst`eme, il ne sera plus
necessaire de placer les processus dans une zone contig
ue de la memoire. Il devient possible dallouer
de la memoire `a un processus sans avoir `a realiser de compactage !
Ce principe des page necessite de nouvelles possibilites materielles. Toute adresse est maintenant consideree comme un couple
(Numero de page, Position dans la page)
A : adresse logique, P : taille de page
Numero de page = A div P
Position = A modulo P

8.3.2

Ordonnancement des processus dans une m


emoire pagin
ee

Le choix de lorganisation memoire a une influence preponderante sur lordonnancement des


processus, qui devient beaucoup plus independant de la memoire quand celle-ci est paginee.
Le desavantage de la methode de gestion de memoire par un mecanisme de page est le phenom`ene
de fragmentation interne. On alloue une page enti`ere alors que le processus ne lutilise quen
partie. Mais la taille des memoires et des processus deviennent tels par rapport aux tailles de page
que cette perte devient minime.


8.3. ALLOCATION NON-CONTIGUE

69
Adresse
physique

Adresse
logique
unit
centrale

mmoire

p
f

Table des pages

Fig. 8.14 Calcul dune adresse avec la table des pages

page 0
page 1
page 2
page 3
mmoire
logique

0
1
2
3

1
4
3
7

Table des pages

0
1 page 0
2
3 page 2
4 page 1
5
6
7 page 3
mmoire
physique

Fig. 8.15 La memoire logique et la Table des pages.


Un avantage des pages est une plus grande simplicite du partage de la memoire entre differents
processus. En particulier quand plusieurs processus partagent le meme code. La page qui contient
du code utilise par les processus sera partageable et protegee en ecriture.
Sous Unix le compilateur produit automatiquement des programmes dont la partie code est
partageable.

8.3.3

Comment prot
eger la m
emoire pagin
ee

Les protections dacc`es sont faites au niveau de la table des pages.


On a une table des pages globale. Cest donc le syst`eme qui alloue les pages `a un processus,
qui par construction (du syst`eme de pagination) ne peut pas ecrire en dehors de ses propres pages.
De plus, dans la table des pages dun processus, des drapeaux indiquent le type de page (droits
dacc`es en lecture/ecriture/execution).

8.3.4

La m
emoire segment
ee

Nous venons de voir que les adresses logiques utilisees par le programmeur sont differentes des
adresses physiques.
La memoire segmentee est une organisation de la memoire qui respecte le comportement usuel
des programmeurs, qui generalement voient la memoire comme un ensemble de tableaux distincts
contenant des informations de types differents. Un segment pour chaque type : donnees, code, table
des symboles, librairies etc. Ces differentes zones ayant des tailles variees, et parfois variables au
cours du temps (le tas par exemple).


CHAPITRE 8. LA MEMOIRE

70
Table des segments
Adresse
logique
unit
centrale

Adresse
physique

d<l

mmoire

oui

non
interruption erreur dadresse

Fig. 8.16 Memoire segmentee


La memoire segmentee non paginee pose des probl`emes de compactage (defragmentation). La
strategie ideale est : la memoire en segments pagines.

Chapitre 9

La m
emoire virtuelle
Les methodes de gestion memoire que nous venons de voir ont toutes un defaut majeur qui est
de garder lensemble du processus en memoire, ce qui donne :
un co
ut en swap important
Impossibilite de creer de tr`es gros processus.
Les methodes de memoire virtuelle permettent dexecuter un programme qui ne tient pas enti`erement
en memoire centrale !
Nous avons commence par presenter des algorithmes de gestion de la memoire qui utilisent le
concept de base suivant :
lensemble de lespace logique adressable dun processus doit etre en memoire pour pouvoir executer
le processus.
Cette restriction semble `a la fois raisonnable et necessaire, mais aussi tr`es dommageable car
cela limite la taille des processus `a la taille de la memoire physique.
Or si lon regarde des programmes tr`es standards, on voit que :
il y des portions de code qui g`erent des cas tr`es inhabituels qui ont lieu tr`es rarement (si ils
ont lieu)
les tableaux, les listes et autres tables sont en general initialises `a des tailles beaucoup plus
grandes que ce qui est reellement utile
Certaines options dapplication sont tr`es rarement utilisees
Meme dans le cas o`
u le programme en entier doit resider en memoire, tout nest peut-etre pas
absolument necessaire en meme temps.
Avec la memoire virtuelle, la memoire logique devient beaucoup plus grande que la memoire
physique.
De nombreux avantages :
Comme les utilisateurs consomment individuellement moins de memoire, plus dutilisateurs peuvent
travailler en meme temps. Avec laugmentation de lutilisation du CPU et de debit que cela implique (mais pas daugmentation de la vitesse).
Moins dentrees-sorties sont effectuees pour lexecution dun processus, ce qui fait que le processus sexecute (temps reel) plus rapidement.

9.0.5

Les overlays

Une des premi`eres versions dexecutables partiellement en memoire est celle des overlay qui
est lidee de charger successivement des portions disjointes et differentes de code en memoire,
executees lune apr`es lautre.
Les differentes passes dun compilateur sont souvent realisees en utilisant un overlay (preprocesseurs,
pass1, pass2, pour les compilateurs C).
71


CHAPITRE 9. LA MEMOIRE
VIRTUELLE

72

Les overlay necessitent quelques adaptations de lediteur de liens et des mecanismes de relocation.

9.0.6

Le chargement dynamique

Un autre syst`eme couramment utilise dans les logiciels du marche des micros est le chargement
dynamique. Avec le chargement dynamique, une fonction nest chargee en memoire quau moment
de son appel. Le chargement dynamique demande que toutes les fonctions soient repositionnables
en memoire de facon independante.
A chaque appel de fonction on regarde si la fonction est en memoire sinon un editeur de liens
dynamique est appele pour la charger.
Dans les deux cas (overlay et chargement dynamique), le syst`eme joue un role tr`es restreint, il
suffit en effet davoir un bon syst`eme de gestion de fichiers.
Malheureusement, le travail que doit realiser le programmeur pour choisir les overlays et/ou
installer un mecanisme de chargement dynamique efficace est non trivial et requiert que le programmeur ait une parfaite connaissance du programme.
Ceci nous am`ene aux techniques automatiques.

9.1

Demand Paging

La methode de Demand Paging est la plus repandue des implementations de memoire virtuelle, elle demande de nombreuse capacites materielles.
Nous partons dun syst`eme de swap o`
u la memoire est decoupee en pages. Comme pour le
swap, quand un programme doit etre execute nous le chargeons en memoire (swap in) mais au lieu
de faire un swap complet, on utilise un swappeur paresseux (lazy swapper).
Un swappeur paresseux charge une page uniquement si elle est necessaire.
Que ce passe-t-il quand le programme essaie dacceder `a une page qui est hors memoire ?
le materiel va traduire ladresse logique en une adresse physique grace `a la table des pages.
tant que les pages demandees sont en memoire, le programme tourne normalement, sinon si
la page est contenue dans lespace des adresses logiques mais nest pas chargee, il y a une
page fault.
En general, une erreur dadresse est d
ue `a une tentative dacc`es `a une adresse exterieure
(invalide). Dans ce cas, le programme doit etre interrompu, cest le comportement normal dun
syst`eme de swap.
Mais il est possible avec un swappeur paresseux que la page existe mais ne soit pas en memoire
centrale, do`
u les etapes suivantes dans ce cas :
On peut faire demarrer un processus sans aucune page en memoire. La premi`ere Page Fault
aurait lieu `a la lecture de la premi`ere instruction (linstruction netant pas en memoire).
Il faut realiser une forme speciale de sauvegarde de contexte, il faut garder une image de letat
du processus qui vient deffectuer une Page Fault mais de plus il faudra redemarrer (reexecuter)
linstruction qui a place le processus dans cet etat, en effet il est possible que linstruction ne se
soit pas termine par manque de donnees.
Le syst`eme dexploitation a ici un role important, cest lui qui va realiser le chargement de la
page manquante puis relancer le processus et linstruction.
Les circuits necessaires `a la methode de Demande Paging sont les memes que ceux que lon
utilise pour un syst`eme de swap pagine, cest-`a-dire une memoire secondaire et un gestionnaire de
pages (table des pages).
Par contre, la partie logicielle est beaucoup plus importante.
Enfin il faut que les instructions soient interruptibles, ce qui nest pas toujours le cas sur
tous les processeurs et ce qui est fondamental, comme nous allons le voir sur des exemples :
add A,B in C

9.1. DEMAND PAGING

73
3 la page existe
en zone de swap

noyau
1 rfrence

2 interruption

load M
6 relancer
linstruction table des
pages
disque
de
swap

5 mise jours
de la table des
page du P.
mmoire

4 swap in
de la page
fautive ...

Fig. 9.1 Etapes de la gestion dune erreur de page


1. chercher et decoder linstruction add
2. charger le contenu de ladresse A
3. charger le contenu de ladresse B
4. sommer et sauvegarder dans C
Si lerreur de page a lieu dans le 4i`eme acc`es `a la memoire (C), il faudra de nouveau recommencer
les 3 acc`es memoire de linstruction, cest-`a-dire lire linstruction, etc.
Un autre type de probl`eme vient dinstructions comme la suivante que lon trouve sur PDP-11
:
MOV (R2)++,(R3)
cette instruction deplace lobjet pointe par le registre R2 dans ladresse pointe par R3, R2 est
incremente apr`es le transfert et R3 avant.
Que se passe-t-il si lon a une erreur de page en cherchant `a acceder `a la page pointe par R3 ?

9.1.1

Efficacit
e

Efficacite des performances de Demand Paging :


Soit ma = 500 nanosecondes, le temps moyen dacc`es a une memoire.
le temps effectif dacc`es avec le Demand Paging est
temps effectif = (1-p)*ma + p * temps de gestion de lerreur de page
o`
u p est la probabilite doccurrence dune erreur de page (page fault).
Une erreur de page necessite de realiser les operations suivantes
1. lever une interruption pour le syst`eme
2. sauvegarder le contexte du processus
3. determiner que linterruption est une erreur de page
4. verifier que la page en question est une page legale de lespace logique, determiner o`
u se
trouve la page dans la memoire secondaire.
5. executer une lecture de la page sur une page memoire libre (liberer eventuellement une page
cf. algorithme de remplacement de page)
attendre que le peripherique soit libre


CHAPITRE 9. LA MEMOIRE
VIRTUELLE

74
temps de latence du peripherique
commencer le transfert

6. allouer pendant ce temps-l`a le cpu `a un autre utilisateur


7. interruption du peripherique
8. sauvegarde du contexte du processus courant
9. determiner que linterruption etait la bonne interruption (venant du peripherique)
10. mise `a jour de la table des pages et dautres pages pour indiquer que la page demandee est
en memoire maintenant.
11. attendre que le processus soit selectionne de nouveau pour utiliser lunite centrale (cpu)
12. charger le contexte du processus !
Toutes ces instructions ne sont pas toujours realisees (on peut en particulier supposer que
lon ne peut pas preempter lunite centrale, mais alors quelle perte de temps pour lensemble du
syst`eme).
Dans tous les cas, nous devons au moins realiser les 3 actions suivantes :
gerer linterruption
swapper la page demandee
relancer le processus
Ce qui co
ute le plus cher est la recherche de la page sur le disque et son transfert en memoire, ce
qui prend de lordre de 1 `a 10 millisecondes.
Ce qui nous donne en prenant une vitesse dacc`es memoire de 1 microseconde et un temps de
gestion de page de 5 millisecondes un
temps effectif = (1 p) + p 5000 microsecondes
Une erreur de page toutes les mille pages nous donne un temps effectif onze fois plus long que
lacc`es standard.
Il faut reduire `a moins dune erreur de page tout les 100000 acc`es pour obtenir une degradation
inferieure `a 10
On comprend bien que les choix `a faire sur des pages quil faut placer en memoire sont donc
tr`es importants.
Ces choix deviennent encore plus importants quand lon a de nombreux utilisateurs et quil y a
sur-allocation de la memoire, execution concurrente de 6 processus de la taille superieure ou egale
`a la memoire physique !
Si lon suppose de plus que nos 6 programmes utilisent dans une petite sequence dinstructions
toutes les pages de leur memoire logique, nous nous trouvons alors dans une situation de penurie
de pages libres.
Le syst`eme dexploitation peut avoir recoure `a plusieurs solution dans ce cas-l`a
1. tuer le processus fautif ...
2. utiliser un algorithme de remplacement de page
Cet algorithme de remplacement est introduit dans notre sequence de gestion derreur de page
l`a o`
u lon sattribuait une page libre de la memoire centrale.
Maintenant il nous faut selectionner une victime, cest-`a-dire, une des pages occupees de la
memoire centrale qui sera swappee sur disque et remplacee par la page demandee.

9.2. LES ALGORITHMES DE REMPLACEMENT DE PAGE

75

Remarquons que dans ce cas-l`a notre temps de transfert est double, comme il faut `a la fois lire
une page et sauvegarder une page sur disque (le temps de transfert disque est ce qui est le plus
co
uteux dans la gestion dune erreur de page).
Il est possible de realiser des syst`emes de demand segments, mais le lecteur avise remarquera
rapidement les probl`emes poses par la taille variable des segments.

9.2

Les algorithmes de remplacement de page

Un algorithme de remplacement de page doit minimiser le nombre de Page Faults.


On recherche lalgorithme qui reduit au mieux la probabilite doccurrence dune erreur de page.
Un algorithme est evalue en prenant une chane de numeros de page et en comptant le nombre de
fautes de page qui ont lieu au cours de cette suite dacc`es, et cela en fonction du nombre de pages
de memoire centrale dont il dispose.
Pour illustrer les algorithmes de remplacement, nous utiliserons la suite de pages suivante :
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
et 3 pages en memoire centrale.

9.2.1

Le remplacement optimal

Utiliser comme victime la page qui ne sera pas utilisee pendant le plus longtemps.
Soit pour notre suite :
7xx 70x 701 201 - 203 - 243 - -203 - - 201 - - - 701 - soit seulement 9 fautes de page.
Mais cet algorithme nest valable que dans un cas o`
u lon connat `a lavance les besoins, ce
qui nest generalement pas le cas.

9.2.2

Le remplacement peps (FIFO)

Lalgorithme le plus simple est Premier Entre Premier Sorti (First-In-First-Out ).


Quand une victime doit etre selectionnee cest la page la plus ancienne qui est selectionnee.
Soit pour la liste
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
et trois page de memoire centrale :
7XX/70X/701/201-201/231/230/430/420/423/
023-023-023/013/012-012-012/712/702/701
soit Quinze Page Faults.
Ce mecanisme rapide et simple `a programmer nest malheureusement pas tr`es efficace. Il existe
des suites de pages pour lesquelles cet algorithme fait plus de page faults avec quatre pages memoire
quavec trois ! (par exemple : 1,2,3,4,1,2,5,1,2,3,4,5).


CHAPITRE 9. LA MEMOIRE
VIRTUELLE

76

9.2.3

Moins r
ecemment utilis
ee LRU.

LRU (Least Recently Used page).


Nous utilisons ici le vieillissement dune page et non plus lordre de creation de la page. On fait
le pari que les pages qui ont ete recemment utilisees le seront dans un proche avenir, alors que les
pages qui nont pas ete utilisees depuis longtemps ne sont plus utiles.
Soit pour notre suite :
7xx 70x 701 201 - 203 - 403 402 432 032 - - 132 - 102 - 107 soit Douze Page Faults.
Lalgorithme LRU est un bon algorithme mais il pose de nombreux probl`emes dimplementation
et peut demander de substantiels outils materiels.
Des solutions logicielles :
Des compteurs `a chaque entree de la table des pages, on ajoute un compteur de temps qui est
mis `a jour `a chaque acc`es `a la page. Il faut rechercher sur lensemble de la table la victime.
De plus, ces temps doivent etre mis `a jour quand on change de table de page (celle dun
autre processus ...). On ne peut utiliser le temps reel ...
Une pile `a chaque fois que lon acc`ede `a une page, la page est placee en sommet de pile. Le dessus
est toujours la page la plus recemment utilisee et le fond de la pile la moins recemment
utilisee.
Des masques On utilise un octet associe `a chaque page. Le syst`eme positionne `a 1 le bit de
poids fort `a chaque acc`es `a la page. Toutes les N millisecondes (click dhorloge, cf clock, N
= 100 sur fillmore) le syst`eme fait un decalage `a droite de loctet associe `a chaque page. On
obtient ainsi un historique de lutilisation de la page. Loctet `a 00000000 indique que la page
na pas ete utilisee depuis 8 cycles, 11111111 indique que la page a ete utilisee pendant les
8 cycles. La page de masque 11000100 `a ete utilisee plus recemment que 01110111. Si lon
interpr`ete ces octets comme des entiers non-signes, cest la page ayant le plus petit octet
qui a ete utilisee le moins recemment (lunicite des numeros netant pas assuree, la selection
entre numeros identiques se fait avec lordre FIFO).

9.2.4

Lalgorithme de la deuxi`
eme chance

Un bit associe `a chaque page est positionne `a 1 `a chaque fois quune page est utilisee par un
processus. Avant de retirer une page de la memoire, on va essayer de lui donner une deuxi`eme
chance. On utilise un algorithme FIFO plus la deuxi`eme chance :
Si le bit dutilisation est `a 0, la page est swappee hors memoire (elle na pas ete utilisee depuis la
derni`ere demande de page).
Si le bit est `a 1, il est positionne a zero et lon cherche une autre victime. Ainsi cette page ne
sera swappee hors memoire que si toutes les autres pages ont ete utilisees, et utilisent aussi leur
deuxi`eme chance.
On peut voir ceci comme une queue circulaire, o`
u lon avance sur les pages qui ont le bit `a 1
(en le positionnant `a zero) jusqu`a ce que lon trouve une page avec le bit dutilisation `a zero.

9.2.5

Plus fr
equemment utilis
e MFU

Plus frequemment Utilisee :


Comme son nom lindique, cest la frequence dutilisation qui joue au lieu de lanciennete, mais
cest le meme mecanisme que LRU. Ces deux algorithmes de LRU et MFU sont rarement utilises
car trop gourmands en temps de calcul et difficiles `a implementer, mais ils sont assez efficaces.

9.3. ALLOCATION DE PAGES AUX PROCESSUS

9.2.6

77

Le bit de salet
e (Dirty Bit)

Remarquons que si il existe une copie identique sur disque (zone de swap) dune page de
memoire, il nest pas necessaire dans le cas dun swapout de sauvegarder la page sur disque, il
suffit de la liberer.
Le bit de salete permet dindiquer quune page est (ou nest plus) conforme `a la page en zone de
swap.
Ce bit de proprete est utilise dans les autres algorithmes, on choisit entre deux victimes possibles
la plus propre, cest-`a-dire celle qui ne necessite pas de swapout.

9.3

Allocation de pages aux processus

Comment repartir les pages sur les differents processus et le syst`eme ?


remplacement local le processus se voit affecte un certain nombre de pages quil va utiliser de
facon autonome, son temps dexecution ne depend que de son propre comportement.
remplacement global le comportement dallocation de pages aux processus depend de la charge
du syst`eme et du comportement des differents processus.
Le remplacement local demande que lon realise un partage entre les differents processus.
Le partage equitable : m pages de memoire physique, n processus, m/n pages par processus
! On retrouve ici un probl`eme proche de la fragmentation interne, un grand nombre de pages est
donne `a un processus qui en utilise effectivement peu.
On fait un peu mieux en utilisant : S = si o`
u si est le nombre de pages de la memoire
logique du Processus i. Chaque processus se voit attribue (si /S)m pages. On ameliore en faisant
varier ce rapport en fonction de la priorite de chaque processus.

Probl`
emes d
ecroulement Si le nombre de pages allouees `a un processus non-prioritaire tombe
en dessous de son minimum vital, ce processus est constamment en erreur de page : il passe tout
son temps `a realiser des demandes de pages. Ce processus doit etre alors ejecte enti`erement en
zone de swap et reviendra plus prioritaire quand il y aura de la place.
Un exemple de bonne et mauvaise utilisation des pages (rappel les compilateurs c allouent les
tableaux sur des plages dadresse croissante contig
ues int m[A][B] est un tableau de A tableaux
de B entiers) :
/* bonne initialisation */
int m[2048][2048];
main()
{int i,j;
for(i=0;i<2048;i++)
for(j=0;j<2048;j++)
m[i][j] = 1;
}
ce processus acc`ede a une nouvelle page toute les 2048 affectation.
/* mauvaise initialisation */
int m[2048][2048];
main()
{int i,j;
for(i=0;i<2048;i++)
for(j=0;j<2048;j++)
m[j][i] = 1;
}


CHAPITRE 9. LA MEMOIRE
VIRTUELLE

78

ce processus acc`ede a une nouvelle page toute les affectations !


Attention : En fortran lallocation des tableaux se fait dans lautre sens par colones . . .
Si la memoire est libre et assez grande, les deux processus sont grossi`erement aussi rapides,
par contre si on lance dix exemplaires du premier, le temps dattente est juste multiplie par 10.
Pour le deuxi`eme, le temps dattente est au moins multiplie par 100 (je nai pas attendu la fin de
lexecution).

9.4

Lappel fork et la m
emoire virtuelle

Nous avons vu que la primitive fork() realise une copie de limage memoire du processus p`ere
pour creer le processus fils. Cette copie nest pas integrale car les deux processus peuvent partager
des pages marquees en lecture seule, en particulier le segment du code est partage par les deux
processus (reentrance standard des processus unix).
Mais avec le syst`eme de demand-paging, on peut introduire une nouvelle notion qui est la
copie sur ecriture (copy on write). On ajoute `a la structure de page de la table des pages des
indicateurs de copie sur ecriture. Lidee est de realiser la copie de la page uniquement dans le
cas o`
u lun des processus qui peuvent y acc`eder realise une ecriture. Dans ce cas-l`a, la page est
recopiee avant lecriture et le processus ecrivain poss`ede alors sa propre page.
Linteret de ce mecanisme est surtout visible dans le cas tr`es frequent o`
u le fork est immediatement
suivi par un exec. En effet, ce dernier va realiser une liberation de toutes les pages, il est donc
inutile de les recopier juste avant cette liberation.
Le syst`eme BSD a introduit la premi`ere version de cette idee en partant de lappel syst`eme
vfork() qui lui permet le partage totale de toutes les pages entre le processus p`ere et le processus
fils sans aucune copie. Linteret est de pouvoir realiser rapidement un execve sans avoir `a recopier
lespace dadressage du processus p`ere.

9.5

Projection de fichiers en m
emoire

La fonction mmap permet la projection de fichiers en memoire. Le segment du fichier indique


est place en memoire `a partir de ladresse indiquee. Le segment de fichier peut ainsi etre parcouru
par des acc`es par adresse sans utiliser de commande de lecture ou decriture.
#include <sys/mman.h>
#include <sys/types.h>
void *mmap(void
int
int

*adr, int len,


prot, int options,
desc, int offset);

int munmap(void *adr, int len);


Ladresse adr indique o`
u doit etre place le fichier, cette adresse doit etre une adresse de debut
de page (un multiple de sysconf( SC PAGE SIZE)), si le param`etre est NULL alors le syst`eme
selectionne ladresse de placement qui est retournee par la fonction. Lintervalle de position
[offset, offset+len]
du fichier desc est place en memoire.
prot indique les protections dacc`es sous HP-UX les protections suivantes sont disponible :


9.5. PROJECTION DE FICHIERS EN MEMOIRE
--r-r-x
rw
rwx

79

PROT_NONE
PROT_READ
PROT_READ|PROT_EXECUTE
PROT_READ|PROT_WRITE
PROT_READ|PROT_WRITE|PROT_EXECUTE

options indique si lon veut que les ecritures realisees dans les pages contenant la projection soient partagees (MAP SHARED), ou au contraire quune copie sur ecriture soit realisee
(MAP PRIVATE).
La fonction munmap permet de liberer la zone memoire dadresse adr et de longueur len.
Pour une autre forme de memoire partagee, voir le chapitre sur les IPC (sur le web).
Un exemple dutilisation de mmap pour copier un fichier :
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fdin,fdout ;
struct stat statbuf ;
char *src,*dst ;
if (argc != 3)
{
fprintf(stderr,"usage : %s source destination ",argv[0]) ;
exit(-1) ;
}
if ((fdin = open(argv[1], O RDONLY)) < 0)
{
fprintf(stderr,"impossible d\ouvrir : %s en lecture ",argv[1]) ;
exit(-2) ;
}
if ((fdout = open(argv[2], O RDWR|O CREAT|O TRUNC,0666)) < 0)
{
fprintf(stderr,"impossible d\ouvrir : %s en ecriture ",argv[2]) ;
exit(-3) ;
}
if (fstat(fdin,&statbuf) < 0 )
{
fprintf(stderr,"impossible de faire stat sur %s ",argv[1]) ;
exit(-4) ;
}
if (lseek(fdout, statbuf.st size -1 , SEEK SET) == -1 )
{
fprintf(stderr,"impossible de lseek %s ",argv[2]) ;
exit(-5) ;
}
if (write(fdout,"",1) != 1)
{
fprintf(stderr,"impossible d\ecrire sur
%s ",argv[2]) ;
exit(-6) ;
}


CHAPITRE 9. LA MEMOIRE
VIRTUELLE

80

if ((src = mmap (0,statbuf.st size, PROT READ,


MAP FILE | MAP SHARED, fdin,0)) == (caddr t) -1 )
{
fprintf(stderr,"impossible de mapper
%s ",argv[1]) ;
exit(-7) ;
}
if ((dst = mmap (0,statbuf.st size, PROT READ | PROT WRITE,
MAP FILE | MAP SHARED, fdout,0)) == (caddr t) -1 )
{
fprintf(stderr,"impossible de mapper
%s ",argv[2]) ;
exit(-8) ;
}
memcpy(dst,src,statbuf.st size) ; /* copie */
exit(0) ;
}

Attention, quand vous utilisez mmap cest de la memoire, mais cest a vous de gerer lallignement.
Exemple :
char *p = map(...);
int *q = p+1; // warning
*q = 1 ; // probl`
eme dallignement

9.6

Les conseils et politiques de chargement des zones mmapp


ees

Une foit que lon decider de faire des projection en memoire avec mmap il peut etre oportin de
faire appel `a la fonction madvise qui permet de donner un conseil au syst`eme en le prevenant par
avance de la facon dont vous aller utiliser le segement de memoire. En particulier allez vous lire
le fichier sequentiellement ou de facon alleatoire. Avez vous encore besoin du fichier apr`es lecture
etc. Biensur la fonction madvise ne se limite pas aux pages mappes mais cest sur celle ci quil est
le plus facile de prendre des decisions, les autres pages etant gerer dans la pile le tas et le code
zone plus delicates et moins bien cartographiees en generale (sic).
#include <sys/mman.h>
int madvise(void *start, size_t length, int advice);
La valeur du conseil advice :
MADV NORMAL Comportement par defaut.
MADV RANDOM prevoit des acces aux pages dans un ordre aleatoire.
MADV SEQUENTIAL prevoit des acces aux pages dans un ordre sequentiel.
MADV WILLNEED prevoit un acces dans un futur proche.
MADV DONTNEED Ne prevoit pas dacces dans un futur proche. Biensur si cest une mmap
vous pouvez aussi utiliser la commande munmap.
Biensur ce ne sont que des conseils le syst`eme les utilisera si il en a la possibilite, soit parce quil
y a du temps idle (sans activite) soit parce quil profitera des lectures groupees sur disque en
realisant des lectures en avance cas sequentiel. Il peut aussi profiter de lindication DONTNEED
pour prendre des decissions dans le code de remplacement de page.

9.7. CHARGEMENT DYNAMIQUE

9.7

81

Chargement dynamique

Independement de lexistance de la memoire virtuel il est possible de gerer `a la main le code


accessible en utilisant le chargement direct (non automatique) de librairies.
Pour construire une librairie de fichier lib.c :
#include <stdio.h>
/* fonction optionelle qui permet dinitialiser la libraire */
void _init()
{
fprintf(stderr," intialisation \n");
}
/* fonction optionelle qui est appell
ee avant le d
echargement */
void _fini()
{
fprintf(stderr," d
echargement ex
ecution de _fini \n");
}
/* des fonctions sp
ecifiques a votre libraire */
int doit(int u)
{
fprintf(stderr," doit to u= %d " , u );
return u*u;
}
Compilation de la libraire, loption nostartfile pour que le compilateur ne construise pas
dexecutable.
gcc -shared -nostartfiles -o ./malib lib.c
Le fichier main qui va charger la libraire puis appeler une fonction de cette libraire.
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
int (*doit)(int);
char *error;
handle = dlopen ("./malib", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
doit = dlsym(handle, "doit");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}
printf ("%d\n", (*doit)(23));
handle = dlopen ("./malib", RTLD_LAZY); // nouveau r
ef
erencement avce le m^
eme handle
dlclose(handle); // d
ecrementation du conteur de r
ef
erence

82

CHAPITRE 9. LA MEMOIRE
VIRTUELLE

fprintf(stderr," avant le deuxieme dlclose \n");


dlclose(handle);
}

Chapitre 10

Tubes et Tubes Nomm


es
Les tubes sont un mecanisme de communication qui permet de realiser des communications
entre processus sous forme dun flot continu doctets. Les tubes sont un des elements de lagrement
dutilisation dUNIX. Cest ce mecanisme qui permet lapproche filtre de la conception sous UNIX.
Mecanisme de communication lie au syst`eme de gestion de fichier, les tubes nommes ou non
sont des paires dentrees de la table des fichiers ouverts, associees `a une inode en memoire geree
par un driver specifique. Une entree est utilisee par les processus qui ecrivent dans le tube, une
entree pour les lecteurs du tube.
Lop
eration de lecture y est destructive !
Lordre des caract`
eres en entr
ee est conserv
e en sortie (premier entr
e premier
sorti).
Un tube a une capacit
e finie : en g
en
eral le nombre dadresses directes des inodes
du SGF (ce qui peut varier de 5 `
a 80 Ko).

10.1

Les tubes ordinaires (pipe)

Un tube est materialise par deux entrees de la table des ouvertures de fichiers, une de ces
entrees est ouverte en ecriture (lentree du tube), lautre en lecture (la sortie du tube). Ces deux
entrees de la table des fichiers ouverts nous donnent le nombre de descripteurs qui pointent sur
elles. Ces valeurs peuvent etre traduites comme :
nombre de lecteurs = nombre de descripteurs associes `a lentree ouverte en lecture.On ne peut
pas ecrire dans un tube sans lecteur.
nombre d
ecrivains = nombre de descripteurs associes `a lentree ouverte en ecriture. La nullite
de ce nombre definit le comportement de la primitive read lorsque le tube est vide.

10.2

Cr
eation de tubes ordinaires

Un processus ne peut utiliser que les tubes quil a crees lui-meme par la primitive pipe ou quil
a herites de son p`ere grace `a lheritage des descripteurs `a travers fork et exec.
#include <unistd.h>
int pipe(int p[2]);
On ne peut pas manipuler les descripteurs de tubes avec les fonctions et primitives : lseek,
ioctl, tcsetattr et tcgetattr, comme il ny a pas de peripherique associe au tube (tout est
83


CHAPITRE 10. TUBES ET TUBES NOMMES

84
processus A
pipe(p)

Dans le noyau

descripteurs
inodes en mmoire
p[0]
2 0
1 rd
p[1]
1 wr

Fig. 10.1 Ouverture dun tube


processus A
fork()

ouvertures
de fichiers

inodes

p[0]
2 rd

2 0

p[1]
processus B
fils de A p[0]

2 wr

p[1]

Fig. 10.2 Heritage dun tube


fait en memoire).
Heritage dun tube dans la figure 10.2 : le processus B herite des descripteurs ouverts par son
p`ere A et donc, ici, du tube.
Dans la Figure 10.3, les descripteurs associes aux tubes sont places comme descripteurs 0 et
1 des processus A et B, cest `a dire la sortie de A et lentree de B. Les autres descripteurs sont
fermes pour assurer lunicite du nombre de lecteurs et decrivains dans le tube.

10.3. LECTURE DANS UN TUBE

85

ouvertures

processus A
dup2(1,p[1]) 1
close (p[0])
close (p[1])

1 rd
processus B
fils de A

1 wr

dup2(0,p[0])
close (p[0])
close (p[1])

Fig. 10.3 Redirection de la sortie standard de A dans le tube et de lentree standard de B dans
le tube, et fermeture des descripteurs inutiles

10.3

Lecture dans un tube

On utilise lappel syst`eme read.


int nb_lu;
nb_lu = read(p[0], buffer, TAILLE_READ);
Remarquer que la lecture se fait dans le descripteur p[0].
Comportement de lappel :
Si le tube nest pas vide et contient taille caract`eres :
lecture de nb lu = min(taille, TAILLE READ) caract`eres.
Si le tube est vide
Si le nombre decrivains est nul
alors cest la fin de fichier et nb lu est nul.
Si le nombre decrivains est non nul
Si lecture bloquante alors sommeil
Si lecture non bloquante alors en fonction de lindicateur
O NONBLOCK nb lu= -1 et errno=EAGAIN.
O NDELAY nb lu = 0.


CHAPITRE 10. TUBES ET TUBES NOMMES

86

10.4

Ecriture dans un tube

nb_ecrit = write(p[1], buf, n);


Lecriture est atomique si le nombre de caract`eres `a ecrire est inferieur `a PIPE BUF, la taille
du tube sur le syst`eme. (cf <limits.h>).
Si le nombre de lecteurs est nul
envoi du signal SIGPIPE `a lecrivain.
Sinon
Si lecriture est bloquante, il ny a retour que quand
les n caract`eres ont ete ecrits dans le tube.
Si ecriture non bloquante
Si n > PIPE BUF, retour avec un nombre inferieur `a n
eventuellement -1 !
Si n PIPE BUF
et si n emplacements libres, ecriture nb ecrit = n
sinon retour -1 ou 0.
Comment rendre un read ou write non bloquant ? en utilisant fctnl sur le descripteur du tube.
F SETFL fixe de nouveaux attributs pour le descripteur de fichier fd. Les nouveaux attributs sont
contenus dans arg. Seuls O APPEND, O NONBLOCK et O ASYNC peuvent etre modifies ainsi,
les autres attributs ne sont pas affectes.

10.5

Interblocage avec des tubes

Un meme processus a deux acc`es `a un tube, un acc`es en lecture, un acc`es en ecriture et essaie
de lire sur le tube vide en mode bloquant le processus est bloque indefiniment dans la primitive
read.
Avec deux processus :
deux tubes entre les deux processus, tous les deux bloques en lecture ou tous les deux bloques en
ecriture, tous les deux en attente dune action de lautre processus.

10.6

Les tubes nomm


es

Les tube nommes sont des tubes (pipe) qui existent dans le syst`eme de fichiers, et donc peuvent
etre ouverts grace `a une reference.
Il faut prealablement creer le tube nomme dans le syst`eme de fichiers, grace `a la primitive mknod
(mkfifo), avant de pouvoir louvrir avec la primitive open.
int mknod(reference, mode | S_IFIFO,0);
mode est construit comme le param`etre de mode de la fonction open.
En POSIX, un appel simplifie :
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *ref, mode_t mode);
On peut creer des FIFOs `a partir du shell grace `a
mkfifo [-p] [-m mode] ref ...
Louverture dun tube nomme se fait exclusivement soit en mode O RDONLY soit en mode
O WRONLY, ainsi le nombre de lecteur et decrivain peut etre comptabilise.


10.6. LES TUBES NOMMES

10.6.1

87

Ouverture et synchronisation des ouvertures de tubes nomm


es

Il y a automatiquement synchronisation des processus qui ouvrent en mode bloquant un tube nomm
e.
Loperation douverture sur un tube nomme est bloquante en lecture.
Le processus attend quun autre processus ouvre la fifo en ecriture.
Louverture en ecriture est aussi bloquante, avec attente quun autre processus ouvre la fifo en
lecture. Louverture bloquante se termine de facons synchrone pour les deux processus.
Ainsi un unique processus ne peut ouvrire `a la fois en lecture et ecriture un tube nomme.
En mode non bloquant (O NONBLOCK, O NDELAY), seule louverture en lecture reussit
dans tous les cas. Louverture en ecriture en mode non bloquant dun tube nomme ne fonctionne
que si un autre processus a dej`a ouvert en mode non bloquant le tube en lecture, ou bien quil
est bloque dans lappel dune ouverture en lecture en mode bloquant. Ceci pour eviter que le
processus qui vient douvrir le tube nomme, necrive dans le tube avant quil ny ait de lecteur
(quun processus ait ouvert le tube en lecture) et ce qui engendrerait un signal SIGPIPE (tube
detruit), ce qui nest pas vrai car le tube na pas encore ete utilise.

10.6.2

Suppression dun tube nomm


e

Lutilisation de rm ou unlink ne fait que detruire la reference, le tube nest reellement detruit
que lorsque son compteur de liens internes et externes est nul.
Une fois que tous les liens par reference sont detruits, le tube nomme devient un tube ordinaire.

10.6.3

les appels popen et pclose

Une interface plus facile pour lancer un coprocessus est propose avec les primitives popen et
pclose.

88

CHAPITRE 10. TUBES ET TUBES NOMMES

Chapitre 11

Les signaux
Les signaux sont un mecanisme asynchrone de communication inter-processus.
Intuitivement, il sont comparables `a des sonneries, les differentes sonneries indiquant des ev`enements
differents. Les signaux sont envoyes `a un ou plusieurs processus. Ce signal est en general associe
`a un ev`enement.
Peu portables entre BSD et ATT, ils deviennent plus commodes `a utiliser et portables avec
la norme POSIX qui utilise la notion utile de vecteur de signaux et qui fournit un mecanisme de
masquage automatique pendant les procedures de traitement (comme BSD).
Un signal est envoye `a un processus en utilisant lappel syst`eme :
kill(int pid, int signal);
signal est un numero compris entre 1 et NSIG (defini dans <signal.h>) et pid le numero du
processus.
Le processus vise recoit le signal sous forme dun drapeau positionne dans son bloc de controle.
Le processus est interrompu et realise eventuellement un traitement de ce signal.
On peut considerer les signaux comme des interruptions logicielles, ils interrompent le flot normal dun processus mais ne sont pas traites de facon synchrone comme les interruptions materielles.

11.0.4

Provenance des signaux

Certains signaux peuvent etre lances `a partir dun terminal grace aux caract`eres speciaux
comme intr, quit dont la frappe est transformee en lenvoi des signaux SIGINT et SIGQUIT.
Dautres sont d
us `a des causes internes au processus, par exemple : SIGSEGV qui est envoye en cas
derreur dadressage, SIGFPE division par zero (Floating Point Exception).
Enfin certains sont d
us `a des ev`enements comme la deconnection de la ligne (le terminal)
utilise : si le processus leader dun groupe de processus est deconnecte, il envoie `a lensemble des
processus de son groupe le signal SIGHUP (Hangup = raccrocher).

11.0.5

Gestion interne des signaux

Cest dans le bloc de controle (BCP) de chaque processus que lon trouve la table de gestion
des signaux (attention, sous System V < V.4, la table de gestion des processus est dans la zone
u, cest `a dire dans lespace-memoire du processus).
Cette table contient, pour chaque signal defini sur la machine, une structure sigvec suivante :
{
bit pendant;
89

90

CHAPITRE 11. LES SIGNAUX


void (*traitement)(int);
}

En BSD et POSIX, on a un champ supplementaire : bit masque ;


Le drapeau pendant indique que le processus a recu un signal, mais na pas encore eu loccasion
de prendre en compte ce signal.
Remarque : comme pendant est un unique bit, si un processus recoit plusieurs fois le meme
signal avant de le prendre en compte, alors il ny a pas memorisation des receptions successives,
un seul traitement sera donc realise.
Comme nous lavons vu dans le graphe detat des processus, la prise en compte des signaux
se fait au passage de letat actif noyau `a letat actif utilisateur. Pourquoi la prise en compte de
signaux se fait-elle uniquement `a ce moment l`a ?
Parce que
Une sauvegarde de la pile utilisateur et du contexte a ete effectuee quand le processus est passe en
mode noyau. Il nest pas necessaire de faire un nouveau changement de contexte. Il est facile pour
traiter le signal de realiser immediatement une nouvelle augmentation de pile pour le traitement
du signal, de plus la pile noyau est vide (remarque : en POSIX, il devient possible de creer une
pile speciale pour les fonctions de traitement de signaux).
Lappel `a la fonction de traitement est realise de facon `a ce quau retour de la fonction, le
processus continue son execution normalement en poursuivant ce qui etait en cours de realisation
avant la reception du signal. Si lon veut que le processus se poursuive dans un autre contexte (de
pile), il doit gerer lui-meme la restauration de ce contexte.
La primitive longjmp peut permettre de realiser des changements de contexte interne au processus, grace `a un desempilement brutal.
Pendant ce changement detat, la table de gestion des signaux du processus est testee pour la
presence dun signal recu mais non traite (cest un simple vecteur de bit pour le bit pendant, et
donc testable en une seule instruction, ceci doit etre fait rapidement comme le test de reception
dun signal est souvent realise).
Si un signal a ete recu ( et quil nest pas masque), alors la fonction de traitement associee est
realisee. Le masquage permet au processus de temporiser la mise en euvre du traitement.

11.0.6

Lenvoi de signaux : la primitive kill

kill(int pid, int sig)


Il y a NSIG signaux sur une machine, declares dans le fichier /usr/include/signal.h.
La valeur de pid indique le PID du processus auquel le signal est envoye.
0 Tous les processus du groupe du processus realisant lappel kill
1 En syst`eme V.4 tous les processus du syst`eme sauf 0 et 1
pid positif le processus du pid indique
pid n
egatif tous les processus du groupe | pid |
le param`etre sig est interprete comme un signal si sig [0-NSIG], ou comme une demande
dinformation si sig = 0 (suis-je autorise `a envoyer un signal `a ce(s) processus ?). Comme un
param`etre errone sinon.
La fonction raise(int signal) est un raccourci pour kill(getpid(), signal), le processus
senvoie `a lui-meme un signal.
Remarquez que lon peut reecrire kill(0, signal) par kill(-getpid(), signal). Rappel :
les PID sont toujours positifs.

AVEC LA FONCTION SIGNAL


11.1. LA GESTION SIMPLIFIEE

11.1

91

La gestion simplifi
ee avec la fonction signal

ZZZ : cette section est historique, utiliser la norme POSIX decrite plus loin.
ancien C : (*signal(sig, func))()
int sig;
int (*func)();
ANSI C :

void (*signal(int sig, void (*action)(int)))(int);

La fonction signal permet de specifier ou de connatre le comportement du processus `a la


reception dun signal donne, il faut donner en param`etre `a la fonction le numero du signal sig
que lon veut detourner et la fonction de traitement action `a realiser `a la reception du signal.
Trois possibilites pour ce param`etre action
SIG DFL Comportement par defaut, plusieurs possibilites
exit Le processus se termine (avec si possible la realisation dun core)
ignore Le processus ignore le signal
pause Suspension du processus
continue Reprise du processus si il etait suspendu.
SIG IGN le signal est ignore.
Remarque : les signaux SIGKILL, SIGSTOP ne peuvent pas etre ignores.
HANDLER Une fonction de votre cru.

11.1.1

Un exemple

Exemple pour rendre un programme insensible `a la frappe du caract`ere de controle intr sur le
terminal de controle du processus.
void got_the_blody_signal(int n) {
signal(SIGINT, got_the_blody_signal);
printf(" gotcha!! your (%d) signal is useless \n");
}
main() {
signal(SIGINT, got_the_blody_signal);
printf(" kill me now !! \n");
for(;;);
}
une version plus elegante et plus fiable :
signal(SIGINT, SIG_IGN);

11.2

Probl`
emes de la gestion de signaux ATT

Les phenom`enes suivants sont decrits comme des probl`emes mais la norme POSIX permet den
conserver certains, mais fournit aussi les moyens de les eviter.
1. un signal est repositionne `a sa valeur par defaut au debut de son traitement (handler).
#include <signal.h>
traitement() {
printf("PID %d en a capture un \n", getpid());

92

CHAPITRE 11. LES SIGNAUX


->

reception du deuxieme signal, realisation dun exit


signal(SIGINT, traitement);

}
main() {
int ppid;
signal(SIGINT,traitement);
if (fork()==0)
{/* attendre que pere ait realise son nice() */
sleep(5);
ppid = getppid(); /* numero de pere */
for(;;)
if (kill(ppid,SIGINT) == -1)
exit();
}
/* pere ralenti pour un conflit plus sur */
nice(10);
for(;;) pause(); <- reception du premier signal
/* pause cest mieux quune attente active */
}
Si lon cherche `a corriger ce defaut, on repositionne la fonction traitement au debut du
traitement du signal. Ceci risque de nous placer dans une situation de depassement de pile :
en effet, dans le programme precedent, nous pouvons imaginer que le p`ere peut recevoir
un nombre de signaux arbitrairement grand pendant le traitement dun seul signal, do`
u
une explosion assuree de la pile (il suffit en effet que chaque empilement de la fonction
traitement soit interrompu par un signal)
traitement(){
signal(SIGINT,traitement);
->
signal SIGINT
printf("PID %d en a capture un \n",getpid());
}
On peut aussi ignorer les signaux pendant leur traitement, mais cela peut creer des pertes
de reception.
Enfin, la solution BSD/POSIX o`
u lon peut bloquer et debloquer la reception de signaux `a
laide du vecteur de masquage (sans pour autant nous assurer de la reception de tous les
signaux ! !). De plus, en POSIX, le traitement dun signal comporte une clause de blocage
automatique. On indique quels signaux doivent etre bloques pendant le traitement du signal,
grace `a un vecteur de masquage dans la structure sigaction.
Ceci est le comportement naturel de gestion des interruptions materielles : on bloque les
interruptions de priorite inferieure pendant le traitement dun interruption.
2. Seconde anomalie des signaux sous System V < V4 : certains appels syst`emes peuvent etre
interrompus et dans ce cas la valeur de retour de lappel syst`eme est -1 (echec). Il faudrait,
pour realiser correctement le mod`ele dune interruption logicielle, relancer lappel syst`eme en
fin de traitement du signal. (Sous BSD ou POSIX, il est possible de choisir le comportement
en cas dinterruption dun appel syst`eme grace `a la fonction siginterrupt, c-a-d relancer
ou non lappel syst`eme, un appel `a read, par exemple, peut facilement etre interrompu si il
necessite un acc`es disque).
3. Troisi`eme anomalie des signaux sous ATT : si un signal est ignore par un processus endormi,
celui-ci sera reveille par le syst`eme uniquement pour apprendre quil ignore le signal et doit
donc etre endormi de nouveau. Cette perte de temps est d
ue au fait que le vecteur des
signaux est dans la zone u et non pas dans le bloc de controle du processus.

`
11.2. PROBLEMES
DE LA GESTION DE SIGNAUX ATT

11.2.1

93

Le signal SIGCHLD

Le signal SIGCHLD (anciennement SIGCLD) est un signal utilise pour reveiller un processus
dont un des fils vient de mourir. Cest pourquoi il est traite differemment des autres signaux. La
reaction `a la reception dun signal SIGCHLD est de repositionner le bit pendant `a zero, et dignorer le signal, mais le processus a quand meme ete reveille pour cela. Leffet dun signal SIGCHLD
est donc uniquement de reveiller un processus endormi en priorite interruptible.
Si le processus capture les signaux SIGCHLD, il invoque alors la procedure de traitement
definie par lutilisateur comme il le fait pour les autres signaux, ceci en plus du traitement par
defaut.
Le traitement normal est lie `a la primitive wait qui permet de recuperer la valeur de retour
(exit status) dun processus fils. En effet, la primitive wait est bloquante et cest la reception du
signal qui va reveiller le processus, et permettre la fin de lexecution de la primitive wait.
Un des probl`emes de la gestion de signaux System V est le fait que le signal SIGCHLD est
recu (raised) au moment de la pose dune fonction de traitement.
Ces proprietes du signal SIGCHLD peuvent induire un bon nombre derreurs.
Par exemple, dans le programme suivant nous positionnons une fonction de traitement dans
laquelle nous repositionnons la fonction de traitement. Comme sous System V, le comportement
par defaut est repositionne pendant le traitement dun signal. Or le signal est leve `a la pose de la
fonction de traitement, do`
u une explosion de la pile.
#include <stdio.h>
#include <unistd.h> /* ancienne norme */
#include <signal.h>
void hand(int sig) {
signal(sig, hand);
printf("message qui nest pas affiche\n");
}
main() {
if (fork()) { exit(0); /* creation dun zombi */ }
signal(SIGCHLD, hand);
printf("ce printf nest pas execute\n");
}
Sur les HP, un message derreur vous informe que la pile est pleine : stack growth failure.
Deuxi`eme exemple :
#include <signal.h>
#include <sys/wait.h>
int pid, status;
void hand(int sig) {
printf(" Entree dans le handler \n");
system("ps -l");
/* affichage avec etat zombi du fils */
if ((pid = wait(&status)) == -1) /* suppression du fils zombi */
{
perror("wait handler ");
return ;

94

CHAPITRE 11. LES SIGNAUX


}
printf(" wait handler
return;

pid: %d

status %d \n", pid, status);

}
main() {
signal(SIGCHLD,hand); /* installation du handler */
if (fork() == 0)
{
/* dans le fils */
sleep(5);
exit(2);
}
/* dans le pere */
if ((pid = wait(&status)) == -1) /* attente de terminaison du fils */
{
perror("wait main ");
return ;
}
printf(" wait main pid: %d
status %d \n", pid, status);
}
resultat :
Entree dans le handler
F S UID
PID PPID C PRI NI
ADDR
1 S 121 6792 6667 0 158 20 81ac180
1 S 121 6667 6666 0 168 20 81ac700
1 Z 121 6793 6792 0 178 20 81bda80
1 S 121 6794 6792 0 158 20 81ac140
1 R 121 6795 6794 4 179 20 81bd000
wait handler pid: 6793
status 512
wait main: Interrupted system call

SZ WCHAN
TTY TIME COMD
6 49f5fc ttys1 0:00 sigchld
128 7ffe6000 ttys1 0:00 tcsh
0
ttys1 0:00 sigchld
78 4a4774 ttys1 0:00 sh
43
ttys1 0:00 ps
(2 * 256)

A la mort du fils, Le p`ere recoit le signal SIGCHLD (alors quil etait dans le wait du main),
puis le handler est execute, et ps affiche bien le fils zombi. Ensuite cest le wait du handler qui
prend en compte la terminaison du fils. Au retour du handler, lappel a wait du main retourne -1,
puisquil avait ete interrompu par SIGCHLD.

11.3

Manipulation de la pile dex


ecution

La primitive
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int indicateur);
sauvegarde un environnement dexecution, cest `a dire un etat de la pile, et si indicateur est
non nul, sauvegarde le masque de signaux courant. La valeur de retour de cette fonction est zero
quand on fait une sauvegarde, et sinon depend du param`etre valeur de la fonction siglongjmp.
int siglongjmp(sigjmp_buf env, int valeur);
La primitive siglongjmp permet de reprendre lexecution `a lendroit sauvegarde par sigsetjmp
dans la variable env.
Deux remarques : env doit avoir ete initialise par sigsetjmp, les valeurs de pile placees audessus de lenvironnement repris sont perdues. Lenvironnement de pile doit encore exister dans
la pile au moment de lappel, sinon le resultat est indetermine.

11.4. QUELQUES EXEMPLES DUTILISATION

11.4

95

Quelques exemples dutilisation

/*un exemple de signaux BSD */


#include <stdio.h>
#include <signal.h>
void gots1(int n)
{ raise(SIGUSR2); printf("got
void gots2(int n)
{ printf("got s2(%d) ", n); }

s1(%d) ", n); }

main()
{
int mask ;
struct sigvec s1,s2;
s1.sv_handler = gots1;
s1.sv_mask = sigmask(SIGUSR1);
sigvec(SIGUSR1, &s1, NULL);
s2.sv_handler = gots2;
s2.sv_mask = sigmask(SIGUSR2);
sigvec(SIGUSR2, &s2, NULL);
printf(" sans masquage de SIGUSR2: ")
raise(SIGUSR1);
printf(" \n avec masquage de SIGUSR2: " );
s1.sv_mask = sigmask(SIGUSR2);
sigvec(SIGUSR1, &s1, NULL);
raise(SIGUSR1);
}
Nous donne les affichages suivant :
sans masquage de SIGUSR2: got
avec masquage de SIGUSR2: got

s2(31) got
s1(30) got

s1(30)
s2(31)

Sous BSD, pas de fonction de manipulation propre des groupes de signaux (on regroupe les
signaux par des conjonctions de masques).
Le probl`eme de linterruption des appels syst`eme par les signaux est corrige par la fonction :
int

siginterrupt(int sig, int flag);

le drapeau flag prend comme valeur 0 ou 1, ce qui signifie que les appels syst`emes interrompus
par un signal seront :
soit relances avec les memes param`etres.
soit retourneront la valeur -1, et dans ce cas la valeur de errno est positionnee `a EINTR.
Certaines fonctions comme readdir utilisent des variables statiques, ces fonctions sont dites
non reentrantes. Il faut eviter dappeler ce type de fonctions dans un handler de signal, dans le cas
o`
u lon fait dej`a appel `a la fonction dans le reste du processus. De la meme facon la variable errno
est unique. Si celle-ci est positionnee dans le main mais quun signal arrive avant son utilisation,
une primitive appelee dans le handler peut en changer la valeur ! (ce probl`eme de reentrance sera
vu plus en detail avec les processus multi-activites).

11.4.1

Lappel pause

Fonction de mise en attente de reception dun signal :

96

CHAPITRE 11. LES SIGNAUX

pause(void);
cette primitive est le standard UNIX dattente de la reception dun signal quelconque, BSD
propose la primitive suivante :
sigpause(int sigmask)
qui permet lattente dun groupe specifique de signaux, attention les signaux du masque sont
debloques (c.f. sigprocmask).

11.5

La norme POSIX

La norme POSIX ne definit pas le comportement dinterruption des appels syst`emes, il faut le
specifier dans la structure de traitement du signal.

Les ensembles de signaux La norme POSIX introduit les ensembles de signaux :


ces ensembles de signaux permettent de depasser la contrainte classique qui veut que le nombre
de signaux soit inferieur ou egal au nombre de bits des entiers de la machine. Dautre part, des
fonctions de manipulation de ces ensembles sont fournies et permettent de definir simplement des
masques. Ces ensembles de signaux sont du type sigset t et sont manipulables grace aux fonctions
suivantes :
int
int
int
int

sigemptyset(sigset_t *ens)
sigfillset(sigset_t *ens)
sigaddset(sigset_t *ens, int sig)
sigdelset(sigset_t *ens, int sig)

/* raz */
/* ens = { 1,2,...,NSIG} */
/* ens = ens + {sig} */
/* ens = ens - {sig } */

Ces fonctions retournent -1 en cas dechec et 0 sinon.


int sigismember(sigset_t *ens, int sig);

/* sig appartient `
a ens ?*/

retourne vrai si le signal appartient `a lensemble.

11.5.1

Le blocage des signaux

La fonction suivante permet de manipuler le masque de signaux du processus :


#include <signal.h>
int sigprocmask(int op, const sigset_t

*nouv, sigset_t *anc);

Loperation op :
SIG SETMASK affectation du nouveau masque, recuperation de la valeur de lancien masque.
SIG BLOCK union des deux ensembles nouv et anc
SIG UNBLOCK soustraction anc - nouv
On peut savoir si un signal est pendant et donc bloque grace `a la fonction :
int sigpending(sigset_t *ens);
retourne -1 en cas dechec et 0 sinon et lensemble des signaux pendants est stocke `a ladresse
ens.

11.5. LA NORME POSIX

11.5.2

97

sigaction

La structure sigaction decrit le comportement utilise pour le traitement dun signal :


struct sigaction {
void (*sa_handler) ();
sigset_t sa_mask;
int sa_flags;}
sa handler fonction de traitement (ou SIG DFL et SIG IGN)
sa mask ensemble de signaux supplementaires `a bloquer pendant le traitement
sa flags differentes options
SA NOCLDSTOP le signal SIGCHLD nest pas envoye `a un processus lorsque lun
de ses fils est stoppe.
SA RESETHAND simulation de lancienne methode de gestion des signaux, pas de
blocage du signal pendant le handler et repositionnement du handler par defaut
au lancement du handler.
SA RESTART les appels syst`eme interrompus par un signal capte sont relances au
lieu de renvoyer -1. Cet indicateur joue le role de lappel siginterrupt(sig,0)
des versions BSD.
SA NOCLDWAIT si le signal est SIGCHLD, ses fils qui se terminent ne deviennent
pas zombis. Cet indicateur correspond au comportement des processus pour SIG IGN
dans les versions ATT.
Le positionnement du comportement de reception dun signal se fait par la primitive sigaction.
Linstallation dune fonction de traitement du signal SIGCHLD peut avoir pour effet denvoyer un
signal au processus, ceci dans le cas o`
u le processus a des fils zombis, cest toujours le probl`eme
lie `a ce signal qui na pas le meme comportement que les autres signaux.
Un handler positionne par sigaction reste jusqu`a ce quun autre handler soit positionne, `a la
difference des versions ATT o`
u le handler par defaut est repositionne automatiquement au debut
du traitement du signal.
#include <signal.h>
int sigaction(int sig,
const struct sigaction *paction,
struct sigaction
*paction_precedente);
Cette fonction realise soit une demande dinformation. Si le pointeur paction est null, on obtient la structure sigaction courante. Sinon cest une demande de modification du comportement.

11.5.3

Lattente dun signal

En plus de lappel pause, on trouve sous POSIX lappel int sigsuspend(const sigset t
*ens) ; qui permet de realiser de facons atomique les actions suivantes :
linstallation du masque de blocage defini par ens (qui sera repositionne `a sa valeur dorigine)
`a la fin de lappel,
mise en attente de la reception dun signal non bloque.

98

CHAPITRE 11. LES SIGNAUX

Chapitre 12

Les verrous de fichiers


Mecanismes de controle dacc`es concurrents `a un fichier, les verrous sont dune grande utilite
dans les applications de gestion et dans lelaboration de bases de donnees partagees.
Les verrous sont rattaches aux inuds. Ainsi toutes les ouvertures dun meme fichier, et `a fortiori
tous les descripteurs sur ces ouvertures, voient le verrou.
La protection realisee par le verrou a donc lieu sur le fichier physique.
Un verrou est la propri
et
e dun seul processus, et seul le processus proprietaire du verrou peut le
modifier ou lenlever, attention le verrou ne prot`ege pas contre les acc`es du processus proprietaire
(attention `a une situation multi-thread).

12.1

Caract
eristiques dun verrou

Les verrous sont definis par deux caracteristiques :


La port
ee : Ensemble des positions du fichier auxquelles le verrou sapplique. Cet ensemble
est un intervalle, soit une portion du fichier
[position1, position2]
soit jusqu`a la fin du fichier
[position1, fin de fichier[
dans ce dernier cas si le fichier augmente, le verrou prot`ege les nouvelles positions.
Le type : qui decrit les possibilites de cohabitation des differents verrous.
F RDLCK partage, plusieurs verrous de ce type peuvent avoir des portees non disjointes, par
exemple les verrous [80, 150] et [100, 123]
F WRLCK exclusif, pas de cohabitation possible avec un autre verrou quelque soit son type.

12.2

Le mode op
eratoire des verrous

Le mode operatoire joue sur le comportement des primitives read et write. Les verrous dun
fichier sont soit consultatifs, soit imp
eratifs (NON-POSIX) 1 .
Dans le premier mode advisory (consultatif), la presence dun verrou nest testee qu`a la pose
dun verrou, la pose sera refusee sil existe un verrou de portee non disjointe et que lun des deux
verrous est exclusif.
1 En effet le mode imp
eratif nest pas POSIX, et donc par d
efaut nest pas mise en oeuvre sur les disque sous
linux.

99

100

CHAPITRE 12. LES VERROUS DE FICHIERS

Dans le second mode mandatory, la presence de verrous est testee pour la pose mais aussi pour
les appels syst`emes read et write.
Dans le mode consultatif, les verrous nont deffet que sur les processus jouant effectivement
le jeu, cest-`a-dire, posant des verrous sur les zones du fichiers sur lesquels ils veulent realiser une
lecture (verrou partage) ou une ecriture (verrou exclusif).
Dans le mode imperatif, les verrous ont un impact sur les lectures/ecritures de tous les processus :
sur les verrous de type partage (F RDLCK), toute tentative decriture (appel syst`eme write)
par un autre processus est bloquee ;
sur les verrous de type exclusif (F WRLCK), toute tentative de lecture ou decriture (read
et write) par un autre processus est bloquee.
Pour rendre lutilisation imperative il faut sous linux monter le disque avec loption -o mand.
Puis il faut utiliser la commande chmod pour positionner le SETGID bit, soit chmod g+s fichier
en shell soit la meme chose en C : si lon a le descripteur d dune ouverture sur le fichier
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
...
struct stat buf
fstat(d, &buf);
fchmod(d,buf.st_mode |

S_ISGID);

meme chose avec stat et chmod si lon la reference du fichier.

12.3

Manipulation des verrous

La structure de verrou flock :


struct flock
short
short
off_t
off_t
pid_t
};

{
l_type;
l_whence;
l_start;
l_len;
l_pid;

/*
/*
/*
/*
/*

F_RDLCK, F_WRLCK,F_UNLCK */
SEEK_SET,SEEK_CUR,SEEK_END */
position relative a l_whence */
longueur de lintervalle */
PID du processus propri
etaire */

le champ l type
F RDLCK verrou partage
F WRLCK verrou exclusif
F UNLCK deverrouillage
Les manipulations de verrous se font avec la primitive fcntl, cest-`a-dire par le biais dun
descripteur. Pour poser un verrou partage, ce descripteur doit pointer sur une ouverture en lecture.
De meme, il faut un descripteur sur une ouverture en ecriture pour un verrou de type exclusif
.
Pour decrire la portee du verrou que lon veut poser, on utilise la meme syntaxe que pour la
primitive lseek, le debut de lintervalle est whence+l start :
l whence = SEEK SET whence = 0
l whence = SEEK CUR whence = offset courrant
l whence = SEEK END whence = taille du fichier.

12.4. UTILISATION DE FCNTL POUR MANIPULER LES VERROUS

101

La longueur du verrou est definie par le champ l len. Si cette valeur est nulle, le verrou va
jusqu`a la fin du fichier (meme si le processus change cette fin). Remarque : il est possible de poser
un verrou dont la portee est superieure `a la taille du fichier.
Le champ l pid contient le pid du processus proprietaire du verrou, ce champ est rempli par
fcntl dans le cas dun appel consultatif (F GETLK).

12.4

Utilisation de fcntl pour manipuler les verrous


#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int desc, int commande, struct flock *verrou);

fcntl retourne 0 en cas de succ`es, ou -1 en cas dechec.


Trois commandes possibles :
F SETLK pose non bloquante
si il existe un verrou incompatible, errno a pour valeur EAGAIN
si lon na pas les droits dacc`es sur le fichier pour le type de verrou demande, alors
errno a pour valeur EACCES ;
si la pose du verrou cree une situation dinterblocage, alors errno a pour valeur EDEADLK.
F SETLKW pose bloquante (Wait)
succ`es immediat si il ny a pas de verrou incompatible, ou succ`es une fois les verrous
incompatibles leves.
si lappel est interrompu, errno a pour valeur EINTR
si une situation dinterblocage est detectee, alors errno a pour valeur EDEADLK.
F GETLK Test dexistence dun verrou incompatible avec le verrou passe en param`etre (retour
-1 sur des param`etres incorrects)
si il existe un tel verrou incompatible, alors la structure flock passee en param`etre est
remplie avec les valeurs de ce verrou incompatible. Le champ l pid indique alors lidentite
du processus proprietaire de ce verrou incompatible.
sinon, la structure flock reste inchangee excepte le champ type qui contient F UNLCK.
Attention, apr`es un test dexistence qui nous informe de labsence de verrou incompatible, nous
ne sommes pas assure quau prochain appel la pose de ce verrou soit possible, en effet un autre
processus a peut-etre pose un verrou incompatible entre-temps (cf. interblocages chapitre 13).

102

CHAPITRE 12. LES VERROUS DE FICHIERS

Chapitre 13

Algorithmes Distribu
es &
Interblocages
Ce chapitre introduit les probl`emes lies `a la gestion de processus concurrents. Le probl`eme
`a resoudre est le partage de ressources entre differents processus asynchrones. Les I.P.C. et les
verrous sont deux types doutils permettant le partage asynchrone de ressources entre processus.

13.1

exemples

13.1.1

Les m
efaits des acc`
es concurrents

Lexemple le plus simple est une variable enti`ere partagee par deux processus ou threads, ou
bien manipule par une fonction asyncrone comme un handler de signal. Supposont que lon definise
deux fonctions de manipulation de la variable :
int getValue();
void setValue(int );
Pour incrementer la variable, il suffit dexecuter setValue(getValue()+1) ; mais decomposont
en int tmp=getValue() ; setValue(tmp+1) ; ce qui ne change pas grand chose tmp etant simplement allouee sur la pile dans le premier cas. Regardont lexecution suivant du code par deux
thread :
int tmp1=getValue();
| int tmp2= getValue();
setValue(tmp1+1);
| setValue(tmp2+1);
Que cest il passe ?
la variable na ete incrementee quune fois !
Le cas dun signal le code c de prog
#include <stdio.h>
#include <signal.h>
int nbi; // nbre dincrementation acc`
es atomique
int partage; // nbr dincr
ementation acc`
es non atomique
int getValue() { return partage; }
103

& INTERBLOCAGES
CHAPITRE 13. ALGORITHMES DISTRIBUES

104

void setValue(int x) { partage = x; }


void handler(int s)
{
int tmp=getValue();
setValue(tmp+1);
nbi++;
}

int
main(int c, char *argv[])
{
struct sigaction sig;
long diff = 0;
sig.sa_handler= handler;
sig.sa_flags = 0;
sigaction(SIGUSR1, &sig, NULL);
fprintf(stderr,"sigusr1= %d\n",SIGUSR1);
fprintf(stderr,"%d %d\n", nbi,partage);
for(;;)
{
int tmp=getValue();
setValue(tmp+1);
nbi++;
if ((partage != nbi) && (diff!= nbi-partage))
{ diff = nbi-partage; fprintf(stderr,"%d\n", nbi-partage); }
}
}

13.1.2

Exclusion mutuelle

Probl`eme : il y a une rivi`ere que lon peut traverser par un gue fait de pierre alignees, o`
u
il nest pas possible de se croiser, et il nest pas possible de faire demi-tour. Comment doit-t-on
organiser le passage ?
Solutions :
1. regarder avant de traverser
2. si deux personnes arrivent en meme temps sur chaque rive,
si elles avancent en meme temps interblocage
si elles attendent en meme temps interblocage
3. Un rem`ede : un cote prioritaire famine. En effet si le cote OUEST est prioritaire et quun
flot continu de personnes arrive de ce cote, les personnes `a lEST sont bloquees indefiniment.
4. Une solution : alterner les priorites.
Pour des ressources syst`eme comme les fichiers, le partage nest pas gere par le SGF. Il faut
donc un mecanisme de partage : les verrous, qui permettent un partage dynamique et partiel (portions de fichiers). Pour un partage entre utilisateurs, on utilise plutot des outils comme SCCS, RCS.

13.2. MODE DUTILISATION DES RESSOURCES PAR UN PROCESSUS.

13.2

105

Mode dutilisation des ressources par un processus.

Formalisons les operations realisables sur une ressource.


requete : demande bloquante de ressources
utilisation : lecture/ecriture sur la zone verrouillee
liberation : verrou L-type

13.3

D
efinition de linterblocage (deadlock)

Un ensemble de processus est en interblocage si et seulement si tout processus de lensemble


est en attente dun ev`enement qui ne peut etre realise que par un autre processus de lensemble.
Exemple :
Le processus A poss`ede un verrou de portee [0,400] sur un fichier f, et demande un verrou
de portee [800,1000] sur ce meme fichier, alors quun processus B poss`ede un verrou de portee
[600,900] sur le fichier f et demande un verrou de portee [0,33] sur f. Les deux processus sont en
interblocage. Dans le cas de la pose de verrous sous UNIX, il y a detection de cet interblocage et
la commande fcntl echoue.

13.4

Quatre conditions n
ecessaires `
a linterblocage.

Les conditions suivantes sont n


ecessaires pour avoir une possibilite dinterblocage.
Exclusion mutuelle les ressources ne sont pas partageables, un seul processus `a la fois peut
utiliser la ressource.
Possession & attente il doit exister un processus qui utilise une ressource et qui est en attente
sur une requete.
Sans pr
eemption les ressources ne sont pas preemptibles cest-`a-dire que les liberations sont
faites volontairement par les processus. On ne peut pas forcer un processus `a rendre une
ressource. (Contre exemple : le CPU sous Unix est preemptible)
Attente circulaire il doit exister un ensemble de processus Pi tel que Pi attend une ressource
possedee par Pi+1 .
Les quatre conditions sont necessaires pour quune situation dinterblocage ait lieu.
Exercice : montrer que pour les verrous, les quatre conditions tiennent.
Exercice : montrer que si lune des condition nest pas verifiee alors il ne peut y avoir dinterblocage.

13.5

Les graphes dallocation de ressources

Les graphes dallocation de ressources permettent de decrire simplement les probl`emes dinterblocage.
G = (N,T) N = P U R
P : ensemble des processus
R : ensemble des ressources
T est inclus dans RXP U PXR
Soit le couple (x,y) appartenant `a T,
si (x,y) appartient `a RXP, cela signifie que la ressource x est utilisee par le processus y.
si (x,y) appartient `a PXR, cela signifie que le processus x demande la ressource y.

106

& INTERBLOCAGES
CHAPITRE 13. ALGORITHMES DISTRIBUES

Chapitre 14

S
ecurit
e et S
uret
e de
fonctionnement
Comme pour une habitation il faut que votre syst`eme offre deux chose importante, dune part
que la vie dans lhabitation soit sur, pas de risque pour les utilisateurs ni pour les elements materiel.
Feux , indondation, enfermement, tremblement de terre etc. Cest la su
rete de fonctionnement.

Dautre par lhabitation est protegee ainsi que ses habitants contre des attaques plus ou moins
malveillantes. La porte du jardin est fermee pour eviter que des animaux deteriore le jardin. Lhabitation est munie de systeme de verouillage pour se proteger contre un cambriollage. Cest la
securite.

La s
urete de fonctionnement est un element stategique qui doit etre gerer par la direction
informatique en fonction de contraintes operationnelles. La securite est le probl`eme de tout le
monde. Pour que la securite fonctionne, il faut que toutes les personnes ayant un acc`es `a une
ressource soient conscient du degre de securite associe `a la ressource. La strategie de securite doit
bien sur etre definie par la direction informatique mais cest un travail collectif (installation dune
serure na pas deffet si tout le monde laisse la porte ouverte).

14.1

Protection des syst`


emes dexploitation

Securiser un syst`eme, cest proteger ce syst`eme contre un fonctionnement imprevu ou defectueux.


Il peut sagir :
derreurs de programmation (dun utilisateur, ou du syst`eme lui-meme) qui se propagent au
syst`eme (du fait de controles insuffisants ou mal effectues).
dun mauvais fonctionnement du materiel.
enfin, dun operateur, concepteur ou realisateur malveillant ou peu scrupuleux (quand il
sagit dinformations financi`eres !).
Le recensement des operations frauduleuses aux Etats-Unis au cours dune annee a donne 339 cas
de fraude, pour un co
ut dun milliard de francs.
La protection des sites a egalement un co
ut tr`es important (temps et complexite), do`
u des
syst`emes de protection qui resultaient dun compromis co
ut/efficacite.
Le co
ut en ressources de la protection etant reste stationnaire, les syst`emes et les machines
actuelles plus rapides ont rendu ce co
ut moins prohibitif.
Lidee dun syst`eme de protection est de traiter les differents types de probl`emes de mani`ere
generale et unitaire.

107


ET SURET

DE FONCTIONNEMENT
CHAPITRE 14. SECURIT
E
E

108

Fig. 14.1 Un compromis entre le cout dune attaque et celui de la securite


Implantes seuls, les dispositifs de protection co
utent cher.
Heureusement, si ces dispositifs permettent daugmenter les performances du logiciel, dans des
domaines comme celui de la fiabilite ou de la resistance aux erreurs, leur co
ut relatif diminue. Si,
de plus, ces dispositifs permettent une gestion des ressources partagees plus facile et plus s
ure, ils
peuvent devenir competitifs dun point de vue commercial.
Il est difficile de definir precisement ce que lon entend par protection dun syst`eme dexploitation (et dinformation en general), tant les facteurs qui peuvent influer sur cette notion (humains,
sociaux, economiques), sont nombreux. On peut dire cependant que la protection se rapporte `a
tout ce par quoi linformation peut etre modifiee, divulguee ou detruite. Dans certains cas, la
gestion du trafic aerien par exemple, elle peut etre la garantie des performances du syst`eme. La
confidentialite denregistrements financiers, medicaux ou personnels rel`eve aussi de la protection,
comme le fait quun processus utilisateur ne puisse etre execute en mode syst`eme. La protection
exige enfin la correction des processus syst`eme.
perennite du syst`eme
confidentialite des donnees (syst`eme, utilisateur, etc.)
correction du syst`eme
A loppose, nous ne parlerons pas de :
protection physique de lordinateur (feu, vol, coupures, etc.)
malveillance ou incompetence de loperateur (il est eventuellement possible de limiter soigneusement les privil`eges du super-utilisateur afin de preserver le syst`eme).
Le degre de protection du syst`eme depend de deux facteurs :
le degre de protection des informations quil manipule
le degre de confiance en ses logiciels, en particulier le syst`eme dexploitation.
Un logiciel est fiable quand il satisfait correctement ses specifications et quand, de plus, il est capable de resister `a un environnement imprevu (donnees erronees, pannes, etc.), soit en corrigeant
lanomalie, soit en la signalant, mais en evitant que les erreurs ne se propagent et ne contaminent
le syst`eme tout entier.
La protection, lintegrite et lauthenticite des donnees qui transitent dans un syst`eme dinformation sont realisees par les syst`emes cryptographiques (ATHENA et Kerberos au MIT).
Le confinement des erreurs est obtenu en controlant les acc`es aux entites du syst`eme dexploitation, par les domaines de protection.

14.2

G
en
eralit
es sur le contr
ole dacc`
es

Controle tr`es precis de lutilisation des ressources par les processus.

ERALIT

SUR LE CONTROLE

`
14.2. GEN
ES
DACCES

109

Objets
Fichier
1

Sujets

Lire
Processus

Processus

Processus

Segment
1
Executer

Segment
2

Processus
2

Lire
Ecrire

Editeur
Entrer

Lire
Ecrire

Entrer
Lire
Ecrire
Executer

Entrer
Entrer

Fig. 14.2 Matrice dacc`es


Deux niveaux :
un niveau logique (soft), celui du mod`ele de protection, ensemble de r`egles qui definissent
quels acc`es (aux ressources) sont autorises et quels acc`es sont interdits. Ces r`egles sont
definies soit `a la conception du syst`eme, soit par les utilisateurs.
un niveau materiel qui permet dappliquer le mod`ele reellement. Cest le role des mecanismes
de protection.
Le premier doit etre dynamique. Par contre, le deuxi`eme doit etre stable pour faciliter limplementation,
le contr
ole et la fiabillisation.
Les deux doivent de surcrot etre independants du mod`ele pour offrir un vaste ensemble de r`egles
possibles.
Un exemple de protection simple est celui des repertoires sous unix, pour eviter quils soit corompus (ou que larborescence soit corompue), il sont identifies comme des fichiers speciaux et il nest
possible dy acc`eder que par le truchement dappels syst`emes specifiques. Biensur il est toujours
possible de les manipuler si lon peut acc`eder en mode raw au disque dur mais cette option est
reservee au super utilisateur.

14.2.1

Domaines de protection et matrices dacc`


es

On formalise le syst`eme comme un ensemble dentites actives, les sujets, un ensemble dentites
accessibles, les objets. Le mod`ele de protection definit quels sujets ont acc`es `a quels objets et
comment (modalites dacc`es).
On parle alors de droit dacc`es, definis par le couple (objet, modalites)
Exemple : (fichier, lire)
Le mod`ele doit fixer `a tout instant les droits dacc`es dont dispose chaque processus. Cet ensemble de droits est le domaine de protection du processus. Voire un exemple de matrice dacc`es
dans la figure 14.2

14.2.2

Domaines de protection restreints

Il est souhaitable que la matrice dacc`es puisse evoluer dynamiquement. En effet, un meme
processus peut avoir, au cours de son existence, des besoins variables afin que chaque module

110

ET SURET

DE FONCTIONNEMENT
CHAPITRE 14. SECURIT
E
E

qui compose un processus ne mette pas en danger des ressources non utilisees. Par exemple : un
module de lecture de donnees, un module de calcul, un module dimpression. On va donc executer
chaque module dans un domaine de protection le plus reduit possible.
Cest le principe du moindre privil`ege : un programme ne peut endommager un objet auquel
il na pas acc`es !
Pour mettre en place ces domaines dynamiques, une possibilite est de changer les droits dacc`es
du processus au cours de son execution. Une autre possibilite est dajouter aux objets le type
domaine et de controler les acc`es `a la matrice. Ledition de cases de la matrice devient une
operation protegee.

14.2.3

Avantages des domaines de protections restreints

Avantages de cette souplesse :


le maillon faible : un syst`eme rigide laisse souvent des poternes (portes derobees) pour
pouvoir implementer certaines operations ;
si les mesures de protection sont trop pesantes, lexperience prouve que lon cree souvent des
moyens exceptionnels pour les contourner ;
il est interessant de faire varier les controles suivant les utilisateurs ;
on peut realiser des acc`es `a la carte sur certains objets ;
enfin, certains probl`emes de protection necessitent des mesures souples, ce sont : le cheval
de Troie et le confinement.

14.3

Le cheval de Troie

Un utilisateur fait souvent appel `a un certain nombre de programmes quil na pas ecrit luimeme (heureusement), un editeur par exemple. Ce programme peut etre un cheval de Troie : il va
profiter des droits donnes par lutilisateur pour consulter, copier, modifier ou alterer des donnees
auxquelles il nest pas cense acceder.

14.4

Le confinement

Le probl`eme ici est tout simplement le fait que le programme ne manipule pas de donnees de
lutilisateur mais simplement enregistre ses param`etres dappels (les utilisateurs `a qui vous envoyez
du courrier par exemple). Le probl`eme du confinement est donc de vous proteger contre ce type
dextraction dinformations (ce qui peut par exemple etre utilise en bourse pour connaitre votre
comportement dachat).

14.5

les m
ecanismes de contr
ole

Acc`es hierarchiques
UNIX (4)/ MULTICS (8) / VMS
Listes dacc`es
UNIX/MULTICS
Capacites
Les capacites sont des triplets (utilisateur, droits, pointeur). La manipulation des capacites est realisee de facon protegee. Le pointeur nest pas directement utilisable par lutilisateur
de la capacite. La capacite donne le droit dacc`es `a certains utilisateurs dune certaine ressource.
Pour quun autre utilisateur puisse utiliser votre ressource, vous devez lui donner une capacite.
Changer de protection revient `a changer de C-liste.
La notion de domaine se materialise par une simple indirection sur une autre C-liste.
Comme les capacites donnent un acc`es sans controle aux objets, la protection des capacites
doit etre absolue. Elle est donc realisee de facon materielle.

1
2

Domaine
Domaine

Domaine

Sujets

Lire
Ecrire

Lire

Fichier
1

Nom Modalitees dacces Pointeur

Fig. 14.4 Une capacite

Lire
Ecrire

Segment
2

Processus i

Lire
Ecrire
Executer

Executer

Segment
1

Objets

Entrer

Entrer

Entrer

Entrer

Editeur

Domaine i

Processus
2

Entrer

Entrer

Entrer

Domaine Domaine
1
2

14.5. LES MECANISMES


DE CONTROLE
111

Fig. 14.3 Matrice dacc`es

Objet


ET SURET

DE FONCTIONNEMENT
CHAPITRE 14. SECURIT
E
E

112

Nom

Code Editeur

Modalitees dacces Pointeur

Editeur

Executer

Proc

Lire,Executer

Fic1

Lire

Fic2

Lire,Ecrire

Code Procedure
Fichier
Fichier

Fig. 14.5 Une liste de capacites

14.5.1

Application des capacit


es au domaines de protection restreints

Les C-listes sont des objets dun type nayant quun droit dentree, la C-liste contenant le droit
reel.
Cette technique sur les C-listes permet dimplanter facilement le principe de moindre privil`ege.
Les mecanismes dacc`es memoire modernes permettent aisement de realiser les capacites.
Un probl`eme important est la revocation
En effet, une fois que vous avez donne une capacite, lacc`es est definitivement donne. Pour
regler ce probl`eme, on ne fournira pas la capacite dacc`es `a un objet mais `a un domaine, et on
detruira ce domaine si lon veut de nouveau interdire lacc`es `a lobjet. On cree deux capacites en
chaine et lon detruit celle que lon poss`ede quand ont veut retirer lacc`es.

14.5. LES MECANISMES


DE CONTROLE

113

Proc

Entrer
Objet

C-liste1

Entrer
.
.
.

Liste des Capacites


de la Procedure appelante

Liste des Capacites


de la Procedure appelee

Fig. 14.6 Changement du domaine de protection

Objet O

O Lire,Ecrire

Objet
Copie

O Lire,revoquer

Lire

O
O Lire,Ecrire

Copies
O

Lire

Lire
Fig. 14.7 Transmission dune capacite


ET SURET

DE FONCTIONNEMENT
CHAPITRE 14. SECURIT
E
E

114

Objet O

O Lire,Ecrire

Objet
Copie

O Lire,revoquer

Lire

Lire

Copies
Revocation

Lire
Fig. 14.8 Revocation dune capacite

14.6. LES ACL

14.6

115

Les ACL

Les ACL (access control lists) sont une extension des modes de protection standard dUNIX.
Les ACL sont des droits que lon definit en plus des 9 bits de protection classiques, ils permettent
en particulier dautoriser lacc`es ou de le refuser, `a un utilisateur donne, ou `a un groupe donne.
Deux commandes permettent de manipuler les ACL, ce sont chacl et lsacl.
La syntaxe de la commande shell chacl :
chacl (dr.staff,r-x)(zipstein.%,r-x)(%.licence,---) proj
qui donne sur le fichier proj les droits de lecture et decriture `a lutilisateur dr du groupe
staff et `a lutilisateur zipstein quelque soit son groupe et qui refuse cet acc`es aux utilisateurs
du groupe licence.
chacl (binome.%,rwx)(%.@,--x)(%.%,---) catalogue projet
qui donne le droit dacc`es total `a lutilisateur binome (quelque soit son groupe), permet le
parcours du repertoire aux membres du groupe proprietaire et refuse lacc`es `a tous les autres utilisateurs.
Deux symboles speciaux :
% pour nimporte qui (utilisateur ou groupe)
@ pour le proprietaire ou le groupe proprietaire
On retrouve aussi les autres syntaxes de chmod par exemple :
chacl %.%=r fichier
ou
chacl @.%=5 fichier
Attention les acl sont detruits par la commande chmod et la commande chacl ne permet pas
de positioner les autres bits definis dans linode ; seuls les 9 bits de protections sont positionnables
par chacl.
Pour positionner les droits standard et des acl, il faut donc realiser en succession un chmod
puis un chacl.
On utilisera :
chacl (prof.%,rwx) catalogue projet
pour les projets de C ou de syst`eme.
La commande lsacl [fichiers] permet de connatre les acl associes aux fichiers, remarquer
qu`a linverse de /bin/ls cette commande na pas de param`etres par defaut.

14.6.1

Appels systemes setacl et getacl

On trouvera deux appels syst`emes correspondant :


#include <sys/acl.h>
int setacl(
const char *path,
size t nentries,
const struct acl entry *acl
);
int fsetacl(
int fildes,
size t nentries,
const struct acl entry *acl


ET SURET

DE FONCTIONNEMENT
CHAPITRE 14. SECURIT
E
E

116
);

Un bon exercice : recrire lsacl de facon quil fonctionne dune mani`ere similaire `a /bin/ls.
Utilisation de la commande script pour montrer le comportement des acl.
Script started on Fri May 5 10:33:20 1995
$ lsacl *
(dr.%,rw-)(%.staff,---)(%.%,---) fich
(dr.%,rw-)(%.staff,---)(%.%,---) file
(dr.%,rwx)(%.staff,---)(%.%,---) projet
$ chacl (prof.%,rwx) fich
$ lsacl *
(prof.%,rwx)(dr.%,rw-)(%.staff,---)(%.%,---) fich
(dr.%,rw-)(%.staff,---)(%.%,---) file
(dr.%,rwx)(%.staff,---)(%.%,---) projet
$ chacl (%.staff,rx) fich
$ lsacl *
(prof.%,rwx)(dr.%,rw-)(%.staff,r-x)(%.%,---) fich
(dr.%,rw-)(%.staff,---)(%.%,---) file
(dr.%,rwx)(%.staff,---)(%.%,---) projet
$ chacl (illouz.staff= fich
$ lsacl fich
(illouz.staff,---)(prof.%,rwx)(dr.%,rw-)(%.staff,r-x)(%.%,---) fich
$ chacl (prof.%,rx) . ..
$ su prof
Password:
$ cat fich
$ touch fich
$ chacl (dr.staff,x) fich
chacl: file "fich": Not owner (errno = 1)
$ lsacl *
(illouz.staff,---)(prof.%,rwx)(dr.%,rw-)(%.staff,r-x)(%.%,---) fich
(dr.%,rw-)(%.staff,---)(%.%,---) file
(dr.%,rwx)(%.staff,---)(%.%,---) projet
$ exit # du su
$ exit # du script
script done on Fri May

14.6.2

5 10:37:18 1995

Autres pistes sur la s


ecurit
e

crack et autres logiciels dattaque de mots de passe


root-fix et autres Pots de Miel
virus et logiciels antivirus (sous linux ? ? ? ?)
Gestion des mots de passe
Honey Pot
Haute disponibilite
Redondance
RAID (cf chapitre)
Distribution de disques
SAN
Clusters
keep alive
Sauvegardes et syst`emes de sauvegarde

14.6. LES ACL


Les attaques par deni de services

117

118

ET SURET

DE FONCTIONNEMENT
CHAPITRE 14. SECURIT
E
E

Chapitre 15

Multiplexer des entr


ees-sorties
15.1

Gerer plusieurs cannaux dentr


ee sortie

Dans ce chapitre, nous voulons presenter le probl`eme des attentes actives sur plusieurs descripteurs.
Lexemple le plus frequent est celui dun serveur web, le serveur doit gerer simultanement un
tr`es grand nombre de flux dentree et de flux de sortie et de flux de controle (les information de
contr
ole des sockets).

15.1.1

Solution avec le mode non bloquant

Il est possible dutiliser des entree-sorties non bloquantes mais cest loing detre la solution
optimal car notre processus vas realiser de nombreux appels syst`eme inutile dautant plus si dans
le cas dun serveur avec des comportements de clients tr`es alleatoires. Le co
ut en ressources de
cette attente active est extremement cher, et doit etre evite dans le cas dune machine en temps
partage.

15.1.2

Utiliser les m
ecanismes asynchrones

On peut utiliser des entrees-sorties asynchrones et demander au noyau de nous prevenir par un
signal qui informe de larrivee de donnees sur un descripteur. Ce signal est SIGIO, mais ce nest
valable que sur les descripteurs qui sont des peripheriques. De plus ce mecanisme ne designe pas
le descripteur sur lequel sest faite larrivee de caract`eres, do`
u de nouvelles pertes de temps d
ues
aux appels realises inutilement en mode non bloquant.

15.2

Les outils de s
election

La solution la plus efficase vient de syst`emes de selection qui prend un param`etre un ensemble
de descripteurs, et qui permet tester si lun de ses descripteurs est pr`es `a satisfaire un appel syst`eme
read ou write. Cet appel est bloquant jusqu`a larrivee de caract`eres sur un des descripteurs de
lensemble. Ainsi il ny pas de consomation de ressource processus inutile, le travail est fait `a un
niveau plus bas (dans le noyau) de facon plus economique en ressources.

15.2.1

La primitive select

La premi`ere implementation dun outil de selection sous Unix est lappel syst`eme select, malheureusement sa syntaxe est devenu inadapte pour cituations ou le nombre de descipteur utilise
par le programme est tr`es grand ce qui peut arriver facilement avec un serveur de fichier. Nous
fournissont `a la primitive select :
119


CHAPITRE 15. MULTIPLEXER DES ENTREES-SORTIES

120

Les descripteurs que nous voulons scruter. (lindice du plus grand descripteur qui nous
interesse dans la table des descripteurs du processus)
Les conditions de reveil sur chaque descripteur (en attente de lecture, ecriture, ev`enement ?)
Combien de temps nous voulons attendre.
La fonction retourne pour chaque descripteur sil est pret en lecture, ecriture, ou si lev`enement
a eu lieu, et aussi le nombre de descripteur prets. Cette information nous permet ensuite dappeler
read ou write sur le(s) bon(s) descripteur(s).
#include
#include
#include

<sys/types.h>
<sys/time.h>
<unistd.h>

int select(int maxfd,


fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds
struct timeval *delai);
Retourne le nombre de descripteurs prets, 0 en cas dexpiration du delai.
Parametrage du delai :
struct timeval {
long tv_sec;
long tv_usec;
};
delai == NULL Bloquant, attente infinie
delai->tv sec == 0 && delai->tv usec == 0

Non bloquant, retour immediat.

delai->tv sec > 0 && delai->tv usec >0 Semi bloquant, attente jusqu`a ce quun descripteur soit pret ou que le delai en secondes plus microsecondes soit ecoule.
Les trois pointeurs (readfds, writefds, et exceptfds) sur des ensembles de descripteurs sont
utilises pour indiquer en entree les situations qui nous interessent. Cest `a priori (cela peut varier
avec limplementation) des tableaux de bits avec un bit pour chaque descripteur du tableau de
descripteurs du processus. Lentier maxfd est la position du dernier bit significatif de ce tableau
de bits.
Les seules facons de manipuler ces ensembles de descripteurs sont :
Allocation :fd\_set *fd=(fd\_set*)malloc(sizeof(fd\_set));
Creation
Affectation
Utilisation dune des quatre macros suivantes :
FD ZERO(fd set fdset) RAZ de lensemble.
FD SET(int fd, fd set *fdset) Positionne le bit fd a 1.
FD CLR(int fd, fd set *fdset) Positionne le bit fd `a 0
FD ISSET(int fd, fd set *fdset) vrai si le bit fd est `a 1 dans lensemble.
Un descripteur est considere comme pret en lecture si un appel read dessus ne sera pas bloquant. De meme, un descripteur est considere comme pret en ecriture si un appel write ne sera pas
bloquant. Les exceptions / ev`enements sont definis pour les lignes de communication qui acceptent
les messages hors bande comme les sockets en mode datagramme.


15.2. LES OUTILS DE SELECTION

15.2.2

121

La primitive poll

La primitive poll fournit un service proche de select avec une autre forme dinterface. Cette
interface est adaptee quand le nombre de descripteurs ouvert par le processsus est tr`es grand mais
que lon ne sinter`esse qua un petit nombre de ceux-ci.
#include <stropts.h>
#include <poll.h>
int poll(struct pollfd fdarray[],
unsigned long nfds,
int
timeout
);
struct pollfd
int
short
short
};

{
fd;
events;
revents;

Ici on specifie la liste de descripteurs (dans un tableau) et ce que lon veut g`eter sur chacun
deux.
La valeur de retour est -1 en cas derreur, 0 si le temps dattente timeout est ecoule, ou un
entier positif indiquant le nombre de descripteurs pour lesquels la valeur du champ revents a ete
modifiee.
Les ev`enements sont ici :
Pour les ev`enements de events :
POLLIN Donnees non prioritaire peuvent etre lues.
POLLPRI Donnees prioritaire peuvent etre lues.
POLLOUT Donnees non prioritaire peuvent etre ecrites, les messages de haute priorite peuvent
toujours etres ecrits.
Pour les revents (valeurs de retour de la primitive poll) :
POLLIN,POLLPRI les donnees sont l`a.
POLLOUT lecriture est possible
POLLERR Une erreur a eu lieu.
POLLHUP La ligne a ete coupee.
POLLNVAL Descripteur invalide.
Le mode de blocage de la primitive poll depend du param`etre timeout
timeout == INFTIM Bloquant, INFTIM est defini dans stropts.h.
timeout == 0 Non bloquant.
timeout > 0 Semi bloquant, attente de timeout micro secondes.

Un Exemple Attente de donnees sur ifd1 et ifd2, de place pour ecrire sur ofd, avec un
delai maximum de 10 seconds :
#include <poll.h>
struct pollfd fds[3] ;
int ifd1, ifd2, ofd, count ;
fds[0].fd = ifd1 ;
fds[0].events = POLLIN ;
fds[1].fd = ifd2 ;
fds[1].events = POLLIN ;
fds[2].fd = ofd ;


CHAPITRE 15. MULTIPLEXER DES ENTREES-SORTIES

122

fds[2].events = POLLOUT ;
count = poll(fds, 3, 10000) ;
if (count == -1) {
perror("poll failed") ;
exit(1) ;
}
if (count==0)
printf("Rien \n") ;
if (fds[0].revents & POLLIN)
printf("Donn
ees a lire sur ifd%d\n", fds[0].fd) ;
if (fds[1].revents & POLLIN)
printf("Donn
ees a lire sur ifd%d\n", fds[1].fd) ;
if (fds[2].revents & POLLOUT)
printf("De la place sur fd%d\n", fds[2].fd) ;

15.2.3

Le p
eriph
erique poll

Dans le cas de serveur travaillant avec un tr`es grand nombre de descripteurs (plueirus dizaine
de milliers de descripteurs) les deux syntaxes poll et select sont inefficaces. Soit dans le cas
deselect car le nombre de descripteurs scrutes par le noyau est tr`es grand alors quun tr`es faible
par dentre eux sont inutilise. Soit dans le cas de poll car il faut manipuler avant chaque appel
un tr`es grand tableau et que le syst`eme doit relire ce tableau a chaque appel.
Pour resoudre ce probl`eme une nouvelle interface a ete mise au point /dev/poll. Cette interface
permet de creer un peripherique poll dans lequel il suffit decrire pour ajouter un descripteur a
la liste des descipteurs que le noyau doit scruter. Et il suffit decrire de nouveau pour retirer un
descripteur.
Epoll est un patch du noyau !1
1. Il faut verifier la presence depoll sur votre syst`eme, ouvrer le peripherique /dev/epoll en
mode O RDWR, sinon retour a select et poll kdpfd = open("/dev/epoll",O_RDWR);

2. Definiser le nombre maximal maxfd de descipteurs scrutables #include <linux/eventpoll.h> \ldots ioctl(epol
3. Allouer un segment de memoire partage avec char *map = (char *)mmap(NULL, EP MAP SIZE(maxfds,
PROT READ | PROT WRITE, MAP PRIVATE, epoll fd, 0))
4. Maintenant vous pouvez ajouter des descipteurs
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN | POLLOUT | POLLERR | POLLHUP;
pfd.revents = 0;
if (write(kdpfd, &pfd, sizeof(pfd)) != sizeof(pfd)) {
/* gestion derreur */
}
5. Recupere les evenements
struct pollfd *pfds;
struct evpoll evp;
for (;;) {
evp.ep_timeout = STD_SCHED_TIMEOUT;
evp.ep_resoff = 0;
nfds = ioctl(kdpfd, EP_POLL, &evp);
1 Il

existe deux version une version /Dev/poll et une version /dev/epoll qui faut utiliser car plus efficasse.


15.3. UNE SOLUTION MULTI-ACTIVITES

123

pfds = (struct pollfd *) (map + evp.ep_resoff);


for (ii = 0; ii < nfds; ii++, pfds++) {
traitmement(pfds[ii].fd, pfds[ii].revents);
}
}
6. Retirer des descripteurs
pfd.fd = fd;
pfd.events = POLLREMOVE;
pfd.revents = 0;
if (write(kdpfd, &pfd, sizeof(pfd)) != sizeof(pfd)) {
/* gestion derreur */
}
Le petit detail technique genial de cette interface est le fait que pendant que vous recupere des
evenements le syst`eme continu a travailler pour vous dans le segment de memoire fournis par mmap
ce qui fait que votre programme sexecute en parall`ele de la recuperation dinformation sur les
peripheriques et que lappel ioctl est ainsi tr`es rapide.

15.2.4

Les extensions de read et write

Une extension readv, writev de read et write permet en un seul appel syst`eme de realiser
lecriture de plusieurs zones memoire non contigues, ce qui permet daccelerer certaines entreessorties structurees. Mais aussi de mieux organiser les appels syst`eme dans notre cas.
#include <sys/types.h>
#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec iov[], int iovl);
ssize_t writev(int fd, const struct iovec iov[], int iovl);
struct iovec {
void *iov_base ;
int
iov_len;
};

15.3

une solution multi-activit


es

Lutilisation de plusieurs activites (threads, voir chapitre 16) permet de realiser plusieurs appels
de read en simultane, le premier read qui se debloque entraine lexecution de lactivite le realisant,
ainsi le co
ut dattente sur les descripteurs est minimal le syst`eme signalant imediatement `a la thread
levenement. Le seul probl`eme est davoir a gerer cette multiplicite dactivites, ce qui est dans le
cas dun simple echange bidirectionel est raisonable il suffit de deux activites independantes.
Pour un serveur de fichier cette solutions multi-activite peut ne pas supporter la monte en
charge le nombre de threads etant limite plus rapidement que celui des descripteurs (a ma connaissance ont peut creer au plus 10000 threads sous linux et xp)
Pour une situation plus complexe comme un serveur de partage de donnees, des mecanismes
dexclusion mutuelle entre activites devront etre mis en oeuvre, ce qui peut compliquer inutilement
le probl`eme. La solution avec un seul processus gerant rapidement des requetes multiples sur
plusieurs flux etant plus simple a realiser.

124

CHAPITRE 15. MULTIPLEXER DES ENTREES-SORTIES

Chapitre 16

Les threads POSIX


La programmation par thread (actvite) est naturelle pour gerer des phenom`enes asyncrones.
Les entrees utilisateur dans les interfaces graphiques (souris, clavier) sont plus facile a gerer si lon
peut separer lactivite principale du logiciel de la gestion des commandes utilisateur. Les entrees
sorties multiples voir le chapitre 15 correspondant, sont gerees plus simplement en utilisant des
threads.
Les actvities sont une nouvelle facon de voire les processus dans un syst`eme. Lidee est de
separer en deux le concept de processus. La premi`ere partie est lenvironement dexecution, on y
retrouve une tr`es grande partie des elements constitutifs dun processus en particulier les informations sur le proprietaire, la position dans larborescence le masque de creation de fichier etc.
La deuxi`eme partie est lactivit
e, cest la partie dynamique, elle contient une pile, un context
processeurs (pointeur dinstruction etc), et des donnees dordonancement.
Lidee de ce decoupage est de pouvoir associer plusieurs activite au meme environement
dexecution. Pour CHORUS lensemble des ressources dun environnement dexecution est appele
des acteurs, MACH parle de taches et AMOEBA de process. Mais tous designe lunite dexecution
par le terme de thread of control.
Organisation en memoire pour un processus UNIX avec plusieurs threads : voir figure 16.1.
On peut grace au thread gerer plusieurs phenom`enes asyncrone dans le meme contexte, cest
`a dire, un espace dadressage commun, ce qui est plus confortable que de la memoire partagee et
moins couteux en ressource que plusieurs processus avec un segment de memoire partage.
Un processus correspond `a une instance dun programme en cours dexecution. Un thread
correspond `a lactivite dun processeur dans le cadre dun processus. Un thread ne peut pas
exister sans processus (la tache englobante), mais il peut y a voir plusieurs thread par processus,
dans le cas de linux il ne peut y a voir de tache sans au moins une activite.

16.0.1

Description

Un processus est compose des parties suivantes : du code, des donnees, une pile, des descripteurs
de fichiers, des tables de signaux. Du point de vue du noyau, transferer lexecution `a un autre
processus revient `a rediriger les bons pointeurs et recharger les registres du processeur de la pile.
Les divers threads dun meme processus peuvent partager certaines parties : le code, les donnees,
les descripteurs de fichiers, les tables de signaux. En fait, ils ont au minimum leur propre pile, et
partagent le reste.

16.0.2

fork et exec

Apr`es un fork, le fils ne contient quune seule activite (celle qui a execute le fork). Attention aux variables dexclusion mutuelle (qui font partie de lespace dadressage partage) qui sont
125

126

CHAPITRE 16. LES THREADS POSIX

Donnes de la Tache
rpertoire de travail
umask
Descripteurs
Accs aux tables de pages
* programme
* donnes globales
* pile globale
Propritaires
Scheduling
Donnes de Registres
laThread 1 Pile noyau
Scheduling
Donnes de Registres
laThread 2 Pile noyau
Scheduling
Donnes de Registres
laThread 3 Pile noyau

Fig. 16.1 Organisation memoire, partage des fonctions entre le processus et les activites

127
conservees apr`es le fork() et dont le contenu ne varie pas. Ainsi si une activite a pris le semaphore
avant le fork(), si lactivite principale cherche `a prendre ce semaphore apr`es le fork() elle sera
indefiniment bloquee.
Apr`es un exec, le processus ne contient plus que la thread qui a execute lune des six commandes
exec. Pas de probl`eme avec les semaphores comme lespace dadressage a change.

16.0.3

clone

Sous linux (et rarement sous les syst`emes Unix) il existe un appel syst`eme un peut special. Cet
appel syst`eme realise un dedoublement du processus comme fork dou son nom de clone. Cet
appel syst`eme permet de preciser exactement ce que lon entend partager entre le processus p`ere
et le processus fils.
Elements partageables :
ppid Creation dun fr`ere au lieux dun fils.
FS Partage de la structure dinformation liee au syst`eme de fichier (., /, umask),
FILES Partage de la table des descripteurs,
SIGHAND Partage de la table des gestionnaires de Signaux, mais pas des masques de signaux,
PTRACE Partage du crochet (hook) de debug voire lappel ptrace.
VFORK Partage du processeur ! le processus p`ere est bloque tantque le fils na pas execute soit
exit soit execve, cest `a dire quil sest detache de tout les element partageable du processus
p`ere (sauf les FILEs),
VM Partage de la memoire virtuelle, en particulier les allocations et desallocations par mmap et
munmap sont visibles par les deux proccessus.
pid Les deux processus ont le meme numero.
THREAD Partage du groupe de thread, les deux processus sont ou ne sont pas dans le meme
groupe de threads.

16.0.4

Les noms de fonctions

pthread[_objet]_operation[_np]
o`
u
objet designe si il est present le type de lobjet auquel la fonction sapplique. Les valeurs possibles
de objet peuvent etre
cond pour une variable de condition
mutex pour un semaphore dexclusion mutuelle
op
eration designe loperation a realiser, par exemple create, exit ou init
le suffixe np indique, si il est present, quil sagit dune fontion non portable, cest-`a-dire Hors
Norme.

16.0.5

les noms de types

pthread[_objet]_t
avec objet prenant comme valeur cond, mutex ou rien pour une thread.

128

16.0.6

CHAPITRE 16. LES THREADS POSIX

Attributs dune activit


e

Identification dune pthread : le TID de type pthread t obtenu par un appel `a la primitive :
pthread_t pthread_self(void);
pour le processus proprietaire
pid_t getpid(void);
En POSIX, le fait de tuer la thread de numero 1 a pour effet de tuer le processus ainsi que
toutes les autres threads eventuelles du processus.
Pour tester legalite de deux pthreads on utilise
int pthread_equal(pthread_t tid1, pthread_t tid2);

16.0.7

Cr
eation et terminaison des activit
es

Cr
eation
int pthread_create (pthread_t
pthread_attr_t
void
void
);

*p_tid,
attr,
*(*fonction) (void *arg),
*arg

La creation et lactivation dune activite retourne -1 en cas dechec, 0 sinon.


le tid de la nouvelle thread est place `a ladresse p_tid
attr attribut de lactivite (ordonnancement), utiliser pthread attr default
la param`etre fonction correspond `a la fonction executee par lactivite apr`es sa creation : il
sagit donc de son point dentree (comme la fonction main pour les processus). Un retour de
cette fonction correspondra `a la terminaison de cette activite.
le param`etre arg est transmis `a la fonction au lancement de lactivite.
Terminaison
a) les appels UNIX exit et donc exit terminent toutes les threads du processus.
b) Terminaison dune thread
int pthread_exit (int *p_status);
p status code retour de la thread, comme dans les processus UNIX la thread est zombifiee
pour attendre la lecture du code de retour par une autre thread. A linverse des processus, comme
il peut y avoir plusieurs threads qui attendent, la thread zombie nest pas liberee par la lecture du
p status, il faut pour cela utiliser une commande speciale qui permettra de liberer effectivement
lespace memoire utilise par la thread.
Cette destruction est explicitement demandee par la commande
int pthread_detach (pthread_t *p_tid);
Si un tel appel a lieu alors que lactivite est en cours dexecution, cela indique seulement qu`a
lexecution de pthread_exit les ressources seront restituees.

16.1

Synchronisation

Trois mecanismes de synchronisation inter-activites :


la primitive join
les semaphores dexclusion mutuelle
les conditions (ev`enements)

16.1. SYNCHRONISATION

129

extern int errno;


Thread 1

Thread 2

access

open

Lecture
incorrecte
Fig. 16.2 Changement de la valeur errno par une autre thread

16.1.1

Le mod`
ele fork/join (Paterson)

Les rendez-vous : join


La primitive
int pthread_join (pthread_t tid, int **status);
permet de suspendre lexecution de lactivite courante jusqu`a ce que lactivite tid execute
un appel (implicite ou explicite) `a pthread exit. Si lactivite tid est dej`a terminee, le retour est
immediat, et le code de retour de lactivite visee est egal `a **status (double indirection).
La primitive retourne :
0 en cas de succ`es
-1 en cas derreur
EINVAL si le tid est incorrect
ESRCH activite inexistante
EDEADLOCK lattente de lactivite specifiee conduit `a un interblocage.

16.1.2

Le probl`
eme de lexclusion mutuelle sur les variables g
er
ees par
le noyau

Il est necessaire davoir plusieurs variables errno, une par activite. En effet cette variable
globale pourrait etre changee par une autre activite. Voir plus loin comment definir des variables
globales locales `a chaque activite.

16.1.3

Les s
emaphores dexclusion mutuelle

Ces semaphores binaires permettent dassurer lexclusion mutuelle.


Il faut definir un objet de type pthread mutex t qui correspond `a un ensemble dattributs
de type pthread mutexattr t
(on utilisera en general la constante pthread mutexattr default ).
Initialiser la variable par un appel `a la fonction
int pthread_mutex_init(pthread_mutex_t
*p_mutex,
pthread_mutexattr_t attr);
On pourra detruire le semaphore par un appel `a la fonction
int pthread_mutex_destroy(pthread_mutex_t *p_mutex);

130

16.1.4

CHAPITRE 16. LES THREADS POSIX

Utilisation des s
emaphores

Operation P :
Un appel `a la fonction
pthread_mutex_lock (pthread_mutex_t *pmutex);
permet `a une activite de realiser une operation P sur le semaphore. Si le semaphore est dej`
a
utilise, lactivite est bloquee jusqu`a la realisation de loperation V (par une autre activite) qui
lib`erera le semaphore.
Operation P non bloquante :
pthread_mutex_trylock (pthread_mutex_t *pmutex);
renvoie 1 si le semaphore est libre
0 si le semaphore est occupe par une autre activite
-1 en cas derreur.
Operation V :
Un appel `a la fonction
pthread_mutex_unlock(pthread_mutex_t *pmutex);
realise la liberation du semaphore designe.

16.1.5

Les conditions (
ev`
enements)

Les conditions permettent de bloquer une activite sur une attente dev`enement. Pour cela
lactivite doit posseder un semaphore, lactivite peut alors liberer le semaphore sur lev`enement,
cest-`a-dire : elle lib`ere le semaphore, se bloque en attente de lev`enement, `a la reception de
lev`enement elle reprend le semaphore.
Initialisation dune variable de type pthread_cond_t
int pthread_cond_init (pthread_cond_t *p_cond, pthread_condattr_t attr);
Lattente sur une condition
int pthread_cond_wait (pthread_cond_t *p_cond, pthread_mutex_t *p_mutex);
Trois etapes
1. liberation sur semaphore *p mutex
2. activite mise en sommeil sur lev`enement
3. reception de lev`enement, recuperation du semaphore
La condition est independante de levenement et nest pas necessairement valide `a la reception
(cf. exemple).
Exemple, le programme suivant :
pthread_mutex_t m;
pthread_cond_t cond;
int
condition = 0;
void *ecoute(void *beurk)
{
pthread_mutex_lock(m);
sleep(5);
while (!condition)
pthread_cond_wait(cond, m);

16.1. SYNCHRONISATION

131

pthread_mutex_unlock(m);
pthread_mutex_lock(print);
printf(" Condition realisee\n");
pthread_mutex_unlock(print);
}
main()
{
pthread_t lathread;
pthread_create(lathread, pthread_attr_default, ecoute, NULL);
sleep(1);
pthread_mutex_lock(m);
condition = 1;
pthread_mutex_unlock(m);
pthread_cond_signal(cond);
}
Un autre exemple dutilisation de condition avec deux threads qui utilisent deux tampons pour
realiser la commande cp, avec une activite responsable de la lecture et lautre de lecriture. Les
conditions permettent de synchroniser les deux threads. Ici nous utilisons la syntaxe NeXT/MACH.
#include <sdtio.h>
#include <fcntl.h>
#import <mach/cthreads.h>
enum { BUFFER_A_LIRE = 1, BUFFER_A_ECRIRE = -1 };
mutex_t
lock1;
condition_t cond1;
char
int
int
int

/* variables de protection et dexclusion */

buff1[BUFSIZ];
nb_lu1;
etat1 = BUFFER_A_LIRE;
ds, dd;
/* descripteurs source et destination */

lire()
/* activite lecture */
{
for(;;) { /* lecture dans le buffer 1 */
mutex_lock(lock1);
while (etat1 == BUFFER_A_ECRIRE)
condition_wait(cond1, lock1);
nb_lu1 = read(ds, buff1, BUFSIZ);
if (nb_lu1 == 0)
{
etat1 = BUFFER_A_ECRIRE;
condition_signal(cond1);
mutex_unlock(lock1);
break;
}
etat1 = BUFFER_A_ECRIRE;
condition_signal(cond1);
mutex_unlock(lock1);

132

CHAPITRE 16. LES THREADS POSIX


}

}
ecrire()
{
for(;;)
{ /* ecriture du buffer 1 */
mutex_lock(lock1);
while (etat1 == BUFFER_A_LIRE)
condition_wait(cond1, lock1);
if (nb_lu1 == 0)
{
mutex_unlock(lock1);
exit(0);
}
write(dd, buff1, nb_lu1);
mutex_unlock(lock1);
etat1 = BUFFER_A_LIRE;
condition_signal(cond1);
}
}
main()
{
ds
dd
lock1
cond1

=
=
=
=

open(argv[1], O_RDONLY);
open(argv[2], O_WRONLY|O_TRUNC|O_CREAT, 0666);
mutex_alloc();
condition_alloc();

cthread_fork((cthread_fn_t)lire, (any_t)0);
ecrire(); /* la thread principale realise les ecritures */
}

16.2

Ordonnancement des activit


es

16.2.1

Lordonnancement POSIX des activit


es

Lordonnancement des activites DCE base sur POSIX est tr`es similaire `a lordonnancement
des activites sous MACH. Deux valeurs permettent de definir le mode dordonnancement dune
activite :
la politique et la priorite.
Pour manipuler ces deux valeurs, il vous faut creer un objet attribut dactivite (pthread_attr) en
appelant pthread_attr_create(), puis changer les valeurs par defaut avec les fonctions decrites
plus loin et creer la pthread avec cet objet pthread_attr. Ou bien la pthread peut elle-meme
changer ses deux valeurs, priorite et politique.
Les fonctions sont :
#include <pthread.h>
pthread_attr_setsched(pthread_attr_t *attr, int politique);
Les differentes politiques possibles sont :
SCHED FIFO La thread la plus prioritaire sexecute jusqu`a ce quelle bloque. Si il y a plus
dune pthread de priorite maximum, la premi`ere qui obtient le cpu sexecute jusqu`a ce
quelle bloque.


` UNE THREAD
16.3. LES VARIABLES SPECIFIQUES
A

133

SCHED RR Round Robin. La thread la plus prioritaire sexecute jusqu`a ce quelle bloque. Les
threads de meme priorite maximum sont organisees avec le principe du tourniquet, cest-`adire quil existe un quantum de temps au bout duquel le cpu est preempte pour une autre
thread (voire Chapitre 6 sur les Processus).
SCHED OTHER Comportement par defaut. Tous les threads sont dans le meme touniquet, il
ny a pas de niveau de priorite, ceci permet labsence de famine. Mais les threads avec une
politique SCHED FIFO ou SCHED RR peuvent placer les threads SCHED OTHER en situation de
famine.
SCHED FG NP (option DCE non portable) Meme politique que SCHED OTHER mais lordonnanceur peut faire evoluer les priorites des threads pour assurer lequite.
SCHED BG NP (option DCE non portable) Meme politique que SCHED FG NP, mais les threads
avec une politique SCHED FIFO ou SCHED RR peuvent placer les threads SCHED BG NP en situation de famine.
pthread_attr_setprio(pthread_attr_t *attr, int prio);
La priorite varie dans un intervalle defini par la politique :
PRI OTHER MIN <= prio <= PRI OTHER MAX
PRI FIFO MIN <= prio <= PRI FIFO MAX
PRI RR MIN <= prio <= PRI RR MAX
PRI FG MIN NP <= prio <= PRI FG MAX NP
PRI BG MIN NP <= prio <= PRI BG MAX NP
Ces deux fonctions retournent 0 en cas de succ`es et -1 sinon. La valeur de errno indiquant si
lerreur est une question de param`etres ou de permission.
Les deux fonctions que lon peut appeler sur une pthread pour changer sa priorite ou sa
politique sont :
pthread_setprio(pthread_t *unepthread, int prio);
pthread_setsched(pthread_t *unepthread, int politique, int prio);
Il est possible de connatre la priorite ou la politique dune pthread ou dun objet pthread attr
avec :
pthread_attr_getprio(pthread_attr_t *attr,int prio);
pthread_attr_getsched(pthread_attr_t *attr,int politique);
pthread_getprio(pthread_t *unepthread, int prio);
pthread_getsched(pthread_t *unepthread, int politique);

16.3

Les variables sp
ecifiques `
a une thread

Avec un processus multi-threads, nous sommes dans une situation de partage de donnees.
Toutes les donnees du processus sont `a priori manipulables par toutes les threads. Or certaines
donnees sont critiques et difficilement partageables. Premi`erement ce sont les donnees de la biblioth`eque standard. Pour les fonctions de la biblioth`eque standard, on peut resoudre le probl`eme
en utilisant un semaphore dexclusion mutuelle pthread_mutex_t pour POSIX.
Mais certaines variables ne peuvent etre protegees. Cest le cas de la variables errno, comme
nous lavons vu precedemment. Pour cette variable, la solution est davoir une variable par thread.
Ainsi le fichier <errno.h> est modifie et contient :
extern int *_errno();
#define errno (*_errno())
La valeur errno est obtenue par une fonction qui retourne la valeur de errno associee `a la
thread qui fait lappel `a errno .

134

16.3.1

CHAPITRE 16. LES THREADS POSIX

Principe g
en
eral des donn
ees sp
ecifiques, POSIX

Lidee des donnees specifique est de creer un vecteur pour chaque donnee specifique. Ainsi
pour des donnees specifique statiques, chaque thread poss`ede son propre exemplaire. Les donnees
specifiques sont identifiees par des cles de type pthread_key_t.

16.3.2

Cr
eation de cl
es

La creation dune cle est liee `a la creation dun tableau statique (variable globale), initialise `a
NULL `a la creation. La fonction
#include <pthread.h>
int pthread_keycreate (pthread_key_t *p_cle,
void
(*destructeur)(void *valeur));
permet la creation du tableau, 0 succ`es et -1 echec. La structure pointee par p_cle nous
permettra dacc`eder aux valeurs stockees, la cle est evidemment la meme pour toutes les threads. Le
param`etre destructeur de type pointeur sur fonction prenant un pointeur sur void en param`etre
et renvoyant void, donne ladresse dune fonction qui est executee `a la terminaison de la thread
(ce qui permet de faire le menage). Si ce pointeur est nul, linformation nest pas detruite `a la
terminaison de lactivite.

16.3.3

Lecture/
ecriture dune variable sp
ecifique

La fonction
#include <pthread.h>
int pthread_getspecific (pthread_key_t *p_cl
e, void **pvaleur);
permet la lecture de la valeur qui est copie `a ladresse pvaleur retourne 0 ou -1 selon que
lappel `a reussi ou non. La fonction
#include <pthread.h>
int pthread_setspecific (pthread_key_t *p_cl
e, void *valeur);
permet lecriture `a lemplacement specifie de valeur retourne 0 ou -1 selon que lappel a reussit
ou non.

16.4

Les fonctions standardes utilisant des zones statiques

Certaines fonctions standardes comme ttyname() ou readdir() retourne ladresse dune zone
statique. Plusieurs threads en concurrence peuvent donc nous amener `a des situations incoherentes.
La solution des semaphores dexclusion etant co
uteuse, ces fonctions sont reecrites pour la biblioth`eque de thread de facon `a etre reentrantes.
Attention les probl`emes de reentrance peuvent avoir lieu en utilisant des appels syst`emes non
reentrant dans les handlers de signaux ! Ceci sans utiliser de threads !

Chapitre 17

Clustering
Le clustering sont des techniques lies a lutilisation de grappes dordinateurs utilise comme
un super ordinateur avec plusieurs processeurs. Lobjectif est le RAIP : Redundant Array of
Inexpensive PROCESSOR.
la station de trvail individuelle vielli a grande vitesse, une facon de recycler ceux qui sont en
peu trop vieux (mais pas encore trops vieux) est de les rassembler dans votre premier cluster. De
ces PC nous allons tirer un super calculateur, bien sur il est toujours plus rapide dachetter un
G5 si on en a les moyens, pour les mainframes (je laffirme vous nen avez pas les moyens ou alors
vous en avez deja plusieurs...)1 .
Il existe differentes techniques de clustering pour different objectifs :
Tol
erence au pannes Google, le cluster est organise pour assurer la redondance des unite de
calcul pour assurer la continuite de service.
Super calculateur Earth Simulator,Plusieurs processeurs travaillant en meme temps permet
doptenir un super calculateur `a peu de frais, comme les processeurs qui compose chaque
noeud sont bon marche. IL faut que le probl`eme sy pr`ete cest le cas des calculs meteorologiques
et des calculs de simulation `a grande echelle.
Mont
e en charge Google, Le probl`eme pour une application nest pas toujours un probl`eme
de puissance de calcul parfois ce qui posse probl`eme cest la quantite dentrees sorties
qui faut assurer. Vous pouvez dailleurs facilement tester cette propriete en realisant un
petit programme qui sans saturer lunite central sature compl`etement les entrees sorties
while :;do; { cp grosfichier /tmp/$PID } &; done
Ainsi le clustering a essentiellement pour objectif dutiliser le dicton lunion fait la force pour
resoudre une difficulte de calcul.

17.1

Le clustering sous linux

Pour plus dinformation le vous conseil le site suivant qui vous donnera de bonnes references.
http://www-igm.univ-mlv.fr/~dr/Xpose2001/vayssade/

1 Cest evident si vous avez les moyens dacheter un mainframe vous avez les moyens dachetter un super-cluster
haut de gamme.

135

136

CHAPITRE 17. CLUSTERING

Chapitre 18

Bibliographie
J.-M. Rifflet. La programation sous UNIX. Ediscience, 1993. Le manuel de reference.
A.Tanenbaum. Syst`emes dexploitation, sysyt`emes centralises, syst`emes distribues. Inter-Editions,
1994. Cours general sur les syt`emes dexploitation.
M. Bach. The design of the UNIX operating system. 1986. Prentice-Hall, Englewood Cliffs,
N.J. ISBN 0-13-201757-1
J. Beauquier & B. Berard Syst`emes dexploitation concepts et algorithmes. 1991. McGraw-Hill.
ISBN 2-7042-1221-X
W.R. Stevens, UNIX Network Programming. 1990 Prentice-Hall, Englewood Cliffs, N.J.
W.R. Stevens, Advanced Programming in the UNIX Environnement Addison-Wesley ISBN 0201-56317-7

18.1

Webographie

Vous trouverez a lurl suivant une webographie : www-igm.univ-mlv.fr/ dr/Cours.html

137

Index
/dev/epoll, 156
/dev/null, 105
/dev/poll, 156
/dev/pty, 110
/dev/tty, 104

introduction, 41
ioctl, 111
isatty, 103
kill, 113, 114
listen, 177
mkfifo, 100
mknod, 100
mmap, 92
munmap, 92
nice, 60
open, 41
pause, 120, 121
pipe, 97
poll, 155
putmsg, 173
putpmsg, 173
read, 44, 99
recv, 178
recvfrom, 178
recvmsg, 178
sbrk, 60
select, 153
send, 178
sendmsg, 178
sendto, 178
setgid, 59
setpgid, 105
setsid, 104
setsockopt, 179
setuid, 59
sigaction, 121
siginterrupt, 119
siglongjmp, 118
signal, 115
sigpause, 120
sigprocmask, 120
sigsetjmp, 118
sleep, 57
socket, 175
socketpair, 176
tcdrain, 110
tcflush, 110
tcgetattr, 109
tcgetgrp, 106
tcgetsid, 106

acc`es direct, 34
acc`es sequentiel, 34
Allocation contigue, 77
appels syst`emes
exit, 38
accept, 178
brk, 60
cfgetispeed, 110
cfgetospeed, 110
cfsetispeed, 110
cfsetospeed, 110
chdir, 59
chroot, 59
close, 46
connect, 177
creat, 44
dup, 45
dup2, 46
exec, 51
execle, 61
execlp, 61
execv, 61
execve, 50, 61
execvp, 61
exit, 57
fchdir, 59
fcntl, 46
fork, 50, 51, 56, 61
getgrp2, 105
getmsg, 173
getpeername, 179
getpgrp, 59, 105
getpgrp2, 59
getpid, 59
getppid, 59
getsid, 106
getsockname, 179
getsockopt, 179
htonl, 179
138

INDEX
tcsetattr, 109
tcsetpgrp, 106
times, 58
ttyname, 104
ulimit, 60
umask, 60
write, 44, 100
arri`ere plan, 105
Best-fit, 81
biblioth`eques, 5
boot bloc, 10
buffer cache, 25
bufferisation, 35
bufferiser, 25
chargement dynamique, 86
compactage, 81
desarmer, 55
Demand Paging, 86
Demand-Paging, 68
droits, 7
exclusion mutuelle, 63
famine, 63
FCFS, 65
ffs, 17
fichier, 7
inodes, 9
ordinaires, 8
physiques, 8
speciaux, 8
fifo, 100
FILE, 31
First-fit, 81
groupe, 7, 10
handler, 114
HotSwap, 182
inodes, 9, 11
interruption, 54
intr, 104, 113
lazy swapper, 86
load, 68
longjmp, 114
Metadisque, 182
masquer, 55
mkfifo, 100
noyau, 5

139
ordonnancement, 63, 82
overlays, 85
page fault, 86
pages, 82
pendant, 114
physique, 103
pile, 50
pointeur de fichier, 34
preemption, 65
premier plan, 105
priorite, 67
proc, 22
processus, 49
$DATA$, 50
$TEXT$, 50
etats, 55, 57
accumulateur, 53
changement de contexte, 53
commutation de mot detat, 53, 54
compteur ordinal, 53
context, 53
creation, 49
decomposition, 49
format de fichier, 50
mode dun, 55
mot detat, 53
niveau dinterruption, 54
struct proc, 49
recouvrement, 50
swapin, 57
swapout, 57
table des processus, 51
table des regions par processus, 51
struct user, 49
zone u, 51, 58
proprietaire, 7, 10
protocole, 175
pseudo-terminaux, 103, 110
quit, 104, 113
reference, 7
RAID, 181
redirection, 32
registre barri`ere, 77
registre base, 77
Round Robin, 66
SIGHUP, 104, 113
SIGINT, 113
signaux, 113
kill, 113
SJF, 65

140
static, 104
stdio.h, 31
stdlib
atexit, 38
clearerr, 39
exit, 38
fclose, 36
feof, 33, 39
fflush, 36
fopen, 32
fread, 33
freopen, 32, 35
fseek, 34
ftell, 35
fwrite, 33
mkdir, 39
perror, 39
printf, 31
remove, 37
rename, 37
rewind, 35
rmdir, 39
scanf, 31
setbuf, 37
setbuffer, 37
setlignebuf, 37
setvbuf, 36
stderr, 31
stdin, 31
stdout, 31
system, 38
tmpfile, 33
tmpnam, 33
Xalloc, 51
super bloc, 10
susp, 104, 113
swap, 79, 85
synchronisation, 101
Syst`eme de Gestion de Fichiers, 7
tas, 50
terminal de controle, 104
termios, 106
tubes, 97
tubes nommes, 100
Worst-fit, 81

INDEX

Vous aimerez peut-être aussi