Professional Documents
Culture Documents
Mail: aleksapsg@gmail.com
Facebook: www.facebook.com/aleksaps
Mail: me@kristijanziza.com
Facebook: www.facebook.com/kristijan.ziza
Website: www.kristijanziza.com
JUL 2015.
1
SADRŽAJ
Uvod .................................................................. 3
Klase Thread i PCB............................................. 5
Semaphore ...................................................... 11
Event ............................................................... 12
Sistemski pozivi ............................................... 14
Mogudi problemi ............................................. 18
Pitanja za odbranu .......................................... 19
Kako izgleda odbrana ...................................... 21
2
Uvod
Sigurno ste do sada od mnogih stariji studenata čuli za jednu od najtežih,
ako ne i najtežu prepreku na vašem putu studiranja. Zaista, veliki broj studenata
ima problema sa ovim projektom, što zbog apstraktnosti materije, što zbog priča
starijih kolega. U ovom tekstu du vas najpre savetovati kako pristupiti rešavanju,
da vam pomognem da se organizujete, a zatim detaljno objasniti svaki deo
projekta. Odmah da vas upozorim da ovde nedete nadi mnogo koda i moj savet
vam je da ne gledate u tuđe projekte jer de vas to samo nervirati i zbunjivati i
mislidete da je to jedino mogude rešenje i onda rizikujete da vas profesori kazne
nakon provere sličnosti. Mnogi studenti pristupe rešavanju projekta na taj način
što čitaju tuđ kod pa iz njega kapiraju šta treba da rade – nemojte to da radite!
Mislim da de vam ovom uputstvo biti sasvim dovoljno da ukapirate šta se od vas
traži i na koji način da razrešite tražene probleme.
Na početku par opštih informacija – tekst projekta, kada početi, kako raditi i kako
se organizovati.
Pre nego što krenem na objašnjavanje samog projekta, još par napomena.
Što se tiče okruženja, novije generacije na treba da brinu jer su kolege Maja
Vukasovid i Miloš Radid napravili plugin za Eclipse, tako da problemi sa BCC-om i
Paskaloidnim okruženjem su sada prošlost. Ako iz nekog razloga ne gotivite
Eclipse, možete preuzeti od starijih kolega uputstvo za podešavanje Notepad++
gde, ne samo što možete kucati kod, ved i build-ovati i pokretati testove.
Sve to naravno mora da se radi na virtuelnoj mašini 32-bitnog sistema. Da bi vam
virtuelna brže i bolje radila, instalirajte VM tools (samo prevucite neki file/folder
sa vašeg sistema na virtuelnu i ponudide vam instalaciju).
Podsetite se C++, pogotovo što je stari standard iz 1992. godine (mnoge stvari ne
postoje kojih ima u novom standardu, na primer bool, pa demo koristiti int ili
izuzeci, pa demo greške obrađivati drugačije itd) pa da ne gubite vreme na to.
I da, idite na LAB vežbu, ali verujem da vam nede biti baš najjasnije sta da radite
nakon nje (bar meni nije bilo), sem što dete znati kako da podesite okruženje.
Tamo de vam dati par dobrih saveta i pitajte sve što vas interesuje. I najvažnije –
onaj pdf sa lab vežbe sadrži mnogo informacija koje možete iskoristiti u vašem
projektu.
E sad, konačno kad ste pročitali mnogo teksta, što iz ovog uvoda, što gradiva i
zadatka, da konačno krenemo sa realizacijom problema. Podvukao sam najvažnije
4
stvari u uvodu, pa se povremeno vradajte da vidite da li to poštujete dok kucate
projekat.
Da bih objasnio klasu Thread, prvo je potrebno objasniti PCB. Šta je uopšte
PCB? Process control block ili PCB je struktura podataka koja opisuje objekat klase
Thread. Ona sadrži sve one podatke potrebne da bi se jedna nit uspešno i efikasno
izvršavala. Pročitajte arhitekturu 8086 da biste znali koji registri postoje u
procesoru. To se nalazi na materijalima sa vežbi, prva prezentacija. Ono što nam,
za sad, treba za PCB su stek (niz unsigned podataka) i registri SS, SP i BP. SS je stek
segment, a SP je stek offset. Stek pointer se dobija kada na segment nalepimo
offset (to procesor sam radi, ne brinite o tome). Za BP takodje pročitajte sa
materijala čemu služi (ima i na lab vežbi), ali za sada – ono što treba da znate da
ove tri stvari se čuvaju. Ukratko, BP se čuva ako imamo lokalnih podataka pa da bi
dohvatali preko njega parametre funkcije, jer SP de se menjati. Bez obzira dal
imate lokalne podatke ili ne, ne škodi da čuvate BP. Jedna važna napomena, stek
raste ka nižim lokacijama i zauzima poslednju zauzetu.
Sve niti (tj PCB-ovi) se prilikom startovanja stavljaju u raspoređivač, tj
Scheduler. Implementacija vam je data, ne treba pisati, iskoristite to.
Da rezimiramo:
Thread ima PCB
PCB ima:
unsigned *stack
5
unsigned sp
unsigned ss
unsigned bp
Promena konteksta ili preuzimanje je upravo gore opisani proces. Jedna nit
je aktivna i izvršava se. Kada dođe red na drugu, ovu sačuvamo i iz Schedulera
uzmemo drugu i njene parametre – podmetnemo njen stek. Promenu konteksta
je potrebno vršiti u metodama sa modifikatorom interrupt. To je jedna olakšica
koju nam omogudava prevodilac. Ako označimo metodu kao interrupt – na ulasku
u metodu se čuvaju svi registri, na izlasku se restauriraju njihove vrednosti. Naš
jedini zadatak je da polja iz PCB-a (SP, SS, BP) prvobitno sačuvamo, a na kraju da
podmetnemo druge.
Pre nego što objasnim kako timer izgleda, da se vratim još malo na PCB. PCB mora
da ima neke flegove koji opisuju nit. Na primer, ako je nit gotova, moramo
obeležiti da je gotova, ako je nit blokirana (bilo na semaforu, bilo da spava ili
slično) moramo obeležiti da je blokirana. U oba slučaja, ne smemo vradati niz u
Scheduler jer u Scheduleru stoje samo niti spremne za izvršavanje! Da li dete
koristiti int kao fleg ili enum pa pisati stanje niti, sasvim je svejedno.
6
Zbog toga, PCB sada izgleda ovako:
unsigned *stack
unsigned sp
unsigned ss
unsigned bp
unsigned timeSlice //koliko dugo se nit izvršava
flegovi ili enum
ostalo (navedeno kasnije u metodi waitToComplete klase Thread)
Kako demo brojati koliko dugo se nit izvršava? Jedan globalni podatak unsigned
counter rešava problem. Koja nit se izvršava? Opet jedan globalni podatak PCB*
running rešava problem. Da ne bih sad objašnjavao kako se to koristi, najbolje da
pročitate sa laba.
Šta ako su sve niti blokirane ili sve spavaju? Jedna nit (ili samo PCB koji dete
čuvati u globalnom podatku) rešava problem. Telo te niti je while(1); timeSlice joj
je 1. U slučaju da vam Scheduler vrati 0 (null u ovom standardu ne postoji!),
prebacite globalni PCB* running na tu „zaludnu“ nit. Nju nikako ne smete stavljati
u Scheduler, ved čuvajte globalni pokazivač na nju.
E sad ono najvažnije. Kako redi niti (tj PCB) koji je njen zadatak, tj. od koje
linije da počne izvršavanje. Postavlja se pitanje kako inicijalizovati stek PCB-a?
Ako ste pročitali arhitekturu 8086, kao što sam vam napomenuo malopre, znate
koji registri postoje u procesoru. Čim sam rekao „od koje linije počinje
7
izvršavanje“, jasno vam je da treba da promenimo PC. Šta je PC na 8086? Na 8086
PC se sastoji od code segment CS (segment za PC) i instruction pointer IP (offset
za PC). Upisivanjem vrednosti u te registre, manervišemo program counter-om.
Prva linija koda naše niti je prva linija omotačke funkcije wrapper(Thread*
running). Primetite da ona ima argument koji takođe treba staviti na PCB stek. Još
jedna važna stvar – treba podesiti PSW, 16b registar, tako da njegov I fleg, koji
omogudava prekide, bude 1. I naravno, pokazivače na stek. Verujem da vam ovo
opisano rečima ne znači mnogo pa du ovde priložiti malo koda za konstruktor PCB.
Prvo što treba uraditi je za zadati stackSize napraviti stek. Ali obratite pažnju na to
da je zadati stackSize u bajtovima, a unsigned je 16b. Znači, ako nam je dato 4096
bajtova, to je 2048 indeksa za niz unsigned* stack. Kako to srediti? Pa jednostavno
stackSize /= sizeof(unsigned).
Potrebno je paziti na ograničenje veličine niza (tj. steka) – na 8086 je maksimalno
mogude 65535 bajtova, inače de program pucati.
Sada je lako: stack = new unsigned(stackSize);
Posto smo napravili stek, treba ga inicijalizovati po gornjem tekstu. Na vašu sredu,
u zaglavlju <dos.h> su napisani makroi za dohvatanje segmenta i offseta. Pošto
stek raste ka nižim lokacijama, inicijalizujemo s kraja niza.
Postavljamo PSW:
stack[stackSize – 5] = 0x200; //Ovo je 10000…000 – I fleg enable-ovan
8
sp = FP_OFF(stack + stackSize - 16);
bp = sp; //po pravilu BP se na početku stavlja da pokazuje na SP
Ono što vam verovatno nije jasno je, zašto ovi brojevi (-1, -2, -5, -6, -7, -16) i šta je
između. Pa, za početak, na -3 i -4 su segment i offset funkcije callback. To je
funkcija koja se poziva nakon završetka naše metode wrapper. Ali to nas ne
interesuje jer metoda wrapper nikad nede dodi do kraja – poslednja linija de
tražiti promenu konteksta.
Od -8 do -15 su mesta za registre procesora – ax, bx, cx, dx, es, ds, si, di. Na -16 je
bp. Zašto uopšte stavljamo te registre? Pa, prvi put kad nit se izvadi iz Schedulera
u timeru, krenude da restaurira redom vrednosti svih registara (koje je mislio da je
sačuvao na ulasku; on i jeste sačuvao, ali ne za ovu nit nego za onu koja je upravo
izgubila procesor). Zato moramo podmetnuti sve vrednosti. Za ove registre ax, ...,
di vrednosti slobodno mogu da budu random. To je sve u vezi sa inicijalizacijom
PCB-a.
Thread konstruktor:
Pravi objekat PCB, dodeljuje ID i smešta taj PCB u neku globalnu listu ili niz (u
daljem tekstu du pretpostaviti da ste uzeli niz). Na primer možete napraviti da ID
bude indeks u nizu.
Thread destruktor:
Samo obrisati PCB iz niza i resetovati pokazivač niza na 0 (null). Nema potrebe
zvati ovde waitToComplete jer de se svejedno zvati u izvedenoj klasi.
9
WaitToComplete:
Kada se pozove ova metoda za neki PCB, to znači da trenutna running nit čeka
završetak niti čiju waitToComplete metodu je pozvala. Upravo zbog toga moramo
napraviti i dodati polje u svakom PCB-u, pokazivač na listu svih PCB-ova koji
čekaju na završetak.
Sve što treba uraditi u metodi je ubaciti running PCB u tu listu, staviti mu status na
blokiran i promeniti kontekst.
Sleep:
Ova metoda uspavljuje running nit na određeno vreme (dato parametrom
funkcije, voditi računa o specijalnom slučaju ako se prosledi vreme 0). To radi tako
što smesti running PCB u jednu listu i obeleži ga kao spavajudi. Postavlja se pitanje
kako napraviti tu listu, kako buditi niti i kako znati kad treba da se probude?
Ta lista je opisana na materijalima sa vežbi, vežbe 5. U listi se čuva samo razlika
vremena. Ukratko, ako nekoliko niti spavaju redom 5, 8, 8 i 9 (odnosno n x 55ms),
u listi demo čuvati 5, 3, 0, 1 (čuvamo razliku). Na svakih 55ms, tj u timeru, demo
smanjivati vrednost prvog elementa u listi i kad postane 0, njega i sve susedne sa
vremenom 0, smestiti u Scheduler (naravno prvo ih obeležiti da su spremne za
izvršavanje, tj da više nisu blokirane). Umetanje u listu realizujte sami, ne bi
trebalo da imate problema oko toga. Moj savet vam je da to dobro istestirate, jer
dešava se da vam se sve blokira samo zbog sleep liste jer je niste dobro napravili,
na primer vreme spavanja greškom ode u minus.
Dispatch:
Za sada, kao na labu – one četiri linije koda. Kada uradite sistemske pozive preko
kernel steka, promenidemo.
Start:
Samo obeleži nit kao spremnu i stavi je u Scheduler. Voditi računa ako se više puta
poziva za istu nit - to ne sme da se dogodi.
Wrapper:
U tekstu zadatka je rečeno je da je prva linija thread->run(). Nakon toga sve što
treba da uradite je da probudite sve niti koje su čekale na nju da završe, odnosno
da protrčite kroz onu listu koju smo pomenuli gore, i da sve niti vratite u
Scheduler (naravno, opet prvo im promenite stanje na spremne). Nakon toga,
obeležiti da je nit završila posao da je ne bismo opet stavljali u Scheduler i pozvati
10
dispatch jer smo pominjali da wrapper ne sme da se završi jer mu nismo stavili
callback, pa ko zna gde bi otišlo i kakve bi katastrofalne posledice imalo.
Što se tiče zaključavanja sekcija, to, za sad, isto uradite kao na labu. Al nemojte
mnogo da se mučite oko toga gde staviti, a gde ne – jer, verujte mi, kad uradite
drugi zadatak (onaj sa kernel stekom) bide vam skroz jasno gde to treba staviti –
na jedno jedino mesto.
Semaphore
Ovo je najlakši deo svim studentima, za koji treba ubedljivo najmanje posla
i razmišljanja. Klasa Semaphore je detaljno objašnjena na slajdovima sa
predavanja, tako da se ja ovde nedu puno zadržavati, samo ukratko objasniti. Za
sad, metode klase Semaphore samo pozivaju metode klase KernelSem preko
objekta sa kojim je u vezi preko identifikatora ID (te dve klase su u odnosu kao
Thread i PCB, takođe čuvati sve KernelSem u globalnom nizu, opet, ID je indeks u
tom nizu), sem konstruktora i destruktora koji treba realizovati na isti način kao i
kod klase Thread (naravno u ovom slučaju koristiti KernelSem objekat umesto
PCB).
U klasi KernelSem dodati i jedan pokazivač na listu blokiranih niti na tom
semaforu. Metode klase KernelSem treba da izgledaju upravo onako kao što
izgledaju na predavanjima. Samo postavlja se pitanje kako blokiranje i
odblokiranje? Pa, ako je nit potrebno blokirati, obeležiti da je blokirana, staviti je
u listu blokiranih na semaforu i tražiti promenu konteksta. Ako je potrebno
odblokirati, uzeti prvu iz liste, promeniti joj status na spremna i staviti u
Scheduler. Ako ste me poslušali pa radite prvi zadatak sa izmenama iz drugog (pa
dete kasnije dodati i obradu sistemskih poziva preko kernel steka), ne morate
mnogo da se mučite oko zaključavanja sekcija – sredide se to posle.
Naravno, zbog testiranja, ono sto mislite da treba da se zaključa – zaključajte,
nemojte baš skroz ignorisati.
11
Event
Pre nego što krenem da objašnjavam događaje, da vam malo približim javni
test. Javni test se sastoji od nekoliko proizvođača i jednog potrošača. Vi pritiskate
po tastaturi i na taj način prozvodite slova. Potrošač ta slova uzima i ispisuje po
konzoli. Ako ništa nije pritisnuto, uzima od svakog proizvođača po znak koji mu je
dodeljen. Konceptom događaja vi dete omoguditi ovo u vezi sa tastaturom.
Prvo demo, naravno, objasniti lakši deo, koncept događaja. Klasu Event
treba realizovati kao binarni semafor. Šta to znači? To znači da value na
semaforu, tj. event-u, može biti samo 0 ili 1 – ili se nešto desilo, ili nije. Takođe to
znači da se samo jedna nit (i to ona koja je napravila event) može blokirati na tom
binarnom semaforu, pa nam ne treba lista, ved samo jedan pokazivač.
Naravno, i u ovom slučaju uvezati klase Event i KernelEv kao kod semafora.
Kako onda izgledaju signal i wait?
Pa, umesto sto inkrementiramo i dekrementiramo value, samo demo ga
postavljati na 0 ili 1 i to na slededi način:
KernelEv::signal():
Ako je pokazivač na blokiranu nit jednak 0, postaviti value na 1.
U protivnom, odblokirati nit i postaviti pokazivač na 0.
KernelEv::wait():
Ako je running nit jednaka kreatoru ovog dogadjaja (potrebno je zapamtiti ko je
napravio događaj) raditi sledede:
Ako je value jednak 0 – blokirati nit.
Ako je value jednak 1 – postaviti value na 0.
12
E sad, onaj teži deo u vezi sa rutinom, makroom i klasom IVTEntry.
Šta je posao makroa PREPAREENTRY?
Ovaj makro de nam pripremiti rutinu, staviti je u određeni ulaz i napraviti objekat
klase IVTEntry koji sadrži potrebne podatke. Ovo du vam, na vašu sredu, najlakše
objasniti, ako vam napišem kod za taj makro.
Šta su ove silne tarabice? Pa pošto za svaki događaj moramo napraviti posebnu
rutinu i poseban objekat klase IVTEntry, moramo ih različito imenovati iako u
suštini rade isti posao. Ove tarabice upravo to omogudavaju. Kada se prilikom
prevođenja izvrši tekstualna zamena, a na primer, pozvan je PREPAREENTRY(9, 0),
ovaj gore makro de izgledati ovako:
Sada imamo rutinu i objekat, ali šta se radi u konstruktoru objekta klase
IVTEntry?
Potrebno je naravno čuvati staru rutinu da bismo je restaurirali ili zvali ako je
drugi parametar makroa jednak 1.
Tip polja u kom se ta rutina čuva, kao i još neka objašnjenja su data na lab vežbi:
typedef void interrupt (*pInterrupt)(...);
13
Kada imamo taj tip uraditi sledede:
oldRout = getvect(numEntry);
//oldRout je upravo tipa pInterrupt
setvect(numEntry, interruptRoutine);
//Ova dva parametra su prosleđenja konstruktoru i predstavljaju broj ulaza i samu
rutinu koja se upisuje u taj ulaz
Takođe je potrebno uvezati objekat klase KernelEv i objekat klase IVTEntry jer
onaj signal koji se poziva u gore napisanoj rutini, de pozivati signal klase KernelEv,
da mu signalizira da se nešto desilo.
Metoda callOld() samo poziva staru rutinu: oldRout();
Sistemski pozivi
Po mom mišljenju, ovaj projekat je mnogo lakši ako se na ovakav način radi
obrada sistemskih poziva, jer kao što sam ved napomenuo, ovde ne morate da
razmišljate o zaključavanju sekcija. Obavezno još par puta pročitajte tekst zadatka
i nekoliko puta dok budete čitali ovo uputstvo se vradajte i čitajte onaj deo teksta
koji opisuje ovu obradu. Prvo se postavlja pitanje, šta su uopšte u našem slučaju
sistemski pozivi, tj. šta potpada pod sistemski poziv? To su upravo one metode
koje su dostupne korisniku, tj. nekom ko bude koristio naše malo jezgro. Znači svi
konstruktori, destruktori i javne metode iz interfejsa iz teksta zadatka.
Prvo treba napisati deklaraciju metode koja de predstavljati rutinu koja obrađuje
sistemske pozive:
void interrupt SysCallRout(...) i postaviti je u neki slobodan ulaz (slobodni ulazi su
od 60h) pomodu metode setvect.
14
4. Prelazak na kernel stek
5. Prepoznavanje šta se desilo
6. Izvršavanje operacije
7. Povratak iz sistemskog poziva
Imademo jednu strukturu koja de nam čuvati sve podatke potrebne za obradu.
Ona de, pored ostalih podataka, imati i jedan enum koji de nam govoriti koji
sistemski poziv se desio.
Potrebno je sad sve javne metode izmeniti tako da rade na slededi način (a njihov
kod sačuvati, to nam je svejedno potrebno, samo de se kasnije izvršiti):
SystemData sysData;
sysData.name = ….
sysData.param1 = ….
sysData.param2 = ….
....
sysData.paramX = ....
15
unsigned tcx = FP_SEG(&newData); //Saljemo adresu sa &
unsigned tdx = FP_OFF(&newData);
asm{
mov cx, tcx;
mov dx, tdx;
}
Kada smo sve zapakovali, zovemo prekidnu rutinu kao: asm int brojUlaza, gde je
brojUlaza onaj ulaz gde ste smestili rutinu. I na kraju, skidamo sa steka prethodno
sačuvane vrednosti registara cx i dx (paziti na redosled kojim ih skidate!).
Slededi korak je prelazak na kernel stek. Taj stek je ništa drugo nego običan niz,
koji nije potrebno inicijalizovati kao PCB, samo mu treba staviti SS, SP i BP na
stackSize (ne na stackSize – 1 jer na 8086 stack pointer ukazuje na poslednju
zauzetu lokaciju). Jednostavno, pomodu asemblerskih instrukcija promenite stek.
Kada smo prešli na kernel stek, preko parametra name iz našeg pokazivača demo
preko jednog ogromnog switcha (ili if else if else if, ....) prepoznati sta se desilo.
Kada nađemo koja operacija je zahtevana, jednostavno je izvršimo. Možete
napraviti neke kernel metode pa ih pozivati, npr. za sleep napravite _sleep i slično
i one de imati jako sličan (ako ne i isti) kod koji su imale javne metode, dostupne
korisniku, pre nego što smo izmenili projekat.
Na kraju, restauriramo kontekst running niti. Kontekst kernel niti (tj kernel steka,
kernel nit nije prava nit) nije potrebno snimati.
16
Napomena: Kako uraditi Semaphore::value? To je jedina metoda koja ima
povratnu vrednost. Jednostavno upišete tu vrednost u pokazivač (je l’ vam sad
jasnije što je bolje da bude globalni?), pročitate je u metodi Semaphore::value i
vratite.
Ono što je jako važno je da, dok smo na kernel steku, nikako ne sme dodi do
promene konteksta. Kako onda uraditi blokirajude pozive (pozivi koji oduzimaju
procesor niti – sleep, dispatch, wait, ...)? Jednostavno, blokirajudi pozivi nede
menjati kontekst, nego de samo postavljati neki fleg da je zahtevana promena
konteksta. Na kraju rutine, pre nego što restauriramo running nit, prvo demo
pitati da li je potrebna promena konteksta. Ako jeste, onda pitamo da li smemo da
stavimo running nit u Scheduler, uzmemo novu nit iz Schedulera i promenimo
kontekst (slično kao u timeru – nemojte pozivati timer ovde!).
Na ovaj način smo regulisali da se timer nikad ne poziva kao timer(); ved samo po
pravilu, na svakih 55ms.
I sad onaj deo što se tiče zaključavanja sekcija. Jedan lock kao prva linija u rutini,
jedan unlock kao poslednja linija u rutini. To je sve. Taj lock samo brani promenu
konteksta softverskim flegom, ne brani prekide. Prekide je potrebno dozvoliti
asemblerskom instrukcijom asm sti dok smo u kernel niti.
Nemojte da vam sad pada koncentracija dok ovo čitate, ovaj deo je jako važan.
U tekstu zadatka je rečeno da nakon svakog događaja je potrebno menjati
kontekst. Takođe, timer menja kontekst kada je counter == 0. Ali šta dok smo na
kernel steku? Kontekst nikako ne sme da se promeni! Zbog toga, u timeru (samo
ako je potrebna promena konteksta, tj ako je counter == 0) i u KernelEv::signal
pitati da li sistem lock-ovan, pa ako jeste, postaviti fleg koji zahteva promenu
17
konteksta (isti onaj koji smo postavljali za blokirajude pozive), a ako nije sistem
lockovan, onda uraditi promenu konteksta.
I da, ovaj KernelEv::signal nema potrebe (staviše ako ste radili ovako ko što sam
naveo gore i ne sme) raditi preko kernel steka, nego jednostavno, samo neka
odradi ono što i treba, tj. što smo napisali u sekciji Event.
Mogući problemi
Ved vam u tekstu zadatka piše koji su najčešdi problem. Imajte ono u vidu dok
kucate projekat. U ovoj sekciji du navesti one probleme koje smo mi imali dok smo
radili projekat. Kada projekat počne da vam neobjašnjivo puca ili vam kompajler
izbacuje neobjašnjivu grešku, pokušajte rešenje nadi ovde.
18
Pazite da slučajno dve iste rutine ne upišete u isti ulaz (npr. i za timer i za
event upišete u 60h)
Marko PREPAREENTRY se poziva pre svih vaših inicijalizacija, tako da ako
objekat IVTEntry smeštate u dinamički niz, pravite grešku, jer taj niz još nije
napravljen
Greškom ste negde zaboravili da podesite fleg (ili enum) koji opisuje stanje
niti (spremna, blokirana, gotova)
Obavezno oslobađati memoriju (nemojte to ignorisati, bcc nede to sam
uraditi pa može dodi do velikih problema)
Restaurirajte rutine za timer i za događaje
Ako vam javni test puca kada pritisnete ESC, vrlo verovatno da vam se
rutina za događaj (tj. za tastaturu) ne restaurira dobro
Zbog greške u javnom testu (koja nisam siguran da je ispravljena) prilikom
pokretanja javnog testa, dešava se da tastatura prestane da reaguje nakon
drugog pokretanja u konzoli – rešenje – pre nego što u destruktoru
restaurirate rutinu, samo je još jednom pozovite. Naravno ovo uradite tek
nakon što vam se javi ovakva situacija, ali prvobitno kontaktirajte asistenta.
Pitanja za odbranu
Ovo su samo neka od pitanja koja vas mogu pitati na odbrani. Uglavnom se
pitanja baziraju na tome šta i kako ste radili, ali mogu biti i neka što se tiče teorije.
Na ova pitanja možete odgovore nadi u celom ovom tekstu, tako da ih nedu
odgovarati.
19
7) Sta je preuzimanje?
8) Brojna pitanja za efikasniju obradu (kako efikasnije su mogli sistemski pozivi na
primer).
9) Zašto je potrebno da budu dozvoljeni prekidi dok obrađujemo sistemski poziv?
10) Da li, dok smo na kernelu (tj dok obrađujemo sistemski poziv), mogu da se
ugnezde prekidi?
Ne mogu jer prvi put kad dođe prekid od timera ili događaja, interrupt fleg
de se obrisati
11) Pošto su prekidi na kernelu dozvoljeni, a potrebno je nakon svakog događaja
promeniti kontekst, zar to nede napraviti problem i ako hode, kako ga razrešiti?
12) Zašto nipošto ne smemo vršiti promenu konteksta dok smo na kernel steku?
13) Brojna pitanja koja bukvalno stoje u tekstu zadatka (tipa parametri
prepareentry i slično).
14) Promena konteksta - Šta je SS, SP i kad mora da se menja i BP?
15) Šta je PC, tj kako na se 8086 "pravi"?
16) Šta je 8086?
17) Zašto na 8086 je moguce uraditi Type* pointer = 0; pointer->callMethod();
8086 nema virtuelnu memoriju pa je mogude dereferencirati čak i null
18) Šta se dešava na ulazu u interrupt metodu, a sta na izlasku?
Na ulasku se implicitno zabranjuju prekidi, a na izlasku se implicitno
dozvoljavaju
19) Sta označava modifikator interrupt (odgovor prekidna rutina se ne uvažava)?
20) Metoda/funkcija koja menja kontekst, koji modifikator mora da sadrži I zašto i
šta bismo morali da radimo ako ne bi sadržala taj modifikator?
21) Šta je volatile i na promenljivu na koju ste ga stavili, zašto ste to stavili?
22) Šta de se desiti ako obrišemo aktivnu nit, a nije pozvan waitToComplete u
destruktoru?
23) Da li nit može sama za sebe da pozove waitToComplete()?
24) Da li je potrebno konstruktor zaštititi od promene konteksta i zašto?
Gradivo OOP2
25) Prilikom promene konteksta potrebno je čuvati podatke iz pitanja 15). Zašto
samo to? Ako smo mi u metodi method() i desi se prekid od timera, u trenutku
kad sačuvamo kontekst u timeru, zar nas slededi put nede vratiti na to mesto gde
je urađeno running->sp = tsp, ....; a ne na deo koda u method() u kom se desio
prekid od timera?
PC je sačuvan na ulazu u metodu jer smo je obeležili kao interrupt. On se
menja dok idemo kroz metodu, ali je sačuvana potrebna vrednost
20
Kako izgleda odbrana
21