Ift320 Enonce tp3
Ift320 Enonce tp3
Ift320 Enonce tp3
SYSTÈMES D'EXPLOITATION
Travail pratique 3
Travail en équipe:
Pour les groupes de deux étudiants exactement, les parties à réaliser sont :
1-a) b) c) d) e) f)
2-a) b) c)
3-a) b)
Pour les étudiants voulant être seuls, les parties à réaliser sont :
1-a) b) c) d) e) f)
2-a) b) c)
Pour les étudiants voulant être en groupe de trois, toutes les parties sont à faire. L’omission des
parties supplémentaires vous pénalise de 20% de la note.
Les parties supplémentaires peuvent être faites en bonus par les personnes seules ou les équipes
de 2. Les bonus sont plus payants pour les personnes seules (note pondérée sur un total plus bas).
Les trois derniers travaux pratiques du cours IFT320 portent tous sur NachOS (Not
Another Completely Heuristic OS), un système d'exploitation minimaliste à but
pédagogique. Au cours de ces TPs, vous aurez à modifier différentes parties du
système afin de leur rajouter des fonctionnalités.
Cependant, notez bien que dans ce document les anciens énoncés des travaux et
les dates de remise indiqués ne sont plus valides. Les dates de remise pour cette
session sont celles indiquées dans le plan de cours, et les énoncés des travaux se
trouvent ci-dessous.
Les tests seront faits dans l'ordre dans lesquelles les questions sont posées; il est donc
fondamental que vous complétiez chaque question avant de commencer la suivante.
Pour chaque travail pratique, vous devrez soumettre par turnin web vos sources
modifiées de NachOS. La structure de répertoires du dossier « nachos » qui vous est
fourni doit demeurer intacte. Vous devez remettre le répertoire « nachos » au complet
avec ses sous-répertoires.
Toute demande de resoumisson ou de recorrection se verra octroyer une pénalité de
10% de la note.
Processus noyau
Dans son état initial, NachOS est capable d’exécuter des processus, avec quelques
restrictions. Tout d’abord, il peut simuler plusieurs processus concurrents, mais ils
exécutent tous des parties du code de NachOS même, on peut les qualifier de
« processus noyau ». Ces processus sont représentés par la classe Thread (bloc de
contrôle de processus tel que vu en classe). Attention! Ici, la classe Thread ne
représente pas des fils d’exécution (terme Thread dans la littérature) mais bien des
processus. Chaque utilisation du terme Thread dans ce document réfère à un
processus, pas un fil d’exécution.
Afin de réaliser cette simulation, NachOS est capable de sauvegarder l’état de son
exécution (zone de sauvegarde au début de l’objet de type Thread). Pour faire comme
si on avait plusieurs processus, on n’a qu’à sauvegarder une copie des registres
SPARC (incluant le compteur ordinal) dans chaque objet Thread représentant une
exécution concurrente de NachOS. Pour changer le processus en cours, il suffit de
sauvegarder les valeurs courantes des registres SPARC dans le Thread courant
(currentThread), puis de copier les valeurs des registres sauvegardées dans le Thread
qu’on veut exécuter dans les registres SPARC. Finalement, on fait un branchement à
l’adresse conservée dans la copie du compteur ordinal sauvegardée dans le Thread
qu’on veut exécuter et le tour est joué.
Ces changements sont réalisés et contrôlés par la classe Scheduler (dans
scheduler.cc/.h). Une fonction spéciale qui réalise ces opérations en assembleur
s’appelle SWITCH, et se trouve implantée en assembleur dans switch.s.
En plus de supporter des processus noyau, la version actuelle de nachos supporte des
processus utilisateurs (ou applications).
Ces processus et leurs états sauvegardés sont représentés par la classe AddrSpace
(addrspace.cc/.h).
Un processus utilisateur (AddrSpace) ne peut pas s’exécuter sans avoir son processus
noyau (Thread) correspondant.
Pour ce faire, il crée un objet AddrSpace, l’initialise, place le simulateur dans le bon état
et démarre la simulation (machine->run()). Ceci est réalisé dans la fonction
StartProcess, dans le fichier progtest.cc.
Un fichier exécutable pour nachos est un programme compilé pour être exécuté sur le
simulateur MIPS. Plusieurs de ces fichiers sont fournis dans les répertoires /test et
/test_tp3. Dans /test, seul le fichier « halt » va fonctionner correctement d’ici à la fin de
ce devoir. Dans /test_tp3, avec un peu de chance, TOUS les fichiers devraient
fonctionner d’ici la fin.
Le code source des exécutables chargeables sur nachos est écrit en C, pas en C++!!!
Un compilateur spécial les transforme en exécutables dans un format que nachos peut
charger dans son simulateur MIPS.
Le code simulé des processus utilisateurs, ainsi que leurs données se trouvant
chargées dans le simulateur MIPS peuvent être vues comme étant dans dans des
espaces d’adresse utilisateurs, tandis que le code de nachos sur lequel vous travaillez,
qu’exécutent les objets Thread, peut être vu comme étant dans l’espace d’adresse
noyau. Le transfert de données entre les deux implique des accès à la mémoire de la
machine virtuelle MIPS (ReadMem et WriteMem).
Tâches à réaliser
Beaucoup d’étapes doivent être franchies avant de faire de NachOS un système avec
une gestion des processus un peu plus respectable. Le travail se divise en trois parties
importantes :
Chaque partie contient plusieurs numéros. Pour chaque numéro, des tests sont fournis,
afin de vous permettre de vérifier leur réalisation. Ces tests sont les mêmes qui seront
faits sur le travail que vous allez remettre. Les noms mentionnés pour les tests sont des
scripts qui exécutent un ou plusieurs processus utilisateurs sur nachos (nachos –x …).
Vous pouvez taper ces commandes directement dans le répertoire /userprog. Si vous
voulez savoir quels programmes sont chargés par un test en particulier, vous pouvez
afficher le script avec la commande « cat » (cat tjoin par exemple, pour voir la
commande faite par le test « tjoin »). Les fichiers de code source des tests sont tous
dans le répertoire /test_tp3 et continennent généralement des commentaires qui
expliquent ce que les tests devraient faire.
Les modificatons pour cette partie sont presque entièrement réalisées dans le fichier
exception.cc.
a) Appel Système Exit
Script de test : texit
Réalisation : 20 minutes (y’a un peu de lecture, quand-même…)
b) Erreurs de programmes
Script de test : terror
Réalisation : 20 minutes
Les programmes utilisateurs peuvent parfois faire des erreurs et c’est au système
d’exploitation de les détecter et de les traiter. Ces erreurs sont générées par la machine
virtuelle MIPS, lorsque le code simulé fait des erreurs. Allez faire un tour dans
machine.h et regardez l’enum ExceptionType, il est assez informatif à ce sujet…
Syscall est un type d’exception, le seul qui ne représente pas une erreur (pour lequel
vous avez un paramètre, qui est le sujet du switch-case).
NoException : Aussi utile qu’un Branch Never. Si ça arrive, blue screen of death
(nachos au complet doit crasher et vous devez vous en rendre compte au plus vite). Ne
va vous arriver que si VOUS avez fait des erreurs substancielles plus loin dans votre
implémentation. Vous avez probablement bousillé l’état interne de la machine MIPS
simulée (corruption mémoire). Probablement le résultat d’un duel au sabre laser dans
AddrSpace.
Afin de pouvoir communiquer avec le monde extérieur, il faut leur offrir l’appel système
Write. Cet appel écrirait normalement dans un fichier, mais il faudrait implanter le
support pour quelques autres appels (read, open, create) du même coup, ce qui est une
trop grosse bouchée.
Pour les récupérer, il faut implanter CopyFromUser, une routine qui sert à récupérer
des données dans l’espace d’adresses utilisateur et les ramener dans une variable
noyau (un tampon de la bonne taille).
Tout d’abord, il faut récupérer les paramètres de l’appel système. Ceux-ci sont dans les
registres r4, r5 et r6 respectivement (utilisez ReadRegister). Le paramètre qui
représente les données à afficher est une adresse où celles-ci commencent dans le
processus utilisateur, mais c’est une adresse valide seulement dans le contexte du
MIPS simulé.
Les données ne seront pas tout à fait transférées de la forme qui vous plaît, un petit
retour sur vos connaissances de la représentation des types de données et des règles
de conversion de type (sans oublier le type Word32 déclaré dans exception.cc) devrait
permettre de trouver une solution.
Finalement, il est important de constater que c’est le premier appel système que vous
implantez qui retourne le contrôle au processus utilisateur après sa réalisation. Pour
qu’un appel qui se termine correctement puisse être pleinement réalisé, il faut
manuellement avancer le compteur ordinal du MIPS simulé (fonction incrementPC).
Ceci est valide pour tous les cas d’appel système pour lesquels le processus utilisateur
va un jour continuer son exécution (peut importe si c’est remis à plus tard à cause d’un
changement du processus courant via scheduler).
Pour tous les numéros, si vous souhaitez mettre des affichages de traces pour fins de
débuggage, rappelez-vous de les retirer avant de soumettre votre travail. Plusieurs des
tests avancés chargent des programmes qui font des boucles infinies, si vous avez
laissé des traces, votre devoir va polluer les résultats du script de correction et il devra
être corrigé manuellement, ce qui vous octroiera une pénalité de 10%.
d) Create
Script de test : tcreate
Réalisation : 20 à 30 minutes
Il est temps d’implanter les services pour la gestion des fichiers. Notez bien, le système
de fichiers tel qu’implanté lors du TP2 ne rentre pas en ligne de compte pour ce devoir.
La version du système de fichiers qui sera utilisée se trouve complètement implantée
(corps de méthode et tout!) dans le début du fichier filesys.h. Les fichiers que vous allez
créer, ouvrir, lire et modifier seront tous directement dans votre répertoire unix sur tarin
(chemins relatifs au répertoire où s’exécute nachos).
Aucune gestion de la table des fichiers ouverts ne doit être implantée… ce qui implique
une petite perte de mémoire qu’on devra tolérer (objets OpenFile qui seront créés, mais
jamais détruits dans le cas de l’appel système Open).
Tout d’abord, l’appel système Create vous envoie en paramètre une chaîne de
caratères dont la taille est inconnue. Ceci implique que votre fonction CopyFromUser
actuelle, qui a besoin de savoir la taille, ne peut pas fonctionner. Implantez une
seconde version qui est spécifique à la copie de chaînes de caractères. Le caractère de
fin de chaîne a la valeur 0.
Afin de réaliser quelque-chose d’intéressant, on doit pouvoir écrire dans les fichiers
qu’on a créés. Pour ce faire, il faut d’abord permettre l’ouverture des fichiers, puis
ensuite, l’écriture dans autre chose que le journal noyau.
Écrivez d’abord le code pour l’appel sytème Open. Celui-ci devrait produire un objet de
type OpenFile et retourner la valeur de ce pointeur à l’utilisateur (sous forme de
OpenFileId).
Ensuite, modifiez votre appel système Write pour supporter l’écriture lorsque vous
recevez un OpenFileId autre que ConsoleOutput (qui servait à envoyer des messages
au journal).
Les modifications pour cette partie sont surtout dans exception.cc, et dans
addrspace.cc, avec quelques-unes dans thread.cc/h.
Ce service est implémenté par l’appel système Exec. Pour démarrer un nouveau
processus, on appelle Exec avec le nom du fichier exécutable en question (doit être un
exécutable en format NachOS, comme ceux dans /test et /tp3_test). Une priorité doit
également être fournie pour calibrer les algorithmes de planification (sera utile plus tard,
vous pouvez l’ignorer pour l’instant).
Présentement, la planification est faite avec l’algorithne FCFS, premier arrivé, premier
servi. De plus, il n’y a pas de situation qui va mettre un processus dans l’état bloqué!
Ceci implique qu’une fois qu’il prend le contrôle de l’UCT, un processus s’exécute au
complet avant de laisser la place à un autre. Par exemple, si le programme P1
commence à s’exécuter et fait Exec(P2), le contrôle de l’UCT n’est pas passé à P2
immédiatement, celui-ci est placé dans la file des processus prêts et sera exécuté
quand P1 aura terminé.
Bien que tout ceci paraîsse compliqué, vous avez deux fonctions relativement
magiques qui font déjà la majorité du travail : Thread ::Fork et StartProcess (dans
fstest.cc).
Ces deux fonctions n’ont pas besoin d’être modifiées, seulement appelées
correctement... et c’est là que ça se corse.
L’objectif de Thread ::Fork (que vous allez constater si vous lisez le code) est de donner
une adresse initiale à la copie de compteur ordinal du Thread, pour qu’on sache quoi
exécuter lorsque le Scheduler le choisit pour l’exécution. Fork prend donc une adresse
dans le code de nachos (pointeur de fonction) en paramètre. Si cette fonction reçue en
paramètre doit elle-même recevoir un paramètre, alors Fork lui transmet sous forme
d’un int (devrait se transtyper sans problème si votre paramètre est quelque-chose qui
rentre dans un mot de 32 bits... int ,float, pointeur, etc).
Une fois les préparations faites, Fork place le processus dans la file des processus
prêts (scheduler->ReadyToRun). Éventuellement, ce processus sera choisi pour
l’exécution et la routine SWITCH va copier ses valeurs initiales de registres dans les
registrses SPARC et brancher sur sa copie du compteur ordinal, qui contient l’adresse
de la fonction en question.
Que devrait faire un nouveau processus noyau qui a pour objectif d’exécuter un
processus utilisateur lorsqu’il démarre? Charger l’exécuable contenant le programme
dans la mémoire du MIPS et démarrer la simulation. Heureusement, toute la procédure
est déjà réalisée dans StartProcess...
ATTENTION!
À cette étape, vous n’avez pas encore modifié le chargement de programmes dans la
machine MIPS simulée. Un programme utilisateur ne se voit chargé que lorsque son
processus noyau associé (Thread) prend le contrôle de l’UCT. Avec l’algorithme FCFS
et aucune condition bloquante, ça arrivera uniquement après que le programme
précédent ait complètement terminé. Ceci implique que le nouveau programme
utilisateur peut carrément écraser l’ancien dans la mémoire du MIPS simulé sans
aucune conséquence grave. Vous allez devoir améliorer ça dans les numéros suivants.
Cette partie du devoir risque d’être la plus problématique. Si vous la réalisez mal, vous
allez rencontrer des problèmes un peu partout (peut briser les numéros précédents, ou
causer des erreurs qui ne seront révélées que dans les numéros suivants).
Les modifications que vous allez faire pour cette partie sont majoritairement dans
addrspace.cc, plus précisément, dans le constructeur d’AddrSpace. Allez y jeter un
coup d’oeil et revenez lire la suite.
Pour réalisez cette partie, il faut comprendre comment la mémoire du MIPS simulé est
représentée.
La mémoire du simulateur est en fait un grand tableau d’octets, conservé dans l’objet
machine (machine->mainMemory). Lire et écrire dedans paraît assez simple vu que la
la variable en question est publique, mais vous ne devriez JAMAIS faire ça.
Bon, vous allez me dire : oui mais c’est précisément ce qui est fait dans
AddrSpace ::AddrSpace(). Oui, mais c’est précisément la raison pour laquelle on
n’arrive pas à charger deux programmes en même temps dans la mémoire du MIPS.
La mémoire du MIPS est divisée en blocs, qu’on appelle des « pages physiques ». Le
terme technique qu’on utilise habituellement pour ça est « cadre ». En anglais, vous
verrez « physical page » ou « frame ».
Chaque morceau du programme qu’on veut exécuter (page virtuelle) doit être chargé
dans un morceau de la mémoire du MIPS (page physique). Tous les morceaux, virtuels
ou physiques, ont toujours tous exactement la même taille.
Une page physique peut être assigné à un processus comme bon nous semble. Pour
réaliser cette association, on a besoin d’une table de pages (PageTable). C’est un
tableau associatif qui dit quelle page physique contient les données de chacune des
pages virtuelles du programme (donc, où sont chargés les morceaux du programme).
Il faut donc pouvoir se rappeler de quelles pages physiques sont déjà utilisées.
Pour ce faire, vous avez besoin d’une variable qui sera globale à tous les AddrSpace
(variable de classe, ou juste une variable globale dans addrspace.cc), vous permettant
de déterminer quelles pages physiques sont libres et peuvent être assignées à votre
nouveau processus.
ATTENTION!!!
Juste après l’initialisation de la table de pages, vous devez appeler la fonction
RestoreState. La suite de votre constructeur risque de demander à la machine d’utiliser
la table de pages fraîchement initialisée, il faut donc remplacer le pointeur de table de
pages anciennement utilisé par celui de votre nouvelle table. Si vous avez réalisé votre
appel système Exec tel que prescrit, alors vous ne devriez pas avoir de problème. Vous
ne devriez pas faire ça si le currentThread n’est pas le Thread qui possèdera l’objet
AddrSpace en cours d’initialisation.
Bon, vous avez réussi à associer des pages physiques libres à votre nouveau
processus via sa table de pages... mais vous ne l’avez pas encore chargé en mémoire!
Cette partie du travail est délicate et peut mener à des erreurs catastrophiques.
Heureusement, vous avez plusieurs outils à votre disposition pour éviter de faire des
erreurs.
-Une table de pages correctement initialisée (utilisez donc PrintPageTable pour
vérifier...)
-Une fonction CopyToUser
-Une implémentation de l’appel système Read
Reste à comprendre ce que vous devez lire dans le fichier exécutable, et où ça doit être
transféré dans l’espace d’adresses de l’utilisateur.
Eh bien, vous devez interpréter les lignes de code à la fin du constructeur d’AddrSpace
pour cela... grosso modo, noffH (l’en-tête de l’exécutable) indique où commencent les
sections de données et de code dans le fichier exécutable (inFileAddr), quelle taille ils
ont (size) et à quel endroit dans l’espace d’adresses de ils doivent être chargés
(virtualAddr).
Si vous aviez une fonction SysCallRead qui pouvait lire où vous désirez dans votre
fichier exécutable, le tour serait presque joué!
N.B. Si vous désirez utiliser des fonctions qui sont définies dans exception.cc alors que
vous êtes dans addrspace.cc, il suffit de les redéclarer (pas les redéfinir!!!) dans
addrspace.cc, en précédant la déclaration du mot-clé extern.
Finalement, pour arriver à faire des tests qui vont charger plusieurs programmes à la
fois, il doit être possible pour un processus de lâcher l’UCT avant d’avoir terminé.
Comme les demandes d’entrée/sortie ne bloquent pas les processus et que l’algorithme
est FCFS, on a besoin de tricher et de permettre à un processus de lâcher
volontairement l’UCT.
Ce service est l’appel système Yield. Il n’est pas particulièrement difficile à implanter,
étant donné que cette fonctionnalité est déjà prévue du côté de Thread...
Une fois Yield implanté, vous pouvez lancer tspace et tyield, qui devraient mettre à
l’épreuve votre impantation du partage de la mémoire entre les processus utilisateurs.
Pour réaliser cet appel système, vous devez pouvoir manipuler des identificateurs de
processus. Un type a été prévu pour ça dans syscall.h : SpaceId. Qu’est-ce qu’un
SpaceId? Un int, apparemment, mais que devrait-il contenir?
Eh bien, quelque-chose qui identifie un processus de façon unique. C’est comme une
poignée de fichier pour la table des fichiers ouverts et les opérations sur les fichiers,
juste une clé qu’on donne à l’utilisateur lors de l’ouverture pour savoir de quel fichier il
parle lorsqu’il fait des demandes comme read et write ultérieurement.
Dans le cas d’un processus, l’utilisateur obtient le SpaceId comme résultat de l’appel
système Exec, puis utilise cette valeur comme paramètre pour l’appel système Join plus
tard.
P1 : Exec P2
P1 : fait des trucs
P1 : Join P2
-P1 lâche l’UCT
P2 : fait des trucs
P2 : Exit
P2 : lors de son exit, signale P1 qu’il a terminé.
Donc, il faut modifier Exit pour signaler à un processus qui nous attendait qu’on a
terminé, et lui envoyer notre code de sortie (paramètre du exit).
Pour seulement deux processus, dans un test très simple, on peut utiliser des variables
globales pour se synchroniser. Une qui indique si le processus attendu a terminé (FIN),
puis une qui contient le code de retour du processus attendu (CODE).
Pour Exit :
FIN = vrai
CODE = parametre du Exit
ATTENTION! Cet algorithme est incomplet, mais devrait être suffisant pour que
tminijoin s’exécute correctement. L’implantation complète du join est le numéro 2 e).
d) Utilisation responsable de la mémoire du MIPS
Script de test : tfull
Réalisation : 1h à 24h.
Cette partie est un bonus pour les équipes de 1 et 2 (5% de la note), mais obligatoire
pour les équipes de 3.
Dans le numéro 2 b), on n’a pas prévu qu’un processus pourrait libérer de la mémoire
qui serait ensuite réutilisée par un autre processus.
Pour y arriver, il faut avoir une meilleure gestion des pages physiques libres.
Allez faire un tour dans bitmap.cc/h et vous y trouverez la structure de données toute
indiquée pour réaliser ce travail.
Cette partie doit être correctement réalisée pour faire l’algorithme HRN (partie 3 c)).
Voici les trois situations de Join à 2 processus possibles (si P1 est celui qui exec P2):
Si vous avez impanté ce genre de structure de données dans le TP2 pour votre table de
fichiers ouverts, vous ne devriez pas être trop dépaysé(e).
Les modifications pour cette partie sont surtout dans scheduler.cc, avec quelques-unes
dans system.cc et thread.h/.cc; peut-être aussi dans list.cc/.h. N’oubliez pas que vous
pouvez faire afficher le contenu de la file des processus prêts à l’aide de la fonction
Scheduler ::Print().
Notre gestion des processus est enfin suffisante pour qu’on puisse implanter des
algorithmes de planification.
Le plus facile à faire est un algorithme à priorité statique sans réquisition. Grosso modo,
lorsqu’un processus est chargé, il est mis en file dans un ordre déterminé par la priorité
qu’on lui a donné lors de son Exec. Ainsi, on exécute les processus dans l’ordre de leur
priorité.
Par exemple :
Pour savoir comment récupérer les paramètres, regardez le code déjà fait pour les
autres options (-x est un bon exemple, il se trouve dans main.cc).
ATTENTION!! Le comportement de votre planificateur (scheduler) va nécessairement
être différent selon l’algorithme choisi. Vous devez conserver l’ancien fonctionnement
(FCFS) intact pour que tous les anciens tests fonctionnent comme avant. FCFS doit
également être choisi lorsqu’on ne spécifie pas l’algorithme (pas d’option –a).
Pour réaliser correctement la priorité statique, c’est une bonne idée d’aller faire un tour
dans list.cc/.h pour comprendre comment utiliser la file des processus prêts.
Il est temps de se mettre le nez dans les réquisitions et les tranches de temps.
Vous devez implanter l’algorithme du tourniquet (Round Robin), qui octroie une tranche
de temps fixe à chaque processus et leur réquisitionne l’UCT si celle-ci s’épuise.
Pour calculer le temps, vous allez avoir besoin d’une routine d’interruption et d’une
horloge. L’horloge est implantée du côté de machine (timer.cc/.h). Elle appelle une
routine d’interruption à toutes les fois qu’un certain nombre d’instructions sur la machine
virtuelle MIPS ont été simulées. Elle peut générer des interruptions au hasard, mais
vous ne voulez pas que ça se produise (doRandom devrait être FALSE lors de la
création du Timer).
Finalement, c’est l’heure d’implanter un algorithme plus complexe, qui tient compte des
priorités et de l’écoulement du temps. L’algorithme tout indiqué pour ça est une variante
de l’algorithme HRN vu en classe.
La priorité de tous les processus doit être recalculée à toutes les interruptions d’horloge.
On mettra donc le temps de service du processus en cours d’exécution à jour, puis le
temps d’attente de tous les processus qui sont dans la file des processus prêts à jour.
Chaque interruption d’horloge compte pour une unité de temps.
Si, en raison de cette mise à jour, un processus a maintenant une priorité plus élevée
que celui qui est en cours d’exécution, on doit lui réquisitionner l’UCT.
Pour réaliser correctement cette partie, il est probable que vous deviez ajouter des
fonctionnalités à la classe List (attention de ne pas la briser pour les anciens tests et le
reste de nachos!!) ou changer la file des processus prêts pour une structure de
données que vous jugez plus appropriée.
Mini-Tutoriel
cd nachos
cd code
make
cd userprog
Ici, vous devriez voir tous les fichiers source, les fichiers intermédiaires, et finalement,
l’exécutable « nachos ». Cet exécutable est le système d’exploitaton simulé. Chaque
fois que vous entrez la commande « nachos », c’est comme si vous démarriez un
ordinateur avec le système Nachos dessus. Quand le programme se termine, c’est
l’équivalent de dire que l’ordinateur sur lequel Nachos s’exécute s’est éteint.
mtest
Cette commande compile tous les tests se trouvant dans /test_tp3. Vous ne devriez pas
avoir besoin de la refaire si vous ne modifiez pas les tests.
nachos –x ../test/halt
Ceci exécute le seul test fonctionnel actuellement, c’est un programme qui demande
l’arrêt du système.
make
texit
Vous devriez voir apparaître votre message parmi les affichages que fait nachos. Vous
devriez ensuite retourner à la description des tâches et réaliser l’appel système Exit
correctement (numéro 1 a)).
Bon travail!