920 likes | 1.04k Views
Kuva 1.1. Hierarkkinen kone. Rekisterit:. yleisrekisterit R0 ja R1. ohjelmalaskuri PC (program counter). Käskyrekisteri INSTR:. OPCODE. ADDRESS. Kuva 1.2. Algoritmi 1.1.
E N D
Rekisterit: yleisrekisterit R0 ja R1 ohjelmalaskuri PC (program counter) Käskyrekisteri INSTR: OPCODE ADDRESS Kuva 1.2.
Algoritmi 1.1. while ( true ) {INSTR = mem[PC]; // Hae käsky PC = PC+1; // Päivitä ohjelmalaskuriaswitch ( INSTR.OPCODE ) {// Tässä kuvaamattomia käskyjä …case ST0: mem[INSTR.ADDR] = R0; // kirjoita rekisteri 0 muistiinbreak; case LD0: R0 = mem[INSTR.ADDR]; // lue rekisteri 0 muististabreak; case JMP: PC = INSTR.ADDR; // hyppää osoitteeseenbreak; case READ_CR: lue reikäkortti // esimerkiksi 80 merkkiä osoitteeseen INSTR.ADDR;break; } }
Algoritmi 1.2 while ( true ) { if (TIMER == 0) {mem[10] = PC; PC = 0; USER_MODE = false; }TIMER = TIMER-1; INSTR = mem[PC]; PC = PC+1;switch ( INSTR.OPCODE ) {// tässä kuvaamattomia käskyjä …case ST0:if ( USER_MODE && INSTR.ADDR < FENCE ) {PC = 1; USER_MODE = false;} else mem[INSTR.ADDR] = R0;break; case LD0: R0 = mem[INSTR.ADDR];break; case SVC: mem[10] = PC; R1 = INSTR.ADDR; PC = 2; USER_MODE = false;break; case RETI: USER_MODE = true; PC = mem[10];break; case READ_CR:if ( USER_MODE ) { PC = 1; USER_MODE = false;} elselue kortti osoitteeseen INSTR.ADDR;break; } }
sivu 22. while ( CR_STATUS == BUSY ) ; // tyhjä silmukkaif ( "kortti alkaa merkillä $" ) { … // käsitellään erikseen käyttöjärjestelmäkomennot} else {siirrä kortti käyttöjärjestelmän puskurista sovelluksen alueelle; käynnistä seuraavan kortin luku (READ_CR); palaa sovellukseen (RETI);}
Algoritmi 1.3. while ( true ) { if ( "kello- tai I/O-keskeytys on tulossa" && !mask ) { mem[10..13] = (PC, R0, R1, TIMER); R1 = "keskeyttäneen laitteen numero (0 = TIMER)"; MASK = true; PC = 0; USER_MODE = false;}TIMER = TIMER-1; INSTR = mem[PC]; PC = PC+1;switch ( INSTR.OPCODE ) {:case RETI: USER_MODE = true; MASK = false; (PC, R0, R1, TIMER) = mem[10..13];break; case SVC: USER_MODE = false; MASK = true; mem[10..13] = (PC, R0, R1, TIMER); R1 = INSTR.ADDR; PC = 2;break; } }
Algoritmi 1.4. void interrupt ( int i, int CR1 ) {mem [CURRENT..CURRENT+6] = (PC, R0, R1, TIMER, BASE, LIMIT, PSW); PSW.MASK = true; PSW.USER_MODE = false; R1 = CR1; PC = i; BASE = 0; LIMIT = 9999999;} while ( true ) { if ( "ulkoinen keskeytys tulossa" && !PSW.MASK )interrupt ( 0, "laitenumero"); TIMER = TIMER-1; if ( PC > LIMIT ) interrupt (1, invalid_address ); INSTR = mem[BASE+PC]; PC = PC+1;switch ( INSTR.OPCODE ) {// tässä kuvaamattomia käskyjäcase ST1:if ( INSTR.ADDR > LIMIT )interrupt (1, invalid_address);elsemem[base+INSTR.ADDR] = R1;break; case SVC: interrupt (2, INSTR.ADDR);break; case RETI: (PC, R0, R1, TIMER, BASE, LIMIT, PSW) = mem [CURRENT..CURRENT+6];break; case SET_CURRENT:if ( PSW.USER_MODE )interrupt (1, privileged_instruction);elseCURRENT = mem[INSTR.ADDR];break; } }
Kuva 2.10 struct PCB { int process_id; // prosessin identiteettienum { FREE, READY, RUN, WAIT } state;int uid; // omistajaint euid; // tehollinen omistajaint priority, native_priority; // käyttö- ja perusprioriteettiint event_number; // odotettavan tapahtuman numeroint signal_number; // tulleen signaalin numerovoid (*signals) () [NUM_SIGNALS]; // signaalinkäsittelijätbool timer_expired; // laukesiko ajastus? address saved_current; // ympäristöpinon osoite file_descriptor files [NUM_FILES]; // käsiteltävät tiedostotint cpu_usage; // suorittimen käyttö viime sekunnin aikana // Lisäksi vielä tietoja muistinhallintaa varten sekä // laskutustietoja ja statistiikkaa, esimerkiksi // läsnäolokeskeytysten lukumäärä (tarkemmin luvussa ).};
Wait_event • void wait_event (int e_number, int pri) {// Päivitetään event_number-kenttä prosessin prosessielementissä: pr_table[running].event_number = e_number; pr_table[running].state = WAIT; // Prosessi tilaan WAIT pr_table[running].priority = pri; // Prioriteetti odotuksen päätyttyägoto vuorontaja ; // jatketaan vuorontajaan}
Event void event (int e_number) { int i;for ( i = 0; i < P_NUM; i++ ) {// käydään läpi kaikki prosessitaulun prosessielementit i:if(pr_table[i].state == WAIT&& pr_table[i].event_number== e_number) {pr_table[i].event_number = 0; pr_table[i].state = READY;} } }
Algoritmi 2.1 void Dispatcher {// Estetään keskeytykset asm(IOF); // tarkoittaa, että suoritamme konekäskyn IOF // Passivoidaan suorituksessa ollut prosessi: CURRENT = CURRENT - 6;pr_table[running].saved_current = CURRENT; if ( pr_table[running].state == RUN )pr_table[running].state = READY;// Jos ollaan palaamassa sovellukseen, palautetaan kentän // PRIORITY arvoksi NATIVE_PRIORITY eliif ( "ympäristöpinossa vain yksi ympäristö" )pr_table[running].priority = pr_table[running].native_priority; /*Etsitään prosessitaulusta prosessi, joka on tilassa READY, ja jonka prioriteetti on suurin ja asetetaan running osoittamaan tähän prosessielementtiin (huomaa, että pieni luku tarkoittaa suurta prioriteettia ja että taustaprosessin olemassaolo takaa, että ainakin yksi suorituskelpoinen prosessi löytyy aina). */ int i; for ( i = 0; pr_state[i] != READY; i++ ) ; // huomaa: tyhjä runko running = i;// etsittiin ensimmäinen READY-tilan prosessifor ( ; i != LAST_PROCESS; i++) {if ( pr_table[i].state == READY &&pr_table[i].priority < pr_table[running].priority ) running = i; } // käytiin läpi loputkin ja näistä suuriprioriteettisin talteen pr_table[running].state = RUN;// CURRENT-rekisteri asetetaan osoittamaan uuteen ympäristöön eli CURRENT = pr_table[running].saved_current; if ( pr_table[running].signal_number != 0&& "palaamassa sovellukseen" )// tämä toiminto selviää vasta hieman myöhemmin …elseasm(RETI);
sivu 73 struct TIMER_QUEUE {PCB* pcb_ptr; // ajastinta odottavan prosessin prosessielementtiint time; // kellonaika, jolloin ajastin laukeaa TIMER_QUEUE* next;}; Alarm-rutiini laskee tapahtuman tapahtuma-ajan clock-muuttujan avulla: time = clock + "halutun ajastuksen pituus" Kellokeskeytyksen käsittely tapahtuu nyt pääpiirteissään seuraavasti: clock = clock+1;// Poista ajastinjonon alusta kaikki elementit joille time<clock.for ( p = ajastinjono; p != 0; p = p->next ) { if ( p->time <= clock ) { if ( p->pcb_ptr->status == WAIT )p->pcb_ptr->status = READY; p->pcb_ptr->timer_expired = true;} else break; // else-osa toimii, jos ajat järjestyksessä}
Sivu 92 • Esimerkkikäyttöjärjestelmässä kriittiseen alueeseen voitaisiin liittää muuttujat lock_bit ja waiting seuraavasti: • L: if ( lock_bit == 1 ) {waiting = true; wait_event (&waiting);goto L;}lock_bit = 1; • … kriittisen alueen käskyt … • lock_bit = 0;if ( waiting ) {waiting = false; event (&waiting);}
Algoritmi 3.1 class semaphore { void P (); void V ();semaphore (int); private int val; PCB* link; } semaphore :: P (){val = val-1; if ( val < 0 ) {linkitä prosessin PCB LINK-ketjun loppuun; Aseta prosessin tilaksi WAIT; Siirry vuorontajaan;}} semaphore :: V (){val = val+1; if ( val <= 0 ) {Linkitä jonon ensimmäinen prosessielementti pois semaforijonosta ja siirrä se tilaan READY; Jos herätetyn prosessin prioriteetti on herättävän prosessin prioriteettia suurempi, siirry vuorontajaan;} } semaphore :: semaphore (int initial), val (initial), link (NULL){}
Algoritmi 3.2 lukko: .word 0 lock: mov #1,%1 // Varausvakio 1 rekisteriin yksi l1: swap %1,lukko// Vaihdetaan varattutieto lukkoon brpos l1 // Mikäli lukossa oli 1, yritetään uudestaan ret // Lukitus onnistui unlock: mov #0,lukko ret
Algoritmi 3.3 lukko: .word 0 lock: btset lukko,lock // Jos bitti asetettu, testaa uudelleen ret // Lukitus onnistui unlock: bclr lukko // Nollaa bitti, bit clear ret
Algoritmi 3.4 volatile boolean flag[2] = { false, false };volatile int turn; void Dekker (int i, j){flag[i] = true; // Haluan alueellewhile (flag[j]) // Mikäli toinenkin haluaa, jäädään silmukkaanif (turn == j) { // Itse asiassa on toisen vuoro flag[i] = false; // joten päästetään toinen sisään,while (turn == j); // odotetaan sen poistumista flag[i] = true; // ja yritetään taas}} void unlock(void){turn = j; // Tällä annetaan toiselle prosessille etuoikeus flag[i] = false; // Vapautetaan alue}
Algoritmi 3.5 volatile enum{idle, want_in, in_cs} flags [n];volatile int turn; void Eisenberg_McGuire (int i){ int j; do {flag[i] = want_in;j = turn; // tällä on etuoikeuswhile (j != i) // odotetaan etuoikeutetut poisif (flag[j] != idle) j = turn; // jäit toiseksi, aloita alustaelse j = (j+1) % n; // tämä ei ole kiinnostunut, ohita flag[i] = in_cs; // luulen päässeeni läpi // Käydään kaikki prosessit läpi. Jos kukaan muu ei ole // in_cs-tilassa, silmukasta poistuttaessa j == n j = 0; while ((j < n) && ( j == i || flag[j] != in_cs)) j += 1; // Lukitus onnistui, mikäli i == n ja turn-muuttujan // osoittama prosessi ei ole kiinnostunut}while((j < n) || (turn != i && flag[turn] != idle));turn = i; // Varmistetaan varaus} void unlock(void){ j = (turn+1) % n; // Etuoikeuden hakeminen: seuraava prosessiwhile(flag[j] == idle) {j = (j+1) % n; // Jos ei kiinnostunut, hae seuraava}turn = j;flag[i] = idle; // Sijoitus täällä, jotta edellinen silmukka päättyy aina }
Algoritmi 3.6 • volatile boolean flag[2] = { false, false };volatile int turn; • void Patterson (i, j){flags[i ] = true;turn = j ; // Anna vuoro pois!while((flags[j ]) && (turn != i )) {// Odota niin kauan, kunnes toinen luovuttaa vuoron}} • void unlock(void){ • flags[i ] = false; • }
Algoritmi 3.7 typedef item_type … // käsiteltävän alkion tyyppiconst int size = 100; // puskurin koko item_type buf [size]; // puskuriint in_index(0), out_index(0); // puskuriosoittimiasemaphore mutex1(1), mutex2(1); // semaforit poissulkemiseensemaphore free(size); // vapaiden alkioiden semaforisemaphore full(0); // täysien alkioiden semafori process Tuottaja (i, j){ while ( true ) { // ikuinen silmukka … tuota alkio item … P(free); // varmista, että vapaita puskureita on P(mutex1);buf[in_index] = item;in_index = (in_index+1) % size; // % on siis jakojäännös V(mutex1);V(full); } } process Kuluttaja{while ( true ) { P(full); // varmista, että täysiä puskureita on P(mutex2);item = buf[out_index];out_index = (out_index+1) % size;V(mutex2);V(free);… kuluta alkio item …}}
Algoritmi 3.8 int read_count = 0; // aktiivisten lukijoiden määräsemaphore mutex(1); // lukijalaskurin poissulkemiseensemaphore write_mutex(1); // kirjoittaijen poissulkemiseeni process Lukija{ while ( true ) {// ikuinen silmukka // tekee jotain, jonka jälkeen haluaa lukea… P(mutex); // varmista, että vapaita puskureita onread_count = read_count+1; // lukijoita yksi enemmänif ( read_count == 1 ) { // ensimmäinen lukija? P(write_mutex); // käyttäydy kuin kirjoittaja}V(mutex);// Varsinainen lukeminen tapahtuu tässä P(mutex); read_count = read_count+1; // lukijoita yksi vähemmänif ( read_count == 0 ) { // viimeinen lukija?V(write_mutex);// käyttäydy kuin kirjoittaja}V(mutex); }} process Kirjoittaja{ while ( true ) { //… miettii mitä pitäisi muuttaa … P(write_mutex); // Kirjoittaa tässä kohtaa V(write_mutex);}}
Algoritmi 3.9 monitor Philosophers { const last_phil = 4; enum{ thinking, hungry, eating } state[last_phil]; condition self[last_phil]; void test (int k) { if (state[(k-1) % last_phil] != eating && -- huom: -1 mod 4 = 3 state[k] = hungry && state[(k+1) % last_phil] != eating) { state[k] = eating;signal(self[k]);} } void pick_up(int i){state[i] := hungry; test(i);if (state[i] != eating) { await(self[i]);} } void put_down(int i){state[i] := thinking; test[(i-1) % last_phil]; test[(i+1) % last_phil];}}