|
Memorie virtuala si multiprogramare
Memorie virtuala
Pentru a implementa memorie virtuala, va trebui sa rezolvati urmatoarele aspecte: translatarea adreselor, mecanismul de stocare a paginilor de memorie pe disc (backing store), copierea paginilor intre memoria fizica si disc si mecanismul de alocare de pagini (incluzand si algoritmul de revendicare a paginilor (page eviction -- poate o traducere mai potrivita ar fi "recuperare")).
Translatarea adreselor se face de catre hardware-ul emulat. In Machine::ReadMem si Machine::WriteMem se apeleaza metoda Machine::Translate , ce foloseste tabela de pagini sau TLB-ul pentru a traduce din adresa virtuala in adresa fizica. TLB-ul este folosit atunci cand, la compilare, se defineste macro-ul USE_TLB. In acest laborator nu il vom folosi.
Pana acum, translatarea adreselor se facea unu la unu, adica practic nu avea loc nici o modificare a adresei. Pentru ca translatarea sa aiba loc, trebuie sa completati tabela de pagini in mod corespunzator, de fiecare data cand alocati o pagina.
Mecanismul de stocare (backing store), poate lua doua forme (oarecum extreme): un "swap space" comun tuturor proceselor, sau cate un fisier separat pentru fiecare proces in parte. Swap-ul poate sa stea la randul lui intr-un fisier, de dimensiune fixa (de obicei). El poate sa fie creat si pe o partitie separata in diverse sisteme de operare, dar in cazul nostru nu are rost sa ne complicam.
Atunci cand trebuie alocate pagini unui nou proces, sau o pagina nu este in memorie dar este necesara pentru executarea unei instructiuni (page fault), pagina trebuie copiata de pe disc in memoria fizica. Daca nu exista o pagina libera in memoria fizica, atunci trebuie "facut loc", prin indepartarea unei pagini ocupate de un proces (copierea ei pe disc).
Un aspect important este acela ca va trebui, probabil, sa modificati corespunzator mecanismul de copiere intre memoria proceselor si aceea a nucleului Nachos.
Clasa Bitmap , definita in userprog/bitmap.* , poate fi utila pentru alocarea de pagini atat pentru memoria fizica cat si pentru stocarea lor pe disc.
Multiprogramare
Un sistem de operare trebuie, in cele mai multe cazuri, sa permita coexistenta, in memoria fizica, a mai multor procese utilizator, si executarea acestora pe rand si/sau intr-o ordine oarecare (data de algoritmi de planificare).
De obicei, un proces utilizator este lansat in executie la initializarea sistemului (init, in UNIX), care ulterior porneste alte procese conform unor fisiere de configurare. Va trebui sa pastrati posibilitatea de a specifica un program in linie de comanda, iar prin intermediul apelului sistem Exec() acesta va putea lansa, la randul lui, alte procese. Ca punct de plecare pentru implementarea lui Exec() vedeti userprog/progtest.cc: StartProcess si de asemenea constructorul clasei AddressSpace .
In Nachos, fiecarui proces utilizator ii corespunde un fir de executie al nucleului, in care se executa masina virtuala (Machine::Run() ). Asta nu inseamna insa ca exista mai multe instante ale clasei Machine . Clasa Machine este instantiata o singura data, la initializarea programului Nachos, si obiectul respectiv poate fi accesat prin variabila globala machine .
Atunci cand se trece de la un proces la altul, starea proceselor trebuie salvata si restaurata. De acest lucru se ocupa AddrSpace (citit codul!). Tot ea are grija ca atributul Machine::pageTable , al lui machine , sa fie initializat astfel incat mecanismul de translatie sa foloseasca tabela corecta.
Mersul lucrarii
Pasii descrisi aici nu trebuie urmati intocmai, si nu neaparat in ordinea data. Exista multiple abordari pentru a rezolva tema data.
- Cititi codul Nachos:
userprog/addrspace.* ,userprog/progtest.* ,userprog/syscall.h ,machine/machine.* ,machine/translate.* ,userprog/bitmap.*
- Planificati mecanismele, structurile de date, functiile (metodele) importante.
- Extindeti clasa
AddrSpace astfel incat sa aloce memorie la incarcarea programului si sa foloseasca tabela de pagini.
- Modificati mecanismele de copiere de date intre spatiul de adrese al procesului si cel al nucleului.
- Implementati mecanismul de memorie virtuala cu stocare pe disc a paginilor care "nu incap in memorie". Testati-l folosind programul
test/matmult.c , care foloseste multa memorie (mai multa decat cea fizica a Nachos-ului).
- Implementati apelurile de sistem
Exec() si Join() .
- Folosind (de exemplu)
Timer -ul, generati intreruperi a caror rutina de tratare sa ruleze planificatorul de procese si sa treaca de la procesul curent la un altul.
- Testati scriind cateva programe utilizator care fac diverse apeluri de sistem, lanseaza alte programe, etc.
Documentatie
Pe langa codul in sine, cititi urmatoarele:
- "A Roadmap Through Nachos", capitolul 4
- "A Roadmap Through Nachos", sectiunea 2.4
- "A Roadmap Through Nachos", sectiunea 6.3
- ../doc/userprog.ps si ../doc/vm.ps
Observatii
- Lucrati in subdirectorul "userprog" si "vm". Nu este strict necesar sa lucrati in subdirectorul "vm", dar poate fi util pentru structurarea codului.
- Ganditi mecanismele pe care le veti implementa, atat pentru partea de memorie virtuala cat si pentru multiprogramare, inainte de a va apuca sa scrieti cod! Imaginati-va scenariile posibile, care sunt actorii si cum interactioneaza ei cu sistemul.
- Testati rand pe rand fiecare parte a proiectului. Scrieti mici programe utilizator in acest scop, sau scrieti teste in codul nucleului, unde este cazul. Acestea le puteti ulterior comenta.
- Daca alocam un fisier pentru fiecare proces in parte, putem face observatia ca nu este necesar sa copiem codul procesului in acest fisier, deoarece el nu se modifica. Prin urmare, fisierul-imagine trebuie sa contina doar datele si zona stivei. Aceasta observatie se poate folosi si in cazul utilizarii unui "swap". Putem scrie in swap doar acele pagini din proces care nu contin cod, urmand ca atunci cand ele trebui readuse in memoria fizica, sa fie citite din fisierul executabil. Acest lucru ne complica insa implementarea, deoarece trebuie sa ne asiguram ca o pagina de cod contine doar cod, nu si date; astfel ajungem la segmentare. Nu este obligatoriu sa implementati o astfel de optimizare.
- Testati sistemul de memorie virtuala cu ajutorul programelor sort si matmult. Testati executia concurenta a mai multor procese extinzand programul shell astfel incat sa poata lansa mai multe programe in paralel. Lansati astfel mai multe instante ale programelor sort, matmult, si alte programe de test facute de voi.
- Folositi un debugger (gdb sau interfata grafica pentru acesta, ddd).
Tema
Implementati un mecanism de gestionare a memoriei (memorie virtuala) cu paginare si spatiu de stocare a paginilor pe disc.
Implementati apelurile de sistem de mai jos, prin care sistemul sa permita executia a mai multor procese concomitent:
Folosind mecanismul (emulat) de intreruperi, asigurati-va ca un proces utilizator este intrerupt dupa un anumit timp si se trece la un alt proces.
De asemenea, scrieti programe pentru a testa functionalitatea intregului sistem.
|