Planen for i dag Repetition af kerner med r Kerner med tvungent processkift Præsentation af K1 Kerner med r Vi erstattede aktiv venten med: ventende processer placeres i ventekøer r aktiverer ventede processer ved at flytte dem til klarkøen Bedre udnyttelse af CPU Introduktion af parallelisme i kernen: sroutiner kan udføres når som helst (undtagen når vi lukker for r) fokus på kritiske regioner 1 2 Kerne med r Tætkoblede drivprogrammer readerproc writerproc KReadLine() KWriteLine() KInitSem() KWait() KSignal() KReadChar() KWriteChar() KInitProc( ) KReadyQ KSleep() KCurProc KPause() KSelectNewProcess() KInterruptHandler() KReadQ KWriteQ Hver slags hændelse (tegn skrevet, tegn læst, ) er tilknyttet en ventekø: char KReadChar() { while(!(rdio(com1lsr) & 0x01)) KPause(KReadQ); return rdio(com1rbr); 3 4 Synkronisering med ydre enheder void KInterruptHandler() { if( rdio(com1iir) & 2) while(!kreadq.isempty()) KReadyQ.Put(KReadQ.Get()); else if( rdio(com1iir) & 4) while(!kwriteq.isempty()) KReadyQ.Put(KWriteQ.Get()); Uheldig rækkefølge <KReadChar> while(!(rdio(com1lsr) & 0x01)) <UART> sætter ready-bit <KInterruptHandler> while(!kwaitq.isempty()) <KReadChar> KPause(KReadQ); <KSelectNewProcess> <sætter proces i ventekø> AAAAARGH: vi opdager ikke at tegnet er læst 5 6 1
Problem Vi har to parallelle processer: brugerproces sroutine der deler data: kontrolregistre proceskøer Vi må sikre udelelig udførsel af kritiske regioner Implementering af udelelighed Luk for r: char KReadChar() { forbid(); while(!(rdio(com1lsr) & 0x01)) KPause(KReadQ); char ch = rdio(com1rbr); permit(); return ch; Nu bliver vi ikke afbrudt mellem check af statusregister og KWaitQ.Put() Vi åbner for r i KPause() 7 8 Ny KPause KPause skal skifte sniveau (ipl er en del af processens tilstand): void KPause() { <gem sniveau i PKB>; <gem registre på stakken>; <gem stakpeger i PKB>; <find ny proces>; <gendan stakpeger fra PKB>; <gendan registre>; <gendan sniveau fra PKB>; Andre routiner der skal beskyttes? Afbrydelsesroutiner og alm. kernefunktioner deler køstrukturer Beskyt køoperationerne: int isempty() { int oldipl = forbid(); int b = (size == 0); permit(oldipl); return b; ; 9 10 Kerner med tvungent processkift Indtil nu har vi kun set på kerner med frivilligt processkift via KPause() En sroutine sætter processen i klarkøen, men der kan gå lang tid inden den aktive proces opgiver CPU en Vi vil tvinge et processkift som en del af n: dette sikrer hurtigere behandling af r Ny sprocedure void KInterruptHandler() { if(rdio(com1iir) & 2) KSleep (KReadyQ, KWriteQ); else if(rdio(com1iir) & 4) KSleep (KReadyQ, KReadQ); 11 12 2
KSleep og venner Queue<Process>* KPutQ, KGetQ; void KSleep(Queue<Process>& put, Queue<Process>& get) { KPutQ = &put, KGetQ = &get; KPause(); Registers* KSelectNewProcess (Registers* sp) { KCurProc->sp = sp; KPutQ->Put(KCurProc); KCurProc = KGetQ->Get(); return KCurProc->sp; 13 Tvungent processkift - eksempel a2 BP1_start() a1 printl() a0 gp KWriteLinepc KWriteChar ps Processkift sker KPause EFTER behandling af og kvittering for Skift: stakpeger sniveau B_start() Wait(sem) ent_int KSleep KPause 14 Semaforroutiner Nu kan vores semaforroutiner også blive afbrudt: void KWait (KSem *sem) { if (!sem->value) KSleep(sem->WaitQ, KReadyQ); sem->value--; Førhen var dette sikkert fordi r ikke rørte ved semaforerne Men nu kan en vilkårlig proces blive afbrudt 15 En anden uheldig rækkefølge <BP1> if(!sem->value) <antag sem->value == 1> <Afbrydelse> KPause(KReadyQ, KReadQ);...... <B> if(!sem->value) <sem->value stadig == 1> <B> sem->value--; <Afbrydelse> KPause(KReadyQ, KWriteQ);...... <BP1> sem->value--; UUUPS: der er 2 processer i kritisk region!! Nye semaforroutiner Nu kan vores semaforroutiner ikke mere blive afbrudt: void KWait (KSem *sem) { forbid(); if (!sem->value) KSleep(sem->WaitQ, KReadyQ); sem->value--; permit(); Andre routiner der har problemer? Måske KSleep generelt? Kan vi klare at skifte proces mens vi skifter proces? Registers* KSelectNewProcess (Registers* sp) { KCurProc->sp = sp; KPutQ->Put(KCurProc); KCurProc = KGetQ->Get(); return KCurProc->sp; De to globale variable KPutQ og KGetQ ser suspekte ud 17 18 3
Endnu en uheldig rækkefølge <BP1> < KSleep(KReadyQ, mywaitq) > < KPutQ = KReadyQ, KGetQ = mywaitq > <Afbrydelse> < KSleep(KReadyQ, KReadQ) > < KPutQ = KReadyQ, KGetQ = KReadQ > <BP4>...... < KSleep(KReadQ, KReadyQ) > < KPutQ = KReadQ, KGetQ = KReadyQ > <BP1> < KSelectNewProcess > < Sætter sig selv på KReadQ men aktiverer proces fra KReadyQ > Morale Man skal være forsigtig!!!! Identificer alle variable der deles mellem sroutiner og alm. kerneroutiner Foretag sikring af kritiske regioner Ved aflusning af kerner (f.eks. K1) kan det være en god ide at starte med helt at lukke for r i kernen og så langsom bløde det op 19 20 Kerner med periodisk processkift Hidtil har vi udskiftet den kørende proces ved fra I/O enhed: Har vi kun en CPU tung proces, er det fint nok, da den vil blive afbrudt Men hvis vi har flere, kan der stadig gå lang tid inden en ventende proces kommer til fadet KPause() kaldes typisk som led i et systemkald: ved hvert systemkald kunne man undersøge om en proces har kørt for længe, og derefter kalde KPause Hvad med beregningstunge processer, der sjældent bruger systemkald? Kræv at de skal indsætte frivillige processkift Tving dem væk fra CPU en Implementering af periodisk processkift void KInterruptHandler (ulong a0) { if ( a0 & 0x01) KSleep(KReadyQ, KReadyQ); else...... Hver gang uret afbryder puttes den aktive proces bagerst i klarkøen (round robin) Men hvad hvis der ingen aktiv proces er? 21 22 Tomgangsprocessen For at sikre, at der altid er en proces i klarkøen, har vi en tomgangsproces: void KIdleProcess { for(;;;) KSleep(KReadyQ,KReadyQ); men man kunne nu stadig bruge en venteløkke i selve KSelectNewProcess 23 Brug af to sikkerhedsniveauer Hardware indeholder en eller flere bits, der viser sikkerhedsniveau, f.eks. (0) brugertilstand og (1) kernetilstand Ved r skiftes til kernetilstand, f.eks. ved en trap operation Specielle privilegerede instruktioner kan kun udføres i kernetilstand, typisk instruktioner der har med ressourcedeling at gøre trap/ exception kernetilstand skift til brugerniveau brugertilstand 24 4
2 slags stakke Når brugerprogrammer udføres i brugertilstand benytter de en brugerstakpeger Systemkald samt r udføres i kernetilstanden og benytter en kernestakpeger Kernestakpegeren peger på et andet lagerområde end brugerstakpegeren Kerne sp vil typisk være beskyttet mod skrivning og læsning fra brugertilstand Skiftet mellem stakpegerne foretages på Alphaerne af PAL koden ved skift mellem bruger og kernetilstand Brugerstak og kernestak eksempel kerne sp BP1_start() findmin() findmin() ent_int BP1_start(void) { findmin(t3_root); PAL registre: bruger sp: ikke BP1 def. sp kerne sp: 0x200000 kerne $sp = bruger kerne sp = $sp 25 26 Processkift i sprocedure Hvis vi ønsker at skifte proces i en sprocedure skal vi dels: gemme kørende proces tilstand ændre brugerstakpeger i PAL register gendanne nye proces tilstand Ændring af bruger sp er nemt: PAL_rdusp læser bruger stakpeger fra PAL register PAL_wrusp skriver en ny bruger stakpeger til PAL register Men processernes tilstande omfatter: Registre gemt af ent_int (sniveau) 27 Skift mellem stakke ved processkift under Vi ser på fire eksempler Skift mellem processer i brugertilstand: én kernestak en kernestak pr proces Processkift med en proces i systemtilstand og en i brugertilstand Processkift ved indlejrede r, f.eks.: først fra UART (ipl 3) KInterruptHandler afbrydes af uret (ipl 5) 28 2 processer i brugertilstand: én kernestak kerne sp BP1_start() calc() calc() P1 B_start() calc() calc() P1 PAL registre: Gem kopi af bruger Bs sp: kernestak XXXXX B ent_int kerne sp: 0x200000 (f.eks. på brugerstakken) Gendan kopi af BP1s kernestak 29 2 processer i brugertilstand: en kernestak per proces BP1 kerne sp BP1_start() calc() calc() P1 Registre P1 ent_int PAL registre: B_start() bruger sp: B XXXXX kerne sp: 0x220000 0x200000 calc() calc() B kerne sp ent_int 30 5
2 processer: en i brugertilstand og en i kernetilstand BP1 kerne sp BP1_start() printl() P1 ent_sys Registre P1 KWriteChar KPause B kerne sp Skift: brugerstakpeger aktiv stakpeger sniveau B_start() calc() ent_int KPause 31 Indlejrede r kerne sp Er flag for processkift sat og er vi den sidste? B_start() Så kan vi skifte til calc() en anden proces calc() Vi sætter et flag, der Duer fortæller ikke at vi vi var skal allerede i gang foretage med et at processkift behandle et interrupt ent_int KPause ent_int KPause 32 Indlejrede r Hvordan ved man at man er det eneste interrupt? På stakken ligger et statusregister, der fortæller hvad sniveau var inden den aktuelle : ipl == 0 => ingen forudgående r Opsummering Kerner med r: introduktion af parallelisme i kernen implementation af udelelighed ved styring af sniveau Tvungent processkift: øget parallelisme i kernen (alle processer kan afbrydes) periodisk processkift indlejrede r 33 34 K1: Multiprogrammeringskerne med prioriteret skedulering Udvikling af en multiprogrammeringskerne: procesafvikling procesadministration synkronisering I/O der skal kunne afvikle et sæt brugerprogrammer Procesafvikling Brugerprocesser skal køre i brugertilstand og kernefunktioner afvikles i kernetilstand: i modsætning til kernerne i kursusbog bind 4 hvor alt foregår i kernetilstand En konsekvens (og et krav) er at alle kernefunktioner skal aktiveres vha. alpha ernes systemkaldsmekanisme: PAL_callsys, PAL_rti Kernen skal implementere tvungen tidsdeling: uret afbryder 1024 gange i sekundet processkift under udførsel af kerneoperationer 35 36 6
Procesadministration start_proc: starter en proces exit: terminerer en proces sleep: sætter proces til at vente i X 1/1024 sekunder yield: frivilligt processkift Ved kernens start overgives kontrollen til processen INIT(), der starter de resterende brugerprocesser. Skedulering Prioritetsbaseret skedulering: 32 prioritetsniveauer: 0 højest, 31 lavest round-robin indenfor hvert prioritetsniveau ældning af lavprioritetsprocesser for at undgå udsultning Systemkald: set_priority(unsigned int priority) sætter processens prioritet unsigned int get_priority() returnerer processens aktuelle prioritet 37 38 Synkronisering Prioritetsinvertering Klassisk tællesemafor: struct KSem { unsigned int value; Queue<Process> queue; med operationerne: KSem *new_sem(int i) wait_sem(ksem *) signal_sem(ksem *) free_sem(ksem *) I systemer med prioritetsbaseret skedulering kan der optræde prioritetsinvertering: en højprioritetsproces venter på en kritisk region, der er låst af en lavprioritetsproces 39 40 Prioritetsinvertering - eksempel høj P1 S1 S3 aktiv medium S2 aktiv lav P3 S3 aktiv Prioritetsnedarvning For at undgå prioritetsinvertering: arver en proces i en kritisk region prioriteten fra den højest prioriterede proces associeret med den kritiske region Prioritetsnedarvning er transitiv: P1 (pri = 0) venter på (pri = 15) venter på P3 (pri = 31) P3 skal arve prioritet = 0 Indlejrede kritiske regioner 41 42 7
Kritiske regioner Kritiske regioner synliggøres overfor kernen ved hjælp af en speciel mutex semafor med operationerne: KSem *new_mutex() wait_mutex(ksem *) signal_mutex(ksem *) free_mutex(ksem *) Prioritetsnedarvning kan knyttes til wait_mutex og signal_mutex I/O readdata: indlæser et antal tegn fra COM og returnerer hurtigst muligt writedata: udskriver et antal tegn på COM readpacket: indlæser en pakke fra ETH0 readline: writeline: indlæser en linie fra COM udskriver en linie på COM I/O operationer skal foregå udeleligt 43 44 Afbrydelser Sporingsmekanisme Kernen skal håndtere r fra COM, ETH0 samt uret Kernen skal kunne håndtere indlejrede r Drivprogramskoden til Ethernet kortet og uret udleveres Sporingsmekanisme udviklet af Søren Debois: en cyklisk hændelsesbuffer: systemkald r returnering fra systemkald brug den fra starten af!! 45 46 Milepæle 1. Start med at få brugerprocesser til at køre i brugertilstand: 1. Start uden r 2. INIT i brugertilstand 3. Systemkaldsgrænseflade med simpelt kald 4. Slå r til 2. Udvid systemkald 1. Dynamisk lagerallokering 2. Procesoprettelse 3. Prioriteret skedulering 3. Tvungent processkift 1. Tillad r fra uret uden processkift 2. Tillad processkift ved ur i brugertilstand 3. Tillad processkift ved ur i begge tilstande Instruktorvagter Fra på mandag vil der være instruktorvagter alle hverdage Lørdag den 27. marts er der også instruktorvagt Kernemaskinen archimedes er reserveret til instruktorvagten under instruktorvagten Der er ingen øvelser i de næste 3 uger 47 48 8
Kilder Disse slides er baseret på indholdet i Datalogi 1F kursusbog bind 4, kapitlerne 7 & 8. 49 9