Discussie Klaar of niet klaar? | Processen

maarten70

Gevestigd lid
Ik zit met een probleem, multitasking. Ik heb jullie ideeën nodig, niet in alle detail of zeer technisch (al is dat natuurlijk wel toegestaan), meer abstract of schetsend. Deze vraag is voor iedereen die zich hierin wilt mengen.

Stel, de software ('jij') is het enige wat je hebt. Jij, bent hetgeen dat de hele computer in zijn macht heeft. Je hebt geen libraries of besturingssysteem om je te helpen. Jij bent verantwoordelijk voor het geheugen, de opslag, de CPU en alle taken of processen. Kortom, jij bent het besturingssysteem.

Als je een externe taak CPU tijd hebt gegeven, kan jij niks meer doen. Het is wachten tot de taak om jouw hulp vraagt of dat de interne klok een interrupt stuurt naar de processor zodat jij die moet afhandelen. De enige die nu de CPU kan gebruiken is de externe taak.

"In system programming, an interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention."
-Wikipedia
Jij moet echter wel bijhouden wanneer de volgende taak CPU tijd mag krijgen. Dit doe je door elk proces een beetje tijd te geven, wat je gelukkig kan bijhouden door de interne klok van de computer (die ene die een interrupt stuurt). Na die tijd, mag de volgende taak.

Het is tijd om de huidige taak bij de CPU weg te halen (zodat een volgende taak CPU tijd kan krijgen), alle informatie op te slaan en het aan de kant te zetten voor later. Maar, is de taak al klaar met alles wat het moest doen? Als het klaar is hoef je het niet meer in de wachtrij te zetten voor de volgende ronde. Maar toen stuitte je op een probleem.

Hoe had je kunnen weten of de taak klaar was? Tenslotte kan je het niet aan een besturingssysteem vragen, want dat ben je zelf. Je hebt alleen maar de volgende gegevens en middelen:
  • ~3 waarden, waar de taak mee bezig was om dingen te berekenen
  • De locatie van het laatst uitgevoerde commando
  • Het geheugen van de taak (RAM)
  • Locaties van mogelijke hulpmiddelen die je de taak hebt gegeven
Er zijn een aantal dingen die je zou kunnen proberen, zoals het bijhouden of de locatie van het laatst uitgevoerde commando zich aan het eind van het bestand bevindt. Echter zou dit verkeerde conclusies kunnen opleveren, want wie zegt dat de laatste instructie in het bestand ook echt de laatste instructie van het programma is.

Dan kan je nog bij de gestuurde hulpmiddelen een variabele neer zetten die de taak moet invullen als het klaar is. Maar is dat de beste oplossing? Misschien wel. Maar is het betrouwbaar? Als er ook maar iets mis gaat kunnen er vervelende dingen gebeuren. En dan heb je nog de vuistregel binnen programmeren: "Never trust user input".

Wat zou jij doen? Misschien heb je een beter idee? Zou je toch voor een van de opties hierboven gaan?
Als er vragen of onduidelijkheden zijn, hoor ik het graag. Ik hoop dat dit al duidelijk genoeg is, maar ik kan me voorstellen dat dat in de praktijk niet zo is. Ik ben niet de beste in uitleggen namelijk.
 

maulem

Gevestigd lid
Dan kun je toch een soort van eindmarker naar het geheugen wegschrijven zodra de routine klaar is, en na de return uit de interrupt gaat jouw multitask-manager weer verder en die controleert van tijd tot tijd een vooraf vastgesteld register op eindmarkers. Zo'n eindmarker zou dan kunnen bestaan uit het geheugenbereik van de voltooide taak. De multitask-manager moet dan wel het geheugenbereik kunnen relateren aan de identifier van de interruptroutine. Maar dat zou je in een mapping kunnen opnemen. Als een gegeven interrupt tenminste steeds in hetzelfde geheugenbereik plaatsvindt, maar zover ben ik niet in de materie, om te weten of dat zo is. Is een bepaald geheugenbereik aanwezig in het vooraf vastgestelde register, dan wis je de daaraan gerelateerde taak of interruptroutine uit het takengeheugen van de multitask-manager.
 

maarten70

Gevestigd lid
hm, dat is interessant. Hoewel na elke taak eerst de manager wordt uitgevoerd, kan het de register niet op een valide manier controleren. Het probleem is namelijk dat een taak niet weet wanneer het eindigt, met als probleem dat je die register niet kan reserveren. Veel registers worden namelijk onder het uitvoeren van de taak allemaal gebruikt voor de taak, een zo'n register reserveren voor altijd zou een programma of taak ernstig kunnen benadelen. Hierdoor kan je het niet op die manier controleren.

De interrupt routines zitten altijd op een vaste plaats in het geheugen, en de plek waar de taak is geladen (inclusief de informatie van het besturingssysteem over de taak) is beschikbare informatie voor die routines.

Als ik je verhaal goed hebt begrepen lijkt het een beetje op dit:
Dan kan je nog bij de gestuurde hulpmiddelen een variabele neer zetten die de taak moet invullen als het klaar is. Maar is dat de beste oplossing? Misschien wel. Maar is het betrouwbaar? Als er ook maar iets mis gaat kunnen er vervelende dingen gebeuren. En dan heb je nog de vuistregel binnen programmeren: "Never trust user input".
Ik heb het hierover gehad met iemand anders, die vond dat dit (inhoud van de quote) op zich wel een goede manier kan zijn maar tegelijkertijd niet. Want op het huidige moment zou het door alles en iedereen overschreven kunnen worden. Echt te beveiligen is het dus niet, maar het is misschien wel de makkelijktse en efficiëntste manier om het te doen.

Misschien is een andere vraag om te stellen: 'hoe kunnen we deze manier verbeteren zodat het (nog) beter wordt?'.

Thanks!
 

maulem

Gevestigd lid
Bedankt voor je antwoord.

Om eerlijk te zijn heb ik me vergist met de term register. Ik bedoelde eigenlijk: geheugenadresbereik (in het RAM). Dus waar nu register staat, dien je te lezen: geheugenadresbereik.
 

maarten70

Gevestigd lid
Ja, precies. Ik zat ook aan zo'n soort oplossing te denken, maar ik vraag me af of die oplossing wel betrouwbaar is. Misschien is er een betere oplossing.

Toch is dat tot nu toe de manier waarop iedereen die ik gevraagd heb, het zou doen. Dus misschien is dat de beste manier.
 

maulem

Gevestigd lid
Een andere methode waaraan ik dacht is gebaseerd op het aantal klokcycli dat de interrupt in beslag neemt. Stel dat je een timer instelt op het moment dat de interrupt begint, dan meet je een vastgesteld aantal klokcycli en onderbreekt dan de interrupt. Is de taak binnen het vastgestelde aantal klokcycli klaar, dan zal deze eerder retourneren dan het vastgestelde aantal klokcycli en kun je dus deze taak wegstrepen uit de multitask-manager. Taken die langer duren dan het vastgestelde aantal klokcycli blijven op deze manier gewoon in de agenda van de multitask-manager staan. Dit soort administratie vereist wel dat er bij het retourneren van een interrupt een soort flag of bit wordt gezet, waaraan je kunt zien dat er is geretourneerd.
 

maarten70

Gevestigd lid
Ik snap hem niet helemaal, denk ik. Wat bedoel je precies?

Het liefst heb je niet dat het programma/de taak zomaar naar je terug retourneerd. Namelijk, een programma zit in CPU privilege level 3 (Ring 3, user mode, dat is een hardwarematige switch) en een OS heeft meer priviliges en zit in level 0.

Als een taak naar jou terug retourneert op de manier dat een programma in een terminal/bash/shell/cmd dat zou doen, zou je nog steeds in user mode zitten. Als dan de volgende keer de OS een hardeschijf probeerd te lezen krijg je een CPU exception, hierdoor kom je dan uit op een kernel panic (vergelijkbaar met Windows BSOD).

Je hebt me trouwens geantendeerd op een probleem. Een taak wordt gezocht terwijl de interrupt routine nog loopt, als je klaar bent met een interrupt moet je dat doorgeven aan de computer. Eerst sprong de OS gelijk naar user mode en werd gelijk de taak uitgevoerd terwijl er niet was doorgegeven dat de interrupt klaar was. Als gevolg heb je dan dat er geen interrupts meer kunnen plaats vinden want de CPU denkt dat je nog steeds bezig bent met een interrupt. In zo'n geval werkt je toetsenbord of muis ook niet meer.

Een ander idee waar ik nog aan dacht is dat je in de API (want die is sowieso nodig) een exit() (of kill(), destroy()) functie zet, die de taak kan uitvoeren. Die functie geeft aan de OS het geheugen adres van de char* "_VIREO-DONE". Vireo is de naam van de kernel. Zo kan je verzekeren dat het niet zomaar een waarde is die fout geschreven is want dit moet bewust gedaan worden. Verder weet ik nog wel een manier hoe ik ervoor kan zorgen dat alleen de kernel en de taak in kwestie weten waar die char* zit.
 

maulem

Gevestigd lid
Ik bedoel met retourneren de interrupt return. Ik vroeg me af of je een timer kunt laten lopen synchroon met de uitvoering van de taak, om zo te meten of de taak vroegtijdig klaar is, zodat je weet of je de taak kunt schrappen uit de takenagenda. Maar daar het een interrupt betreft, kan er waarschijnlijk geen timer tegelijk lopen, omdat je geen kernelcode kunt uitvoeren tijdens de werking van de interrupt routine (taak). De code moet immers wachten tot na de interrupt return.

Je hebt het over een exit functie, die je, neem ik aan, door de taak laat uitvoeren wanneer die helemaal klaar is? En kan de kernel dan nagaan van welke taak de _VIREO-DONE afkomstig is? Bevat de char* dan het adres van de taak?
 

maarten70

Gevestigd lid
Interrupts horen bij de kernel en dus wordt er ook kernel code uitgevoerd tijdens interrupts, want het is een onderdeel van de kernel. Je zou wel een timer kunnen starten, maar ik denk niet dat je daaruit kan opmaken of de taak klaar is tenzij je de exit() functie gebruikt. (Dan nog zit er een kleine delay tussen wanneer de kernel doorheeft dat iets klaar is en wanneer iets klaar is)

De interrupt doet alleen maar het volgende:
  • het bijhouden hoe lang de taak is, als het 1/32 van een seconde gerund heeft wordt het afgebroken.
  • zorgen dat als er een taak klaar is, een nieuwe taak wordt uitgevoerd (de interrupt doet eerst een soort van return en dan wordt de taak pas uitgevoerd).
Dus de taak loopt niet tijdens de interrupt.

Over de char... De char bevat het adres van de tekst '_VIREO-DONE' (mocht je strings kennen van een programmeertaal zoals Java of C++, dat is exact hetzelfde als een char*) De kernel kan zeker na gaan van welke taak het afkomstig is. De kernel houdt bij welke taak er op dat moment bezig is.

De kernel houdt een lijst bij met taken in de wachtrij. De kernel zoekt naar de taak met de hoogste prioriteit en houdt bij op welke locatie die taak in de wachtrij staat. Zo kan je dus bijhouden welke taak bezig is. Het adres van de tekst staat op een plek die specifiek is toegewezen aan het programma, je kan dus zeker zijn dat het van die taak is. Tevens is de plek waar het adres naar de tekst staat, alleen bekend voor de taak en de kernel. Een andere taak weet namelijk niet waar hij die informatie vandaan moet plukken. In theorie.
 
Bovenaan Onderaan