ITKA203 Käyttöjärjestelmät, luento 5/14, Ke 1.6.2011 ==================================================== Muisteltiin aiemmin nähtyä nouto-suoritussykliä konekieliselle ohjelmalle: 1. Nouto 2. Suoritus Tätä täydennettiin myöhemmin tänään. Katsottiin esimerkkejä tyypillisistä konekielisistä käskyistä (vuoden 2007 materiaalista): Mm. siirtokäskyt, pinokäskyt, laskenta- ja bittilogiikkakäskyt. Samalla tutustuttiin tarkemmin pinon olemukseen (teknisesti vain virtuaalimuistiavaruuden alue) ja käyttöön (push ja pop -käskyt, pinon "huipuun" alati osoittava SP eli stack pointer -rekisteri). Pino kasvaa muistiosoitteiden mielessä alaspäin (SP pienenee pinoon laitettaessa ja kasvaa otettaessa). Tutkittiin suoritusjärjestyksen ohjausta tarkoin: ehtolause, silmukkarakenne, aliohjelma. Näistä esimerkeistä päästäneen hyvin kärryille siitä, millaiset prosessorin käskyt mahdollistavat ohjelmointirakenteiden toteuttamisen ja millä tavoin. Aliohjelmaan siirtyminen käytiin läpi varsin tarkoin ja tutustuttiin pinokehyksen käyttöön siinä. Eli varmisteltiin ymmärrystä suorituspinosta ja pinokehyksistä: - Pino-osoitin (stack pointer, SP) ja kanta-osoitin (base pointer, BP) - Pino-operaatiot: push, pop. Vastaavat konekielikäskyt. - Paikallisten muuttujian tilan varaaminen SP:n vähennyslaskulla. - minkä ohjelmaosan vastuulla on mikäkin osa aliohjelmakutsusta ja mitä käskyjä prosessori tarjoaa näitä varten: + kutsuva osa valmistelee parametrit (x86-64:ssä ensimmäiset parametrit laitetaan rekistereihin ja mahdolliset lisäparametrit pinoon) + kutsuvassa osassa käsky: call + aliohjelman alussa "push BP", sitten "SP->BP" ja paikallisten muuttujien tilan varaaminen. + lopussa käänteiset operaatiot, "leave". Tilanne BP:n ja SP:n osalta palauttuu alkuperäiseksi (eli BP->SP ja ikäänkuin tapahtuisi vielä "pop BP"), joten aliohjelman viimeinen käsky "ret" voi vain napata paluuosoitteen pinon päältä IP:hen. Normaali nouto-suoritussykli jatkuu sen jälkeen taas kutsuvasta ohjelman osasta. + jaah, ja koska esimerkkiohjelmassa ei ollut paluuarvon eli aliohjelman laskeman tuloksen palauttamista kutsuvaan ohjelmaan, niin eipä sitä tullut mieleen demonstroida, vaikka se on vielä yksi aliohjelmien käytössä erittäin tärkeä asia. Eli kait tähän pitää vielä tämän verran palata myöhemmin: Ohjelmassa olisi pitänyt hoitaa paluuarvo RAX rekisteriin ennen lopputoimia leave:sta eteenpäin. Tarkennettiin yhtä asiaa, johon lupailtiin tarkennusta: Mitä tapahtuu heti ensimmäisenä, kun tietokoneeseen kytketään virta? Tämä voidaan nyt ymmärtää johonkin pisteeseen asti... Ilmeisesti laitteisto hoitaa RIP:n arvoksi muistipaikan osoitteen, jossa on "käynnistysohjelma". Se sijaitsee tehtaalla kiinnitetyssä ROM-muistissa, ja sen ensisijainen tehtävä on etsiä esim. kovalevyn alusta siellä olevat bitit, ladata ne muistiin ja siirtää RIP tämän muistialueen alkuun. Toivottavasti ladattu data on konekielinen käskysarja joka kuuluu käyttöjärjestelmäohjelmistoon... Toki ROM-ohjelmassa useimmiten on muutakin, eli kotitietokoneista tuttu "BIOS-asetusten säätö" -ohjelma, jolla esim. voi asettaa tietokoneeseen salasanan ja valita sen laitteen, josta käyttöjärjestelmä ladataan. Vielä täytyy jättää tarinan jatko-osa hiukan auki: eli mitä käyttöjärjestelmä alkaa sitten ensi töikseen tehdä. Sovitaan, että viimeisellä luennolla voidaan listata tärkeimmät asiat, jotka käyttöjärjestelmä tekee käynnistyessään eli "buutatessaan". Ensin pyritään löytämään syy käyttöjärjestelmän tärkeimmille osille, ja tutkitaan hieman sitä kuinka ne ylipäätään toimivat. Nyt ymmärretään miten yhden ohjelman suoritus tapahtuu. Mutta miten sitten tapahtuu moniajo eli monen ohjelman käyttäminen samanaikaisesti? Johdattelua: - Käyttöjärjestelmän tehtävänä ilmeisesti on hallita käyttäjän ohjelmia erilaisin tavoin, koska ohjelmilla itsellään ei ole siihen sinänsä keinoja. Eikä tavallisille ohjelmille voisi antaakaan keinoja toistensa hallitsemiseen, koska silloin olisi liian helppoa ohjelmien sekoittaa toistensa toiminta vahingossa tai tahallaan! - Käyttäjän ohjelmia ilmeisesti täytyy voida käytellä jopa useampia yhtäaikaa (esim. luentosalin tietokoneessa oli käynnissä WWW-selain, pääteyhteys, videokaappaus, ruutuunpiirtelyohjelma...) - Prosessoreita on kuitenkin vain yksi (tai nykyään useampia, mutta harvoin läheskään niin monta kuin ohjelmia tarvitaan yhtäaikaa). - (Jokainen) prosessori on "tyhmä automaatti" joka osaa "vain" suorittaa nouto-suoritussykliä. - Voitaneen ymmärtää relevantiksi kysymys "kuinka prosessori mahdollistaa monen ohjelman toimimisen yhtäaikaa, eli moniajon?" - Ilmenee, että nouto-suoritussykliin liittyy vielä eräs yksityiskohta, joka mahdollistaa modernin moniajon käyttöjärjestelmän ja prosessorin yhteispelinä. Prosessorin toimintatiloja tarvitaan ainakin kaksi: - käyttäjätila (user mode), jossa prosessori on silloin kun se suorittaa normaalin ohjelman käskysarjaa. Käyttäjätilassa tietyt operaatiot on oltava kiellettyjä, etteivät ohjelmat vahingossakaan pääse sotkemaan toistensa toimintaa. - käyttöjärjestelmätila (supervisor mode / kernel mode), jossa prosessorin täytyy aina välillä olla, jotta käyttöjärjestelmä pystyy päätehtäväänsä, joka on käyttäjäohjelmien hallinnointi. Rekisterit ja käskykannan käskyt on jaettu käyttöjärjestelmätilan ja käyttäjätilan välillä. Toki kaikki käyttäjätilan ominaisuudet ovat käytössä myös käyttöjärjestelmätilassa, mutta lisäksi on "suojattuja" rekistereitä ja käskyjä, joita prosessori suostuu suorittamaan vain ollessaan käyttöjärjestelmätilassa (käyttäjätilassa nämä aiheuttavat virhetilanteen). Tila on tallessa esimerkiksi tiettynä bittinä FLAGS-rekisterissä (esim. 1=käyttöjärjestelmätila ja 0=käyttäjätila). Miten tila vaihtuu? Tätä varten prosessoreissa on keskeytys-ominaisuus. Tämän kurssin mielessä lopullinen kuva nouto-suoritussyklistä on seuraavanlainen: 1. Nouto 2. Suoritus 3. Keskeytysten tarkistus, esim: - kellokeskeytys (esim. 1000 kertaa sekunnissa; joka tapauksessa todella paljon harvemmin kuin nouto-suoritussyklin kierrokset, joita voi olla sekunnissa miljoonia tai miljardeja!) (aiheuttaa käyttöjärjestelmän vuorontaja-komponenttiin siirtymisen) - laitekeskeytys (esim. näppäintä painettu) (aiheuttaa laitekäsittelijään siirtymisen) Jos kello tai muu laite pyytää keskeytystä, tapahtuu FLIH first-level interrupt handling. (Miten keskeytyspyyntö käytännössä tapahtuu? Tottakai siten kuin kaikki muukin, eli yksinkertaisesti... keskeytyksen aiheuttaja syöttää prosessorille jännitteen tiettyyn johtimeen eli ns. keskeytyslinjaan. Linjoja voi olla useita eri laitteita varten.) Prosessorin FLIH-toimintaan palataan tarkemmin jollain tulevalla luennolla. Tässä vaiheessa riittää havaita, että keskeytyksiä tarvitaan jotta prosessori pääsisi aina välillä suorittamaan käyttöjärjestelmäohjelman käskyjä. Käyttöjärjestelmä pääsee täten mm. jakelemaan käyttäjän ohjelmille vuoroja sekä siirtämään dataa laitteiston kanssa (eli hoitamaan I/O -toimintoja). Prosessin käsite (tänään alustava näkökulma; tarkentuu tulevilla luennoilla vielä paljonkin): Prosessi on "ohjelman ilmentymä silloin kun se on käynnissä" ... vai miten sen nyt yksinkertaisessa muodossa sanoisi. Huomaa, että sama ohjelma voi olla käynnissä useina ns. ilmentyminä eli instansseina, jotka ovat kaikki omia prosessejaan. Esimerkiksi luennolla mulla oli PuTTY-pääteyhteysohjelma käynnissä kahtena eri prosessina. Ne näkyivät kahtena eri ikkunana. Toinen PuTTY-prosessi otti yhteyden jalavaan ja toinen charra.it.jyu.fi -nimiseen koneeseen. Prosessilla on ainakin: - virtuaalimuistiavaruus (jonka kautta prosessin oma koodi, data, suorituspino ja dynaamiset muistialueet ovat saavutettavissa) - kulloinenkin rekisterien tilanne, konteksti Tämä on alustava lista, joka täydentyy jatkossa. Toistaiseksi ollaan puhuttu konkreettisesti vasta ylläolevista prosessin ominaisuuksista. Ilmeisesti käyttöjärjestelmän täytyy huolehtia prosesseista - käynnistää niitä, antaa niille vuoroja prosessorin käyttöön, valmistella niiden virtuaalimuistiavaruuksien yhteys koneen fyysiseen muistiavaruuteen ym.. Tärkeä käyttöjärjestelmän tehtävä on tämä, nimeltään Prosessinhallinta. Tähän mennessä on nähty, että tarpeen on myös Muistinhallinta, selvästi yhteistyössä prosessinhallinnan kanssa. Arvata saattaa että myös I/O-laitehallinta on tarpeen. Myöhemmin nähdään tarve myös ainakin Tiedostonhallinnalle, Käyttäjienhallinnalle, Oikeuksienhallinnalle. Sovellusohjelma on kirjoitettu korkean tason ohjelmointikielellä ja käännetty konekieliseksi. Mitä tapahtuu, kun ohjelma käynnistetään? Käyttöjärjestelmän tehtävänä on ohjelman lataus esim. kovalevyltä, linkitys jaettuihin kirjastoihin (näihin palataan tarkemmin) ja ensimmäisen suoritusvuoron antaminen. Sanotaan tätä vaikkapa "prosessin luomiseksi", koska lopputuloksena jotakin ohjelmaa ilmeisesti suoritetaan. Siitä on tullut prosessi. Aiheeseen palataan ensi viikolla ja koko kurssin ajan prosessi tulee olemaan suuressa roolissa. Reunahuomautus: Prosessi (engl. process) on joskus nimeltään tehtävä (task) tai työ (job) riippuen siitä kuka puhuu ja mitä sanaa hän milloinkin sattuu käyttämään. Huomautuksia: - Sovellusohjelma "näkee" perustilanteessa vain oman prosessinsa eli omat rekisterisisällöt, oman muistin, jossa ovat mm. suoritettavat konekielikäskyt. (Kaikki prosessien välinen kommunikaatio, jota joskus tarvitaan, tulee tarvitsemaan käyttöjärjestelmää välittäjäksi.) - Normaaliolosuhteissa on täysin mahdollista että uusi keskeytys tulee missä tahansa vaiheessa. Eihän ole mitään kontrollia esimerkiksi siihen, milloin käyttäjä painaa jotakin näppäintä! Voi myös olla että sata muuta ohjelmaa saavat prosessorin hetkeksi käyttöönsä ennen kuin keskeytetty prosessi pääsee jatkamaan. Käyttäjätilan ohjelmalla on hyvin vähän keinoja vaatia että prosessori suorittaisi kaksi sen käskyä nouto-suoritussyklin peräkkäisillä kierroksilla. (Jotain toiveita se voi esittää käyttöjärjestelmälle, myöhemmin nähtävällä tavoin, ja joskus näitä onkin jopa välttämätöntä esittää.) Yhteenveto tämän viikon asioista: - Vain käyttöjärjestelmä saa toimia prosessorissa vapaasti; sen pitää hallita ja hillitä kaikkia muita ohjelmia. - Tähän asti nähdyn perusteella käyttöjärjestelmän täytyy ainakin: + käynnistää ohjelmat + hoitaa ohjelmien vuorottelu + hoitaa ohjelmien muistin hallinta suhteessa fyysiseen muistiin + hoitaa syötöt ja tulostukset laitteiden ja ohjelmien välillä (siis alkaen jo näppäinpainalluksista ja hiiren liikuttamisesta) - Ohjelman täytyy pyytää ainakin näitä palveluita käyttöjärjestelmältä, jos se niitä tarvitsee. Jokainen ohjelma tarvitsee jotakin palvelua, muuten se on järjetön (esim. ei pysty tallentamaan tai näyttämään tuloksia missään!). Ensi viikolla tarkennetaan sitä kuinka nämä palvelupyynnöt itse asiassa tehdään. - Käytännössä sovellusohjelma usein pyytää palveluita kirjastoilta, jotka pyytävät palveluita muilta kirjastoilta... ja vasta "matalamman tason kirjastot" varsinaisesti pyytävät palvelun käyttöjärjestelmältä (eli sovellusohjelmakin ajatellaan kerroksina, joka rakentuu alemman tason kerroksien tarjoamien rajapintojen päälle; rajapintahan näkyy ohjelmoijalle kirjaston kutsuttavissa olevien aliohjelmien/metodien joukkona sekä niiden sovittuina parametreina ja paluuarvoina) (HUOM: Java-ohjelma pyytää palveluita matalan tason luokilta, jotka yhteistyössä virtuaalikoneen kanssa pyytävät palveluita virtuaalikonetta isännöivältä käyttöjärjestelmältä.)