This is an old revision of the document!
Examen
Examen final
Puteți participa la un singur examen final.
Datele de examen de SO pentru sesiunea iunie 2019 sunt:
Datele de examen de SO pentru sesiunea septembrie 2019 sunt:
Puteți veni o singură dată la examen. Studenții care refac materia pot veni doar în primele două date de examen (TODO și TODO). Pentru ei sesiunea este mai scurtă (TODO - TODO).
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, să trimită un e-mail către Elena 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.
Urmăriți precizările din pagina de reguli.
Foi de examen
Lucrări
Lucrare 1
La începutul cursului 4:
11.03.2019, seria CA
13.03.2019, seria CB
13.03.2019, seria CC
3CA, varianta 1
Explicaţi de ce apelul printf(”aici”)
înainte de o instrucţiune care accesează o zonă de memorie invalidă nu afişează nimic la consolă.
Răspuns: Biblioteca va stoca local mesajul aici pentru a-l trimite la consolă atunci când bufferul se umple sau utilizatorul scrie
EOL (i.e. \n). Atunci când procesul este întrerupt în urma accesului invalid la memorie, bufferul nu mai este scris la consolă.
Explicați semnificația stării RUNNING în viața unui proces și tranzițiile posibile din această stare.
Ce valori va afișa execuția codului următor atunci când fork reușește?
int i = 0;
if (fork()==0)
i++;
else sleep(1);
printf(”%d\n”,i);
3CA, varianta 2
Explicați de ce apelul fwrite(..)
este mai rapid decât write(..)
atunci când facem multe scrieri.
Răspuns: fwrite scrie într-un buffer în memoria procesului și execută write cu mai multe date, reducând numărul de apeluri de sistem. Apelurile de sistem sunt costisitoare, iar reducerea lor creste performanța.
Explicați semnificația stării READY în viața unui proces și tranzițiile către această stare.
Răspuns: Procesul este gata să ruleze însa așteaptă să fie planificat. Un proces ajunge în READY după ce este pornit, dacă este RUNNING si este preemptat, sau dacă este WAITING și operația pe care o asteptă se termină.
Câte procese noi vor fi create la execuția codului următor atunci când fork reușește?
int i = 0;
for (i = 0;i<5;i++)
if (fork()>0)
break;
3CB, varianta 1
Numiți un rol al bibliotecilor în sistemul de operare și exemplificați.
Fie secvența int fd2 = dup(fd)
. Execuția apelului de sistem write
pe fd2 va influența în vreun fel apelurile ce folosesc ca parametru fd? Explicați.
Care este diferența între un proces zombie și unul orfan?
3CB, varianta 2
Care este motivul pentru care există noțiunea de “apel de sistem” într-un sistem de operare? De ce nu se fac pur și simplu apeluri simple de funcție?
Fie secvența int fd2 = dup(fd)
. Execuția apelului de sistem write
pe fd va influența în vreun fel apelurile ce folosesc ca parametru fd2? Explicați.
Numiți un avantaj și un dezavantaj al structurării ierarhice al proceselor într-un sistem de operare (în comparație de exemplu cu o structură liniară). Explicați.
Răspuns: Reprezentarea proceselor într-o ierarhie ajută la partajarea de date între procesul părinte și procesul copil, însă implementarea este mai dificilă, deoarece trebuie păstrate mereu legături cu procesul părinte (ex. Procesele orfane sunt adoptate de init).
3CC, varianta 1
De ce preferăm să folosim un apel de bibliotecă care NU realizează în spate un apel de sistem în locul unui apel de bibliotecă ce face apel de sistem? De exemplu fwrite()
în loc de write()
.
Răspuns: Un apel de sistem are un overhead mai mare decât un apel simplu de funcție întrucât se face schimbarea nivelului de privilegiu la apel și revenirea din apel, care consumă timp. Din acest motiv, dacă avem de ales, optăm pentru funcții de bibliotecă ce nu fac apel de sistem ca să reducem overhead-ul.
Fie apelul close(fd)
executat cu succes. Observăm că structura de fișier deschis referită de descriptorul fd (acum închis) nu este eliberată din memorie. De ce?
Răspuns: pelul close(fd)
invalidează descriptorul fd și decrementează contorul de referință din structura de fișier deschis. Structura este dezalocată în momentul în care contorul de referință este 0. Dacă după close(fd)
structura de fișier deschis nu a fost dezalocată înseamnă că mai există un descriptor care o referă, descriptor care a fost obținut printr-un apel dup()
sau dup2()
. Un apel open()
nu este un răspuns corect, pentru că acela creează o structură nouă de fișier deschis.
Un proces zombie devine și proces orfan: procesul său părinte își încheie execuția. Ce se întâmplă acum cu procesul zombie rămas orfan?
3CC, varianta 2
Dați exemplu de acțiune care poate fi executată doar în modul privilegiat (kernel mode). Justificați de ce acea acțiune nu poate fi executată în modul neprivilegiat (user mode).
Răspuns: Acțiuni care pot fi executate doar în kernel mode sunt: lucrul cu I/O, forme de IPC (Inter-Process Communication), alocarea memorie. Acestea sunt privilegiate pentru a garanta integritatea sistemului și izolarea proceselor. Dacă ar fi executate în mod neprivilegiat, un proces ar avea acces la datele altui proces, i-ar putea suprascrie și corupe informații. Cu atât mai mult cu cât dorim separație între procese privilegiate (ce aparțin utilizatorului root) și procese neprivilegiate.
Ce câmpuri din structura de fișier deschis și din structura de fișier de pe disc (FCB: File Control Block) modifică apelul write()
? Argumentați răspunsul.
Răspuns: Apelul write()
modifică pointer-ul/cursorul de fișier, îl crește cu numărul de octeți scriși în fișier; cursorul de fișier este reținut în structura de fișier deschis. În plus, dacă în urma scrierii octeților se trece de limita fișierului, atunci se modifică și dimensiunea fișierului; dimensiunea fișierului este reținută în structura de fișier de pe disc (FCB).
Ce efect are, la nivel de implementare, folosirea operatorului &
în shell?
Greșeli frecvente
Confuzie între procesele zombie și procesele orfan. Un proces zombie este un proces care și-a terminat execuția, dar pe care nu l-a “așteptat” părintele, iar un proces orfan este un proces al cărui părinte și-a încheiat execuția.
Confuzie între kernel mode și utilizator privilegiat. Chiar dacă utilizatorul root este privilegiat, este doar un utilizator. În continuare se face diferențierea între user mode și kernel mode.
Greșeli legate de utilizarea &
în shell. În shell, &
are rolul de a duce un proces în background, nu de a face o dereferențiere (ca de exemplu în C) sau de operator logic AND între comenzi (precum &&
).
Confuzie între procesele trimise în background și daemoni. Unui proces trimis în background NU i se închid stdin
, stdout
și stderr
.
Lucrări foarte bune
APOSTOL Teodor-Petruț, 336CA
ŞENDRE Mihai-Alin, 332CC
RADU Valentin-Gabriel, 333CC
BĂLĂNICĂ Darius, 334CC
COCOŞ Vlad, 334CC
DUMITRU Philip, 334CC
VIŞAN Anamaria, 334CC
FOLEA Rareş, 336CC
ILIE Vlad-Florin 331CB
POPESCU Teodor-Constantin 333CB
SMĂDU Răzvan-Alexandru 335CB
FIRUŢI Bogdan-Cristian, 331CA
IVAN Vlad, 331CA
VASILE Cristian-Ştefan, 331CA
ANDREI Rareş, 332CA
DRAGOMIR Horia-Alexandru, 333CA
POPA Bogdan, 333CA
BUCUR Adrian-Cătălin, 336CA
MARICA Andreea-Mădălina, 336CA
Lucrare 2
La începutul cursului 7:
01.04.2019, seria CA
03.04.2019, seria CB
03.04.2019, seria CC
3CA, varianta 1
Indicați trei surse de overhead care apar la schimbarea de context între două procese.
Cum poate un proces să își modifice propria tabelă de pagini?
Explicați cum funcționează mecanismul copy-on-write pentru memoria virtuală.
Răspuns: Se mapează diferite secțiuni din executabil în memorie, inclusiv sectiunea text. Această mapare presupune adăugarea unor intrări în tabela de pagini, acestea sunt marcate ca fiind invalide, dar încărcabile de pe disk. Atunci când se accesează o adresă dintr-o astfel de pagină, MMU va genera un fault care va fi prins de SO; atunci SO va citi datele de pe disk într-un frame liber și va updata intrarea din tabela de pagini; instrucțiunea care a generat fault va fi repornită.
3CA, varianta 2
Enumerați pașii efectuați de SO pentru schimbarea de context între două procese.
Descrieți pașii prin care o adresă virtuală este translată la o adresa fizică într-un sistem cu paginare.
Răspuns: MMU identifică pagina dorita prin inspectarea unui număr predefinit (e.g. 20) din biții cei mai semnificativi din adresa virtuală. Acest număr este căutat în TLB; dacă există o intrare, se înlocuiește pagina cu frame-ul asociat și se obține adresa fizică. Altfel MMU folosește PTBR pentru a localiza tabela de pagini activă și găsește frame-ul asociat la adresa PTBR + page * page_entry_size.
Explicați mecanismul prin care SO încarcă în memorie codul unui executabil exact atunci când acel cod urmează să fie folosit.
Răspuns: Mai multe pagini (din mai multe procese) vor fi mapate la același frame, însă intrările respective vor fi marcate R/O. Atunci când se accesează una din aceste pagini, MMU generează trap care este rezolvat de SO prin duplicarea frameului, maparea paginii faulty la frame-ul nou cu permisiuni R/W și reluarea instrucțiunii faulty.
3CB, varianta 1
Ce parametri ai planificatorului trebuie să modificăm și cum pentru a avea un sistem cu productivitate mai mare?
Răspuns: Pentru a avea un sistem cu productivitate mai mare putem mări cuanta de timp alocată unui proces din starea running. O cuantă de timp mai mare înseamnă un număr mai mic de context switch-uri, deci overhead mai mic, ceea ce duce la productivitate mai mare a sistemului per total.
Menționați un avantaj și un dezavantaj al paginării față de segmentare. Explicați avantajul, respectiv dezavantajul.
Răspuns: Un avantaj al paginării față de segmentare este acela că paginarea nu duce la fragmentare externă. Deoarece paginile au dimensiuni fixe, nu vor exista situații în care să avem goluri ce nu pot fi refolosite/sunt greu de refolosit între două pagini alocate, față de cazul segmentării.
Un dezavantaj al paginării față de segmentare este acela că paginarea duce la fragmentare internă. Deoarece paginile au dimensiuni fixe, în momentul în care avem de alocat o secțiune cu dimensiune mică relativă la dimensiunea paginii, se va aloca o pagină întreagă, iar memoria rămasă liberă în cadrul paginii nu poate fi refolosită de alt proces.
La execuția unei instrucțiuni se generează un page-fault dar procesul care a rulat acea instrucțiune continuă să ruleze fără eroare. Motivați/descrieți de ce nu s-a încheiat execuția procesului.
Răspuns: Apariția unui page-fault nu generează neapărat un eveniment care să ducă la încheierea forțată a execuției programului. De exemplu, dacă instrucțiunea care a generat page fault-ul încercă să citească memorie dintr-o pagină care se află în swap, se generează un page-fault pentru aducerea paginii din swap. De asemenea, dacă instrucțiunea respectivă încearcă să scrie într-o pagină marcată ca fiind copy-on-write, se generează un page-fault pentru duplicarea paginii.
3CB, varianta 2
Ce parametri trebuie să modificăm și cum pentru a avea un sistem cât mai responsive?
Răspuns: Pentru a avea un sistem cu responsivitate mai mare putem micșora cuanta de timp alocată unui proces din starea running. O cuantă de timp mai mică înseamnă un număr mai mare de context switch-uri, adică procesele ajung mai des și mai repede să ruleze pe procesor oferind un grad mai ridicat de responsivitate.
Ce avantaj aduce noțiunea de ierarhie în paginare?
Fie următoarele 2 secvențe de cod:
a) a = mmap(...., n * 1024 * sizeof(int),....);
for(i = 0; i < n * 1024; i = i + 1024)
a[i] = i;
b) b = mmap(...., n * 1024 * sizeof(int),....);
for(j = 0; j < n; j++)
b[j] = j;
Care dintre secvențe este mai rapidă și de ce?
Răspuns: Snippet-ul de cod de la punctul b) se va executa mai rapid decât snippet-ul de cod de la punctul a) deoarece vor fi mai puține page-fault-uri. Numarul de iterații este același în ambele cazuri (n), dar în cazul a) se indexează relativ la 1024, generând page-fault la fiecare instrucțiune.
3CC, varianta 1
De ce procesele I/O intensive primesc, în general, o cuantă de timp de rulare mai mare?
Răspuns: Procesele I/O intensive accesează des dispozitive I/O și execută des operații blocante. Aceasta înseamnă că un proces I/O intensive proaspăt planificat se va bloca repede și va trece din starea RUNNING în starea BLOCKED/WAITING. Șansele sunt foarte mici ca un astfel de proces să își încheie cuanta de timp în starea RUNNING. De aceea i se oferă o cuantă de timp mai mare, pe care o va folosi în mai multe runde de planificare, fiecare rundă de planificare încheindu-se, în general, cu tranziția sa în starea BLOCKED/WAITING din cauza unei operații blocante.
Un sistem pe 32 de biți are pagini de 4KB. Presupunând că sistemul folosește schemă de paginare simplă, pe un singur nivel (adică nu ierarhică/multi-nivel), care este dimensiunea aproximativă (ordinul de mărime) al unei tabele de pagini?
Răspuns: Pe un sistem pe 32 de biți, spațiul virtual de adrese are 2^32 = 4GB. Dacă o pagină are 4KB, avem 4GB / 4 KB = 2^20 pagini. O tabelă de pagini simplă, pe un singur nivel avea o intrare pentru fiecare pagină. Dacă o intrare în tabela de pagini ocupă 4-8 octeți (aproximativ) atunci o tabelă de pagini va ocupa 2^20 * (4/8) octeți, adică undeva la 4MB-8MB de memorie.
Fie instrucțiunea *a = 3;
În ce situație executarea acestei instrucțiuni va conduce la evacuarea unei pagini în spațiul de swap (swap out)?
Răspuns: Instrucțiuna *a = 3
înseamnă un acces la memorie în pagina virtuală ce conține adresa indicată de pointerul a. Dacă acea pagină virtuală nu are pagina fizică rezidentă (adică în memoria fizică / RAM), pagina fizică nu a fost alocată încă (demand paging) sau se găsește pe spațiul de swap sau a apărut duplicarea ei ca urmare a copy-on-write. Dacă nu aveam nici o pagină disponibilă, atunci este nevoie de evacuarea unei pagini (swap out) și folosirea paginii eliberate.
3CC, varianta 2
De ce este util ca prioritatea proceselor să fie dinamică? Care este neajunsul folosirii priorităților statice?
Răspuns: În cazul unui sistem cu priorități statice, un proces care este CPU-intensive și care are o prioritate mai bună va fi planificat foarte des: îi expiră cuanta, este trecut în coada READY cu prioritate foarte bună, apoi este replanificat. În această situație un proces care are o prioritate mai slabă va fi planficat foarte rar, posibil deloc, adică să ajungă la situația de starvation. Pentru a compensa aceste dezavantaj, folosim priorități dinamice, care permit proceselor cu prioritate mai slabă să câștige, în timp, priorități mai bune.
De ce, în general, TLB-ul (Translation Lookaside Buffers) este golit (flushed) la schimbări de context?
Răspuns: Intrările din TLB sunt cache-uri din tabela de pagini a procesului curent, intrări folosite recent. La o schimbare de context are loc schimbarea proceselor adică și a tabelelor de pagini. Fiind vorba de o tabelă de pagini nouă, intrările din TLB sunt nevalide și atunci sunt golite (flushed) pentru a fi populate cu intrări din tabela de pagini nouă.
Dați un exemplu de situație în care un page fault conduce la livrarea unei excepții de acces de memorie către un proces (de tipul Segmentation fault) și un exemplu de situație care nu conduce la livrarea unei excepții de acces de memorie.
Răspuns: Un page fault este generat de MMU când o pagină a fost marcată ca nevalidă în tabela de pagini. Dacă acea pagină nu a fost rezervată de proces înseamnă că nu este accesibilă din spațiul de adrese al procesului și atunci sistemul de operare va livra o excepție de acces la memorie (Segmentation fault) procesului. Altfel, dacă acea pagină este marcată în informațiile sistemului de operare ca fiind copy-on-write sau rezervată dar nealocată (demand paging) sau evacuată pe disc (swapped out), se va trata page fault-ul fără ca sistemul de operare să livreze excepție de acces la memorie procesului.
Greșeli frecvente
Multe răspunsuri conform cărora unui proces I/O i se dă cuantă mai mare pentru că este mai lent și are nevoie de mai mult timp pentru a termina operația de I/O.
Multe răspunsuri conțin doar calcule, fără explicații prin care să prezinte ce reprezintă numerele scrise. Multe răspunsuri în care nu se prezintă unitatea de măsură (ex. dimensiunea tabelei este 4 sau 2^20).
Se rotunjesc puterile lui 2 la puterile lui 10 (ex. 1KB == 1000B).
Multe răspunsuri conform cărora, prin folosirea priorităților statice, procesele care așteaptă date (ex. input de la utilizator) consumă timp inutil pe procesor.
Multe răspunsuri care presupun că malloc nu alocă memorie, doar o rezervă (folosește mmap întotdeauna).
Lucrări foarte bune
CEBERE Ioan-Tudor, 331CC
ILIESCU Valentina-Florentina, 331CC
ION Horia-Paul, 331CC
TĂZLĂUANU Bianca, 334CC
VIŞAN Anamaria, 334CC
FOLEA Rareş, 336CC
SULIMAN Anca, 336CC
DANCIU Andra-Maria, 335CB
MĂRGINEANU Cristian, 336CB
ANDREI Rareș, 332CA
MARICA Andreea-Mădălina, 336CA
MARIN Cristian-Alexandru 333CB
TRIFU Andrei-Ștefan 331CB
SECUIU Ana 336CB
Lucrare 3
22.04.2019, seria CA
24.04.2019, seria CB
24.04.2019, seria CC
3CA, varianta 1
3CA, varianta 2
3CB, varianta 1
3CB, varianta 2
3CC, varianta 1
3CC, varianta 2
Greșeli frecvente
Lucrări foarte bune
Lucrare 4
3CA, varianta 1
3CA, varianta 2
3CB, varianta 1
3CB, varianta 2
3CC, varianta 1
3CC, varianta 2
Greșeli frecvente
Lucrări foarte bune
Examene anterioare