Une image / un lien ci-dessous est fourni (tel quel) pour télécharger la présentation
Politique de téléchargement : le contenu du site vous est fourni TEL QUEL pour votre information et votre usage personnel ; il ne peut être vendu, concédé sous licence ni partagé sur d’autres sites sans l’accord de son auteur.Le contenu vous est fourni TEL QUEL, pour votre information et votre usage personnel uniquement.Téléchargez la présentation en cliquant sur ce lien.Lors du téléchargement, si vous ne parvenez pas à télécharger une présentation, l’éditeur a peut-être supprimé le fichier de son serveur.Pendant le téléchargement, si vous ne parvenez pas à obtenir une présentation, le fichier a peut-être été supprimé par l’éditeur.
F I N
Plus de contenu associé
Transcription de la présentation
Planen for idag • Kerner uden afbrydelser (KB4 kap. 6): • akernen: kerne med decentralt processkift • bkernen: kerne med centralt processkift • Kerne med afbrydelser (KB4 kap. 7): • ckernen: løst koblede drivprogrammer • dkernen: kerne med tætkoblede drivprogrammer Datalogi 1F: Multiprogrammering[3]
Processer i akerne • Proces kontrolblokken i akerne: • CPU registre (gemt på stakken) • Vi gemmer kun stakpeger • Køpegere beregnet for ventekø struct Process : public Queueable { Registers *sp; } Datalogi 1F: Multiprogrammering[3]
Processkift • akernen: • har frivilligt processkift • benytter aktiv venten • En proces kalder KPause hvis den venter på en hændelse (fungerer som yield() i Java) • Aktiv venten: void KGenericProcedure() { while(<hændelse ikke indtruffet>) KPause(); <udfør aktion efter hændelse er indtruffet>; } Datalogi 1F: Multiprogrammering[3]
KPause • KPause foretager skiftet fra en proces til en anden: void KPause() { <gem registre på stakken>; <gem stakpeger i PKB>; <find ny proces>; <retabler stakpeger fra PKB>; <retabler registre>; } Datalogi 1F: Multiprogrammering[3]
Akerneversionen af tællesemaforoperationer void KSignal(KSem& sem) { sem++; // Aktivering af ventende } // sker ved aktiv venten void KWait(KSem& sem) { while (!sem) // Aktiv venten KPause(); sem--; } Datalogi 1F: Multiprogrammering[3]
KPause(): et par kommentarer • Tæl stakpeger ned inden registre lægges på stakken: • en afbrydelse vil bruge samme stakpeger og kan overskrive værdier hvis sp er for høj • Tæl stakpeger op EFTER registre er fjernet fra stakken • Selve skiftet af KCurProc sker ikke i KPause men i KSelectNewProcess Datalogi 1F: Multiprogrammering[3]
KSelectNewProcess Registers* KSelectNewProcess(Registers* sp) { KCurProc->sp = sp; KWaitQ.Put(KCurProc); KCurProc = KWaitQ.Get(); return KCurProc->sp; } • Skedulering foregår round-robin • Hvad er det for noget med Registers* ? Var det ikke stakpegeren??? Datalogi 1F: Multiprogrammering[3]
en processtak ved kald af KSelectNewProcess PAL kald stakramme AP: KPause r[29] r[1] r[0] struct Registers struct Registers { unsigned long r [30]; unsigned long ps, pc, gp, a0, a1, a2; }; struct registers placering i lageret a2 ps r[29] Registers* r[1] r[0]
OK – nok show:hvordan starter vi akernen? // Reader processens kernedatastrukturer extern void Reader (); Process readerProc; unsigned long readerStack [stackSize]; void main() { KWait.Init(); KInitProc(Reader, readerStack, &readerProc); KInitProc(Writer, writerStack, &writerProc); KCurProc = KWaitQ.Get(); KFirst(KCurProc->sp); } Datalogi 1F: Multiprogrammering[3]
Hvad sker der i KInitProc? • KInitProc initialiserer en proces’ stak, så det ser ud som om den har kaldt KPause(): void KInitProc(void (*startAddr) (), void *Stack, Process *proc) { Stack += (stackSize * sizeof(unsigned long) – sizeof(Registers) ); proc->sp = (Registers *) Stack; proc->sp->r[26] = proc->sp->r[27] = (unsigned long) startAddr; // ra & pv KWaitQ.Put(proc); } Datalogi 1F: Multiprogrammering[3]
Processtak efter KInitProc r[29] r[28] startAddr procedure value startAddr return address PKB stackSize r[1] r[0] sp Datalogi 1F: Multiprogrammering[3]
Og så skal det hele sættes igang KCurProc = KWaitQ.Get(); KFirst(KCurProc->sp); hvor KFirst er defineret ved: KFirst: ldgp gp, (pv) ldq pv, 0xD8(a0) // Pop pv addq a0, 0xF0,a0 // Skip registre bis a0, 0, sp // Sæt sp jmp (pv) // Hop til processtart Datalogi 1F: Multiprogrammering[3]
OK, hvad var det for noget med decentralt skift? • Venteløkkerne for de enkelte I/O og semaforoperationer var spredt ud over kernen: • ineffektivt: registre skal poppes og pushes hele tiden • svært at vedligeholde: • hvad nu hvis vi gerne vil ændre vores aktiv venten strategi • ugennemsigtigt: • vi ved ikke hvilke hændelser de enkelte processer venter på Datalogi 1F: Multiprogrammering[3]
Kerne med centralt processkift • I modsætning til akerne.cc ønsker vi at have en central venteløkke og processkift • Hvordan specificerer en proces hvad den venter på? • Vi indfører operationen KSleep(), der venter på at en specifik hændelse indtræder Datalogi 1F: Multiprogrammering[3]
Hændelser • En proces kan vente på: • CPU (den er klar til at blive udført) • Ydre enheder (en operation bliver færdigbehandlet) • Semafor (ankomst af et signal) • Specifikationen af en hændelse skal kunne omfatte alle ovenstående hændelser Datalogi 1F: Multiprogrammering[3]
struct Event struct Event { enum { IO, SEM, CPU } id; union { struct { int addr; char mask; } io; struct { KSem* addr; } sem; } Event(int, char); // vent på I/O Event(KSem&); // vent på semafor Event(); // vent på CPU } Datalogi 1F: Multiprogrammering[3]
Proceskontrolblokken • Nu bliver processens tilstand udvidet med hvilken hændelse en proces venter på: struct Process { Registers* sp; Event waitsFor; } *KCurProc; Datalogi 1F: Multiprogrammering[3]
KSleep() • En ”overbygning” til KPause(), der registerer hvilken hændelse en proces venter på: void KSleep(Event e) { KCurProc->waitsFor = e; KPause(); } Datalogi 1F: Multiprogrammering[3]
Ny udgave af semaforoperation Ny udgave: void KWait (KSem& sem) { if(!sem) KSleep( Event(sem) ); sem--; } Gammel udgave: void KWait(KSem& sem) { while (!sem) // Aktiv venten KPause(); sem--; } Datalogi 1F: Multiprogrammering[3]
Kerner med aktiv venten • Vi har flere gange diskuteret at aktiv venten ikke er den mest effektive måde at opdage en hændelse på: • selv med en central venteløkke spilder vi tid på at undersøge ydre enheders statusregistre når der ikke er behov for det • forsinker aktivering af processer, der enten venter på CPU eller har modtaget en hændelse • Men det giver simple kerner: • det hele kan forstås som en sekventiel proces Datalogi 1F: Multiprogrammering[3]
Kerner med afbrydelser • Slut med aktiv venten • Afbrydelsesprocedure aktiverer ventende processer • Men alting bliver mere uforudsigeligt, idet afbrydelser kan indtræde når som helst: • data kan deles mellem afbrydelsesprocedurer og resten af kernen • brug for udelelig adgang til delt data Datalogi 1F: Multiprogrammering[3]
Processkift • Da vi ikke har aktiv venten, skal vi holde rede på de ventende processer. • Vi benytter to proceskøer: • KWaitQ: kø af processer der venter på en hændelse (semaforsignal eller ydre enhed) • KReadyQ: kø af processer der er klar til at blive udført (venter på at få adgang til CPU) • Processer bør først forlade KWaitQ når hændelsen de venter på er indtrådt Datalogi 1F: Multiprogrammering[3]
Suspendering af processer • KPause kalder KSelectNewProcess, der sætter den aktive proces til at vente: Registers* KSelectNewProcess(Registers* sp) { KCurProc->sp = sp; KWaitQ.Put(KCurProc); KCurProc = KReadyQ.Get(); // Her er forskellen return KCurProc->sp; } Datalogi 1F: Multiprogrammering[3]
Aktivering af processer • Vi aktiverer processerne når vi får en afbrydelse: void KInterruptHandler() { while(!KWaitQ.isEmpty()) KReadyQ.Put(KWaitQ.Get()); } • Men hov? alle processerne startes? • Ja, for vi genbruger vores kerne med decentralt processkift Datalogi 1F: Multiprogrammering[3]
I/O operationer char KReadChar() { while(!(rdio(com1Lsr) & 0x01)) KPause(); return rdio(com1Rbr); } void KWriteChar(char ch) { while(!(rdio(com1Lsr) & 0x20)) KPause(); wrio(com1Thr, ch); } • Alle ventende processer aktiveres og udfører check på om hændelse er indtrådt decentralt Datalogi 1F: Multiprogrammering[3]
Afbrydelseshåndtering i ckerne • Afbrydelse fra ydre enhed aktiverer afbrydelseshåndtering via PAL kode: • først aktiveres ent_int • ent_int kalder KInterruptHandler • derefter returneres til ent_int • ent_int returnerer fra afbrydelse • ent_int specificeres i ckernens main funktion via PAL_wrent Datalogi 1F: Multiprogrammering[3]
Stak under afbrydelse Stak for Proces Writer void KWriteLine(char *p, int max) { for (int i=0; (i<max) && *p; i++,p++) KWriteChar(*p); } ent_int: SAVE_REGS br t0, 1f 1: ldgp gp, (t0) lda pv, KInterruptHandler jsr ra, (pv) REST_REGS call_pal PAL_rti proces Write() AP: buf.Write() AP: KWriteLine PAL stakramme AP: KWriteChar void KInterruptHandler() { while(!KWaitQ.isEmpty()) KReadyQ.Put(KWaitQ.Get()); } AP: ent_int AP: KInterruptHa… void KReadyQ.Put() {…} AP: KReadyQ.Put… Datalogi 1F: Multiprogrammering[3]
Synkronisering med ydre enheder char KReadChar() { while(!(rdio(com1lsr) & 0x01)) KPause();// Opdaterer KWaitQ indirekte return rdio(com1Rbr); } void KInterruptHandler() { while(!KWaitQ.isEmpty()) KReadyQ.Put(KWaitQ.Get()); } • Test på LSR og ventekøoperation i KReadChar skal udføres udeleligt, ellers kan følgende ske … Datalogi 1F: Multiprogrammering[3]
Uheldig rækkefølge <KReadChar> while(!(rdio(com1lsr) & 0x01)) <UART> sætter ready-bit <KInterruptHandler> while(!KWaitQ.isEmpty()) <KReadChar> KPause(); <KSelectNewProcess> <sætter proces i ventekø> AAAAARGH: vi opdager ikke at tegnet er læst Datalogi 1F: Multiprogrammering[3]
Implementering af udelelighed • Luk for afbrydelser: char KReadChar() { forbid(); while(!(rdio(com1lsr) & 0x01)) KPause(); char ch = rdio(com1Rbr); permit(); return ch; } • Nu bliver vi ikke afbrudt mellem check af statusregister og KWaitQ.Put() Datalogi 1F: Multiprogrammering[3]
Køoperationerne skal også beskyttes • Eksempel: int isEmpty() { int oldipl = forbid(); int b = (size == 0); permit(oldipl); return b; }; • Gem ipl – så undgår vi at lukke op for afbrydelser ved et uheld • Vigtigt hvis operationer kan benyttes af afbrydelsesprocedurer Datalogi 1F: Multiprogrammering[3]
Hvad gør vi når klarkøen er tom? • En tomgangsproces: • en proces som aldrig kommer i ventekøen, men som hele tiden frivilligt opgiver CPU’en • En tomgangsløkke i KSelectNewProcess: while( KReadyQ.isEmpty() ) { permit(); /* Do nothing */; forbid() } Datalogi 1F: Multiprogrammering[3]
Connexion au compte
Connectez-vous pour publier votre contenu sur SlideServe.