Linköpings universitet Institutionen för datavetenskap TDDI81 Hemuppgift Processer och trådar av Rasmus Cronstrand Per Jonsson Ante Wall Fabian Åberg rascr534 / perjo927 / antwa730 / fabab714 2014-02-24 Tack till: Thomas Henriksson, Tobias Jansson, Martin Lidh, Nicklas Sedbring Examinator: Klas Arvidsson
Case Study: Pintos Rasmus Cronstrand Per Jonsson Ante Wall Fabian Åberg INLEDNING Denna rapport sammanfattar och beskriver det simpla operativsystemet Pintos lösning och implementation av process- och trådhantering. Pintos lösning jämförs med kursboken Operating System Concepts av Silberschatz, Galvin, Gagne, 8 th edition. Pintos har utvecklats på Stanford University och deras källkod inklusive dokumentation används till laborationer i kursen TDDI81 på Linköpings universitet samt utgör även underlag till denna rapport utöver ovan nämnda bok. Det förs förutom en beskrivande sammanfattning och jämförelse även en kritisk diskussion kring Pintos lösning. Utöver det drar rapportförfattarna slutsatser om vad som skulle kunna göras annorlunda. SAMMANFATTNING Vi har i rapportens inledande kapitel Processer samt Trådar sammanfattat Pintos lösning och jämfört den med bokens. Därefter, i kapitlet Diskussion har vi gjort en kritisk granskning av Pintos lösning och slutligen i kapitlet Slutsats kommit fram till vad vi själva skulle föredra för lösning. PROCESSER Vi beskriver först Pintos lösning av de olika koncepten som rör processer i operativsystem, sedan jämförs Pintos lösning med boken. Pintos lösning Pintos tillåter att mer än en process körs åt gången. Varje process har en tråd, flera trådar inuti processer stöds inte. Källkodsfilerna process.c & process.h har ansvar för att ladda in binärfiler och starta processer. syscall.c & sycall.h assisterar processerna när de vill få tillgång till kernelfunktionalitet genom systemanrop, denna funktionalitet är dock ej implementerad i grundversionen av Pintos, vad som istället händer är att processen avslutas med en spårutskrift. Pintos kan köra program skrivna i språket C, under förutsättning att de ryms i minnet och att programmen enbart använder systemanrop och övrig funktionalitet som implementerats utöver grundversionen. Användarprogram har inte åtkomst till kernelminne utan enbart det virtuella minne som finns reserverat för user mode. Det saknas även, utöver systemanrop och korrekt terminering av processer, implementation för att skicka argument till funktioner och att skriva till skärmen. Det ansvaret har lämnats till programmeringsstudenten. (Pfaff, 2006, s.21-37) PCB I Pintos motsvaras PCB (akronym för Process Controll Block) av datastrukturen struct thread i threads/thread.c & thread.h (Pfaff, 2012), som har 4kb reserverat minnesutrymme, resten är avsett för kerneln. I thread finns i grundversionen av Pintos dessa medlemmar deklarerade: tid (tråd-id) status (t.ex. ready) name (tecken-identifierare) stack (stackpekare) priority (schemaläggnings-prioritet) allelem (länkar tråden till trådlistan) elem (listelement till köer) pagedir (minne till processen) magic (upptäcker stack overflow) En konceptuell sammanslagning är att PCB i Pintos även delar likheter med TCB (Thread - 2 -
Control Block), som man kan förstå av namnet på datastrukturen. Det vill säga: Information om processer sparas i thread, men även information om trådar lagras i thread. Man kommer åt den genom en thread-pekare från funktionen thread_ current(). (Pfaff, 2012, threads/thread.c & thread.h ) Trådar diskuteras närmare i kapitlet Trådar. Schemaläggning av processer För att hantera flera processer behövs en algoritm för att hantera när bytena ska ske. Pintos använder sig av en algoritm som heter Round-Robin med policyn FCFS (First come, first served). Pintos har dock möjlighet att byta algoritm till Multi-level Feedback Queue Scheduler genom att sätta variabeln thread_mlfqs till true istället för false vilket är standardvärdet. Round-Robin fungerar på det sättet att en tidsenhet sätts, i Pintos är det TIME_SLICE som är satt till 4. Varje process håller sedan reda på hur länge en variabel har körts och när värdet når TIME_SLICE kommer processen som körs att bytas ut. (Pfaff, 2012, threads/thread.c & thread.h ) Vänteköer Ready-kön i Pintos består av en dubbellänkad lista som heter ready_list och finns implementerad i threads.c. (Pfaff, 2006, s.59) I den listan sparas alla processer som har Figur 1: Förflyttningar i Pintos. statusen THREAD_READY vilket säger att processen kan köras och väntar på att få exekveras. Pintos använder sig av funktionen thread_schedule() för att välja den tråd som ska få köras och ändrar statusen till THREAD_RUNNING. För att skapa en ny tråd på ready_list så kör man funktionen thread_create() som skapar och placerar en ny tråd i listan. thread_yield() förflyttar den körande koden tillbaka till ready_list och tillbaka till kösystemet. thread_block() sätter tråden till vänteläge, statusen till THREAD_BLOCKED och kommer inte att köras igen förrän thread_unblock() väcker och sätter tillbaka den i ready_list i väntan på att få köras. Tråden som arbetas på av processorn har statusen THREAD_RUNNING och kan fås tag på genom att kalla thread_current(). (Pfaff, 2012, threads/thread.c & thread.h ) Exekvering av processer För att en process överhuvudtaget ska kunna startas måste systemet initieras, vilket görs i Pintos huvudprogram i threads/init.c. Där initieras bl.a. trådsystemet, minnesallokering görs, avbrottshanteraren startas, med mera. (Pfaff, 2012, threads/init.c) Det är funktionen process_execute() som har till uppgift att starta processer. Med hjälp av tilldelningen - 3 -
tid = thread_create(file_name, PRI_DEFAULT, start_process, fn_copy); ger man en ny kerneltråd ansvaret för exekveringen. Vi ser i parameterlistan att man får en fil som programmet läses in från, prioritet, samt hjälpfunktionen start_process(), som har ansvaret att bland annat ordna stack till processen, allokera minne och läsa in programfilen så att den kan startas i user-läge. process_execute() returnerar ett id till processen eller en felkod om inte tråden kunde starta processen (som start_process() kommer signalera). (Pfaff, 2012, userprog/process.c & process.h ) Jämförelse med kursboken Exekvering av processer Boken beskriver hur de flesta operativsystem (Linux, UNIX, Windows) tilldelar varje process en heltalsidentifierare (pid), precis som i Pintos (tid). Vidare beskrivs hur processer kan klonas och bilda en trädstruktur där processer kan klonas och få barn (i UNIX med hjälp av fork() och exec()). Den ursprungliga föräldern är då typiskt processen init. Föräldern kan då antingen exekvera samtidigt som dess barn, eller vänta på deras terminering, men de har ingen möjlighet att komma åt dess resurser. (Silberschatz m.fl., 2010, s.116-118) När process_execute() anropas skapas en ny kerneltråd och den nya tråden exekverar därefter funktionen start_process() som startar processen / tråden. När tråden skapas så anropas funktionen thread_create(). Man kan säga att i Pintos så är process och tråd sammankopplade (Pfaff, 2012, threads/thread.c & thread.h) medan i ett UNIX-system så är de separata. I jämförelse med POSIX thread (pthreads) så används funktionen pthread_create() för att skapa en tråd. (Silberschatz m.fl., 2010, s.172-173) I Pintos existerar ingen lösning där processen klonas, process_execute skapar helt sonika en ny process. (Pfaff, 2012, userprog/process.c & process.h) PCB Det så kallade PCB i boken består av ett antal olika delar och dessa är: Process state som håller koll på i vilket state processen är. Program counter som vet var nästa instruktionsadress ligger. CPU registers, t.ex stackpekare, ackumulatorer, indexregister och general purpose-register. Dessa kan dock variera beroende på arkitekturen i datorn. De sparas ner tillsammans med program counter när ett interrupt påträffas så att det går att fortsätta som vanligt när processen sedan ska fortsätta. CPU-scheduling information som innehåller det som behövs för att schemaläggning av processen ska fungera d.v.s. pekare till schemaläggningsköer och processens prioritet. Memory management information. Base registers, limit registers, segment tables och page tables befinner sig här, detta varierar dock beroende på hur operativsystemet hanterar minne. Accounting information är sådant som är viktigt för schemaläggning då den håller koll på hur länge processen använt CPU och om den borde byta med en annan process. Här samlas använd CPU-tid, time limits, account numbers och job & process numbers. I/O status info är en lista över I/Oenheter som processen har allokerat, t.ex. filer. (Silberschatz m.fl., 2010, s.103-105) Denna information går naturligtvis också att hitta i Pintos och man kan se många likheter med den PCB som beskrivs i boken. Detta hittas som tidigare nämnts i threads/thread.h i en så kallad struct thread. (Pfaff, 2012, threads/thread.c & thread.h ) - 4 -
TRÅDAR I detta kapitel ser vi på hur Pintos hanterar kernel- och user-trådar samt jämför med kursboken. Pintos lösning Eftersom att Pintos bara tillåter en process för varje tråd så kan man säga att i Pintos implementering så är en tråd väldigt likt en process. Det funkar så att i thread kan den skapas (med hjälp av ett #ifdef #endif kontroll- block) som en user tråd om den kommer från userprog/process.c och startats med hjälp av process_execute(). (Pfaff, 2012, threads/thread.c & thread.h ) Som nämnts tidigare finns ingen dedikerad TCB i Pintos, datastrukturen struct thread fungerar både som PCB och TCB. Den finns beskriven i kapitlet Processer. Distinktionen man måste göra är att en process i Pintos alltid har endast en motsvarande kerneltråd, men det innebär inte att alla trådar i sig är processer. (Pfaff, 2006, s. 9-19) Jämförelse med boken Multithreading Boken tar upp det faktum att de flesta mjukvaruapplikationer som körs på moderna datorer är multitrådade; som exempel ges att webbläsare kan ha olika trådar för visning av bilder, ordbehandlare kan ha olika trådar för I/O, grafik och rättstavning och dylikt. En webbserver är ett annat typexempel där multitrådning kan vara nödvändigt. Det finns då olika modeller, till exempel one-to-one, manyto-many, many-to-one. (Silberschatz m.fl., 2010, s.163-171) I Pintos är inte multitrådning möjligt på grund av att bara en tråd per process stöds. (Pfaff, 2012, threads/thread.c & thread.h ) DISKUSSION Nedan följer en kritisk granskning av Pintos lösning där fördelar vägs mot nackdelar. Granskning av Pintos lösning Vi delar upp diskussionen i följande områden: PCB Exekvering av processer Schemaläggning av processer Trådar PCB Vad som kan skapa huvudbry i Pintos är sammanslagningen av PCB och TCB. Det gör det svårt att konceptuellt och praktiskt skilja på process och tråd. Fördelen i Pintos fall är det är ett minimalt operativsystem till att börja med och inte behöver mer än väldigt grundläggande strukturer för att fungera. Se kapitlet Slutsatser för ett förslag till en alternativ lösning på detta. Exekvering av processer Exekvering av processer i Pintos är inte olikt men inte heller helt likt vad man ser i större operativsystem, som Linux, Unix och Windows. Vi har nämnt det faktum att processer inte klonas när de skapas. Identifieringen av processer och dess olika livscykler sker dock på ett liknande standardiserat sätt som kan förvänta sig om man studerat andra operativsystem, vilket torde vara till Pintos fördel. Schemaläggning av processer Round-Robin har flera nackdelar, till exempel så kan det vara så att en process snart är färdigt och det smartaste skulle vara att köra färdigt processen men Round-Robin har inget sätt att kolla detta vilket gör att processen läggs längst bak i kön. Dessutom prioriterar den inte processer, vilket gör att det kan förekomma fördröjning på viktiga funktioner som till exempel uppdateringar på skärmen. Trådar Se rubriken PCB angående diskussionen om PCB kontra TCB. Man kan sakna möjligheten för en process att ha flera trådar och utnyttja det faktum att moderna processorer är flerkärniga och schemalägga trådar på olika kärnor samtidigt. En revision av datastrukturen struct thread kan till exempel vara på sin plats - se - 5 -
nästa kapitel. SLUTSATSER I följande kapitel tittar vi på vad som skulle kunna göras annorlunda och vilka fördelar och nackdelar det skulle ge. Vi föreslår ett sätt att utöka Pintos så att processer kan starta flera user-trådar och kerneltrådar, samt anger hur datastrukturen för nya PCB och nya thread skulle se ut. Silberschatz A., Galvin P.B., Gagne G (2010). Operating System Concepts, 8 th Edition. Wiley & Sons. Pfaff, Ben (2012). Pintos Public Repository. http://pintos-os.org/cgi-bin/gitweb.cgi?p=pintosanon;a=tree. Förslag till ny lösning I grundutförande är Pintos uppbyggt så att både PCB och TCB inryms i samma datastruktur och processer enbart kan vara enkeltrådade medan moderna operativsystem tillåter att processer får ett eget PCB och att processen kan ha flera trådar, var för sig kopplade till en kerneltråd. Annars kan inte processen göra flera saker samtidigt. Kernel i Pintos kan dock i nuläget ha flera trådar. Om vi ska realisera den här 1-1-modellen bör vi skapa just den beskrivna arkitekturen från boken där vi har ett särskilt TCB för att hålla context och stack, samt ett PCB som TCB:n pekar till för processer med tillhörande medlemmar såsom id, prioritet, allokerat minne (delas lika mellan alla trådar), lista för filer och lista för multipla trådar. TCB kan lämpligtvis implementeras i nuvarande struct thread, med viss modifiering som mappning till mellan kernel- och usertråd. PCB kan implementeras som en egen struktur och dynamiskt länkas till TCB med pekare, så att man kan se till processer som är avslutade får sina resurser avallokerade. Då skulle vi få ett något modernare Pintos. REFERENSER Pfaff, Ben (2006). http://www.scs.stanford.edu/07aucs140/pintos/pintos_6.html. i. Stanford University. - 6 -