Vous êtes sur la page 1sur 8

NachOS Etape 2 : Entres/Sorties Console

Lvque Florian Dauvergne Lopold

Partie I. Quel est le but ?


La sortie attendue par ce programme est : abcd //appel de la fonction PutChar Machine halting! //appel de Halt qui va arrter la machine

Partie II. Entres-sorties asynchrones Action II.1


En excutant, ./nachos_userprog c, nous voyons que la console attend lentre dun caractre, ds que lon entre, il est affich. En appuyant sur q, nous pouvons arrter la console.

Action II.2
Pour prendre en compte la terminaison de lentre, il suffit de comparer le caractre courant : if (ch == 'q' || ch == EOF ) return;

Action II.3
Pour afficher <c> au lieu de c, il suffit de lire le caractre entre dans la console : readAvail->P (); // attendre quun caractre soit entr ch = console->GetChar (); Il suffit ensuite dcrire le caractre en lencadrant par les chevrons. if (ch != '\n') //Si le caractre est un retour chariot { console->PutChar('<'); // afficher le caractre! writeDone->P (); // attendre que lcriture soit termin console->PutChar (ch);// afficher le caractre! writeDone->P (); // attendre que lcriture soit termin console->PutChar('>'); writeDone->P ();// attendre que lcriture soit termin } else { //faire le retour charriot sans afficher les chevrons console->PutChar (ch); writeDone->P (); }

Action II.4
Nous remarquons que chaque caractre prsent dans le fichier dentre (point par in) est crit dans le fichier de sortie (point par out) et est encadr par des chevrons.

Partie III. Entres-sorties synchrones Action III.2


Pour la cration de la console, il faut instancier tout dabord les deux smaphores qui vont permettre lattente de fin dcriture et lattente de lecture. Il faut ensuite instancier la console. Il faut lui placer en paramtre deux descripteurs de fichiers en entre et en sortie, qui peuvent simuler la lecture clavier (lecture dans le fichier dentre) et laffichage sur lcran (criture dans le fichier de sortie). Il faut aussi lui passer deux fonctions en paramtre qui auront le rle de gestionnaire dentre et daffichage. Nous instancions aussi deux smaphores pour grer les appels des fonctions. En effet, il ne faut pas que deux threads puissent appeler SynchGetString par exemple pour viter des fonctionnements alatoires. SynchConsole::SynchConsole(char *readFile, char *writeFile) { readAvail = new Semaphore("read avail",0); writeDone = new Semaphore("write done",0); put_taken = new Semaphore(Put taken,1); get_taken = new Semaphore(Get taken,1); console = new Console(readFile,writeFile,ReadAvail,WriteDone,0); } Pour la fonction SynchGetChar(), il suffit de se bloquer en attendant larrive dun caractre pour se dbloquer(si lon est le premier dans la file dattente du smaphore). Nous pouvons ensuite lire le caractre entr. char SynchConsole::SynchGetChar() { char c; get_taken->P() ; readAvail->P(); c= console ->GetChar(); get_taken->V(); return c; } Pour la fonction SynchPutChar(), le fonctionnement est symtrique SynchGetChar(), nous crivons dcrire lcran un caractre puis nous nous bloquons jusqu ce que lcriture soit ralise (pas toujours instantan). void SynchConsole::SynchPutChar(char ch) { put_taken->P(); console ->PutChar(ch); writeDone->P(); put_taken->V(); }

Action III.4
Le fonctionnement est parfaitement le mme quavec ConsoleTest, il suffit de sparer les cas o il y a des fichiers en entre/sortie et une lecture/criture dentre clavier. else if (!strcmp (*argv, "-sc")) { if (argc == 1) SynchConsoleTest (NULL, NULL); else { ASSERT (argc > 2); SynchConsoleTest (*(argv + 1), *(argv + 2)); argCount = 3; } interrupt->Halt (); }

Action III.6
Le fonctionnement est en apparence le mme que ConsoleTest, il faut encadrer le caractre par les chevrons. while ((ch = synchconsole->SynchGetChar())!=EOF) { if (ch != '\n') { synchconsole->SynchPutChar('<'); synchconsole->SynchPutChar(ch); synchconsole->SynchPutChar('>'); } else { synchconsole->SynchPutChar(ch); } if (ch == 'q') return; }

Partie IV. Appel systme PutChar


Aprs avoir dfini lappel systme dans userprog/syscall.h (#define SC_PutChar 11), ajouter la procdure void PutChar(char c) au fichier, et avoir dfini le code assembleur de Putchar, nous avons transform la fonction ExceptionHandler. Comme il y a plusieurs types dexception, il faut transformer le if en switch.
switch(type){ case SC_PutChar : synchconsole->SynchPutChar((char)machine->ReadRegister (4)); break; } Nous appelons la fonction SynchPutChar(char c) pour excuter lappel de PutChar() dans un programme. Nous savons que pour un appel systme, largument 1 dune fonction est stock dans le registre 4. Il suffit de lire ce registre et de convertir la valeur retourne en char car le registre r4 est un registre entier et stocke donc une valeur sous forme entire.

Aprs avoir ajout la variable globale dfinissant une console synchrone, il faut mettre jour le fichier systeme.h en incluant le header synchconsole.h pour pouvoir utiliser les fonctions concernant SynchConsole (et pour pouvoir en crer une instance). Nous pouvons alors instancier linstance globale de SynchConsole dans la mthode Initialize() et grer sa destruction dans Cleanup(). Lorsque nous lanons putchar, nous voyons que le programme marche et produit laffichage attendu lors de la partie I.

Partie V. Des caractres aux chanes Action V.1


void copyStringFromMachine(int from, char *to, unsigned size){ int i = 0; //itrateur int val =0;//valeur retourner char c;//caractre de la valeur int f = from ; do{ machine->ReadMem(f,1,&val); //lire un octet ladresse from+i c = (char) val;//caster la valeur retourne to[i] = c;//on insre le caractre lendroit *to+i i++;f++; }while(i < (int)size && c != EOF && c != '\0'); // on sarrte quand si le caractre //symbolise la fin de fichier, fin de //chaine de caractre ou que lon a lu // size caractre to[i] = '\0';//on force lajout de la fin de chaine de caractre }

Action V.2
Lappel systme SynchPutString suit le mme principe que PutChar, seul le code de la fonction dans SynchConsole et le code dexcution de lexception leve changent.
void ExceptionHandler (ExceptionType which) { . int adresse ; int adr_string ; char* tmp ; case SC_SynchPutString : adresse = machine->ReadRegister(4) ; // Rcuprer lendroit o est la //chaine tmp = new char[MAX_STRING_SIZE+1]; //creation du buffer copyStringFromMachine(adresse,tmp,MAX_STRING_SIZE); //Obtenir la chaine de la memoire MIPS synchconsole->SynchPutString(tmp);//ecrire la chaine sur la console delete[] tmp;//supprimer le buffer break; }

Dans lcriture de la fonction SynchPutString(const char s[]), nous utilisons aussi le smaphore put_taken. void SynchConsole ::SynchPutString(const char s[]) { put_taken->P(); //Prendre le semaphore int i =0; char c = s[i]; //recuprer le premier caractere while (c != \0 && c!=EOF){ console->PutChar(c); //on ecrit le premier caractere writeDone->P(); //on attend la fin de lecriture i++; c=s[i]; } console->PutChar(\0); writeDone->P(); put_taken->V(); //on libere le semaphore }

Action V.3
En testant notre programme avec une chaine plus grande que la taille maximal dun string (ici dfini 20 caractres), nous remarquons que seulement les 20 premiers sont affichs.

Partie VI. Mais comment sarrter ? Si nous enlevons lappel halt() la fin du main de putchar.c. Il ny a plus de valeur retourne donc il y a un warning la compilation. Ce warning est trait comme une erreur. Pour ne plus faire appel Halt, il faut retourner une valeur quelconque la place. En testant le programme putchar.c avec une valeur de retour, nous remarquons que lexcution est normale jusqu laffichage du type dexception : Unexpected user mode exception 1 1 . Nous remarquons que lexception a le type 1, ce code dappel systme est SC_Exit. Il faut donc grer un cas pour cette exception dans le gestionnaire dexception ExceptionHandler. De plus, quand nous regardons le code assembleur qui gre lappel dun programme, nous remarquons quelle se fait en plusieurs tapes : La gestion dun programme se faire ltiquette __start : jal main move $4,$0 jal Exit Nous voyons qu la fin du main, sil ny a pas lappel Halt, le programme ira ltiquette Exit. Il y aura donc un appel systme Exit. Pour grer la valeur de retour, il faut aller voir dans le fichier test/start.S. En effet, il faut aussi regarder le code assembleur. Nous savons que la valeur de retour dune fonction est

stocke dans le registre r2. Cependant lors de lexcution de Exit, nous remarquons que le code dappel systme est stock dans le registre r2. Pour avoir le code de retour, une possibilit est denregistre la valeur du registre r2 dans un autre registre, par exemple le registre r4 (il ny a pas paramtre lors de la fin dun programme). Il suffit dajouter linstruction : move $4, $2 avant linstruction denregistrement du code SC_Exit dans r2.
void ExceptionHandler (ExceptionType which) { . int retour; case SC_Exit : retour = machine->ReadRegister(4) ; //recuperer la valeur de retour printf(la valeur retournee du programme est %u\n,retour); interrupt->Halt() ;//arrter la machine break; }

Partie VII. Fonctions de lecture Action VII.1


Lappel systme SynchGetChar suit le mme principe que PutChar, seul le code de la fonction dans SynchConsole et le code dexcution de lexception leve changent. Nous rcuprons la valeur retourne, puis nous lcrivons dans le registre r2 (registre utilis pour le retour dune valeur de fonction).
void ExceptionHandler (ExceptionType which) { . int retour; case SC_SynchGetChar : machine->WriteRegister(2,(int)synchconsole->SynchGetChar())) ; break; }

Action VII.2
Lappel systme SynchGetString suit le mme principe que PutChar, seul le code de la fonction dans SynchConsole et le code dexcution de lexception leve changent. Pour lcriture de SynchGetString, je me suis inspir de ce texte cette description :
char *fgets (char *s, int size, FILE *stream); fgets() lit au plus size - 1 caractres depuis stream et les place dans le buffer point par s. La lecture s'arrte aprs EOF ou un retour-chariot. Si un retour-chariot (newline) est lu, il est plac dans le buffer. Un caractre nul '\0' est plac la fin de la ligne.

void SynchConsole ::SynchGetString(char *s,int n) { get_taken->P(); //prendre le smaphore de lecture readAvail-> P();//attente de lecture char c = console->GetChar(); // on lit le premier caractre int i = 0; s[i] = c; i++;

while (i<(n-1) && c!=EOF && c!=\n && c!=\0 && c!=|r){ readAvail->P(); c = console->GetChar(); if (c != EOF && c != \0){ s[i] = c; i++ } }
s[i] = \0; get_taken-> V(); } Dans le gestionnaire dexception, le cas de SynchGetString doit tre le symtrique de SynchPutString, nous devons rcuperer le string, puis le copier dans la machine MIPS. void ExceptionHandler (ExceptionType which) { int adr_string; int taille; char* string; case SC_SynchGetString : adr_string=machine->ReadRegister(4) ; taille = machine->ReadRegister(5); tmp = new char[MAX_STRING_SIZE]; writeStringtoMachine(adr_string,string,taille); synchconsole->SynchGetString(tmp); delete[] tmp; break; } void writeStringtoMachine(int debut, char* tableau, int size) { int d = debut; int i =0; while(i<size && tableau[i] != \0 && tableau[i] != EOF) { machine->WriteMem(d,1,(int)tableau[i]); i++;d++; } machine-> WriteMem(d,1,(int)\0); } Sil y a plusieurs appels de cette fonction par plusieurs threads, il peut y avoir des comportements nfastes, en effet, les threads peuvent lire les caractres de la chaine en mme temps et donc vont juste avoir un morceau de la chaine.

Action VII.3
Le protocole de snprintf est : snprintf (char *str, size_t size, const char *format, ...);
Le premier argument de cette fonction est la chaine de caractres qui contiendra le rsultat de la conversion. Le deuxime argument est justement le nombre maximal de caractres qui seront renvoys dans cette variable. Le paramtre suivant est le format suivi des variables qui devront tre converties selon ce format.

void SynchConsole ::SynchPutInt(int n) { char c[10] ; snprintf(c,10, %d ,n) ; synchconsole->SynchPutString(chaine) ; } void ExceptionHandler (ExceptionType which) { int valeur; case SC_SynchPutInt : valeur =machine->ReadRegister(4) ; synchconsole->SynchPutInt (valeur); break; }

Le protocole de sscanf est sscanf ( string $str , string $format,) sscanf() lit des donnes dans la chane str, l'interprte en fonction du format format, puis enregistre ladresse des pointeurs passs en paramtre les donnes concordantes au(x) format(s). void SynchConsole ::SynchGetInt(int *n) { char c[10] ; synchconsole->SynchGetString(c,10) ; sscanf(c, %d ,n) ; } void ExceptionHandler (ExceptionType which) { int valeur; case SC_SynchGetInt : adresse =machine->ReadRegister(4) ; synchconsole->SynchGetInt (&entier); machine->WriteMem(adresse,sizeof(int),entier) ; break; }

Partie VIII. Dtection de fin de fichier


Nous navons pas russi faire cette partie, nous avons juste implment lactionVIII.2 en modifiant la mthode SynchGetChar (et GetChar) pour quelle retourne un entier.

Vous aimerez peut-être aussi