Ordinarie tentamen med lösningar

Download Report

Transcript Ordinarie tentamen med lösningar

Preliminära lösningar till tentamen i IS1350/ID2200/ID2206
Operativsystem 
måndag 2014-05-28 kl 1400-1800 (GMT+1)
Skolan för Informations och Kommunikationsteknik
Examinator: Robert Rönngren
Hjälpmedel: Inga. Mobiltelefoner skall vara avstängda och får inte finnas vid skrivplatsen.
Tentamensfrågorna behöver inte återlämnas efter avslutad tentamen.
Ange på omslaget vilken kurs du tenterar och vilken termin du läste kursen ffg.
Varje inlämnat blad skall förses med följande information:
• Namn och personnummer
• Nummer för behandlade uppgifter
• Sidnummer
Rättning:
• Alla svar, även på delfrågor, måste ha åtminstone en kortfattad motivering för att ge poäng
• Resultat beräknas anslås inom 3 arbetsveckor
• Frågor markerade med ¤ ingår inte i tentamen för kursen ID2200
• Frågor markerade med * ingår inte i kursen IS1350
Betygsgränser:
• Godkänt (E) garanteras från 50% av det totala poäng antalet för respektive kurs
Lösningsförslag: anslås på kursens webbsida efter tentamen
1) a) Förklara vad ett systemanrop är, hur ett systemanrop genomförs och vad som händer i OS:et vid 
ett systemanrop!
b) UNIX/LINUX och Microsoft har haft olika strategier för vad som skall vara systemanrop eller inte. 
Förklara de huvudsakliga skillnaderna i hur man sett på vad som skall vara systemanrop och vad som 
inte skall vara det.
(2p)
(1p)
a) Systemanropen är det gränssnitt/de funktioner som operativsystemet gör tillgängligt för användarprogram att anropa för att få tjänster utförda av operativsystemet. (dvs . de är operativsystemets API). När ett användarprogram utför ett systemanrop så anropas normalt en biblioteksfunktion i C som utför själva systemanropet. Dessa biblioteksfunktioner är det som standardiseras i t.ex POSIX standarden. I biblioteksfunktionen läggs parametrarna på de ställen där de skall ligga för att os:et skall kunna hitta dem, vilket ofta är i register. Man laddar också in systemanropsnumret i ett register och sedan TRAPas till kärnan. Det som händer då är att processen/tråden som utför systemanropet byter stack till en stack som används när den exekverar i kärnan och den fortsätter att exekvera i kernel‐mode och hanterar systemanropet. I kärnan kontrolleras först varför man trappade till kärnan. När man konstaterat att det var pga ett systemanrop så kontrolleras vilket systemanrop det var. Var det ett systemanrop som implementeras i själva kärnan anropas den funktionen direkt. Var det ett systemanrop somimplementeras av en drivrutin slår kärnan upp den drivrutinen i en drivrutinstabell och anropar rätt funktion i drivrutinen. Antingen returnerar man direkt eller om det är ett blockerande systemanrop, som vid t.ex. blockerande I/O, så kan processen blockeras och återupptas då ett avbrott kommer som talar om att operationen är klar.
b) I UNIX/LINUX världen vill man hålla systemanropsgränssnittet litet och därför har man försökt begränsa antalet systemanrop och man är noga med att se vad som verkligen behöver vara systemanrop. Microsoft har ett betydligt större antal systemanrop (c:a 10 ggr fler) delvis beroende på att man integrerat bland annat grafiska gränssnitt etc. i kärnan. man kan uttrycka det som att Microsoft inte lika tydligt försökt renodla och minimera systemanropen både till antal och funktionalitet.
2) * printf() är en vanligt förekommande funktion i de flesta C-program. Men hur fungerar printf()
egentligen? Förklara i detalj vad som händer från det att funktionen anropas till dess att operativsystemet
hanterar utskriften utgående från exemplet nedan:

int tal = 44;
printf(”tal = %d\n”,tal);
(2p)
printf() tar ett variabelt antal parametrar: en formatsträng och parametrar som motsvarar det som skall konverteras för utskrift. Det första som sker i själva printf funktionen är att man börjar tolka (parsa) formatsträngen (första parametern). Man går igenom den från början och skriver in de tecken som skall skrivas ut i en buffert. Den bufferten allokeras via malloc()/realloc()/free() biblioteksfunktionerna. Om man i formatsträngen hittar konverteringsdirektiv, tecken sekvenser Sida 1
som börjar med %, så plockar man av motsvarande parameter från stacken, tolkar dessa och skriver in de tecken som skall skrivas ut i bufferten. När hela formatsträngen tolkats så anropas systemanropet write för att genomföra själva utskriften. Till write skickar man parametrarna: fildeskripter=1 (stdout), pekare till den buffert i vilkenman byggt upp strängen som skal skrivas och antal tecken som skall skrivas ut. Operativsystemet sköter sedan utskriften. Efter retur från write avallokeras bufferten via free().
3) * Du skall tillsammans med en labbpartner implementera en enkel kommandotolk (shell) som skall
möjliggöra att man kan koppla ihop ett godtyckligt antal processer via pipes. Systemet skall ha bra
felhantering. Din labbpartner föreslår att ni bara startar en process i taget som läser in sin indata från en 
pipe, eller om det är första processen i kedjan från någon annan källa, och sedan låter den mata ut utdata 
på en pipe. Tanken är att ni ska kontrollera att processen terminerar utan fel innan ni startar nästa process 
i kedjan. Din labbpartner tycker idén är bra då den förenklar felhanteringen och gör att man kan klara sig 
med att som mest ha två pipes öppna samtidigt. Är detta en bra eller en dålig idé? Förklara!
(1p)
Detta är en genuint dålig idé. Problemet är att en pipe implementeras som en buffert av begränsad storlek. Om en process fyller en pipe kan den inte skriva mer data till pipen om inte någon process läser ut data ur pipen. Det betyder att om man följer idén i frågeställningen kan man hamna i en situation där en process fyller pipen och sedan blir blockerad för evigt (baklås/deadlock) då den process som skulle kunna läsa från pipen inte startats.
4) Schemaläggningen av processer på operativsystem som Unix/LINUX/Windows sker i två nivåer. 
Förklara vilka nivåerna är och vad man vill uppnå med att ha två separata nivåer!
(2p)
På en övergripande nivå sker schemaläggning i samarbete med virtuellminnessystemet. Om det inte finns tillräckligt mycket ledigt minne (ramar) så swappas processer ut. Utswappade processer är inte tillgängliga för den "vanliga" schemaläggaren. Syftet med detta är att så långt möjligt skydda systemet mot överlast. Den "vanliga" schemaläggaren schemalägger de processer/trådar som finns tillgängliga (dvs. inte utswappade). Dess syfte är att ge processerna/trådarna en rättvis tillgång till att få köra på de processorkärnor som finns tillgängliga. Har man system med kärntrådar som schemaläggs tar schemaläggaren också hänsyn till att försöka schemalägga trådar från samma process samtidigt och på flerkärniga maskiner försöker man så långt möjligt schemalägga processer/trådar på samma kärna som de kört på tidigare.
5) Jämför processchemaläggningen så som den såg ut från början i Unix och den variant på schemaläggning
i Linux som vi gått igenom i kursen. På vilka sätt skiljer de sig och vad är respektive schemaläggningsalgoritms för- och nackdelar jämfört med den andra.
(2p)
Båda är prioritetsbaserade preemptiva schemaläggningsmetoder. I Unix original så används fixa timeslices. Periodvis (~1 gång/sekund) beräknas processernas prioriteter om. De processer som använt stor del av sin timeslice får temporärt lägre prioritet. I den version av LINUX schemaläggningen vi tagit upp i kursen så schemaläggs trådar (inte processer). Den har två klasser av realtidstrådar som har fix hög prioritet. Den prioritet man schemalägger efter är en temporär prioritet som kallas goodness. Den beräknas för varje process vid varje schemaläggningstillfälle och beror bland annat av hur stor del av det individuella tidskvantat processen har kvar. Det individuella tidskvantat beräknas om när inga schemaläggningsbara proceser finns ‐ dvs. då alla är blockerade eller har kört slut på sitt tidskvanta. Tidskvantat är proportionellt mot grundprioriteten och ev resterande del av tidigare tidskvanta som inte utnyttjats. Unix orginalschemaläggning har förelen att vara relativt enkel att beräkna och ganska rättvis. Den kan få problem med svältning om man har många högprioriterade processer och et fåtal lågprioriterade eftersom man inte kan garantera att de lågprioriterade kommer att få köra. LINUX schemaläggaren har nackdelen att kräva betydligt mer beräkningar, å andra sidan är den förhållandevis rättvis då den tilldelar processortid i stort sett proportionellt mot grundprioriteten och den säkerställer att alla processer, även lågprioriterade, får köra.
6) Processtabellen implementeras oftast som en vektor med fix storlek. Vilka för-och nackdelar innebär det? (1p)
Fördelen är att man direkt via en enkel indexering hittar en process processkontrollblock (informationen om en process). Den enda nackdel som finns är att det maximala antalet processer är begränsat. Normalt sett är det ingen allvarlig inskränkning då maxantalet oftast är så stort att systemet skulle bli överlastat om så många processer var aktiva samtidigt.
7) I system med sidindelat virtuellminne har man en sidutbytesalgoritm. 
a) Vilket är det viktigaste målet för sidutbytesalgoritmen?
b) Resonera kring hur väl man kan anta att följande algoritmer uppfyller 
målet från a): FIFO, Clock, LRU.
(1p)
(1.5p)
a) Det viktigaste målet för sidutbytesalgoritmen är att försöka minimera antalet sidfel vilket är samma sak som att den skall försöka se till att de sidor processerna för tillfället använder finns tillgängliga i primärminnet (inladdade i ramar) och inte är ut‐pageade till disk.
b) FIFO väljer den sida som först laddades in i primärminnet som "victim‐page". Det säger väldigt lite, eller egentligen inget Sida 2
alls, om om det är en sida som används eller inte. Det märks också på att den kan få ökat antal idfel om antalet tillgängliga ramar (dvs. primärminnet) utökas.
Clock organiserar sidorna i FIFO ordning i en cirkulär lista. Den använder också en referensbit som ettställs varje gång en sida i refereras. Algoritmen har en visare (pekare) som pekar ut nästa sida att kontrollera om någon sida behöver slängas ut ur promärminnet. Om den sidan har sin referensbit satt så nollställs den och man kontrollerar nästa sida i den cirkulära listan på samma sätt. När en sida med nollställd referensbit hittats så byts den ut. Clock ger en ganska bra uppskattning av vilka sidor som används eller inte.
LRU har en tidsstämpel som sätts varje gång en sida används (refereras till), När en sida behöver bytas ut byts den sida ut som det var längst sedan den refererades. LRU ger en så bra uppskattning som är möjlig att göra av vilka sidor som används eller inte (ligger i Working Set eller ej) men till en hög kostnad.
8) I system med sidindelat virtuellminne har man normalt något som kallas TLB.
a) Förklara vad en TLB är
b) Hur är en uppslagning i en TLB implementerad?
c) Vilka fält innehåller en post i en TLB normalt?
(0.5p)
(0.5p)
(1p)
a) en TLB (Translation Lookaside Buffer) är ett cacheminne som innehåller de senaste använda adressöversättningarna från sidnummer till ramnummer och används för att snabba upp adressöversättningarna i system med sidindelat virtuellminne.
b) den implementeras normalt med en typ av minne som kallas CAM‐minne (eller TCAM) vilket är ett minne som man kan adressera sig i med innehållet i minnet som söknyckel (Content Adressable Memory) Eller uttryckt på annat sätt, ett minne där man kan göra en sökning på innehållet i hela minnet på en klockcykel. Normalt söker man i TLBn med en söknyckel som består av <ProcessID, sidnummer> och om man får en träff i TLBn så får man fram ramnumret där sidan lagras om den ligger i primärminnet.
c) <valid/invalid bit, virtuellt sidnummer (PID+sidnummer), modifierad bit, protection (RWX), ramnummer> + kort beskrivning av varje fält/vad det används till)
9) Antag att vi i ett system med sidindelat virtuellminne hamnar i en situation där lasten på systemet är hög, 
att det inte finns några lediga ramar och att en process börjar generera väldigt många sidfel på kort tid. 
Vilka åtgärder kan och bör vi vidta om vi använder en lokal respektive global sidutbytesalgoritm?
(1p)
I fallet med en lokal sidutbytesalgoritm så kan vi inte med sidutbytsesalgoritmen frigöra ramar som används av andra processer för att på så sätt kunna tilldela den thrashande processen fler ramar. Eftersom man vill undvika thrashing så är det rimliga alternativet att istället swappa ut någon process för att på så sätt kunna frigöra ramar.
Har man en global sidutbytesalgoritm så börjar man med att se om det finns någon sida (oavsett vilken proess den tillhör) som är inladdad i primärminnet och som används lite som man kan slänga ut för att på så sätt frigöra ramar som den thrashande processen kan använda. Räcker inte det tvingas man swappa ut processer.
10) Ge en formel för den effektiva minnesaccesstiden där efterfrågat data finns i primärminnet. Datorsystem
implementerar sidindelat virtuellminne med en TLB och hashad inverterad sidtabell. Givet är följande
parametrar: träffsannolikhet i TLB = P, söktid i TLB= T, tid för att beräkna hashfunktionen = H,
genomsnittligt antal element som mappar mot samma hashvärde = N, minnesaccesstid (RAM) = M,
contextswitchtid = C.
(1p)
P(T+M) + (1‐P)(T + H + (N+1)M) Den första termen P(T+M) är det fall då vi får en träff i TLBn och direkt kan göra adressöversättningen och accessa data i minnet. Den andra termen motsvarar det fall då vi missar i TLBn. Då gör vi ändå en sökning i TLBn (som misslyckas), beräknar hahsfunktionen, går igenom N element i listan och sedan accessar data i minnet (+1 termen)
11) * Beskriv hur en effektiv, adaptiv algoritm för minneshantering (dvs som implementerar malloc(), free(),
realloc()) som anpassar sig till objektorienterade programs behov skulle kunna vara designat. Förklara 
vad du förväntar dig för tids- och minneskomplexitet.
(2p)
I ett objektorienterat program allokeras minne på heapen av användaren indirekt när man instansierar objekt. Typiskt är att antalet klasser som man skapar objekten från är begränsat. Det betyder att om det är program som exekveras under en längre tid så skulle minneshanteringsrutinerna kunna fungera så här: börja med att allokera minne baserat på en enkel algoritm som t.ex Kernighan&Ritchies next‐fit algoritm. Under tiden loggar man vilka storlekar på minne som begärs ofta. För dessa kan man sedan skapa speciella listor med block av fix storlek i varje lista som passar exakt mot en viss klass/
objekttyp. Allokering/avallokering mot dessa listor kan sedan ske i konstant tid för i de flesta fall förutum då man behöver utöka antalet block i en tom fri‐lista. Det enda problemet med en sådan lösning är att snabbt kunna identifiera ur/till vilken lista ett block skall hämtas eller läggas tillbaka i. Ett alternativ till att anpassa sig efter ett visst programs behov av blockstorlekar är den sk. Quick‐fit algoritmen som beskrivs i labbPM till labb 3.
Sida 3
12) Historiskt sett har man haft olika organisation av filer internt. Från början stödde OS:et oftast en ström av
bytes, sedan gick utvecklingen att mot att vissa OS stödde en intern struktur med records eller sökträd, på
1980-talet var man sedan tillbaka till att OS:en oftast bara stödde att en fil innehöll en byte ström. Idag har
man i många OS/filsystem börjat stödja mer komplex intern organisation av filer. Beskriv vad som stödjs i
Microsofts OS från och med Windows NT filsystemet och förklara varför man åter gått mot en mer 
komplex intern struktur på filerna!
(1.5p)
Microsofts filsystem stödjer att en fil kan ha inte bara en utan flera dataströmmar. Detta för att kunna stödja multi‐media applikationer och andra applikationer som har flera dataströmmar som t.ex. ljud‐ och bildinformation, på ett enkelt sätt.
13) Filsystem har historiskt sett implementerats baserat på i huvudsak två olika tekniker: FAT resp. indexnoder.
Beskriv de olika teknikernas huvuddrag och deras för- och nackdelar!
(2p)
FAT: File Allocation Table ‐ Man har blockindelad allokering av filerna på disken. I en directory/katalogpost har man ett index till första blocket i filen. FAT är en vektor med en post per diskblock. I indexet för första blocket i filen som hittas via directory/katalogposten finns index för nästa block i filen eller en slutmarkör. På så sätts byggsen länkad lista för filens block upp i FAT‐tabellen. Fördelen med FAT är att den är enkel att implementera medan nackdelarna bland annat är att storleken på diskblocken inte kan sättas hur som helst utan beror på diskens/partitionens storlek samt på hur stor FAT‐
tabellen är. Dessutom samlas inte all information om en fil på ett ställe vilket kan få konsekvensen att en fil kan ha olika accessrättigheter om den accessas via olika directoryn och positionering till godtycklig position i filen är en O(N) operation (N = antalet block i filen) när det skulle kunna vara en O(log(N)) operation.
Index noder: en indexnod är en liten datastruktur i vilken man samlar alla attribut kopplade till en instans av datatypen fil. I en indexnod finns uppgift om länkräknare, ägare, skapare, när filen skapats/modifierats/accessats, RWX‐rättigheter, device id, vilka blockfilen består av etc. Detta gör att en fil alltid har samma accessrättigheter oavsett från var i filsystemet den accessas, positionering i filen kan implementeras som en O(log(N)) operation och man kan i princip fritt välja blockstorlek. Enda nackdelen är att det är något mer komplex att implementera jämfört med FAT.
14) Ett av problemen med filsystem är att hålla dessa konsistenta. Ofta används program, som fsck eller scandisk,
för att kontrollera konsistensen. Dessa brukar kontrollera block- och/eller filsystemskonsistens. Men vad
innebär dessa begrepp?
(2p)
Block‐konsistens: Man kontrollerar att ett diskblock bara finns en gång i antingen listan över felaktiga block, i en fil eller i listan över lediga block.
Filsystemskonsistens: (främst i system med indexnoder) Man kontrollerar att antalet referenser via hårda länkar till en inod från filsystemet (från directoryna) stämmer med länkräknaren i inoden.
15) errno är enligt definierad att vara en global variabel för en process.
a) Vad används errno till?
b) I system som implementerar kärntrådar har man ibland en errno-variabel per kärntråd. Förklara 
varför detta kan vara bra?
(1p)
(1p)
a) errno är en variabel som sätts för att indikera vilken typ av fel som inträffat då ett fel skett i ett systemanrop (och i vissa andra fall). 
b) För att undvika att errno blir en kritisk sektion. Om man hade en global errno skulle följande problem kunna uppstå: Om en tråd gör ett systemanrop i vilket errno sätts för att indikera ett fel och en annan tråd hinner göra ett annat systemanrop som också gör att errno sätts innan den första tråden kontrollerat errno så skulle den första tråden inte se rätt felkod i errno när den kontrollerar denna. Har man en errno per tråd undviker man detta problem ‐ å andra sidan kan man inte lika enkelt implementera en centraliserad felhantering.
16) I en del programmeringsspråk, som Erlang, implementerar man något som i allt väsentligt förefaller vara 
trådar men där man är noga med att påpeka att det handlar om (lättvikts) processer. Vad är det för 
egenskap som skiljer dessa sk. lättviktsprocesser från vanliga trådar?
(1p)
Detta har att göra med hur felhantering sker. Normalt är att ett fatalt fel under exekvering försorsakar att hela processen termineras oavsett om felet uppstått i en tråd i en flertrådad process eller om processen var bara hade en tråd. Skillnaden mellan en kärntråd och en "(lättvikts)process" är ett fatalt fel endast påverkar "(lättvikts)processen" och inte hela den process den är en del av. Detta är en fördel framförallt när man vill skapa feltoleranta system.
17) När är det fördelaktigt att använda DMA istället för ren avbrottstyrd I/O? 
(förklara vad som skiljer dessa åt)
(1p)
Om man skall överföra en större mängd data till/från primärminnet och någon I/O‐enhet är det fördelaktigt om man kan använda DMA. Då sköts överföringen av en speciell processor och belastar inte CPUn. När överföringen är klar sker ett Sida 4
avbrott. Om man i stället skulle överföra samma data avbrottstyrt så skulle ett avbrott genereras för varje dataenhet som överförs. Skillnaden är att man får 1 avbrott med DMA och en context switch medan man med avbrottsstyrning får N avbrott och medföljande context switchar. Eftersom varje context switch är kostbar kan man alltså spara mycket tid på att använda DMA.
18) * I distribuerade system talas ibland om sk. "overlay networks". Förklara begreppet!
(1p)
Ett overlay network är ett abstrakt/virtuellt nät som implementeras ovanpå det fysiska nätet. I ett overlay network kan det t.ex. se ut som om det finns en direkt länk utan mellanliggande noder mellan två noder A och B medan det i det fysiska nätet kan finnas flera mellanliggande noder och länkar. Det är alltså en abstraktion som man gör för att förenkla/
effektivisera implementationen av det distribuerade systemet/tjänsten.
19) För att undersöka om man har deadlock i ett system kan man rita upp resursallokeringsgrafer. Vad 
indikerar det om man hittar en cykel i en sådan graf?
(1p)
Om och endast om det finns endast en resurs av varje resurstyp som är inblandad i cykeln betyder det at processerna inblandade i cykeln befinner sig i deadlock. Om det däremot finns flera resurserser av en eller flera av resurstyperna så indikerar det bara att de inblandade processerna i cykeln kan befinna sig i deadlock men de behöver inte göra det.
20) ¤ a) Varför vill man i realtids OS ofta kunna avbryta både kärnan och ev. pågående systemanrop?
¤ b) Beskriv två sätt att implementera detta och deras för- och nackdelar!
(1p)
(1p)
a) Det är för att minska det som kallas dispatch latency. Om en högprioriterad realtidsprocess vill få ett systemanrop utfört av kärnan kan den annars behöva vänta på att få systemanropet utfört om en lägre prioriterad process håller på att utföra ett systemanrop och för att skydda kärnan från att få inkonsistenta dataareor har låst hela kärnan (sk. Big Kernel Lock) under tiden systemanropet utförs.
b) Man kan antingen tillåta att kärnan (eller snarare en process som exekverar i kärnan) kan avbrytas vid vissa bestämda punkter, sk. pre‐emption points eller var/när som helst. I bägge fallen måste man se till att eventuell data i kärnan som den avbrutna processen arbetade med hålls konsistent. Det betyder tt man antingen måste spara dessa data (checkpointa) så att de kan återställas senare och/eller att man så långt möjligt ser till att processer som exekverar i kärnan arbetar med egna lokala kopior av data.
21) På vilket sätt kan det vara en säkerhetsrisk att låta vanliga användare installera drivrutiner på sin 
egen dator?
(1p)
En drivrutin exekveras i kernel‐mode. Det betyder att om drivrutinen innehåller skadlig kod (malware) så ger man den skadliga koden access till kärnan direkt om man skulle installera en skadlig drivrutin.
Sida 5