This is an old revision of the document!


Examen

Urmăriți precizările din pagina de reguli.

Examen final

Puteți participa la un singur examen final.

Datele de examen de SO sunt:

  • TODO 2018

Studenții de anul 4 care refac disciplina pot veni și la examenul de sâmbătă, TODo 2018. Sesiunea de examene pentru anul 4 se încheie pe 9 iunie 2017. Studenții de anul 3 pot veni în alte zile față de cea aferentă grupei/seriei lor. Studenții în alte situații (de exemplu transferați de la IS) pot veni oricând. Cei care doresc să vină în altă zi față de cele alocate (inclusiv studenții de anul 4 care vor să vină sâmbătă, 3 iunie 2017), să trimită un e-mail către TODO cu subiectul [SO][Examen] Transfer: Prenume NUME, grupă, de exemplu [SO][Examen] Transfer: Ana POPESCU, 332CB.

Informații despre desfășurătorul și conținutul examenului găsiți în secțiunea aferentă din pagina de notare. În pregătirea examenului recomandăm să parcurgeți subiectele de examen anterioare.

Lucrări

  • Dacă nu puteți participa la seria fiecăruia, puteți veni la cealaltă serie. Pentru aceasta trimiteți un e-mail catre Alexandru Rotaru cu subiectul [SO][Lucrare X] Transfer Prenume Nume, Grupa unde:
    • X este indexul lucrării (1, 2, 3 sau 4)
    • Prenume este prenumele.
    • Nume este numa.
    • Grupa este grupa.
  • Nu există sesiune de contestații propriu-zisă; dacă sunteți de părere că nu a fost corectată corespunzător lucrarea, trimiteți un e-mail (solicitare de recorectare) către Vladimir Olteanu. Cererile de recorectare se vor trimite după publicarea soluțiilor pe această pagină, până la data limită anunțată pe lista de discuții.
    • Folosiți subiectul [SO][Lucrare X] Prenume NUME - grupa; de exemplu [SO][Lucrare 1] Andreea POPESCU - 332CA.
  • Pentru a fi punctat, răspunsul la o întrebare trebuie să fie justificat.

Lucrare 1

  • La începutul cursului 4:
    • 12 martie 2018, seria CA
    • 14 martie 2018, seria CB
    • 14 martie 2018, seria CC

3CA, varianta 1

  1. Explicați diferența dintre descriptorii rezultați din două apeluri de open către acelasi fisier, și un apel de open urmat de un apel dup pe descriptorul rezultat.
    • Răspuns: Descriptorii rezultați din două apeluri de open către același fișier vor indica spre două structuri de fișier deschis diferite, pe când în cazul unui apel open() urmat de un apel dup() descriptorii vor indica spre aceeași structură.
  2. Ce va afișa la rulare următorul cod, presupunând că fork este executat cu succes?
       int i = fork();
       if (i==0)
         i = getppid();
       else
         sleep(1);
     
       printf(%d\n”, i);
    • Răspuns: La rularea codului se va afișa:
      <pid-ul procesului părinte>
      <pid-ul procesului copil>

      Fork returnează 0 în cadrul procesului copil și pid-ul procesului copil în cadrul procesului părinte. Astfel, procesul copil va afla pid-ul procesului părinte și își va continua execuția prin printarea acestuia în timp ce procesul parinte face sleep de 1 secundă.
  3. Scrieți secvența de cod care implementează comanda ls > /dev/null.
    • Răspuns:
          pid_t pid = fork();
          switch(pid) {
          case 0:
            fd = open(/dev/null, O_WRONLY | O_TRUNC | O_CREAT, 0644);
            dup2(fd, STDOUT_FINENO);
            close(fd);
            execlp(“ls”, “ls”, NULL);
          default:
            waitpid(pid, NULL, 0);
          }


      De asemenea, au fost punctate și variantele care conțin variante în pseudocod ale apelurilor precum: open(”/dev/null”), exec(“ls”) etc.

3CA, varianta 2

  1. Dați un exemplu de funcție I/O care permite transmiterea de date către disk, rețea și dispozitive de tip caracter.
    • Răspuns: O funcție de I/O care permite transmiterea de date către disk, rețea și dispozitive de tip caracter este apelul de sistem write().
  2. Ce va afișa la rulare următorul cod, presupunând că fork este executat cu succes?
        int i = fork();
     
        if (i==0)
          i++;
        else
          sleep(1);
     
        printf(%d\n”, i);
    • Răspuns: La rularea codului se va afișa:
      1
      <pid-ul procesului copil>

      Fork returnează 0 în cadrul procesului copil și pid-ul procesului copil în cadrul procesului părinte. Astfel, procesul copil va afla va incrementa variabila i, și o va afișa. Părintele va face sleep de 1 secundă și va afișa pid-ul procesului copil.
  3. Scrieți secvența de cod care lansează în execuție ls | wc -l.
    • Răspuns: O variantă de răspuns posibilă:
          fd_redirect;
       
          fd = fork();
       
          if (fd == 0) { //child
            close(STDOUT);
            dup2(STDOUT, fd_redirect);
            exec("ls");
          } else if (fd > 0) { //parent
            close(STDIN);
            dup2(STDIN, fd_redirect);
            wait(); //for child
            exec("wc -l");
          } else {
            //error
          }

3CB, varianta 1

  1. Când este necesară execuția unui apel de sistem?
    • Răspuns: Execuția unui apel de sistem este necesară în momentul în care se interacționează cu hardware-ul.
  2. Cum ați implementa redirectarea pentru următoarea comandă bash ls >> test.out (este de interes implementarea redirectării, în locul comenzii ls putea fi orice alta comandă)?
    • Răspuns: Variantă de răspuns:
          int fd = open("test.out");
          close (STDOUT_FILENO);
          dup(fd);
          close(fd);
          lseek(STDOUT_FILENO,0, SEEK_END);
  3. Câte procese se pot afla în starea RUNNING la un moment dat?
    • Răspuns: În starea RUNNING, se pot afla la un moment dat un număr de procese egal cu numărul de core-uri ale sistemului de calcul.

3CB, varianta 2

  1. Indicați cel puțin un rol al nucleului (kernel-ului) într-un sistem de calcul.
    • Răspuns: Variante de răspuns: Nucleul are rolul de a abstractiza hardware-ului SAU rol de interfațare a hardware-ului SAU Nucleul oferă controlul accesului la resurse.
  2. Ce apeluri de sistem sunt necesare pentru a porni două procese care comunică prin intermediul unui pipe (ex ls | grep test)?
    • Răspuns: O variantă de răspuns: Apelurile de sistem necesare pentru a porni două procese care comunică prin intermediul unui pipe sunt fork() pentru crearea celor două procese, pipe() pentru deschiderea unor pipe-urilor folosite de cele două procese, close() pentru închiderea unuia din capetele pipe-urilor create înainte, dup2() pentru redirectarea capetelor pipe-ului și execve() pentru execuție.
  3. Care este cauza principală pentru care un proces este în starea WAITING?
    • Răspuns: În general un proces ajunge în starea de WAITING în urma efectuării unei operații blocante.

3CC, varianta 1

  1. Stiva de rețea a unui sistem de operare poate fi implementată în user space sau în kernel space. De ce se preferă implementarea în kernel space?
    • Răspuns: Preferăm implementarea stivei de rețea în kernel space din rațiuni de performanță. Prelucrarea pachetelor se întâmplă în kernel space iar tranziția (costisitoare) către și din user space are loc doar pentru payload-ul pachetelor.
  2. Dați un exemplu de apel de bibliotecă/sistem, altul decât open()/fopen() care duce la ocuparea unei intrări din tabela de descriptori de fișier a unui proces.
    • Răspuns: Popularea unei intrări în tabela de file descriptori se poate face cu apelul dup() (sau dup2()) pentru duplicarea unei intrări existente sau cu apeluri precum socket() sau pipe() pentru crearea unui socket sau a unui pipe care ocupă, respectiv, o intrare și două intrări.
  3. Un proces execută apelul getppid() în două situații diferite. În prima situație apelul întoarce valoarea 2832, iar în a doua situație apelul întoarce valoarea 1. Cum explicați?
    • Răspuns: getppid() întoarce pid-ul procesului părinte. În prima situație valoarea returnată este diferită de 1 deoarece procesul are un părinte (creator) care încă rulează. În cea de-a doua situație procesul a fost adoptat de init deoarece părintele creator al procesului și-a terminat execuția și nu l-a așteptat.

3CC, varianta 2

  1. Oferiți un motiv pentru care este necesară existența modului privilegiat (supervisor/kernel mode) într-un sistem de calcul.
    • Răspuns: Este nevoie de modul privilegiat pentru a asigura integritatea sistemului, izolarea între procese și accesul mediat la resurse. În absența modului privilegiat (kernel/supervisor mode), un proces ar putea scrie în memoria altui proces, ar putea corupe resurse sau ar putea citi informații de la resursele I/O fără să știe dacă sunt ale sale sau alte altcuiva.
  2. Care este un avantaj și un dezavantaj al folosirii apelului printf() în locul apelului write() pentru afișarea unui mesaj la ieșirea standard a unui proces?
    • Răspuns: Avantajele folosirii printf() sunt: formatare, portabilitate, mai puține apeluri de sistem (când mesajul este buffered). Dezavantaje: buffer-ul ocupă memorie, nu se afișează instant mesajul (este buffered).
  3. Unui proces îi expiră cuanta de rulare (time slice) în momentul în care rulează pe un procesor (se află în starea RUNNING). Ce se întâmplă cu procesul?
    • Răspuns: La expirarea cuantei de timp, un proces este mutat din starea RUNNING în starea READY, unde va rămâne până va fi din nou planificat: adică până atunci când va primi o altă cuantă de rulare și va fi lăsat să ruleze pe procesor.

Greșeli frecvente

Lucrări foarte bune

Lucrare 2

  • La începutul cursului 7:
    • 2 aprilie 2018, seria CA
    • 4 aprilie 2018, seria CB
    • 4 aprilie 2018, seria CC

3CA, varianta 1

  1. Presupunând un sistem cu timp de access la RAM de 100ns, ̧si ̧stiind că un

context conține zece valori ale regiștrilor, estimați timpul necesar pentru o schimbare de context.

  • Răspuns: Worst case: 10 read * 100ns, 10 write * 100ns = 2 microsecunde. Dacă sunt în cache, timpul poate fi mai mic.
  1. Un proces execută următorul cod:
    for (i=0; i<100000; i++)
      if (fork() == 0)
        exit(1);

    Care este consumul total de memorie fizică folosită de toate procesele copil în plus față de procesul părinte, exceptând structurile de date din kernel?

  • Răspuns: Variantă răspuns: Fiecare proces copil va aloca o pagină pentru stivă prin mecanismul copy-on-write (care va fi scrisă atunci când funcția exit își inițializează stack-frame-ul, salvând base pointer). Consumul total va fi 400MB. Variantă de răspuns acceptată: nu se va aloca nici o pagină în copil din cauza copy-on-write, pentru că nu se modifică nici o variabilă.
  1. Dați un exemplu de algoritm de înlocuire de pagini pentru care creșterea memoriei fizice nu garantează reducerea numărului de major page faults.
  • Răspuns: FIFO.

3CA, varianta 2

  1. Într-un sistem preemptiv cu planificator round-robin, explicați dacă este posibil ca două procese ce sunt planificate alternativ pe același procesor să primească timp de procesor diferit.
    • Răspuns: Procesele sunt I/O bound.
  2. Dați un exemplu de situație în care unei pagini din procesul părinte nu i se aplică mecanismul copy-on-write după apelul fork(), deși pagina respectivă este scrisă atât de copil cât și de părinte.
    • Răspuns: Pagina a fost mapată cu mmap (…, MAP_SHARED,…);
  3. Dați avantaj și un dezavantaj al memory-mapped IO comparativ cu standard I/O.
    • Răspuns: Memory mapped I/O este mult mai rapid în general pentru că nu implică syscalls la fiecare acces; deasemenea mecanismul de paging nu încarcă în memorie decât paginile efectiv accesate. Orice eroare de I/O, de exemplu disk removed, este transmisă procesului prin semnale de genul SIGSEGV sau SIGBUF - iar programele trebuie să prindă și să trateze aceste semnale explicit. În cazul standard IO tratarea astfel de erori e mult mai simplă (-1, look at errno).

3CB, varianta 1

  1. Într-un sistem doar cu procese I/O intensive, cuanta de rulare pe procesor ar trebui să fie mai mică sau mai mare decât în mod obișnuit pentru a eficientiza per ansamblu sistemul? Explicați.
    • Răspuns: Cuanta de rulare trebuie să fie mai mică întrucât subsistemele I/O sunt mult mai încete ca procesorul iar o cuantă de rulare mai mare nu ar face decât să blocheze procesorul fără ca acesta să execute nimic util.
  2. Câte operații sunt necesare într-o arhitectură load/store pentru a copia o valoare între 2 locații de memorie RAM?
    • Răspuns: 2 operații (încărcare din memorie în registru și salvare din registru în memorie).
  3. Alocăm un spațiu contiguu de 128MB folosind apelul mmap. Presupunând că dimensiunea paginii este de 4K, care este numărul maxim de page-fault-uri ce vor putea fi generate?
    • Răspuns: 128MB / 4k = 32K page fault-uri.

3CB, varianta 2

  1. Într-un sistem doar cu procese CPU intensive, cuanta de rulare pe procesor ar trebui să fie mai mică sau mai mare decât în mod obișnuit pentru a eficientiza per ansamblu sistemul? Explicați.
    • Răspuns: Cuanta de rulare trebuie să fie mai mare întrucât la un context switch se pierde o perioadă importantă de timp, iar dacă cuanta ar fi prea mică, mai mult am sta în schimbarea de context decât să procesăm volumul mare de date pe procesor.
  2. Precizați un avantaj și un dezavantaj al paginării.
    • Răspuns: Avantaje: memoria ocupată per proces, un proces are acces la tot spațiul virtual de memorie propriu, etc; Dezavantaje: mai multe accese la memoria fizică, prezența hardware-ului specializat (MMU, TLB), etc
  3. Precizați 2 cazuri care generează un page fault atunci când accesăm o adresă validă de memorie.
    • Răspuns: Swapping, Demand paging.

3CC, varianta 1

  1. De ce este important ca prioritățile proceselor să fie dinamice, nu statice, în contextul planificării proceselor?
    • Răspuns: Dacă prioritățile sunt statice, atunci procesele prioritare vor rula întotdeauna în fața celor mai puțin prioritare. Dacă sunt CPU bound, atunci acestea vor ocupa foarte mult procesorul și procesele mai puțin prioritare vor avea puțin timp să ruleze, ducând la starvation.
  2. La ce este folosit PTBR (Page Table Base Register)? De ce sistemul nu ar putea funcționa fără un PTBR?
    • Răspuns: PTBR este folosit pentru a referi adresa fizică a tabelei de pagini a procesului curent. În abența PTBR-ului, nu am avea un mod prin care să identificăm tabele de pagini a unui proces și deci nici un mod prin care să putem face translatarea de adrese când folosim memorie virtuală.
  3. Apelul de mai jos este efectuat cu succes. În ce situație duce apelul la două page fault-uri?
           memset(a, 0, 8); /* fill a with 8 bytes of 0 */ 
    • Răspuns: Scrisul de 8 octeți poate genera două page fault-uri atunci când sunt “atinse” două pagini de memorie care fie sunt în demand paging fie swappate. Dacă avem, de exemplu, 4 octeți pe o pagină (la sfârșit) și 4 octeți în pagina următoare (la început) vor rezulta două page fault-uri.

3CC, varianta 2

  1. De ce procesele I/O bound primesc, în general, o cuantă de timp de rulare mai mare?
    • Răspuns: Procesele I/O bound sunt procese care se blochează des (și generează schimbări de context voluntare). Le alocăm o cuantă de timp mai mare pentru că nu vor apuca să o consume, se vor bloca. La următoarea planificare va consuma din restul de cuantă. Un proces CPU bound primește o cuantă mai mică pentru a fi forțat să iasă de pe proces (schimbare de context nevoluntară) atunci când îi expiră cuanta.
  2. De ce este utilă prezența unei zone dedicate pentru kernel în spațiul virtual de adrese al fiecărui proces, față de un spațiu virtual de adrese dedicat pentru kernel?
    • Răspuns: La un apel de sistem se schimbă nivelul de privilegiu al procesorului dar nu se schimbă tabela de pagini, pentru că nu se schimbă spațiul de adresă. În felul acesta nu mai facem flush la TLB și avem overhead mai redus. În cazul în care kernel-ul ar avea un spațiu virtual de adrese propriu ar trebui făcută schimbarea tabelei de pagini (și flush la TLB).
  3. De ce zona de text/cod a bibliotecii standard C poate fi partajată între mai multe procese, dar nu și zona de date?
    • Răspuns: Zona text este o zona read-only, pe când zona de date e modificabilă. Întrucât modificările trebuie să fie vizibile doar la nivelul procesului curent, zona de date e unică per proces (și nepartajate). Zona text nu se modifică și poate fi partajată de mai multe procese.

Greșeli frecvente

Lucrări foarte bune

Lucrare 3

  • La începutul cursului 11:
  • 7 mai 2018, seria CA
  • 9 mai 2018, seria CB
  • 9 mai 2018, seria CC

3CA, varianta 1

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CA, varianta 2

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CB, varianta 1

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CB, varianta 2

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CC, varianta 1

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CC, varianta 2

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

Greșeli frecvente

Lucrări foarte bune

Lucrare 4

  • La începutul cursului 13:
    • 21 mai 2018, seria CA
    • 23 mai 2018, seria CB
    • 23 mai 2018, seria CC

3CA, varianta 1

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CA, varianta 2

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CB, varianta 1

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CB, varianta 2

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CC, varianta 1

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

3CC, varianta 2

  1. TODO
    • Răspuns: TODO
  2. TODO
    • Răspuns: TODO
  3. TODO
    • Răspuns: TODO

Greșeli frecvente

Lucrări foarte bune

Examene anterioare

so/meta/examen.1522864305.txt.gz · Last modified: 2018/04/04 20:51 by maria.mihailescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0