Försättsblad till skriftlig tentamen vid Linköpings Universitet Cover page for written exam at Linköping University Datum för tentamen Date of exam Sal Room Tid Time Kurskod Course code Provkod LADOK code Kursnamn/benämning Course name Institution Department Antal uppgifter som ingår i tentamen Number of assignments Antal sidor på tentamen (inkl. denna) Number of pages including cover Jour/Kursansvarig Responsible/Examiner Telefon till examinator Phone to examiner Besöker salen ca kl. Time of exam visit Kursadministratör Course administrator Tillåtna hjälpmedel Allowed aids 2014-06-02 TER4: TDDI81 TER4, TER3: TDDI04 14:00-18:00 TDDI81 TDDI04 (näst sista gången) TEN1 Processprogrammering och operativsystem Concurrent programming and operating systems IDA 7 uppgifter med totalt 45p (90 halvpoäng) 7 assignments for a total of 45 points 5 Klas Arvidsson klas.arvidsson@liu.se 013-28 21 46 013-28 24 90 (grupprum) Examinator besöker salen efter ca en timme After about one hour Madeleine Häger Dahlqvist 013-28 23 60, madeleine.hager.dahlqvist@liu.se Ordbok, enkel miniräknare (+,-,*,/) Dictionary, pocket calculator. Övrigt Other information Typ av papper Paper to use Antal anmälda Number of students signed up För betyg 3 krävs minst 11p på varje del. Godkänd dugga ersätter del VT1. Godkänd del på denna tentamen gäller även och endast nästkommande tentamen. Går du inte upp nästkommande tentamenstillfälle kan du inte tillgodoräkna delen. Betygsgränser: U < 50% < 3 < 67% < 4 < 84% < 5 Gränserna är ungefärliga och kan komma justeras. Gränserna är endast stark vägledning till betyget. Det faktiska betyget sätts baserat på helhetsintryck (speciellt för gränsfall). Resultatet tillkännages efter (inom) 10 arbetsdagar. För full poäng krävs tydliga och motiverade svar om inget annan anges. Råder oklarhet om frågans formulering skall examinator tillfrågas vid besök i salen. Är detta inte möjligt skall oklarheten beskrivas i ditt svar, och du svarar så som du tror frågan är menad. Orimliga antaganden eller förenklingar av frågan ger poängavdrag. Rutigt, linjerat eller blankt No preference TDDI81: 84 st TDDI04: 13 st 1 (5)
Del VT1 (22.5p) 1. Operativsystemets grundstenar (7.5p) a) Ange utöver process-id tre viktiga uppgifter som brukar återfinnas i ett PCB. (1.5) b) Ange utöver tråd-id viktiga uppgifter som utgör en tråd, samt syftet med dessa. (2p) c) Rita en enkel figur med tre kerneltrådar, ett PCB, och en process med tre usertrådar och visa i figuren hur allt detta är sammanlänkat när kopplingen 1-1 används. (2p) d) Beskriv hur ett systemanrop går till med korrekt användning av alla termerna user mode, kernel mode, och avbrott. (2p) 2. Schemaläggning (4p) På ready-kön finns, här återgivna i bokstavsordning, de tre processerna P(2), Q(5) och R(4) när processen S(3) exekverar systemanropet exit. På en väntekö finns T(1). a) I denna deluppgift anger siffrorna inom parentes prioriteten. Lägre siffra har högre prioritet. Kan situationen som beskrivits uppstå med preemptive priority scheduling? Motivera. (2p) b) I denna deluppgift anger siffrorna inom parentes uppskattad återstående exekveringstid. Förklara vad som händer i köerna när systemanropet slutförs om schemaläggningsalgoritmen shortest job first används. Ange vad som finns i respektive kö och vad som exekverar precis efter systemanropet. (För process S visar sig återstående tid vara 0.) (2p) 3. Minneshantering (5p) a) Rita en figur över hur paging i två nivåer går från user-mode adress till fysisk adress. Numrera och förklara varje steg i figuren. Du får istället förklara en nivås paging för lägre poäng. (3p) b) Vad är en TLB och varför är den viktig? (1p) c) Vad menas med demand paging (virtuellt minne)? (1p) 4. Filhantering (6p) a) Process P har filen main.c öppen. Process Q har filerna main.c, score.c och engine.c öppna. Rita upp system-wide open file table och per-process open file table med dessa filer öppnade. Ange vilka data som lagras i varje tabell om varje fil som minst. (3p) b) Vad är fördelarna med indexed allocation jämfört med andra metoder? (1p) c) Du får uppdraget att skapa en hierarkisk filkatalog. Funktioner för att skapa, läsa och skriva inoder på disk finns. Förklara hur du bygger upp ett enkelt katalogträd och vad du lagrar i varje katalog. Redogör för hur sökning efter en fil med full sökväg går till. Godtyckligt antal katalognivåer ska fungera för full poäng. Använd gärna en tydlig figur i din förklaring. (2p) Del VT2 (22.5p) 5. Säkerhet (6.5p) a) Lista tre mekanismer ett normalt Linux-system bör använda för att skydda systemets lösenordslista så väl som möjligt och visa att du kan skilja på mekanism och policy. (2.5p) b) En vanlig fil har filskyddet rw-r--r-- och ägs av jambo007. Beskriv koncist hur jambo007 ska använda mekanismen setuid för att låta andra användare lägga till rader i filen. (2.5p) c) Discretionary Access Control (DAC) bygger på en accessmatris. Rita en accessmatris för objekten O1, O2 och subjekten S1, S2. Ge sedan S1 läsrätt på O1, O2 och skrivrätt på O2. Ge S2 körrätt och ägarskap på O1. Låt sist S1 skapa O3 i matrisen med allt som det innebär. (1.5p) 2 (5)
6. Deadlocks (6p) a) Rita en standard allokeringsgraf där P1 väntar på resurs R och P2 håller resurs R. (1p) b) När deadlock uppstått är 4 villkor uppfyllda. Beskriv kort och koncist varje villkor. (2p) c) Fyra processer behöver och håller resurser av följande typer: MAX BEHOV ALLOKERAT JUST NU A B C D A B C D P ( 2 3 8 11 ) ( 1 1 1 11 ) Q ( 1 5 2 17 ) ( 0 2 0 6 ) R ( 5 4 10 5 ) ( 2 3 2 4 ) S ( 4 8 4 20 ) ( 0 0 3 0 ) Lediga just nu: ( 2 2 7 0 ) Totalt i systemet: ( 5 8 13 21 ) Systemet är i ett säkert läge och process S ber om ytterligare en resurs A. Använd Bankers algoritm för att beräkna om begäran skall godkännas eller nekas. Visa alla steg och motivera ditt svar. (3p) 7. Synkronisering (10p) Att skapa trådar är inte helt gratis. Minne skall allokeras, datastrukturer initieras och en del annat administrativt arbete måste utföras för att skapa och köra igång tråden. Det är på motsvarande sätt kostsamt att förstöra en tråd. I ett system med mycket många förhållandevis små uppgifter som fördelas med en uppgift per tråd kan denna administration sluka en stor del av prestandan. Det är även svårt att kontrollera så inte för många trådar skapas i systemet. I denna situation vore det bra om det gick att skapa en fix samling trådar ("thread pool") och återanvända efter varje uppgift. När en uppgift blir tillgänglig hämtas en tråd från samlingen, tråden utför uppgiften, och sedan återvänder tråden till samlingen. Vips så slipper vi skapa och förstöra en tråd för varje uppgift. Bertram har börjat skissa på hur en sådan trådsamling kan implementeras och rådfrågar nu dig. Det kommer vara flera trådar (som ej ingår i samlingen) som genererar och tilldelar uppgifter till trådarna i samlingen. Sida 4 listar de mekanismer som finns att tillgå samt de typer och datastrukturer som används, inlklusive initiering därav. Koden som skall synkroniseras återfinns på sida 5. a) Leta upp en kritisk sektion i koden och förklara varför det är en kritisk sektion. Var börjar den? Var slutar den? Förklara steg för steg hur ett olägligt trådbyte kan leda till fel. (2p) b) Ett exempel på problem är loopen på rad 32-33. Vad är problemet och varför? (1p) c) Korrigera implementationen så synkroniseringen är korrekt och så effektiv som möjligt. Förklara kortfattat allt du gör och motivera hur du initierar eventuella semaforer. (5p) d) När du är klar kommer Bertrams dotter Latrina och granskar lösningen. Hon undrar varför Bertram och du inte använde en bounded buffer för att implementera trådsamlingen. Förklara kort hur en sådan lösning skulle fungera och vilka fördelar det skulle ge. Tänk bland annat på ett system med mycket många trådar i samlingen (stort värde på POOLSIZE). (2p) 3 (5)
Följande synkroniseringsmekanismer finns att tillgå enligt det du är van vid från lab: struct semaphore; void sema_init(struct semaphore*, int); void sema_down(struct semaphore*); void sema_up(struct semaphore*); struct lock; void lock_init(struct lock*); void lock_acquire(struct lock*); void lock_release(struct lock*); struct condition; void cond_init(struct condition*); void cond_wait(struct condition*, struct lock*); void cond_signal(struct condition*, struct lock*); Det finns även atomiska hårdvaruinstruktioner att tillgå. Dessa kan anropas genom följande högnivåfunktioner (som i detta fall kompileras ned till rätt assemblerinstruktion): bool test_and_set(bool*); void swap(int* a, int* b); int compare_and_swap(int* mem, int oldval, int newval); Bertrams uppskissade lösning ser ut så här: 1: // Vi skapar en lista som anger vad varje tråd i 2: // samplingen har för uppgift just nu. 3: struct pool_task 4: { 5: function_type task; // Uppgiften att bearbeta. 6: bool is_running; // Om uppgiften bearbetas. 7: } 8: 9: struct pool_task thread_pool[poolsize]; 10: int threads_available = POOLSIZE; 11: 12: // Här skapas en tråd för varje element i listan. 13: // Alla trådar i samlingen kör funktionen pool_worker 14: void pool_init(void) 15: { 16: for (int id = 0; id < POOLSIZE; ++id) 17: { 18: // Initiera datamedlemmar... 19: thread_pool[id].task = NULL; 20: thread_pool[id].is_running = false; 21: //... och starta sedan pool_worker i egen tråd. 22: thread_create(pool_worker, id); 23: } 24: } 25: 4 (5)
26: // Funktionen varje tråd i samlingen kör. 27: void pool_worker(const int id) 28: { 29: while ( true ) 30: { 31: // Vänta på att en ny uppgift blir tillgänglig. 32: while ( thread_pool[id].is_running == false ) 33: ; // Tom loop 34: 35: // Här börjar uppgiften bearbetas. Vi antar att 36: // bearbetningnen inte använder delade resurser. 37: thread_pool[id].task(); 38: // Uppgiften är klar, vi är redo för en ny uppgift. 39: thread_pool[id].is_running = false; 40: ++threads_available; 41: } 42: } 43: 44: // Ge en uppgift till en tråd i samlingen. Enbart trådar 45: // utifrån anropar denna, inte trådar inifrån samlingen. 46: void pool_assign_work(function_type task) 47: { 48: // Invänta en sysslolös tråd i samlingen. 49: while ( threads_available == 0 ) 50: ; // Tom loop 51: --threads_available; 52: 53: // Leta upp en sysslolös tråd. 54: for (int id = 0; id < POOLSIZE; ++id) 55: { 56: if (! thread_pool[id].is_running ) 57: { 58: // Ge tråden en uppgift att utföra... 59: thread_pool[id].task = task; 60: //... och sätt sedan igång tråden. 61: thread_pool[id].is_running = true; 62: break; 63: } 64: } 65: } 66: 67: // Alla trådar i samlingen får uppgiften att avsluta. 68: // Anropas när det inte finns fler uppgifter. 69: void pool_terminate_all(void) 70: { 71: for (int id = 0; id < POOLSIZE; ++id) 72: { 73: pool_assign_work(thread_exit); 74: } 75: } 5 (5)