P I N TO S - P RO C E S S E R O C H T R Å DA R En kodstudie i hur Pintos hanterar processer och trådar. marhe414, sebto088, timan976, joncr042, joakv409 P RO C E S S E R O C H T R Å DA R programmet Word vill man ju kunna skriva samtidigt som rättstavningsprogrammet körs i bakgrunden. Detta styrs med flera trådar. Detta dokument kommer att ge en övergripande syn av Pintos operativsystem och mer specifikt hur operativsystemet hanterar och sköter processer samt trådar. Pintos kommer att jämföras mot boken Operating System C o n c e p t s s o m b e s k r i ve r h u r v a n l i g a operativsystem är uppbyggda för att ge perspektiv på det som Pintos gör speciellt. Vidare kommer vi även reflektera över hur Pintos kan förbättras och vilka ändringar som kan göras för att skapa denna förbättring. För varje tråd behöver man även där ha koll på viss information. Denna information sparas ner i ett så kallat Thread Control Block. Data som skulle kunna sparas i denna är frame pointer, stack pointer, CPU flags och nästa instruktion att utföra. I Pintos hittar man denna information i datastrukturen intr_frame som ligger i threads/ interrupt.h. PCB Schemaläggning För varje process som skapas i ett operativsystem kan det vara bra att ha koll på viss information. Denna information sparar man ner i ett så kallat Process Control Block, eller Task Control Block som det även kallas. I Pintos används First Come First Serve Roundrobin algoritmen för schemaläggning. Detta innebär att trådar plockas från ready-kön i den ordning de kom in men att en tråd endast får exekver a i ett visst antal ticks innan schemaläggaren tvingar ett trådbyte. Antalet ticks som en tråd får exekvera i skiljer sig från operativsystem till operativsystem, men i Pintos är det satt till 4 ticks. Då det i Pintos går 100 ticks per sekund innebär det att 4 ticks är lika med ungefär 40 millisekunder. I ett vanligt Process Control Block kan man finna data såsom process state, program counter, CPU registers, CPU-scheduling, Memor ymanagement infor mation, Accounting information samt open files. I Pintos finns det endast en tråd per process så därför har man valt att lägga den väsentligaste informationen från ett PCB i datastrukturen thread. Denna datastruktur finns i threads/ thread.c eftersom det inte finns någon datastruktur i userprog/process.c för att göra detta. Man har valt att lägga information såsom thread ID (som är exakt samma som process ID), thread state, stack pointer, priority, list of open files och page director y i denna datastruktur. Som man kan se stämmer många av dessa överens med de olika delarna som finns i ett vanligt PCB. Till skillnad från andra operativsystem använder sig Pintos av endast en kö för att hålla reda på trådar. Denna kö benämns ready-kön och måste såklart implementeras på något sätt; i Pintos används en enkellänkad lista, deklarerad i thread.c:25: static struct list ready_list; Denna lista lagrar instanser av struct thread (indirekt genom struct list_elem) vilka representerar trådar som är redo att exekvera. Trådar i den här kön har alltid statusen THREAD_READY. Andra statusar en tråd kan ha är THREAD_BLOCKED , THREAD_RUNNING , och THREAD_DYING. TCB Varför skapar man en så kallad "tråd" för och inte lägger allt detta i processen? De har ju trots allt samma ID. Jo, för i de flesta operativsystemen vill man kunna köra flera trådar för varje process. I t.ex. 2 Figur 1. Olika states en tråd kan befinna sig i samt vilka funktioner som påverkar statet. Som man ser i figuren ovan finns det tre funktioner som förflyttar en tråd till ready-kön: och vise versa. När de i boken t.ex. lägger in en process i en schema kö lägger vi in en tråd i kön. • thread_create, Om man öppnar thread.h filen och undersöker structen för hur en tråd är uppbyggd märker man snart att flera variabler som ska tillhöra en process tillhör själva tråden. Den som sticker ut mest är: vars uppgift är att skapa en ny tråd. Använder sig utav thread_unblock för att göra förflyttningen då en tråd alltid börjar sin livscykel som blockerad. som förflyttar en f.d blockerad tråd till ready-kön. • thread_unblock enum thread_status status; vilket är något man ofta brukar ha för en process. sköter preemption, vilket innebär att den aktiva tråden (som kan fås via thread_current) tvingas ge upp CPU:n för att andra trådar skall få en chans att exekvera. • thread_yield Tråden saknar även vem dess förälder är och vilka barn den bringat till liv i systemet, medan en process har dessa variabler. Detta kan ses som en allvarlig brist då man i boken beskriver att man bygger upp processer i en form av processträd. I det fallet skulle barnprocesser avslutas i samband med att föräldraprocessen avslutas. En annan funktion som är värd att nämna är schedule. Denna funktion, tillsammans med schedule_tail, tar en tråd från ready-kön och gör den till den aktiva tråden som exekverar. schedule funktionen använder sig utav next_thread_to_run för att välja en tråd från ready-kön, vilken helt enkelt tar den första tråden i kön (kom ihåg att Pintos använder sig utav FCFS Round-robin). Beroende på hur man utför t labben för filhantering så sparar man en öppen fil-lista i tråden eller ej. Jag valde att spara detta i tråden vilket resulterar i att tråden mer påminner om en process än en tråd. Då de i boken tar upp att man öppnar filer för en process inte för själva tråden. Trådars relation till processer Trådar och processer är "ett" i Pintos medan i boken så är de delade, vilket har resulterat i att mycket av koden är hopvir ad och funktionaliteter hos processer finns hos trådar 3 Slår man upp process_wait funktionen i process.c så finner man snart att den arbetar direkt med den nuvarande tråden och inte en nuvarande process. Det finns inte heller någon struct för en process i Pintos vilket betyder att processer är något abstrakt, de finns där men ändå inte. Man har dem men man lagrar informationen i respektive tråd. operativsystem (mer info se ovan) så initieras tråden lite speciellt. När en tråd skapas så byggs den ihop blockerad för att sedan läggas redo sist i ready kön, vilket är vad thread_create funktionen utför. thread_unblock tar bort blockeringen från tråden och lägger den i ready kön. Sammanfattning Process creation som finns förklarat i boken om hur man skapar en process finns inte som funktion i process.h, istället måste vi gå in i thread.h och ser snart att skapandet av en tråd påminner mer om skapandet av en process än en tråd. Den största skillnaden mellan implementationen av processer och trådar i pintos och moderna operativsystem är att pintos mer eller mindre slagit ihop processer och trådar till en entitet. I ett modernt operativsystem är processen en egen datastruktur och implementerar ett eget PCB. Sedan har processen en eller flera trådar, oftast enligt one-to-one -modellen där varje user-tråd har en motsvarande kerneltråd och kan på så sätt blockera medan de andra kerneltrådarna och motsvarande user-trådar kan fortsätta att exekvera. För att göra en sådan implementation i pintos skulle processen behöva vara en egen struct istället för att bara implementera en tråd. Tråd-structen skulle behöva skilja på user och kernel-trådar för att kunna implementera one-to-one modellen. PCB, som just nu är implementerad i tråden, skulle behöva flyttas till processens struct. TCB skulle dock kunna ligga kvar på ett liknande sätt i tråd-structen. Process-structen skulle dessutom behöva implementera en lista för att kunna ha fler än en tråd. Process termination som kallas process_exit i Pintos är tom och utför inget. Vi får röra oss till thread.h där vi kan se att thread_exit avslutar den nuvarande körande tråden, vilket process termination skulle ha uppnått. Vi har en bool som bestämmer om vi ska använda oss utav Round-robin eller multi-level feedback queue scheduler. Som standard kör vi Round-robin och har endast hittat implementation för multi-level feedback queue scheduler i testfilerna. Var 100 ms sker en interrupt som avbryter och kallar på intr_yield_on_return som sparar den nuvarande trådens arbete och kallar på nästa tråd med hjälp av next_thread_to_run. Finns det ingen tråd i ready kön returneras idle_thread. Skulle en tråd avslutas i förtid körs thread_exit som i sin tur kallar på schedule för att hämta nästa tråd till exekvering. Källor 1. http://www.scs.stanford.edu/12au-cs140/ notes/l2.pdf [Hämtad 2013-02-21] Som tidigare förklarat så är en process egentligen ganska irrelevant och gör inte så mycket utan det är själva tråden som skapar och lagrar det mest vitala för vad en process bör innehålla. Det finns inte så många större skillnader på den Pintos gör vid skapandet av dessa trådar gentemot vad boken förklarar. Dock finns det några saker som inte görs som är värt att nämna. Förutom att trådarna i Pintos inte bygger trädstrukturer med fler childprocesser som är standard i nästan alla 2. Silberschatz, A., Galvin, P.B. och Gagne G. Operating System Concepts 8th Edition International Student Version (2010) 3. Filer från operativsystemet Pintos: • threads/thread.{h,c} • userprog/process.{h,c} • threads/interrupt.h 4