-*- coding:utf-8 ; mode:org -*- Käyttöjärjestelmät, kevät 2016. Tämä on suunnitelma, joka muuttuu ajankäytön ja muun perusteella. Pohjana luentojen eteneminen viime vuonna, jolloin kokonaisuus oli jo aika perushyvä. * Luentojen toteuma 2016: ** Luento 1: Aloitus, yleisinfo ja suoritusvaatimukset Luennon päätavoite oli kuvailla kurssin tekniset vaatimukset ja muu perusinfo. Varsinaiseen asiaan ehditään hyvin keskiviikkona. - Esittelyt: opettajat, opiskelijat, opiskelijoiden pääaineet (suurin osa tietotekniikalta, noin puolet tästä määrästä tietojenkäsittelytieteeltä, lisäksi fyysikalta, matematiikalta sekä englannin ja suomen kielen opiskelijoita. Opiskelijoiden pääasialliset käyttöjärjestelmät omassa käytössä: suurimmalla osalla Windows, mutta Linuxeja ja Mac OS X:iä myös runsaasti käytössä. Lisäksi salista löytyi ehkä Windowsia useammin myös Android (Linux-ytimen päällä sekin) ja myös Sailfish (joka toimii monen vaihtoehtoisen alustan päällä). Linkit kahden viimeksi mainitun yleisarkkitehtuurikuviin: https://source.android.com/security/ https://sailfishos.org/about/ Linuxia käydään kurssilla läpi eri kanteilta. - Perinteinen ryhmäkuva, tällä kertaa ilman teknisiä tai muita ongelmia. Okei, tämä koreografia oli harjoiteltu... Kaikki, mitä "koreografiassa" nähtiin, liittyi yksityiskohtiin, joiden parissa kurssilla pyöritään alusta loppuun, muiden asioiden muassa. - Käydään läpi, mistä kaikki kurssiin liittyvä löytyy (kaikkiin löytyy linkki kurssin nettisivulta): * Luentomoniste * Osaamistavoitteet * Demot ja niiden palautusjärjestelmä (HUOM: toistaiseksi vielä viime vuoden versiot - muutokset tulleevat olemaan hyvin pieniä; päivitetään ministi jotain jossain vaiheessa, mikäli tarvetta ilmenee). Seuraavalla luennolla tulee opastus ensimmäisiin demoihin, joten sinne asti voi olla ihan hyvä vielä malttaa ja käyttää aikaa vaikkapa esitietojen kertaamiseen, erityisesti Ohjelmointi 1:n osalta. Demojen miettiminen ryhmässä on aina suotavaa, mutta jokaisen tulee palauttaa tiedosto omalla tunnuksellaan jo teknisistä syistä. [Lisäksi jokainen vastatkoon omalta kohdaltaan siitä, että aivan itselle kertyy käytännön osaamista, vaikka frendi jeesaa! On se myös frendin vastuulla!] * Aikataulut ja salit: Korpissa. Ryhmäohjauksia mikroluokissa vain käyntiin pääsemiseksi; sen jälkeen henkilökohtaisesti varattavia aikoja Tomilta; ohjeet Korppi-varauksiin tulevat listalle. Pääsiäisen alusviikolla täysi tauko opetuksesta; opiskelu ei ole kiellettyä ;). Luennoitsijanne naputtaa kyseisen viikon väitöskirjaansa, eikä toivottavasti paljon muuta teekään. Luennot ovat iltapäivästä - tehdään yhteinen ratkaisu, pidetäänkö niissä tauko vai jätetäänkö tauko pois ja lopetetaan aiemmin: Tänä vuonna ei pidetä taukoa! Luennot päättyvät täten klo 17:45, kulloisenkin luentosalin tietokoneen kellon mukaan. * Materiaalin reaaliaikainen tilanne -> YouSourcessa. Päivitysten julkaisu useimmiten 1-2 tunnin kuluttua luennon päättymisestä. - Käytiin läpi määrälliset vaatimukset, jotka ovat jo näkyvillä myös nettisivulla ja palautusjärjestelmässä: Pakolliset demot ja tentti. Vapaaehtoiset demot ovat "porkkana" ja "täky" syvällisemmän osaamisen hakemiseen; kevään kurssin aikana niistä saa bonuspisteitä. - Tomin ohjauksista: Henkilökohtaiset ajanvaraukset Korpin kautta (tiedotetaan ja ohjeistetaan, kun on varattavissa). Varaus ajoissa sen mukaan kuinka vaativiin "ongelmiin" tarvitsee apua. Kysymykset hyvä olla mietittynä, että aika saadaan paikan päällä käytettyä tehokkaasti. Kysyä saa paitsi demoista niin kurssin asioista muutenkin. - Tomin "palopuhe" demojen tekemisestä. Olennaisimmat kohdat taisivat olla: Ohjeet on syytä lukea ja ymmärtää ennen palautuksen tekemistä. (Vastausten ei tarvitse olla täydellisiä - tarkistus on harkinnan mukaan, voidaanko vastauksen perusteella ns. "epäillä" ettei ole ymmärretty asiaa. On suorastaan epäkohteliasta palauttaa lähdekoodia, joka ei käänny syntaksivirheen takia! Palautettavan tiedoston muoto on tärkeä, joten ohjeet on tosiaankin luettava. ** Luento 2: Luentomuoto, taustamateriaali, demo-ohjeistus, varoitukset(!) Tästä luennosta alkaen mennään kaikki asiat juurta jaksaen käytännön esimerkkejä näyttäen ja auki selittäen. Tavoite on, että viimeistään demojen 1 ja 2 jälkeen opiskelijat uskaltautuvat myös itse kokeilemaan samoja juttuja omatoimisesti. Turvallisuus- ja mukavuussyistä tämän luennon varoitukset on syytä ensin sisäistää. Mini-info: - Ensimmäinen mahdollisuus aloittaa demoja mikroluokassa ohjaajan avustamana on heti huomenna (to 17.3.2016) mikroluokassa Lakes (AgB213.1) klo 8:30-12:00 välisenä aikana. Konsepti on: * sali on meille varattuna aamupäivän * mie päivystän siellä, josko paikalle tulee opiskelijoitakin. * avustan henkisesti ja teknisesti, mikäli tarvetta ilmenee. Tehtävien luonteen vuoksi niitä tehdään joka tapauksessa itsenäisesti lukien ja kokeillen myös paikan päällä. * Tomikin tulee, jos Tomi ehtii. * ei tarvitse ilmoittautua.. tule sopivassa välissä paikalle, jos tuntuu, että alussa tarvitsee tukea. Kokemuksen perusteella oletukseni on, että mikroluokka ei täyttyisi ääriään myöten missään vaiheessa - saa nähdä miten tänä vuonna käy.. * lisää mikroluokkapäivystystä luvassa niin kauan kuin näyttää, että "massaohjaukset" ovat tarpeen. Varattu tässä vaiheessa sali Africa (AgB112.1) pe 18.3.2016 klo 8:30-10:00 ja 14:15-15:45. Mikroluokkatouhu jatkuu pääsiäistauon jälkeen, mikäli tarpeen. * tarkoitus on, että myöhemmin olisi vain henkilökohtaiset varaukset Tomin ohjaukseen Agoran 4. kerroksen avotilassa (max. 3 henkeä yhdenaikaisesti). Näistä ilmoitetaan, kun Tomilla on aikoja saatavilla. - Etenkin etäopiskelijoille, mutta myös muille, meillä on käytössä kaksi vertaistukikanavaa: yksi virallinen ja yksi epävirallinen: * Sähköpostilista itka203_kevat2016_keskustelu@korppi.jyu.fi on virallinen. Viestit arkistoituvat listan jäsenille, mutta eivät julkisesti. Tarkoitus: kysykää apua kaverilta -> kaverit vastaa -> seuraavat kaverit oikaisevat, jos edellinen vastaus ei ollut aivan nappiin -> opettajat saattavat kommentoida ehtimisensä mukaan. Lista on erillinen, jotta informaatioähkyä välttävä opiskelija voi halutessaan poistua omatoimisesti listalta. Viralliset tiedotteet tulevat sen toisen listamme kautta, joka myös arkistoituu julkisesti. * IRC-kanava ircnetissä, jonka nimi on tässä "kryptattuna" seuraavan muotoinen: risuaitamerkki + kurssikoodi pienillä kirjaimilla. Sinne ei haluta ulkopuolisia, ja siksi kryptaus. Luennolla näytetään esimerkki. HUOM: IRC-palvelu EI ole Jyväskylän yliopiston tukema palvelu, eikä se ole kurssin tiedotuskanavana virallinen. Tarkoitus: jutelkaa pizzan tilauksen lisäksi tarvittaessa kurssinkin asioista -> yleensä ollut porukkaa hengaamassa, joten usein reaaliaikainen vastaus ongelmakohtiin -> nieminen idlaa kanavalla ja logaa keskustelua + vastaa ehkä ennen toukokuuta, jos on vastatakseen. Yksi täkäläinen IRC-ohje: http://linkkijkl.fi/ohjeita/irc-ohje/ Sitten itse asiaan: - Luentomuoto ja kurssin työkalut alusta alkaen ja esimerkit näyttäen: pääteyhteys, bash-shell ja tekstipohjaiset työkaluohjelmat. Oppikirja, kurssimoniste ja internetin ihmeellinen maailma. Käytännön esimerkit. - Ensimmäinen vilkaisu "jyrkempään" taustamateriaaliin: AMD64-manuaalit, POSIX. Mitä ihmettä ja miksi? - Miten lähdetään tekemään demoa 1: Alkuvaroitukset ja toisaalta rohkaisu. - HUOM: Windows-pääteyhteysohjelman (esim. KiTTY) todennäköinen ääkkösongelma ja sen korjaaminen: Omissa asetuksissa todettava etäkoneen merkistö; meidän tapauksessa UTF-8 - Miten homma jatkuu demossa 2: Screen-ohjelman käyttely. Demossa tulee paljon muutakin. Mennään siihen luennoilla pääsiäistauon jälkeen. - Esitietojen varmistaminen: Mitä ohjelmointi 1 -kurssilta pitäisi muistaa ( ks. https://trac.cc.jyu.fi/projects/ohj1/wiki/sisallys ) ** Luento 3: Yleiskuvaa, tavoitteita, esitietoja ja motivoiva räjähdys. - Yleisiä kommentteja demoista 1 ja 2 (näköjään yhtä luentoa aiemmin kuin viime vuonna, mutta samat asiat varmaan on syytä käydä läpi ilman yllätyksiä:)) + (muistakaa ekan demon varoitukset; pitää tietää mitä tapahtuu, ennen kuin laittaa sen tapahtumaan;) + jos pelottaa, voi tehdä kokeiluja palvelimella itka203-testi.it.jyu.fi missä ei voi häiritä jalavalaisia / halavalaisia. [demotaan lyhyesti luennolla] + välttäkää tarpeetonta monimutkaisuutta - esimerkiksi komento "echo `ps -u nieminen`" antaa echo-ohjelman tulosteen eikä tehtävänannossa pyydettyä ps-ohjelman tulostetta!! Voi olla, että "mystinen" ilmiö rivinvaihtojen puuttumisen suhteen saattaa selittyä tällä asialla, joka onkin vain väärä käsitys - korjataan käsitystä ja koettakaa palauttaa demoa 1 uudelleen, jos se on hylätty rivinvaihtoilmiöiden vuoksi. Koetetaan konkretisoida luennolla. - Demon 2 sisällöstä: Moniajo, ps ja top -ohjelmat. Lisää viimeistään demossa 2 vastaan tulevia termejä: Prosessi, prosessi-ID. lapsiprosessi, vanhempiprosessi, prosessipuu. - Lukekaahan Tomin kommentit demoista ym. sähköpostilistalta. Löytyy myös Korpin sähköpostiarkistosta, jos olet ilmoittautunut kurssille esim. vasta eilen... Mennään luentomonisteen puolelle: - Sisällysluettelon pääotsikot suhteessa kansainvälisiin osaamistavoitteisiin. Samoja ovat.. jatkokurssien opettajat aika-ajoin kyselevät, mitä tällä kurssilla käsitellään. Päädyn lupaamaan noin yhden luennon mittaisen ensijohdannon aika monesta tärkeästä asiasta, joissa myöhemmin mennään syvemmälle. - Johdanto: Kerrokset ja rajapinnat. Käyttöjärjestelmän rooli informaatioteknologian kokonaiskuvassa. Käyttöjärjestelmäkurssin rooli IT-alan oppisisällössä ja suhde muihin osaamiskohteisiin. - Esi- tai ennakkotiedot: Palautellaan mieleen Ohjelmointi 1 -kurssia: alkeistietotyypit, määrämuotoiset tietorakenteet ja taulukot. Ilmeneminen C:n lähdekoodissa (ei kovin erilaista kuin esim. C#:ssa tai Javassa, joiden syntaksi tarkoituksella jäljittelee C:tä). - Pintapuolisia esi- tai ennakkotietoja kurssien Algoritmit 1&2. -puolelta. Arkihavaintoja abstrakteista tietorakenteista: tietue/olio, taulukko, lista, jono, pino, puu. - Lukujärjestelmistä - tavallaan "esitieto", joka tavallaan käydään läpi Ohjelmointi 1:n sisällössä, mutta melko varmasti tarvitsee kertausta. Laitteiston lähellä toimittaessa välttämätön ymmärtää. Erityisesti binääri-, heksa- ja oktaaliluvut. - Päätettiin luento videoon, joka löytyi ensimmäisenä Google-haulla "Ariane 5 test launch". Kurssin asiat eivät ole rakettitiedettä, kuten luennolla pari kertaa mainitsin, mutta rakettienkin kanssa toimittaessa ne täytyy ymmärtää, mm. lukujärjestelmät ja tallennustilan rajallisuus laitteistossa. Videolla paukahtaa puolisen miljoonaa euroa nätisti, koska 16 bitin mittaiseen tallennustilaan yritettiin laittaa luku, joka olisi tarvinnut vähintään 17. Näihin kuviin, näihin tunnelmiin. Kerratkaa tai opetelkaa ensimmäistä kertaa binääriluvut, heksaluvut ja oktaaliluvut!! Ensi viikolla katsotaan heksoja! ** Luento 4: Tietokonelaitteisto Tällä viikolla (luennot 4-5) vaelletaan viime viikolla selatun kerroskuvan matalimmilla tasoilla, lähellä tietokonetta ja prosessorin rajapintaa. Aluksi: - Tomi mainostaa alussa Linkin järjestämää tekstieditorijumppaa. - Tomi kertoo havainnon tai pari demoista tähän asti. Välttämätön päällekkäisyys kurssin Tietokoneen rakenne ja arkkitehtuuri kanssa (joka ei välttämättä mahdu samaan sivuainepakettiin tämän kurssin kanssa): - Tietokoneen perusrakenne (CPU, muisti, IO-laitteet, väylä) - CPU:n välttämättömät osat (kontrolliyksikkö, ALU, rekisterit, sisäiset väylät); vähintään käskyosoiterekisteri (IP), jokin rekisteri laskutoimituksille sekä loogisia ehtoja kuvaavia lippubittejä. - Nykypäivä: symmetrinen moniprosessorijärjestelmä / multicore [klusterit? pilvipalvelut? virtualisointi? - pääasiassa jatkokurssien aiheita; samoin rinnakkaislaskenta GPU:lla eli grafiikkaprosessorilla. Mainittakoon nämä kuitenkin ohimennen.] - muistihierarkia (rekisterit, välimuistit L1, L2,.. , keskusmuisti) lokaalisuusperiaate mainittu jo myös. POSIX-vartti: - Mikä on POSIX? Kuka sen on tehnyt? Mitä se sanoo esimerkiksi tällä luennolla tai aiemmin nähdyistä asioista? + Tsekataan alun yleiskuvaukset ja rajaukset - POSIX ei ota kantaa laitteistorajapintaan eikä käyttöjärjestelmän sisäiseen rakenteeseen; kyseessä siis nimenomaan rajapintadokumentaatio. C, minimalistiset kirjastot, shell ja tietty minimijoukko apuohjelmia. Vain tekstiä; ei mitään grafiikkaan liittyvää. + Base definitions Intro: (mm. XBD Sec. 1.7 "Portability"), Modulaarinen rakenne, laajennukset ja marginaalihuomioiden formaatti. ** Luento 5: Tiedosto, lähdekoodi, kääntäminen, konekieli, debugger Pyöritään luennoilla sen jälkeen hetken verran laitteistorajapinnassa niin konkreettisesti kuin pystytään. Lähdetään sitten hiukan nousemaan sieltä kohti ohjelmistorajapintoja asteittain. - Demo 3:n esittely; tehdään samoja asioita, joita siinä demossa on tarkoitus omin käsin toistaa ja toivottavasti myös miettiä läpi.. ympäristömuuttujat, argumentit, kieliasetukset, C-ohjelman kääntäminen. - Konekielisen ohjelman suoritus. "Hei maailma" taas kerran, tällä kertaa C-kielellä. Toteutus: + tehdään shellissä hakemisto tämän vuoden esimerkkikoodeille + vaihdetaan hakemistoon + editoidaan yhdessä screen-ikkunassa ja kokeillaan toimintaa toisessa + raapustellaan koodi sisään alusta lähtien + kokeillaan kääntämistä ja ajamista - Lähdekooditiedoston sisällön katselua hexdumpilla (ja ehkä myös POSIXin määräämällä oktaalivedostajalla "od"). Normaali tekstitiedostohan se vain on.. - Katsotaan tiedoston metatietoja (jotka on tallessa eri paikassa kuin tiedoston sisältö - komennot "ls -l" sekä "stat"); myös tiedoston nimi ja osoite hakemistopuussa on erillinen sen sisällöstä, eikä nimellä ja sisällöllä ole teknisesti tekemistä keskenään. - Tutkitaan mm. rivinvaihtojen ja skandinaavisten kirjaimien kuvaamista tekstitiedostossa. Mainittakoon UTF-8 -merkistökoodaus (yksi Unicoden koodaus). Ehkä myös ASCII sekä POSIXin minimaalisin merkistökoodaus. - Jotta ohjelma voidaan ajaa, se pitää kääntää C-käntäjällä. Katsotaan käännetyn, suoritettavan ohjelmakooditiedoston (ELF-formaatti) sisältöä hexdumpilla ja etsitään sieltä kohta, jossa "Hello world" löytyy selväkielisenä. - gdb -debuggeriohjelma: bitti bitiltä, tavu tavulta, helloworldin pääohjelmassa suoritettavat konekieliset käskyt ja vasemmassa laidassa muistiosoitteet, joissa ne ovat tallennettuna silloin, kun ohjelma on käynnissä. (Huom: tässä kohtaa puhutaan vahvasti laiterajapinnasta, johon POSIX _ei_ ota kantaa; niinpä työkalut ovat sidoksissa GNU-tuotoksiin, tiedostoformaatit Linuxiin, ja konekieli AMD64 prosessoriarkkitehtuuriin, jotka meillä yliopiston palvelimelta löytyvät) - (Kenties.. ja toki kyllä..) palautettiin ohjelmistoon perinteinen luennoitsijan elvistelysetti.. eikäs kun yksi esimerkki kurssin opeista, joka saattaa joitakuita motivoida. Mainitaan muitakin käyttökohteita reaalimaailmassa. ** Luento 6: Ohjelman argumentit ja virhekoodi, ympäristö, debuggeri, konekieli Info: Seuraava luento sattuu erityispäivän päätteeksi... - Tutkimuksen avoimet ovet on kaikille suositeltava tapahtuma: https://www.jyu.fi/it/uutiset/tiedekunta/avoimetovet - Pyritään aloittamaan luento 16:15 - 16:30, mutta varmistetaan, että käydään ensin nauttimassa tapahtuman tarjoiluista. Ilmoittautukaahan mukaan; huomennakin ehtii vielä ilmoittautua. Asiaan... Ohjelman toimintaympäristö: argumentit, ympäristömuuttujat (demo 3:n asiaa). - Lavennetaan "hei maailmaa" käyttämään argumenttejaan. - POSIX-vartti? Mitä POSIX sanoo seuraavista: shellin syntaksi, komennon/sovelluksen virhekoodi, ympäristömuuttuja, argumentti (littyvät demoihin 1-3). Jatketaan "Hei maailma" -ohjelmasta. Kokeillaan huvin vuoksi ja löytämisen ilon kannalta. Konekielisen ohjelman suoritus. "Hei maailma" jatkuu. Uusia esimerkkejä debuggerilla: - Askeltaminen lähdekoodirivi kerrallaan, "step" + mitä tapahtuu, kun askelletaan ohjelman "lopun" ohi eli main()-aliohjelman returnin ja viimeisen aaltosulun jälkeen? (havaittiin, että päädytään C:n standardikirjaston puolelle, josta järjestelmäämme ei nyt ole asennettu lähdekoodia tai debuggaustietoa, joten debuggeri havaitsee että se ei voi nyt paljoa enempää näyttää ja antaa standardikirjaston hoitaa ohjelman lopputoimet.) + katsottiin AMD64-manuaalia: * Idea konekielisten tavujen muodostumisesta [Huom: luennolla äkkiseltään tehty "arvaus" oli epätarkka, kuten oletinkin, ts. tarvittaessa tutki asiaa itse suoraan manuaalista] * Esimerkki käskyn esittelystä, "MOV" - Askeltaminen konekäsky kerrallaan, "stepi" (step instruction). Havaintoja: + Tulostusrivin kohdalla alustakirjasto tekee paljon vaikka mitä. + Debuggerissa voi pyytää tällaisen toisten tekemän ei-kiinnostavan aliohjelman suorittamista sen loppuun saakka komennolla "finish". - Askelletaan heimaailman assembler-versio käsky kerrallaan ja tarkkaillaan muutoksia rekistereissä kunkin käskyn jälkeen: + GDB:n käsky "stepi" askeltaa konekielinen käsky kerrallaan, "disassemble" näyttää koodin ja kohdan, missä ollaan menossa. + prosessin konteksti eli prosessorin rekisterien sisällöt: gdb:n käsky "info registers" näyttää kaikki sovellusohjelman käytössä olevat yleis- ja toiminnanohjausrekisterit. Onko prosessorissa näiden lisäksi muita rekistereitä? Kyllä on, joitain kymmeniä kappaleita. Manuaali kertoo näistä totuuden ja luentomoniste kiteyttää suomeksi oleellisimmat pääkohdat. + Katsotaan luentomonisteen listaa x86-64 -prosessorin yleisrekistereistä. [Videon lopussa ylimääräisiä kysymyksiä assemblerista, jos sattuu kiinnostamaan... virallinen osio päättyi puolentoista tunnin kohdalla.] ** Luento 7: Prosessi, virtuaalimuistiavaruus, osoitteen tulkinta, MMU Tänään lyhyempi luento, johtuen Tutkimuksen avoimet ovet -tapahtumasta. - Luennon alussa oli erikoispäivän kunniaksi pieni esimerkki shellin käyttämisestä tiedonlouhintaan liittyvässä tutkimuksessa: + Alustava kokonaiskuva ennen näkemättömästä datasetistä: minkä muotoinen tiedosto, kuinka paljon, miten jakautunutta (karkeasti ottaen) + Erotinmerkin muuttaminen (tässä pilkku -> välilyönti), mikäli halutaan ladata käsittelyyn ohjelmalla, jolle alkuperäinen erotinmerkki ei käy. Vastaavasti voisi muuttaa myös esim. desimaalierottimen. + Shellin perustyökaluilla pystyy tekemään paljon muutakin hyödyllistä ensivaiheessa, ennen siirtymistä varsinaisen tutkimusohjelmiston käyttöön. + Todellisessa tilanteessa data voi tulla asiakkaalta hyvinkin kummallisessa muodossa, jota ei suoriltaan pysty lataamaan työkaluihin, eikä asiakkaan edustaja välttämättä itse edes tiedä, mikä tiedostomuoto on. Ensimmäinen vaihe voi siis hyvinkin olla "reverse engineering" -tyylistä. - C:llä, assemblerilla ja debuggerilla vielä hetki: + Vastauksia yleisökysymyksiin: * Miksi debuggeri näyttää rivien alussa muistiosoitteet disassembly-tulosteessa? Vastauksessa käytiin läpi tätä sekä muita disassemblyn ominaisuuksia. * Ovatko "disassembly /r":n näyttämät konekieliset tavut mukana "executablessa" eli suoritettavassa ELF-muotoisessa ohjelmatiedostossa? Kyllä ovat. * Edellinen kysymys johti luontevasti esimerkkiin debuggerin komennosta "x" (eli "eXamine"), jolla voi tutkia ladatun ohjelman muistia nimenomaan halutun muistiosoitteen kohdalta. Esimerkki: Varmistettiin, että osoitteeseen 0x400000 on ladattu ohjelmatiedoston alku eli jo aiemmalla luennolla nähty pötkö, joka alkaa ELFiä käyttävissä järjestelmissä aina samoilla neljällä tavulla 0x7f, 'E', 'L', 'F'. + Relevantti kysymys (ja vastaus!) prosessien virtuaalimuistista. * Jokaiselle prosessille luodaan oma virtuaalinen muistiavaruus, eli osoitteisto 0..MAKSIMI, jotka prosessorin muistinhallintayksikkö (MMU) kartoittaa automaattisesti fyysisiksi osoitteiksi. Yksi käyttöjärjestelmän tehtävä on tiedottaa prosessorille kunkin prosessin muistikartta eli osoitteiden muuntaminen virtuaalisista fyysisiksi. Tähän palataan kokonaisen luennon verran myöhemmin. * Ohjelman tyypilliset alueet (koodi, data, keko, pino) sijoitetaan yleensä tiettyihin alueisiin prosessin virtuaalimuistia. + Kysymys aiheesta "Second level address translation (SLAT)", joka liittyy virtualisointiin. Käytettiin pari minuuttia keskusteluun etäkäyttökoneidemme (mm. jalava, halava, itka203-testi, ...) todellisesta luonteesta: Ovat isossa räkkilaitteessa toimivia virtuaalikoneita, joita voi luoda muutamalla klikkauksella tarvittaessa lisää. - Sitten täsmennetään tekninen ymmärrys käyttöjärjestelmän kutsurajapinnasta (System call interface): + Käyttöjärjestelmäkutsu exit() matalan tason C-apukirjastosta. + Suora Linuxin käyttöjärjestelmäkutsu, myös tuttavalliselta nimeltään "exit()". Ensimmäinen toteutus C:n epästandardina inline-assemblynä. Ei jatketa tällä tiellä yhtään pidemmälle... Toimii samalla tavoin vain yhdellä kääntäjällä (meillä GNU C), yhdellä käyttöjärjestelmällä (meillä Linux) ja yhdellä prosessoriarkkitehtuurilla (meillä x86-64). + Puhdas Assembler-ohjelma. Motivoidaan kerroksittaisten abstraktioiden käyttöä. - Käyttöjärjestelmäkutsun toimintaperiaate (esimerkki helloasm.s): + AMD64:n konekielikäsky 'syscall' keskeyttää prosessin oman suorituksen ja "siirtää kontrollin" käyttöjärjestelmän koodin puolelle. Käyttöjärjestelmä tekee sitten, mitä haluaa - toivottavasti sen, mitä sen rajapintadokumentaatiossa ilmoitetaan. Käyttäjän prosessi jatkuu sen jälkeen, kun käyttöjärjestelmä on toteuttanut pyydetyn palvelun. Tietysti jos palveluna pyydetään prosessin itsensä päättymistä eli kutsu on exit(), niin paluuta suoritukseen ei koskaan enää pitäisi olla. + Luennoitsija osasi tehdä Helloworldin tarvitsemat käyttöjärjestelmäkutsut write() ja exit() katsomalla tästä varsin helppokäyttöisestä, Googlen kautta helposti löytyneestä, kokoelmasta, mitä missäkin rekisterissä pitää olla siinä vaiheessa, kun syscall-käsky tehdään nykyisessä Linuxissa: https://filippo.io/linux-syscall-table/ + Käyttöjärjestelmäkutsu on erittäin primitiivinen toimenpide, ja puhtaassa apukirjastoja käyttämättömässä assembler-ohjelmoinnissa välttämätön. Nyt kun sen toiminta on kertaalleen nähty, hyväksytään se, että päällä on esimerkiksi C-kielellä tehtyjä matalan tason apukirjastoja sekä lisäksi esimerkiksi POSIX-yhteensopivuuskirjasto, jos jokin käyttöjärjestelmä pyrkii olemaan kyseisen standardin mukainen. - Yleisökysymys: Jos Linuxissa tiedosto numero 1 ohjautuu standarditulosteeksi, niin ohjautuuko tiedosto numero 2 standardivirhetulosteeksi? Kylläpä vain. Yleensä tietenkin on syytä käyttää C-standardin nimiä "stdout" ja "stderr", eikä minkään tietyn järjestelmän määrittämää kokonaislukunumerointia. ** Luento 8: Konekieli ja käyttöjärjestelmäkutsu, käyttäjätila, käyttöjärjestelmätila Luennon lopuksi demo 4:n ensiesittely tosi lyhyesti. Seuraavalla luennolla sitten tarkemmin. Edellinen loppuun: - Tavujärjestys (byte order), jos jotakuta on ihmetyttänyt (AMD64:ssä little-endian) - ohjelman jäljitys strace -apuohjelmalla, joka näyttää kaikki tehdyt järjestelmäkutsut. Ero C-kirjastojen kanssa käännetyn koodin ja puhtaan assembly-käännöksen välillä. Vastaavia jäljitystyökaluja lienee olemassa muissakin käyttöjärjestelmissä kuin esimerkissämme Linuxissa. - Merkkijonon ilmeneminen laiteläheisessä ohjelmoinnissa ja siten esim. C-kielessä: muistiosoite nollaan päättyvän tavujonon alkuun. + varmistutaan asiasta debuggerilla - komento "x/s" + Jos 2016 ei yleisöstä tule tätä kysymystä, vastataan siihen silti: Miten debuggeri tietää merkkijonon pituuden? Sama kysymys olisi, että miten tietokone tietää merkkijonon pituuden? Vastaus on: eivät ne tiedä sitä. Ei ne tiedä mitään, vaan niillä on käytössään peräkkäisiä muistiosoitteita ja jokaisen osoitteen kautta pääsee käsiksi kerrallaan yhteen, kahteen, neljään tai kahdeksaan tavuun (riippuen katsotaanko 8-, 16-, 32- vai 64-bittistä lukua käsittelevää konekielistä käskyä; jotkut käskyt käsittelevät vielä näitäkin pidempiä tavujonoja) + Katsotaan vielä hiukan AMD64-prosessorimanuaalia. Pääosiot ovat "1: Sovellusohjelmoijan käsikirja", "2: Järjestelmäohjelmoijan käsikirja" sekä "3: Käskyreferenssi". Viikko sitten silmäiltiinkin jo hiukan käskyn MOV referenssiä.. Katsotaan vielä joku toinen yleinen, vaikkapa SUB ja CMP. + Katsotaan vielä käyttöjärjestelmäkutsun eli SYSCALL-käskyn selitys pseudokoodeineen. Ristiviittaukset johtavat myös Osan 2 (System Programming) puolelle, ja sieltä takaisin SWAPGS-käskyyn. Linuxin uusimman version toteutus käyttöjärjestelmäkutsun "vastaanottopuoleksi", arvatenkin GNU Assemblerilla toteutettuna: http://lxr.free-electrons.com/source/arch/x86/entry/entry_64.S#L103 Eli tasan tarkkaan se, mitä prosessorin käsketään tehdä välittömästi sen jälkeen, kun käyttäjän prosessin SYSCALL on takana päin nyky-Linuxissa. Tämä osio vaatii mm. tiettyjen rekisterien tilan tallentamista, joten se on pakko toteuttaa konekielellä. Järkevää tämä on tietysti vain symbolisena, ihmisen ymmärtämänä, assemblerina, jonka syntaksi mukailee prosessorin dokumentoitua käskykanta-arkkitehtuuria. + Aliohjelman ja silmukoiden suorittamiseen konekielessä palataan demossa 5, kun ensin on katseltu välissä lisää C-kieltä. Yhteenveto tietokoneen perustoimintaperiaatteesta: prosessori suorittaa yksinkertaisen käskyn, joka muuttaa kontekstia (ts. rekisterien sisältöä) -- vähintäänkin käskyosoiterekisterin sisältönä tulee olemaan aina seuraavaksi suoritettavan käskyn osoite. Johtopäätös: konekieli, assembly ja käyttöjärjestelmäkutsu ovat tavattoman yksinkertaisia ja "putkiaivoisia" rajapintoja. Niiden käyttäminen ja alustasta riippumattomien ohjelmien tekeminen edellyttää korkean tason kieliä sekä kerroksittaista apukirjastoa, jonka välttämättömät ominaisuudet esim. POSIX määrittelee tietyllä abstraktiotasolla. Ts. "yksinkertainen != helppo". Pidetään konkretia mielessä, mutta käytetään jatkossa pääasiassa POSIXin määräämiä palvelukutsuja. Osa niistä on yksi-yhteen Linuxin kutsurajapinnan kanssa, koska molemmat pohjautuvat samaan historialliseen pohjaan (ikiaikainen unix). Osa voi kuitenkin tarvita lisäoperaatioita yhteensopivuuskirjaston koodissa. Täydellinen totuus on Linuxin ja GNU C-kirjastojen nykyversioiden lähdekoodissa; me luotamme POSIXissa sovittuun sovellusrajapintaan, ja katsotaan sitten, tuleeko mahdollisesti ongelmia suorakäyttökoneidemme "jotakuinkin" POSIX-yhteensopivan Linux-jakelun kanssa. Yleisökysymysten pohjalta pari "teaseria" tulevan viikon asioista: - Kysymys keskeytyksistä: suora vastaus... tällä tai ensi viikolla päästään käsittelemään ulkoisia keskeytyksiä, jotka valaisee asian taustoja. Todelliseen toteutukseen tarttuminen tulee vaatimaan spesifikaatioiden lukemista, jonka osaaminen on yleinen tavoite koulutuksessamme kandi- ja maisteritasoilla. - Kysymys moniydinprosessorin käyttöasteen hyödyntämisestä. -> Saattaa liittyä säikeistykseen. Kysyjän ongelma näyttäytyy siten, että tietty Javalla toteutettu sovellus tuntuu käyttävän hyvin vähän prosessoriaikaa, vaikka sitä pitäisi kuusiytimisessä prosessorissa olla käytettävissä enemmän. Eri asia on, että osaako käytetty sovellus ns. säikeistää oman toimintansa kunnolla, ja osaako käytetty Java-virtuaalikoneisto hoitaa säikeet tehokkaasti eri ytimille. Säikeistä tullaan puhumaan jatkossa noin luennon verran, mistä (jälleen) saa peruskäsityksen ongelmaan liittyvästä koneistosta, mutta varsinainen ratkaisu todennäköisesti vaatii enemmän selvittelyä alustan toteutuksessa mahdollisesti olevista pullonkauloista. Ohjelman lataamiseen liittyvät tiedostomuotoasiat: - ELF-tiedoston formaatti (katsotaan speksiä päällisin puolin PDF:istä - 32bit ja 64bit); - Havainto: Myös ELF-spekseissä on C-kielellä määriteltyjä "typedef struct{...sisältö...} TyypinNimi" -rakenteita. Käyttöjärjestelmän konkreettisen toiminnan ymmärtäminen edellyttää jonkinlaista kuvaa C-ohjelmoinnista, ei kiertotietä! - verifioidaan vaikka helloasm-ohjelmasta, että ELF-dokumentissa kuvaillut tiedot ovat oikeilla paikoillaan suoritettavassa objektitiedostossa ja toisaalta myös debuggerin mukaan käynnistetyn ohjelman muistissa. Ajan säästämiseksi jätettiin "uskon asiaksi" ja oman kokeilemisen varaan. Kyllä ELF-tiedosto sisältää vilkaistun speksin mukaiset asiat, jotta on toiveita, että se oikeasti toimiikin. - selväkielisempi listaus ELFin sisällöstä: objdump -x a.out tmv. Havaitaan mm. selväkielisten symbolien taulukko. Ohjelman vaatima sijaintipaikka muistissa osoitteessa 0x400000, aloituskohdan paikka jne. Miksi 0x400000 eikä 0? Muistelisin lukeneeni, että tällä sopimuksella yritetään välttää pahimpia virheitä "Null pointer reference" -ilmiössä eli vahingossa nollaan tai lähelle osoittavien muistiosoitteiden halutaan mieluummin kaatavan ohjelman kuin tekevän odottamattomia asioita. Kartoittamattomalle alueelle osoitteen 0x400000 alapuolelle osuva muistiviittaus aiheuttaa välittömästi prosessorin suojausvirheen. (Uskalias yksilö voi toki sopimuksen vastaisesti ladatuttaa ohjelmansa pienempään tai isompaan osoitteeseen - se on vain yksi kokonaisluku ELF-tiedostossa... Luennoitsijan harraste-ekskursiot pienten "demoscene"-ohjelmien maailmassa sisältävät mm. latausosoitteen vaihtamiseen sopivasti.) Demo 4:n alustava esittely: Kyseessä on "minimaalinen suomenkielinen tutoriaali C-kieleen, olettaen että lukija tuntee jonkin oliopohjaisen C:hen perustuvan kielen, esim. C# tai Java. Saa alkaa tekemään demoa 4. Siihen tullee menemään eniten aikaa kaikista demoista (jos se tehdään ajatuksella, kuten tarkoitus olisi!). Palautettava osio on jälleen paljon pienempi kuin arvosanaan 1 tähtäävä minimiymmärrys, saatikka arvosanaan 5 tähtäävä kokonaisymmärrys. HUOM: Historia on osoittanut, että Ohjelmointi 1 ja jopa Ohjelmointi 2 on ollut mahdollista kahlata läpi ilman kykyä ratkaista tässä demossa vaadittua pientä algoritmista "pähkinää". Ei kannata hätääntyä, jos ei meinaa onnistua... vaan mitä kannattaa tehdä? Kysyä apuja! Ja muistakaa Tomin huomio aiemmalta luennolta: kyllä se on sangen epäkohteliasta palauttaa koodi, joka ei edes käänny syntaksivirheiden vuoksi. Eli nyt, kiitos, kunnioittakaa demon tarkastajaa sen verran, että palautatte version, joka kääntyy (ja parhaimmillaan tietysti myös tekee sen, mitä pyydetään). ** Luento 9: C-kieli, linkitys, aktivaatiopino. (DONE: Yleisön pyynnöstä demotehtävien tekstiosuudet on nyt julkaistu JYU:n verkon ulkopuolelle tuolla, niin tarvii harvemmin säätää VPN:n kanssa: http://users.jyu.fi/~nieminen/kj16/demovedokset/ ) Demon 4:n asioiden tarkempaa esittelyä suoraan demoesimerkkinä olevan koodipaketin pohjalta: - C-kieli, esikääntäjä ja makrot - objektitiedosto, kirjasto, kääntäminen, lataaminen ja linkittäminen (staattinen & dynaaminen, ts. omat ohjelmamoduulit & libm.so -matematiikkakirjasto ja muut, tuhannet, libjotakin.so:t) - useita C-koodisia ohjelmamoduuleita, jotka käännetään erillisiksi objekteiksi ja linkitetään lopuksi yhteen. - makefile ja make-apuohjelma: idean esittely suhteessa graafiseen IDEen. [POSIX-huomio: Uskotaan, että POSIX määrittelee make -apuohjelman olemassaolon ja peruskäyttötavan. Käytetään kuitenkin suosiolla maken GNU-toteutusta. POSIXin "rationale" -osiosta löytyy perustelut, miksi näin on ihan suotavaa tehdä] - ABI eli Application Binary Interface; lataaminen ja linkittäminen; lopullisten osoitteiden asettaminen ja pyydettyjen kirjastojen sisällyttäminen ohjelman muistiavaruuteen. Jaetut eli dynaamisesti ladattavat kirjastot. - Erittäin hyvä kysymys jaettujen kirjastojen (.so /.DLL) "järkevyydestä": Luennoitsija väittää, että jaetuissa kirjastoissa on enemmän plussia kuin miinuksissa, mutta samalla vakuuttaa, että mitään väitettä ei kannata ottaa kritiikittömästi vastaan. Tosiasia on, että aina pitää tehdä tilanteen mukaiset ratkaisut. Toinen tosiasia on, että käytännössä yleiskäyttöisistä kirjastoista pyritään tänä päivänä useimmiten tekemään mieluiten jaettuja objekteja (Windows-nimeltään dynaamisia kirjastoja). Isompi ohjelma, jossa on vaikkapa aliohjelmakutsuja ja silmukoita: - Askellettiin demo 4:n esimerkkikoodia lähdekoodirivi kerrallaan debuggerilla. Havainnoitiin kutsupinoa, jonka tilanteen saa gdb:ssä näkyviin komennolla "backtrace" tai lyhennettynä "bt". Muita nimiä ainakin aktivaatiopino, suorituspino. Aliohjelmien ja pinon käyttö (osin jo myös demon 5 aihepiiriä): - muistiavaruus ohjelman näkökulmasta: koodi (nähty jo aiemmin), pino (nähdään nyt), data (ohjelman tekemisen yhteydessä alustettu), keko eli dynaamiset eli tarpeen mukaan varattavat pienet tai isommatkin muistialueet. - aliohjelmakutsu, kutsupino - debuggerin näkymä kutsupinoon, 'backtrace'-komento näyttää pinoon kullakin hetkellä kertyneet aliohjelma-aktivaatiot. - klassinen pinokehysmalli, aktivaatiotietueen rakentuminen pinon päälle: kutsuva koodi pinoaa parametrit, call-käskyn suoritus pinoaa automaattisesti paluuosoitteen, kutsuttu koodi pinoaa edeltävän aktivaatiotietueen kantaosoitteen (BP) talteen, kiinnittää oman BP:n ja varaa omille paikallisille muuttujilleen tilaa vähentämällä SP:stä sen verran kuin paikallinen data tarvitsee tavuja. Ylösalaisin piirretyssä kuvassa (muistiosoite 0 kuvan ylälaidassa) pino kertyy visuaalisessa mielessä ylöspäin. - Huomautus aktivaatiopinosta: Pinoon tallennetuista BP-osoitteista muodostuu viittausketju, jonka kautta löytää aina pykälää alemman aktivaatiotietueen. Pääohjelmassa tässä kohtaa on nolla eli "NULL-viite", mistä tiedetään että pinon pohja on löytynyt. Tämä on yksi konkreettinen esimerkki abstraktin "listamaisen" tietorakenteen toteutuksesta muistiosoitteilla, jotka niin sanotusti linkittävät mielivaltaisen kokoisia tietueita aina "seuraavaan" eli tässä tapauksessa aiemmin kutsutun aliohjelman aktivaatiotietueeseen. - Monisteen sarjakuvassa on esitetty kutsuvaiheen operaatiot. Paluuvaiheen operaatiot on tehtävä käänteisessä järjestyksessä. Monisteen tekstissä nämä on kuvailtu, ja demo 5:n kohdalla nähdään debuggerin kautta konkreettinen toteutus AMD64:llä. - Lisähuomautus: Aliohjelman kutsuminen ja sieltä palaaminen tulee tietenkin määritellä konekielen tasolla laitteisto- ja käyttöjärjestelmäkohtaisessa ABI-sopimuksessa (Application binary interface), jotta konekielelle käännetyn ohjelman on mahdollista käyttää konekielisiä jaettuja kirjastoja. Yhden ohjelman sisäisiä kutsuja saa kukin tietysti tehdä ihan miten haluaa, joten esimerkiksi koodin automaattinen optimointi saattaa tehdä aivan kummallisen näköisiä kutsuja, joita on hankala ymmärtää ja debuggailla disassemblyn perusteella. Kääntäjän vivut "-g -O0" tekevät ymmärrettävämpää jälkeä. Demossa 5 esimerkkikoodissa on ylimääräinen aliohjelmakutsu, joka ei tee mitään muuta hyödyllistä kuin estää kääntäjää optimoimasta liikaa. ** Luento 10: Ohjelman jälki, aktivaatio, rekursio. Historiakatsaus. Kerrataan tässä kohtaa yleisökysymys, joka viikko sitten tuli vasta varsinaisen luentoajan jälkeen, videoinninkin loputtua. Tämä tulee ihan pian tarkemmin, mutta otetaan silti jo alustava näkemys asiaan: - muistihierarkian käytännön toiminta: laitteisto tosiaankin hoitaa; sovellukselle päin näkyy peräkkäisiä tavun eli 8 bitin mittaisia muistipaikkoja, joilla on omat, peräkkäiset osoitteensa. Vilkaistaan kurssin loppupuolelle (lukuun Muistinhallinta): AMD64:ssä on nelitasoinen hierarkinen "kartasto", jonka kautta konkreettinen osoitteentulkinta virtuaalisesta fyysiseksi tapahtuu. Idean tasolla meille riittää ajatella yksitasoista ns. sivutaulua, jollaisen osaaminen on yleensä ollut tenttikysymyksenäkin. Eli ikään kuin ajateltaisiin vain AMD64:n viimeistä taulukkotasoa, jonka nimi oikeassa manuaalissakin on "Page table". Idean tasolla riittää myös ajatella paljon lyhyempiä muistiosoitteita kuin esim. AMD64:ssä oikeasti on. Joka tapauksessa muistiosoitteen bittijonon alku ilmoittaa, mille sivulle osoitus kohdistuu, ja loppuosa, esim. 12 bittiä ilmoittaa tarkan osoitteen kyseisen sivun sisällä. Fyysinen muisti on jaettu sivukehyksiin. Sivutaulujen (ja tarvittaessa monitasoisten hakutaulukostojen) luonti on käyttöjärjestelmän muistinhallintaosion vastuulla. Se tekee sen prosessorin ja MMU:n manuaalin määrittelemillä keinoilla. Toki itse taulut ja "kartastot" ovat määrämuotoista dataa, joka sijaitsee tietokoneen muistissa (käyttöjärjestelmän hallitsemalla alueella), missä kaikki muukin. Esim. "AMD64 System Programmer's Reference" kertoo kaiken siitä, miten näitä tauluja käytetään. Perinteinen "kaikenlaskija" -esimerkki demonstroimaan aikakatkaisun tarvetta. Demo 5:n olennainen sisältö, eli aliohjelma-aktivaatio ja konekielinen ohjelman suoritus asiana loppuun: - Ohjelman jälki (engl. "trace"; mm. Stallingsin kirjan terminologiaan vedoten) eli varsinaisten suoritettujen käskyjen ketju. Tietyssä muistipaikassa oleva konekielikäsky voi sisältyä jälkeen useita kertoja (toistuvat silmukat, useasti kutsutut aliohjelmat). Toisaalta tietty konekielikäsky ei sisälly jälkeen lainkaan (esim. tiettyä aliohjelmaa ei tarvitse kutsua tai tietty ehto ei koskaan täyty jossakin ehtolauseessa). - Reunahuomautus: Kaikkein tiukimmat laadunvarmistusmenettelyt vaativat muiden seikkojen ohella, että testien koodikattavuus eli "code coverage" on 100%. Tämä tarkoittaa, että testiohjelman jäljen tulee kulkea jokaisen konekielisen käskyn läpi vähintään kerran. Eli testikeisseissä on oltava oikeita ja vääriä syötteitä sekä simuloituja toimintahäiriöitä niin paljon, että kaikki if-then-else -vaihtoehdot ja catch-lohkot käydään testin aikana läpi. Tämä on kallista puuhaa, joten 100% koodikattavuus on järjetön muiden kuin potentiaalisesti ihmishenkeä uhkaavien ohjelmistojen testaamisessa (mm. siviililentokoneiden ohjaus, tietyt lääketieteelliset instrumentit). - Aliohjelmakutsu siten kuin demo 5:ssä käsitellään. - Rekursio (Kokonaisluvun kertoma rekursiivisesti): saman aliohjelman aktivaatiot päällekkäin pinossa. - Jälki, laitekeskeytykset ja reaaliaika: Nykyjärjestelmissä sovellusohjelma ei tiedä, mitä kahden konekielikäskyn välissä tapahtuu ja kauanko siinä kestää. Käyttöjärjestelmän koodi voi estää estää tai sallia uudet keskeytykset, joten "atomisen toimenpiteen" toteutuminen sovellusohjelmassa edellyttää käyttöjärjestelmäkutsun tekemistä. Ja sitten: Katsaus tietokoneiden ja käyttöjärjestelmien symbioottiseen historiaan. Jotta voidaan katsoa nykypäivästä eteenpäin, täytyy tietää, mistä tähän ollaan tultu ja miten! Ensimmäiset tietokoneet 1940-1950 -luvuilla eivät moniajoa mahdollistaneet, mutta siitä se kehitys sitten havaittujen ongelmien ja ratkaisujen kautta lähti... ensimmäisenä ohjelmointikielten ja kääntäjien rakentelulla, suojatun tilan ja käyttöjärjestelmätilan toteuttamisella prosessorin ominaisuutena sekä keskeytysten, mm. aikakatkaisun löytymisestä prosessorin piirteenä, joka keskeyttää sovelluskoodin ja siirtää prosessorin käyttöjärjestelmätilaan aina, kun laitteistossa tapahtuu jotakin uutta. Lähes 70-vuotisen historiikin kautta perusteltakoon tarpeet vuorontamiseen, moniajoon, muistin ja muiden laiteresurssien hallintaan sekä muihin toimenpiteisiin, joihin käyttöjärjestelmää nykypäivänä tarvitaan. Merkkipaaluja tietokoneiden ja käyttöjärjestelmien kehityksessä vuosien varrella. Kehitys nykymuotoisia käsitteitä ja toimintamalleja kohti tapahtui erityisesti 1960-luvun aikana: - hukka-ajan poisto: keskeytykset, I/O:n odotus ja aikakatkaisu - Prosessorin täytyy voida toimia ainakin kahdessa eri tilassa: suojatussa ja rajoitetussa (tietyt muistiosoitteet ja I/O-toimenpiteet kiellettyjä) käyttäjän tilassa ja rajoittamattomassa käyttöjärjestelmän tilassa; tilojen välinen siirtymä täytyy olla mahdollista - erityisesti meneillään olevan suorituksen keskeyttäminen esimerkiksi aikakatkaisuna täytyy olla mahdollista. Myös käyttäjtilan ohjelmalla täytyy olla mahdollisuus pyytää siirtymää käyttöjärjestelmän palveluun ("system call") jolloin prosessorin tilan on vaihduttava. ** Luento 11: Prosessi, "säie", resurssit, haaroitus ja käynnistys Mihin jatkokursseihin seuraavaksi käsiteltävät aiheet johtavat? No kaikkeen ohjelmistotekniikkaan, mutta ks. esimerkiksi seuraava tämän vuoden kesäkurssi Korpista: https://korppi.jyu.fi/kotka/course/student/generalCourseInfo.jsp?course=196089 Huomatkaa esitietokysely, jos ilmoittaudutte kys. kurssille!! Ihan pari historiallista artikkelia: - lokaalisuusperiaatteen historiaa lähdemateriaalista vilkuillen (kirjallisuusviite kiinnostuneille, lisämateriaalia, ei pakollinen: http://denninginstitute.com/pjd/PUBS/CACMcols/cacmJul05.pdf ... edistyneenä osaamistavoitteena on oppia löytämään ja lukemaan tieteellisiä artikkeleita vuosien varrelta) - katsottakoon läpi myös alkuperäinen UNIXin, C-kielen ja putkitusta tukevan shellin uutuuksia hehkuttava artikkeli "The UNIX time-sharing system" vuodelta 1974. Sitten periaatteessa luentomonisteen järjestyksessä etteenpäin... Prosessorin suoritussykli: - käskyn ja operandien nouto, suoritus, tulosten tallentaminen JA mahdollinen ohjelman itsensä aiheuttama (syscall-pyynnöllä tai laittoman/mahdottoman käskyn seurauksena) tai ulkopuolelta tuleva keskeytys. Keskeytys on mahdollinen minkä tahansa käskyn jälkeen, jos sen aiheuttaa ulkopuolinen, kontrolloimaton, lähde. Käytännössä ainoa koodi, joka voi tapahtua ilman keskeytyksiä, on alkupuoli käyttöjärjestelmän keskeytyskäsittelijästä - kunnes kyseinen koodi itse sallii uudet keskeytykset. Luentomoniste kertoo hieman lisää yksityiskohtia. - "FLIH", eli mitä keskeytyksen tullessa tapahtuu prosessorissa ennen seuraavan käskyn noutoa. Yhdenaikaisuus, Prosessi: - prosessin käsite yhteenvetona aiemmasta: muistiin ladattu ja käynnistetty, suorituksessa oleva 'kuva' ohjelmasta. - Yllätys-POSIX-vartti: Miten POSIXin Base Definitions -osion termimäärittelyissä kuvaillaan termi "Process"? Vautsi... Pystytään jo ymmärtämään suurin osa tästä kuvailusta tähän asti käsiteltyjen esitietojen kautta! Määrittelyssä tulee jo mukavasti esille "säie", mikä tarkoittaa yhtä ajan suhteen etenevää suorituskohtaa ohjelmassa. Prosessilla on POSIXinkin mukaan aina vähintään yksi "säie", joka alkaa ohjelman alusta ja päättyy ohjelman loppuessa. Säie muodostaa yhden konekielisen jäljen, eli peräkkäin suoritettujen käskyjen sarjan. Tässä päästään jo pakosti uumoilemaan seuraavaa asiaa, eli että prosessilla voi olla yhden sijasta useampia säikeitä. Prosessilla on vanhempi, mahdollisesti myös lapsia ja sisaruksia - riippuen mikä prosessi on pyytänyt luomaan uusia. Sillä on identiteetti (vähintään ID-numero) sekä käynnistävän käyttäjän ja mahdollisesti ryhmän identiteetit (vähintään ID-numerot). Lisäksi sillä on oma muistiavaruus, joka sisältää koodi-, data-, pino- ja kekoalueen sekä dynaamisten kirjastojen koodialueita. Nykyisin myös käyttöjärjestelmän tarvitsemat alueet on liitetty jokaisen prosessin virtuaalimuistiavaruuteen. Mitä muuta liittyy prosessiin? - resurssin käsite: laitteiston osat, tiedostot ja yhteydet, mukaanlukien prosessorin käyttöaika ja rajallinen keskusmuisti, ovat resursseja, joita käyttöjärjestelmä allokoi prosessien käyttöön niiden pyynnöstä; aiemmin mainittujen lisäksi näihinkin tietoihin on päästävä käsiksi prosessikohtaisten tietojen kautta. (Näkökulma käyttöjärjestelmään resurssimanagerina). - Prosessit käyttöjärjestelmän tietorakenteena: prosessielementti ("Process Control Block", PCB) ja prosessitaulu ("process table" / "process array") tai prosessilista (kuten Linux-toteutuksessa on). - Linuxin task_struct -tietorakenne, eli noin 450 koodiriviä (versiossa 4.4) määritelmiä siitä, mitä tietoja yhteen prosessiin kuuluu. Kiinteä linkki version 4.4 lähdekoodiin: http://lxr.free-electrons.com/source/include/linux/sched.h?v=4.4#L1378 Havaintoja: osa on kokonaislukuja, mutta suuri osa on osoittimia laajempiin tietorakenteisiin, joille on varattu muistia jostain toisesta kohtaa muistia. Suuri osa myös riippuu konfigurointivaiheessa valituista ominaisuuksista (#ifdef CONFIG_JOKIN_OMINAISUUS_MUKANA ... #endif). Kyseessä on normaali C-kielen tietorakenne, jonka sisäiset kentät ovat muistissa tallessa peräkkäisessä järjestyksessä. Huomaa mm. rakenteen määrittelyn lopussa oleva kommentti, joka muistuttaa, että x86-koneiden osalta nykyisellään viimeiseksi kirjoitetun kentän on todellakin oltava viimeinen, eikä sen jälkeen saa lisätä mitään muuta. Liukulukuja ei käyttöjärjestelmäkoodissa juurikaan ole. Esim. ajat mitataan kokonaisina nanosekunteina eikä osittaisina sekunteina tai muuta, mikä edellyttäisi muita kuin kokonaislukuja. - Prosessin tilat ja tilasiirtymät, tilakaavio. - Vuorontaja ja vuorottelu: prosessoriajan jakaminen. "Kiertojono" eli Round Robin. Odottelujonot blokatuille prosesseille. - Kontekstin vaihto laitteiston ja käyttöjärjestelmän yhteistoimintana. Koko kontekstin vaihtaminen (kaikki rekisterit + muistikartta) vaatii aikaa, joka on pois hyötylaskennasta - optimointina esim. pidemmät aikaikkunat ja modernien prosessorien "kevyet vaihdot". Harvemmat vaihdot prosessien välillä -> isompi "throughput". Pakollisena kompromissina tulee pidemmät vasteajat tai huonompi tasapuolisuus. - Prosessin luonti haaroittamalla eli kloonaamalla vanhempiprosessi (unix-pohjaisen käyttöjärjestelmän tapa luoda uusia prosesseja): Esimerkkinä ihan itse käännetty minimalistinen shell, joka odottaa komentoriviä ja osaa käynnistää käyttäjän pyytämän ohjelman. [ Tällä kurssilla tutkitaan unixmaista tapaa luoda prosesseja; jos Windows-maailman variaatio sattuu kiinnostamaan, käyttöjärjestelmäkutsun CreateProcess() rajapinta löytyy tuolta: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx ] Prosessielementin kloonaus fork():illa ja korvaaminen ladattavan ohjelman tiedoilla exec():issä vaatii "maistelua", miettimistä ja parin unen näkemistä. Tätä voi harrastaa vaikkapa vapun ohessa, joka tapahtuu vuonna 2016 tässä välissä ennen seuraavaa luentoa. ** Luento 12: IPC: signaalit, viestijono. Säikeet Alussa paikkaus viime fiikon fork() ja exec() -kuvaan. Rauhallisempi katsanto minish.c -esimerkkiin eli minimalistiseen shell-ohjelmaan. Millainen sää luentosalin ja Agoran ulkopuolella vallitsee tällä hetkellä? Komennetaanpa shellissä: curl wttr.in/Jyvaskyla Mitäs? Joku on tehnyt hauskan palvelun, josta opiskelija vinkkasi irkissä. cURL on POSIXin määrittämä apuohjelma, joka noutaa Internetin yli URLin mukaisen vastauksen palvelimelta ja ohjaa sen standardiulostuloon... "man curl" kertoo lisää. Tämä on standardimpi tapa yksittäisiin WWW-palvelinkyselyihin kuin mm. demo-ohjeissamme käytetty "GNU Wget". Kapeaan terminaali-ikkunaan ei välttämättä mahdu koko tuloste, joten luentosalissa seuraava voi olla parempi komento: curl wttr.in/Jyvaskyla 2>/dev/null | head -7 Tämä komento putkittaa curl'in tulosteen head'ille, jonka avulla voi tulostaa vain argumenttina annetun määrän ensimmäisiä riviä. Nyt curl voi joutua lopettamaan tulostuksensa kesken, kun head ei haluakaan enää lisää syötettä. Curl toteaa tämän virheilmoituksena standardivirhevirtaan, josta ei tässä komennossa olla kiinnostuneita, joten virhetulosteet ohjataan operaattorilla '2>' kankkulan kaivoon eli /dev/null'iin johon ohjatuilla tavuilla ei tehdä mitään. Asiaan. Katsotaan vielä kertaalleen viimeviikkoista minish -shelliä, ja yliopitaan se, sekä siihen liittyvät fork() ja exec() -palvelut. Monisteen kuva fork() ja exec() -kutsuista on myös korjattu viime luennon jälkeen. Oli nimittäin vähän jäänyt sisältöä matkalle ulkoasupäivityksen yhteydessä. Ja sitten uutta... Prosessien (ja säikeiden) välinen kommunikointi eli IPC, alustavasti: - engl. Inter-process communication. Yksi tärkeistä tehtävistä, joihin käyttöjärjestelmää tarvitaan. Alustavia esimerkkejä (joihin ehkä palataan): + signaalin lähettäminen pääteyhteyden näppäilyllä "päällimmäiselle" ohjelmalle, jolle syötteet ohjautuvat. + signaalin lähettäminen kill -komennolla shellistä. Signaalien listaaminen. Esimerkkisovellus: dd -apuohjelman tilannetiedon kysyminen (ei toiminut luennolla jostain toistaiseksi tuntemattomasta syystä; manuaali lupaa, että dd:n pitäisi osata napata SIGUSR1 - kumma juttu.. selvitellään..) + yksi erilainen IPC-tapa, viestijono (message queue): koodi 2016/esimerkit/l12/ -hakemistossa: chattomyself.c + toisin kuin ennakkoon määritellyillä kokonaisluvuiksi koodautuvilla signaaleilla, viestijonolla voi välittää laajempia viestejä. Nimensä mukaisesti viestijonossa on mahdollisuus jonoihin perustuvaan odotteluun. Lähettäjän ja vastaanottajan on molempien osattava löytää sama jono, ja ensimmäisen prosessin täytyy pyytää käyttöjärjestelmää luomaan uusi jono. Säie vs. prosessi: - Säie on yksi ajassa etenevä suorituskohta prosessin koodissa, joka muodostaa konekielisten suoritusten "jäljen" ja vaikutuksia dataan. - Prosessilla voidaan aina ajatella olevan vähintään yksi säie. (ks. esim. POSIXin Base definitions -luvun määritelmä termille "Process") - Jos alusta (ts. käyttöjärjestelmä ja apukirjasto) tukee useampia yhdenaikaisia säikeitä, niitä voi luoda prosessille tarpeen mukaan, esim. POSIXin säielaajennoksen kutsulla pthread_create(). Lähdekoodissa säie ilmenee aliohjelmana, jonka päättymistä voi jäädä odottelemaan esim. POSIXin kutsulla pthread_join() tai säikeen voi jättää suorittamaan tehtäväänsä "taustalle" tarvittaessa vaikka koko prosessin päättymiseen saakka, tai niin pitkään kuin säikeen operaatio ylipäätään kestää. - Suorituksen vuorottelun mielessä säie ja prosessi ovat hyvin samantyyppisiä käsitteitä: periaatteessa kaikki säikeiden avulla tehtävät asiat voitaisiin hoitaa myös luomalla prosesseja. - Säie on kuitenkin yhden sovelluksen sisäisiin tarpeisiin paljon kevyempi konsepti: se tarvitsee olennaisesti vain prosessorin kontekstin, pinomuistin ja muut suorituskohtaan liittyvät tiedot - kaikki muu, mukaanlukien koodi, keko, globaali data, avatut tiedostot, ym. ovat yhteiset säikeen omistavan prosessin kanssa. - mihin säikeitä voi käyttää? Esim. ohjelman sisäiset "tausta-ajot" (esimerkiksi videon toistaminen selaimen välilehdessä samalla kun käyttäjä voi klikkailla muita välilehtiä keskeytyksettä; suurten tiedostojen lataamiset ja tallentamiset), seinäkelloajan minimointi rinnakkaislaskennalla. - Toimintojen nopeuttaminen säikeistämällä edellyttää eri säikeiden suorittamista konkreettisesti yhtäaikaa rinnakkaisilla prosessoriytimillä. Yhdenaikainen tausta-ajo onnistuu tietysti yhdelläkin prosessorilla normaalin prosessien vuoronnusmenettelyn tapaan. - esimerkki: taulukon täyttäminen peräkkäisillä luvuilla koodit 2016/esimerkit/l12/ -hakemistossa: saikeiden_tarve.c saikeet.c - tämän maanantain cliffhanger: "kilpa-ajotilanne" eli race condition: vuoronnus voi milloin vain keskeyttää säikeen (tai prosessin) ja antaa suoritusvuoron toiselle: koodi 2016/esimerkit/l12/ -hakemistossa: race.c ** Luento 13: Kilpa-ajo, lukot, deadlock, semafori - Millainen sää ulkona? (aurinko paistaa ja lämmintä on) Teinpä itselleni näppärän alias-komennon viime viikon wttr.in-palvelun käyttöön. Aliakset ovat POSIXissa määritelty tapa tehdä itselle tosi lyhyitä komentokorvikkeita shellin interaktiivisen käytön tehostamiseksi. Tarkennetaanpa viime kerralla epäselviksi jääneet asiat: - Mitä reittiä näppäimistöllä generoidut signaalit (esim. Ctrl-C, Ctrl-Z, Ctrl-D, ...) menevät ohjelmille? (Alempana on TLDR-versio.) Pidempi vastaus arvailtuna meidän käyttämän bashin manuaalin osiosta "JOB CONTROL" lisättynä pienellä nettiseikkailulla... Jos itse ymmärsin oikein (korjatkaa, jos olen jonkun mielestä pahasti väärässä), niin homma kiteytyy näin: (1) painallushan tapahtuu asiakaskoneella, jonka pääteohjelma ensinnäkin lähettää, mitä haluaa. Yleensä jonkun muinoisen standardin mukaisina tiettyinä ohjausmerkkeinä, jotka nyt on vaan numeroiksi koodattuja kuten muutkin näppäinpainallukset (2) ssh-palvelin ohjaa näppäinpainallukset shellille, jonka se on käynnistänyt ja jolle se kommunikoi (3) jos siinä välissä on "screen"-apuohjelma, niin se nappaa painallukset ja oletusarvoisesti "syö" Ctrl-A:n omaksi ohjausnapikseen. Muut painallukset ohjautuvat sen screen-ikkunan shellille, joka käyttäjällä on valittuna. Screen on aikoinaan käynnistänyt tuon shellin, ja osaapi sille ohjata syötteensä (4) screenissä aktiivinen shell tutkii näppäinkoodin, ja joidenkin osalta se generoi signaaleja, jotka se lähettää ns. "foreground"-prosessille, eli sellaiselle, joka on shellissä "päällimmäisenä" suorituksessa tällä hetkellä. Mainitusta "JOB CONTROL" -osiosta löytyy lisätietoa siitä, miten bashissä voi laittaa komentoja taustalle ("background"-prosessiksi), ja nostaa etualalle tarpeen mukaan. Muihin prosesseihin ei ole vaikutusta. Jos ei shellissä ole mitään prosessia etualalla, se tulkitsee näppäinpainalluksen itselleen. Bash itse ei esimerkiksi reagoi Ctrl-C:hen eikä Ctrl-Z:aan. Tyhjän rivin alussa se tulkitsee Ctrl-D:n kirjaimellisesti muinoisen numerokoodauksen mukaan ohjausmerkiksi "HUP - hangup" ja toteaa, ettei käyttäjä halua enää jutella. Rivin keskellä Ctrl-D tulkitaan GNU:n getline()-funktion mukaisesti editointikomennoksi, jolla poistetaan kursorin alla oleva merkki. TLDR-kiteytys: Painat Ctrl-C, niin shellissä "meneillään oleva" ohjelma saa signaalin, jolla sitä pyydetään loppumaan. Ctrl-Z:lla sellaisen, jolla sitä pyydetään menemään toistaiseksi jäähylle. - Miksi dd ei toiminut, vaan oli "huono esimerkki"? Jotain oli mennyt pahasti kuralle siinä shellissä, josta ajoin dd:tä. Miksi? Halusin käyttää ajan luentomonisteen ja esimerkkien parissa, joten jätin selvittämättä. Todennäköisesti olin painanut jotakin tosi väärää näppäintä epähuomiossa, tai sitten jokin esimerkkikoodi laittoi systeemejä sekaisin vanhempiprosessia myöten. Esim. minish ei välttämättä ole maailman parhaiten käyttäytyvä, vaikka se perusvaatimuksensa täyttääkin. Ongelma poistui, kun suljin kyseisen shellin ja käynnistin screenistä uuden. Esimerkki on siis edelleen yhtä hyvä kuin ennenkin, joten katsotaan se uudelleen ilman ihmettelyä. - Miksi järjestelmässä on "Zombie"-prosesseja, jotka eivät lähde pois edes komennolla "kill -9 1234"? Tähän nyt tajusin vastauksen jo kun luentosalin ovi meni perässäni kiinni: Zombie on esim. Linuxin käyttämä nimi prosessin tilalle, joka monisteessame on geneerisesti "Exit". Prosessin suoritus on jo päättynyt, mutta se on mukana prosessitaulussa, kunnes sen vanhempiprosessi tarkistaa prosessin lopputilanteen. Ts. jos jossain on paljon "Zombieita", niin niiden vanhempiprosessi käyttäytyy jotenkin huonosti, eikä ole tehnyt tarvittavaa wait() kutsua, tai sitten prosessi on siirretty jotenkin väkipakolla vanhemmalta toiselle, ennen kuin se on päättynyt. Vanhemman lopettamisen pitäisi tuhota automaattisesti kaikki lapset, vaikka ne olisivat olleet Zombieita. Vanhemmattomaksi joutunueet Zombiet lienee aika mahdotonta siivota ajamatta järjestelmää alas, ja ne implikoivat, että jokin softa toimii haaroittamisen suhteen väärin. [Vastauksen voi lukea Walking Dead -kontekstissa, vaikka ilmeisesti viime luennon kysymys koski Linuxia. Asiaan? Ei vielä..] - Miksi säie-esimerkin koodi toimi ensin hitaammin, ja seuraavilla yrityksillä nopeammin? Kotimatkalla hokasin pari mahdollista/todennäköistä selitystä: + Voi olla, että fiksu järjestelmä pitäisi prosessoreja hitaammassa "virransäästelytilassa", kunnes tehdään havainto, että näinä aikoina tarvitaan nopeampaa laskentaa. + ylipäätään meidän jalava ja halava ovat virtuaalikoneita, joten siinä on vielä isomman koneen "load balancing" mukana pelissä: paukkuja laitetaan niille koneille, joissa havaitaan laskentatarvetta. + fiksusti tehty adaptaatio molemmissa tapauksissa toimii hiukan jälkijunassa aiheuttavaan ilmiöön nähden, koska aivan lyhyisiin ilmiöihin ei kannatakaan reagoida. + tarkempi vastaus ei selviäisi ihan hetkessä :), mutta tämä "alkuhidastelu" on meidän järjestelmässä ihan toistettavissa oleva havainto, kuten tänäänkin nähtiin. TODO: aiemman kysymyksen tarkennus: "Jos mulla olisi vanhan mallinen rinnakkais-/sarjaportti, miten tekisin/asentaisin sille laiteajurin Linuxiin"? -> I/O -luennolle yhdeksi aiheeksi Linuxin laiteajurin tekeminen (tai ainakin jonkinlainen lähtökohta...) Sitten luentomonistetta eteenpäin. Luku 9 seuraavana edessä. Prosessien/säikeiden välistä kommunikointia (inter-process communication, IPC): - IPC: signaalit; käytiin viimeksi tarkoin läpi - IPC: viestit; käytiin viimeksi päällisin puolin läpi POSIXin mukainen esimerkki - IPC: jaettu muisti; katsotaan luentomonisteen kuvan tasolla läpi - IPC:tä vähän lisää (käsitteiden ja käyttöjärjestelmäkutsujen nimien tasolla): viestit, putket, RPC, socketit, verkkoprotokollat. Ja nyt.. jatketaan suoraan viime luennon cliffhangerista... Yhdenaikaisuuden ongelmia ja ratkaisuja: - esimerkki: "kilpa-ajotilanne" eli race condition, lukotustarve koodi repossa: 2016/esimerkit/l13/race.c - mutex, mutual exclusion; poissulku. - esimerkki: mutexin tekeminen POSIXin säiemutexilla. koodi repossa: 2016/esimerkit/l13/race_fixed_mutex.c - mitä tapahtuu kokonaissuoritusajalle lukituksen kanssa? + jos lukituksia tarvitaan paljon, käytännössä kaikki aika menee lukkologiikkaan ja jonotuksiin, ei hyötylaskentaan. + Saatiin yleisöstä myös muita hyviä tarkennuksia! (ks. video) Kun on lukkoja, niin on niihin liittyviä vaaroja: - lukituksesta aiheutuva synkronointiongelma: deadlock, triviaali esimerkki "lukkiutuva vappu" (nimiä vaille sama kuin luentomonisteen "ruokailevat nörtit") koodi repossa: 2016/esimerkit/l13/vappu_deadlock.c koodi repossa: 2016/esimerkit/l13/vappu_ei_lukkiudu.c - "ruokailevat filosofit" on klassinen esimerkki, jossa on enemmän kuin kaksi prosessia ja resurssia. Rutkasti (ei-pakollista) lisätietoa löytyy Internetin ihmeellisestä maailmasta, esim. tämä lähteineen: http://en.wikipedia.org/wiki/Dining_philosophers_problem Wikejä pitkin löytyi myös mm. seuraava vapaa ja ilmainen oppikirja synkronointiaiheista: http://greenteapress.com/semaphores/ - esimerkki: mutexin toteutus binäärisellä POSIX-semaforilla. koodi repossa: 2016/esimerkit/l13/race_fixed_sem_mutex.c - semafori käsitteenä (+historia) ja tietorakenteena. Esihistoriasta (1960-luku) esim. http://www.cs.utexas.edu/users/EWD/ewd00xx/EWD35.PDF Nykypäivästä esim. WoK-haku sanalla "semaphore" Reunahuomautus: "lukekaa sitä matikkaa" ;) - jaetun resurssin ja kriittisen alueen käsite; Helatorstain ja viikonlopun cliffhanger: - Perusesimerkki tuottajaprosessin ja kuluttajaprosessin tarpeesta: animaation tuottaminen ja pakkaaminen yhdenaikaisena "liukuhihnana". ** Luento 14: Tuottaja-kuluttaja. Muistinhallinta, virtuaalimuisti Viime viikon aihe loppuun: Esimerkki moniarvoisen semaforin käytöstä: - esimerkki: tuottaja-kuluttaja -probleemi sekä sen ratkaisu kolmella semaforilla koodi repossa: 2016/esimerkit/l14/tuottaja_kuluttaja.c "ASCII-sarjakuva" repossa: 2016/esimerkit/l14/tuott_kulutt_rengaspuskuri.txt Vaatii omakohtaista miettimistä! Tämäkin esimerkki on tarkoituksella yliyksinkertainen, vaikka siinä onkin mukana olennaiset osuudet: semaforien alkuarvojen asettaminen ja oikeellinen järjestys semaforikutsuille. Osaamistavoite on ymmärtää, mikä on semafori ja miten rengaspuskuria käyttävä tuottaja-kuluttaja toteutetaan semaforilla. - Pienoishuomioita prosessien/säikeiden synkronoinnista: + Onnistuu semaforeja vastaavalla "vahvuudella" mm. myös viestinvälityskutsuilla ja ns. "monitoreilla"; kauan sitten tutkittu, todettu ja julkaistu asia. + Nykyisissä oliokielissä helppoa: Javassa heitetään avainsana "synchronized" kentälle ja C#:ssa ilmeisesti (tsekattu lyhyesti nettifoorumeilta) tyyliin "[MethodImpl(MethodImplOptions.Synchronized)]" tai "lock { /*lukituksen tarvitsevaa koodia tässä*/ }".) + Deadlock ja muut ongelmat aina mahdollisia myös uudemmissa oliokielissä! Varovasti aina! Yhdenaikaisuus vaatii erityistä tarkkuutta suunnittelussa. + Synkronointia ei pidä käyttää, jos ei sitä tarvita! Mutta pitää tunnistaa kohdat, joissa välttämättä tarvitaan. Erityisesti täytyy tietää aivan yksittäisen muuttujan tasolla, onko se mahdollisesti jaettu usean säikeen kesken. + Säikeitä kannattaa alkaa käyttämään omissa ohjelmissa tarpeen mukaan, muistaen tarkkaavaisuuden ja potentiaaliset ongelmatilanteet! [ lämmittelytauko auringossa, 5 min ] Sitten monistetta eteenpäin... Muistinhallinta: - tavoitteet: + maksimaalinen kapasiteetti, riittävä nopeus. Perusidea: pidetään tällä hetkellä käyttämättömät tiedot hitaassa mutta isossa muistissa, tuodaan tarvittaessa lähemmäs. Eli hyödynnetään lokaalisuusperiaate -havaintoa. + suojaus, eri oikeudet eri muistialueilla. Looginen eriytys segmentteihin: koodi, data, pino, keko (dynaamiset oliot) - käytettävissä: muistihierarkian mukaiset muistit, prosessori, MMU Sivuttava virtuaalimuisti: - sivutus - osoitteen tulkinta, osoitteenmuunnos virtuaalisesta fyysiseksi - prosessorin sivutaulu: sisältää fyysisen sivukehyksen indeksin sekä yksittäisinä bitteinä sivukohtaiset suojaus- käyttöhistoriatiedot ja tiedon, onko sivu muistissa vai kovalevyllä. ** Luento 15: Heittovaihto. Unixin tapa ilmentää moni asia tiedostona Muistinhallinta. Jatketaan suoraan siitä, mihin maanantaina jäätiin: - heittovaihto (swap), working set: + Siinä missä laitteisto hoitaa prosessorin sisäiset välimuistit, käyttöjärjestelmä pystyy ottamaan vastaavalla periaatteella avuksi myös käytännössä rajattoman kokoiset massamuistit. + prosessorissa on ominaisuudet (sivutaulun automaattisesti päivittyvät bitit), joilla heittovaihto on mahdollista toteuttaa. - sivuvirhe (page fault) / sivunvaihtokeskeytys ja sen käsittelijä - käyttöjärjestelmän tietorakenteet: prosessikohtaiset sivutaulut ja kehystaulu. - Korvausalgoritmi, esim. least-recently-used (LRU). Käyttöjärjestelmän operaatiot "swap out" ja "swap in" -vaiheissa. Välimuistin ruuhkautuminen eli "cache trashing" tarkoittaa välimuistin ulkopuolisen väylän tai pahimmillaan heittovaihdon suhteellisesti tiuhempaa käyttöä, joka tuhoaa suorituskyvyn - välimuistien osaltakin dramaattisesti, mutta heittovaihdon osalta jopa rampauttavasti). - Esimerkki: (jälleen simppeli "koeputkiesimerkki", jotta perusilmiö näkyisi mahdollisimman hyvin): koodi repossa: 2016/esimerkit/l15/cache.c - Miten tällaisilta vältytään? + Suunnitellaan algoritmit suoraviivaisiksi ja mahdollisimman vähän operaatioita vaativiksi aivan normaaliin tapaan; lisäksi selvitetään, millä tavoin alla oleva alusta käyttää muistia, eikä tehdä "luonnonvastaista" koodia. + Yhdenaikaisten prosessien/säikeiden ja putkien käyttö mahdollistaa peräkkäisten dataoperaatioiden rakentelun modulaarisesti (operaatiot vaihdeltavissa keskenään; peräkkäiset operaatiot tapahtuvat yhdenaikaisesti, kun data on vielä edeltävän operaation jälkeen lähemmässä muistikomponentissa) + (ja niin edelleen. Lisää jatkokursseilla, joissa puhutaan enemmän ohjelmistojen ja järjestelmien suunnittelusta.) Esimerkki muistin kartoituksesta ja muiden kuin tavallisten tiedostojen ilmenemisestä tiedoston näköisinä, normaalissa hakemistopuussa, unixmaisessa käyttöjärjestelmässä; aasinsilta tiedostojärjestelmiin: - Esim. prosessin 1234 muistikartan saa Linuxissa nähtäville tulostamalla erikoistiedoston nimeltä /proc/1234/smaps - Kokeillaan esim. käynnistää aiempi "lukkiutuva vappu", ja tutkitaan muistikarttaa kaikessa rauhassa säikeiden ollessa ikuisessa jumissaan. - Katsotaan myös jotain oikean ohjelman karttaa, esim. emacs-tekstieditorin. Havaitaan lukuisa joukko kirjastoja Luennoilla on aiemmin nähty esimerkkejä muistakin erikoistiedostoista, esim. /dev/urandom -tiedoston lukeminen saa käyttöjärjestelmän generoimaan satunnaislukuja. Tiedostoon /dev/null voivat kaikki käyttäjät "kirjoittaa", mutta siihen ohjattu data ei mene mihinkään, vaan erikoistiedosto "nielee" tavut. Muita vastaavia, joita unixmaisista usein löytyy: + /dev/random yrittää tuottaa "aitoa satunnaisuutta" tarkkailemalla ulkopuolisesta ympäristöstä riippuvia tekijöitä, kuten nettiyhteyksiä. *Älä käytä turhaan yhteiskäyttökoneella*, koska generointi hidastuu kaikkien tarvitsijoiden osalta. Ulkoisia ilmiöitä tapahtuu harvakseltaan "uskottavan satunnaisuuden" aikaansaamiseksi. Normaalitarpeisiin lue /dev/urandom -tiedostoa ("u"=="unlimited"), joka toimii kuten C:n rand()-funktio. Tiukempiin kryptografiatarpeisiin tällainen pseudosatunnaisuus ei ole välttämättä riittävä. + /dev/zero tuottaa loputtomiin nollatavuja luettavaksi. + /dev/sda vastaa ensimmäisen koneeseen liitetyn fyysisen kovalevyn tavuja ilman tiedostorakennetta; voi käyttää esim. täydellisen varmuuskopion tekemiseen tai palauttamiseen. Tietenkin käyttö on sallittu vain ylläpitäjän oikeuksilla. Kopiointi myös edellyttää järjestelmän käynnistämistä esim. muistitikulta siten, että kovalevy ei ole kopioinnin aikana kytketty tiedostoineen. + /dev/tty on jopa POSIXin määräämä. Se toimii erikseen jokaiselle prosessille, ja sitä tulee voida käyttää syöttöihin ja tulostuksiin samoin kuin päätettä + Hakemiston /dev/ listaaminen näyttää monia muitakin tiedostonimiä, jotka itse asiassa vastaavat fyysisiä I/O-laitteita. Useimmat ovat saatavissa vain järjestelmänvalvojan oikeuksilla, ja niitä on tarkoitus käyttää sovelluksissa käyttöjärjestelmäkutsujen kautta sen sijaan että suoraan esim. päätteeltä. Esimerkki: - kahden eri ohjelman jakama muistialue POSIX-käyttöjärjestelmäkutsuja käyttäen; toinen aasinsilta tiedostojen käsittelyyn (jaettu muistialue näyttäytyy ohjelmalle ja muillekin tiedostona!) koodit repossa (+krediitit alkuperäiselle tekijälle): 2016/esimerkit/l15/shm_msgclient.c 2016/esimerkit/l15/shm_msgserver.c 2016/esimerkit/l15/README_shm_example.txt - Todetaan esimerkissä oleva kilpa-ajotilanne (korjaamisen voi tehdä erittäin vapaaehtoisena, hieman vaativampana, harjoitustehtävänä...; sigesim.c:n malliin olisi syytä myös käsitellä TERM-signaali, jotta serveri osaa poistaa jaetun muistialueen loppuessaan lopetussignaalin johdosta. Oletuskäsittelijä ei voi tietää, että prosessi on pyytänyt yhteisen muistialueen.) - Katsotaan, että muistialue näkyy tiedostona hakemistossa /dev/shm ... POSIXin vaatima kauttaviivalla alkava nimi on vaan lisätty Linux-toteutuksessa /dev/shm:n perään. - Ja juu.. elä anna hakkerin tehdä tätä jaetulle muistillesi: echo Hei vaan hei | dd of=/dev/shm/foo1423 bs=1 seek=4 conv=notrunc - Telmitäänpä hetki tämän esimerkin ja tietoturvakysymysten äärellä, ja varmistutaan että Ohjelmistoturvallisuus ja Tietoverkkoturvallisuus ovat tarpeellisia jatkokursseja... ** Luento 16: I/O, kovalevy, tiedostojärjestelmä. Vuoronnusmenettelyjä, RT, skriptit Kurssin viimeisen viikon startti. Mikä on tilanne? - Vuoden 2016 "mallitentti" on julkaistu: http://users.jyu.fi/~nieminen/kj16/tentti_itka203_2016-05-15_malli.pdf katsotaan sitä tarkemmin keskiviikkona, kun otsikkona on mm. "kertaus ja tärpit" Tällä luennolla käydään vielä läpi luentomonisteen viimeisten lukujen asioita, jotka ehtivät tenttiin. (Kysymyspaperit menevät monistukseen huomenna). Loput jää sitten tulevaisuuden haasteeksi itse kullekin. - Demo 6 lyhyt esittely. Pittäis olla aika "läpihuutojuttu", jos tähän asti ollaan kartalla. - Demojen aikatauluista, ennen kuin tarvitsee kysyä: kaikki pakolliset oltava tehty ennen kuin kurssista saa arvosanan. Tentissä voi käydä yrittämässä tällä viikolla, vaikkei ole vielä kaikki palautukset järjestelmässä. Vapaaehtoisia bonusdemoja ei ole resursseja tarkastaa enää myöhemmin kesällä; se porkkana olkoon voimassa 14 vrk. ensimmäisestä tentistä, eli 2.6.2016 asti. Sitten katsotaan, mihin asti tänä vuonna ehditään... reilu tunti aikaa... Lisää tiedostonhallinnan käyttäjänäkökulmaa: Esimerkki: - Tiedostojen käyttöoikeudet rwx / ugo. Shell-ohjelma chmod. Oktaaliluvut. (HUOM: yliopistomme verkkolevyt eivät sisäisesti tue POSIXin käyttöoikeusmääritelmiä; omat kokeilut kannattaa tehdä siis esim. itka203-testi.it.jyu.fi -palvelimella, joka ei muutenkaan ole kytketty verkkolevyyn, tai sitten jalavan tai halavan /tmp -hakemistossa. Viimeksi mainitusta siivoa lopuksi kokeilutiedostosi pois, etteivät jää muiden vaivoiksi yhteiskäyttöiseen järjestelmään... kyllä /tmp kuulemma kait myös siivotaan aika ajoin myös jonkinlaisella automaattivälineellä...) Tiedostonhallinnan sovellusnäkökulma: Esimerkki: - Tiedostojen käyttöä POSIX-käyttöjärjestelmäkutsuilla ja C:n alustakirjaston kutsuilla; tiedoston avaaminen ja luominen, kirjoittaminen, sulkeminen. Käyttöoikeuksien asettaminen. koodi repossa: 2016/esimerkit/l16/hellofile.c Esimerkki: - Oman "cat -apuohjelman" raakile; tiedoston avaaminen, lukeminen ja kirjoittaminen tavu kerrallaan, sulkeminen C:n alustakirjaston kutsuilla. koodi repossa: 2016/esimerkit/l16/liit.c Aasinsilta kohti tiedostonhallintaa ja tiedostojärjestelmiä muuttuu oikeaksi sillaksi, kun käsitellään välissä vielä I/O -laitteiston piirteitä, esimerkkinä kovalevy, joka soveltuu tiedon pitkäaikaiseen säilyttämiseen tiedostoihin ja hakemistoihin organisoituna. I/O ja Tiedostonhallinta käyttöjärjestelmätoteutuksessa: - Tavoitteita: datan organisointi, osoitteistaminen, puumainen hierarkia ("kansiot"). [kyseessä on todellisuudessa pikemminkin suunnattu graafi eikä puu, koska hakemistoista voi olla ns. linkkejä muihin hakemistoihin ja muissa hakemistoissa sijaitseviin tiedostoihin. Puu on kuitenkin ehkä hyvä ensimmäinen analogia.] - Käytettävissä olevat laitteet: prosessori, I/O -portit, laitteiden aiheuttamat keskeytykset; rajapinnan takana hyvin erilaisia laitteita - I/O -ohjelmiston kerrosmainen rakenne: laiteriippumaton osuus, laiteriippuva osuus. - I/O -kutsun kulku ohjelmistokerrosten läpi (karkea yleiskuva). - DMA. Tiedostojärjestelmien toteutuksesta fyysiseen massamuistiin: - kovalevyn rakenne - lohkot muistissa ja levyllä; lohkot yleensä isompia kuin levyn sektorit - käyttöjärjestelmän yleiset tavoitteet (läpivienti, tasapuolisuus, vasteajat jne.) voimassa myös I/O:n osalta. Lisäksi saatavuus- ja säilyvyyskysymykset; vikasietoisuus. - RAID - käytännön penkaisua shellin kautta: + komennot ``df`` (POSIX) ja ``mount`` (ei POSIX), ``du`` (POSIX). reunahuomio: Mistä tietää, mikä on POSIXia ja mikä ei? Tietysti standardin tekstistä. Komento joko on siellä tai ei. Tietyn tiedostojärjestelmän toiminta ei ole standardin vaan kunkin käyttöjärjestelmän omien laajennosten varassa. Unixmaisissa tiedostojärjestelmän kiinnittäminen hakemistopuuhun tapahtuu kuitenkin usein mount() -järjestelmäkutsulla ja shellissä mount -apuohjelmalla. Irrottaminen umount() -järjestelmäkutsulla ja umount -apuohjelmalla. POSIX vetää siis määrittelynsä rajan selvästi laiteriippumattoman ohjelmiston ominaisuuksiin (ts. tiedostojärjestelmän ja massamuistien olemassaolo, osoitteistaminen). + inode / POSIXin "sarjanumero" : komennot ``ls -i`` (POSIX) ja ``stat`` (ei POSIX). - esimerkki: vanhan unixin tiedostojärjestelmän toteutuksesta yleiskuva, inodet ja levylohkot, isot tiedostot hierarkkisena lohkolistana - journalointi: kirjataan ensin ylös, mitä levylle aiotaan kirjoittaa; sähkökatkon sattuessa menetetään vain meneillään olleen kirjoituksen tiedot, mutta tiedostojärjestelmän rakenne ei muilta osin korruptoidu, koska kesken jäänyt kirjoitustransaktio voidaan peruuttaa seuraavan käynnistyksen yhteydessä. - levyoperaatioiden vuorontaminen on oma haasteensa. Internetin ihmeellinen maailma kertoo meille paljon hakusanalla "disk scheduling" (tieteelliset artikkelitietokannat kertovat tietysti uusimpia tutkimustuloksia yleistiedon lisäksi) Havainto: myös laitteita on vuoronnettava! Magneettisen kovalevyn vuorontaminen on sidoksissa fyysisen laitteen ominaisuuksiin (pyöriminen, lukupään sijainti) ja tiedostojärjestelmän organisointiin levyn pinnassa. --- tähän ehdittiin 2016. Loput ei tule tenttiin. *** Lisäesimerkki -- kurssin mielessä kokonaisuudessaan liian syvällinen: Kurssin opiskelijan harrastusprojekti: muinoisen rinnakkaisportin keskeytyskäsittely. - Tietoja portista: http://retired.beyondlogic.org/spp/parallel.htm Tässäpä olikin hieno testi luennoitsijan omalle tiedonhakukyvylle :). En voinut käyttää tähän kovin paljon aikaa, mutta tässä ensimmäiset, ei välttämättä aivan oikeaan osuvat, tulkintani: - Jos ymmärsin oikein, laitteelle täytyy lähettää merkki, ikäänkuin se olisi "printteri" (mitä se ei tässä tapauksessa kuitenkaan ole:)). Sitten täytyisi tallentaa aikaleima hetkellä, jolloin "ikäänkuin printteri" ilmoittaa keskeytyksellä, että se on "tulostanut" edellisen merkin ja on valmis vastaanottamaan lisää. Fyysisen laitteen luonteesta johtuen ei voi ennalta tietää, millaisen ajan päästä tämä keskeytys tulee. - Ensimmäisellä googletuksella tuli vastaan tällainen softa: http://parapin.sourceforge.net/ - Tämä Parapin on ilmeisesti tehty Linuxin versiolle 2.6, jota ei pahemmin tueta enää 2016. Ytimen rakenteessa voi olla tapahtunut muutoksia, jotka edellyttäisivät softan porttaamista uuteen versioon. Seuraava perustuu ajatukseen, että Parapin tai vastaava toimisi nykyisessä Linuxissa (tai käyttötarkoitus on sellainen, että laitetta hallinnoivaan koneeseen voisi tietoturvallisesti asentaa version 2.6). Ohjelmiston dokumentaatiossa ensinnäkin on linkki selkeästi hyvään johdantokirjallisuuteen: - Rubini & Corbet: "Linux Device Drivers": http://www.xml.com/ldd/chapter/book/ (ilmainen online) http://shop.oreilly.com/product/9781565922921.do (ostoversio) Jos esim. tuon Parapin-ohjelmiston ominaisuudet eivät riitä, niin kirjan perusteella saanee yleiskuvan siitä, miten Linuxin ajurijärjestelmä ja keskeytyskäsittelijät toimivat :), jotta voi modata esimerkin perusteella oman ajurin. Kyseinen Parapin -ohjelmahan on juurikin esimerkki rinnakkaisporttia käyttävästä ajurista. Siinä näyttäisi kyllä olevan lähes kaikki ominaisuudet, joita kysymyksen esittäjä tarvitsee harrastusprojektissaan. Parapinin voi äkkivilkaisun perusteella kääntää Linuxin ajuriksi, joka toimii yhteistyössä normaalin "parport" -ajurin kanssa. Keskeytyskäsittelijässä näyttäisi olevan callback-funktio, johon ilmeisesti voi ajurin ylösajon kohdalla saada oman C-aliohjelman ajettavaksi aina kun tietty rinnakkaisportti keskeyttää. Keskeytyksen kohdalla voisi *ehkä* tehdä jotain "quick-and-dirty" -tyyppistä, kuten:: static void rakentele_aikaleima_jotenkin(char *buf){...} static laheta_porttiin_taas_uusi_operaatiopyynto_jotenkin(void *id){...}; void oma_koukkufunktio(int irq, void *dev_id, struct pt_regs *regs){ char[20] aikaleima; rakentele_aikaleima_jotenkin(aikaleima); printk(KERN_INFO "Laite sanoi tiks kellon ollessa %s\n", aikaleima); laheta_porttiin_taas_uusi_operaatiopyynto_jotenkin(dev_id); } Ja sitten, teoriassa, jos tällaisen saisi pyörimään, niin ytimen lokitiedosta voisi käydä ajoittain nappaamassa rivit, joilla lukee "Laite sanoi tiks", tyyliin shell-komento ``dmesg | grep "Laite sanoi tiks"`` ja jäsentää riveiltä aikaleimat. Tai sitten tuo oma käsittelijä voisi tehdä jotain hienompaa. "Oikea unixmainen ajuri" näyttäytyisi tietenkin loppukäyttäjälle tiedostona, esim. "/dev/munlaite/tilanne", josta käyttäjä voisi lukea tekstimuodossa aikaleimoista johdetut yhteenvetotiedot (jotka ovat käsittääkseni harrastusprojektin lopullinen käyttötarkoitus). Kevyellä tai raskaalla toteutuksella joka tapauksessa tuossa harrastuksessa joutuu lueskelemaan oppikirjallisuutta ja esimerkkikoodia, että saa homman pelittämään :). Hieno harrastus siis!! :) TODO: Heläytetään löytynyt oppikirja ehkä myös luentomonisteen lisälukemistolistaukseen. -------------- tähän asti on tultu keväällä 2016 -------------- * Viime vuoden toteuma; lienee hyvä suunnitelma myös vuodelle 2016: ** Luento 17: Tarvittavat paikkaukset. Yhteenveto. Kertaus ja tärpit Agendalla olisi: *** Tomin terveisiä demoista: - demot 1, 2 ja 3 mennyt hyvin ja ohjeaikataulussa: + demosta 1 läpi 137, hylkykertoja 26, syy yleensä "oudot rivinvaihdot", jollaisia ei suoraviivaisesti ohjeiden mukaan toimimalla oikein pysty tulemaan.. + demosta 2 läpi 117, hylkykertoja 17, syy yleensä jokin puuttuva tai erilainen tuloste kuin pyydettiin + demosta 3 läpi 108, hylkykertoja 4 (syy ympäristömuuttujan puuttuminen) + demosta 4 läpi 70, hylkykertoja 26 (yleensä useita ongelmia; pienillä on mennyt läpi, mutta vähintään merkin poistamisen) * ei-kääntyviä ohjelmia tänä vuonna vain 2. * varottava "1:llä ohi" virheitä. * yksinkertaisuus on hyve. * kynä ja paperi! + demosta 5 läpi 38, hylkykertoja 41 (pienillä mennyt läpi, ts. noin 2-3 ongelmakohtaa läpi, useampi -> ei vielä läpi) * selkeitä ongelmia ymmärryksessä on, jos esim. kuvittelee paikallisten muuttujien sijaitsevan koodialueella tai toisin päin. * suurin muistiosoite, joka on taulukolla käytössä? * bitit ja tavut sekaisin? "tavu==8 bittiä" Montako tavua varattu tilaa 6:lle 8-tavuiselle int:lle? Ei varmaan 6*8*8 tavua! * kummallisiakin lukuja, joille Tomi ei keksinyt selitystä.. * muistin olemuksesta ei vielä ole selkeää, yksinkertaista mielikuvamallia. * Missä muuttujan "samoja" arvo oli aluksi? + demosta 6 läpi 39, hylkyjä 6 (hyväksymisperusteena, että ohjelma vähintäänkin toimii niinkuin tehtävänannossa on - Hyvin harva on käyttänyt hyödykseen Tomin varattavia ohjauksia. Toivottavasti sessioista on kuitenkin ollut hyötyä. *** Käsittelemättä jäivät edistyneempi vuoronnus ja skriptaus Vuoronnuksesta ja vuoronnusmenettelyistä lyhyesti: - yksinkertaisimmillaan FCFS (first come first serve), "eräajo" - moniajossa yksinkertaisimmillaan Round-robin - prioriteetit, esim. prioriteettikohtaiset kiertojonot; monimutkaistaa vuorojen jakamista - tarvitaan monipuolisempi vuoronnusalgoritmi; vaarana mm. nälkiintyminen (matala prioriteetti ei ehdi saada juuri lainkaan aikaa) - dynaamiset prioriteetit - reaaliaikajärjestelmät ja -vaatimukset, prioriteetit ja pre-emptiivisyys, watchdogit - kompromissit esim. vasteaika vs. throughput - mikroydinmallissa käyttöjärjestelmän omien säikeiden vuoronnus ja prioriteetit vaikuttavat kokonaisuuden toimintaan Eräs IPC:henkin liittyvä yksityiskohta: - Käyttöjärjestelmän suorituksesta ja moduulijaosta; kernel mode vs. user mode. - Käyttöjärjestelmän ajonaikaisesta rakenteesta: monoliittinen vs. microkernel + vuoronnus, kutsurajapinta ja IPC-menettelyt tarvitaan käyttöjärjestelmätilassa, mutta muut palvelut voivat tapahtua joko käyttöjärjestelmätilassa tai käyttäjätilassa; palveluprosessit voivat kommunikoida ja synkronoida toimintonsa IPC-menettelyjen kautta. + Käytännössä yleensä hybridi, jolla haetaan kompromissia (mm. modulaarisuus, turvallisuus ja toimintavarmuus vastaan suorituskyky). - Uusinta tutkimusta aiemmista aihepiireistä? Katsotaan vähän vaikka WoKista ja ACM digital librarysta hakusanoilla "deadlock", "process synchronization", "microkernel" (tai muita tähän mennessä nähtyjä avainsanoja). - Yksi esimerkki microkerneliksi suunnitellusta ytimestä on "Plan 9 from Bell Labs": http://plan9.bell-labs.com/plan9/ Johdattelua skriptaukseen: - katsotaan läpi muutama etäkäyttökoneelta ja/tai netistä löytyvä skripti erilaisiin tarkoituksiin, esim.: + ohjelman käynnistäminen tietyssä ympäristössä tai tietyin lisäargumentein, esim. yliopiston palvelimilla komento "c99" on skripti, joka tekee esivalmisteluja ja käynnistää varsinaisesti gcc -kääntäjän. + järjestelmäpalveluiden käynnistys/pysäytys, kokonaisjärjestelmän ylösajon operaatiot; esim. yliopiston palvelimilla skripti /etc/rc.sysinit tapahtuu käynnistyksessä; mm. yhdistää hakemistopuuhun tiedostojärjestelmiä, aloittaa heittovaihdon ym. + monisteessa luetellaan useita muita shell-sovelluksia - shellin perusrakenteita (demotehtävän 6 tasolla); esimerkkinä c99:n käynnistysskripti, jossa on muuttujia, for-silmukka, case-ehdot, tulosteen ohjaus virhetulosteeksi. *** Mitä siis ehdittiin tänä vuonna Yleiskuva luentomonisteeseen - luvut 1-12, 14 ja 15. Koodiliitekin on.. *** Sitten kertaus ja tärpit! Tentin kysymystyypit ja yleinen rakenne julkaistiin noin 5 vuorokautta ennen tätä luentoa. Yleiskuvaa: - kysymyksiä on muutamaa eri tyyppiä: väittämiä, termien yhdistämistä niitä kuvaileviin määritelmiin tai ominaispiirteisiin. Esimerkkiskenaarioihin tai mallikoodeihin perustuvia väittämiä ja "mikä on lopputulema" -tyyppisiä. Vastauksena joka kohdassa on kirjain, järjestetty jono kirjaimia tai lukuarvo. Kysymyksissä pitää olla tarkkana, koska jokainen sana vaikuttaa luonnollisessa kielessä ja jokainen merkki vaikuttaa ohjelmointikielen syntaksissa! Alkuperäisessä, muotoilemattomassa mallitentissä on kysymysten lisäksi mallivastaukset sekä pohdintaa. - alkupuolella erillisiä osaamistavoitteita on useampia, joten aihepiirit saattavat vaihdella enemmän tenttikerrasta toiseen. - on myös "kestotärppejä" eli aihepiirejä, joista tullaan kysymään joka tentissä (joskin eri kysymyksiä ja mahdollisesti tahallaan eri tavoin toimivan esimerkin kanssa, joten mallivastausten opettelu ulkoa ei auta, vaan koodien ja algoritmien toiminta pitää ymmärtää): + erityisesti shell-komentojonot, minish-toteutus, assembler-ohjelma, pino ja aktivaatio debuggerissa, sivutaulut ja osoitteenmuunnos. - Tehtävissä tarkoituksella "harhautuksia", joten vastaaminen edellyttää ymmärtämistä ja annetun esimerkin tarkkaa läpilukua. Ei muuta kuin onnea (...eipäs kun osaamista) -- tenttiin! Keskustelua, jos aikaa on!! * Tänä vuonna (2016) ei ole allokoitu luentosalia tentin jälkeen kuten viimeksi: ** Palauteluento ekan tentin jälkeen (vapaaehtoinen/täydentävä) Koska salia ei ole, tämä tullee nyt vaan meilitse, kunhan ensimmäisen tentin arvostelu on tehty. *** Agenda: - Arvio vastauspapereihin kirjatuista ja jälkikäteen ilmoitetuista kommenteista kysymyksiin liittyen. Alustavat kommenttini niistä, ennen kuin ehdin meditoida asian ympärillä enemmän. - "Vapaa sana" -vastaukset (anonymisoituina) ja omat kommenttini niistä. - Yleistä palautetta demojen tarkastuksessa havaittujen ilmiöiden pohjalta (pääasiassa tulevia opintoja ja alalla toimimista silmälläpitäen) - Kysymyksiä, kommentteja, keskustelua. *** Sähköpostilistalla esittämäni toimintasuunnitelma: Kysymysmuoto oli uusi, ja silloin on "bugien" riski suuri. Saa nähdä, miten tässä käy.. että onko sitä hommaa nyt enemmän vai vähemmän kuin avoimissa kysymyksissä, ja saadaanko järkevän näköistä arvosanajakaumaa. Mikäli arvosteluperusteita täytyy justeerata, tehdään muutokset tietenkin opiskelijan eduksi, jos niitä päädytään tekemään. Ei ollut vielä lupaus, ennen kuin vastausten kokonaisuus ja koko populaation arvosanajakauma on selvillä. 113 perinteisen "esseetentin" tarkastaminen kestäisi itselläni useita työpäiviä, missä ajassa luultavasti ehdin suorastaan tekemään automaattisen tarkistimen, johon [tämänkertaisen tenttimuodon] vastaukset voi syöttää. Optista lukijaa ei (vielä tässä vastausmuodossa) pysty käyttämään, mutta pikaisen testin perusteella yhden vastauspaperin manuaalinen syöttäminen kestää 30 sekuntia, mikä on kokonaisuuden kannalta olematon aika. Sieltä saapi sitten nähtyä myös kysymysten osalta, onko jokin ollut selvästi vaikeampi / mahdottomampi kuin jokin toinen. *** Arvio tavoista, joilla arvostelua korjataan tarvittaessa: - Kysymyksen poistaminen arvostelusta kaikkien osalta ei tarkemmin ajatellen ole oikeudenmukaista. Monitulkintaisuus on varmasti hienovaraisissa nyansseissa, joita ei ole tullut ajatelleeksi kysymyksen tekijä, eikä luultavasti suurin osa vastaajistakaan. Olisi paha, jos suurimmalta osalta kumoutuisivat pisteet tapauksessa, jossa monitulkintaisuuden havaitseminen vaatii syvällisempää eforttia. Miten sitten voisi toimia? Tämän hetkinen suunnitelmani: + Moniselitteiseen kysymykseen hyväksytään kaikki oikeiksi tulkittavat vastaukset, +0.5 pistettä + Muissa kuin väittämäkysymyksissä ei kuitenkaan hyväksytä vastauksia, jotka ovat tulkinnasta riippumatta vääriä (niistä edelleen miinuspisteitä) + Tyhjä kohta, jossa on mainittu moniselitteisyydestä, tulkitaan oikeaksi vastaukseksi, koska löytyy ymmärrystä osoittaa monitulkinnallisuus. Tästä +0.5 pistettä. + Tyhjä kohta, jossa ei ole mainittu moniselitteisyydestä, tulkitaan edelleen ohitetuksi. Edelleen 0.0p. Uskoisin, että näin (1) ei rokoteta ketään turhaan, (2) ei vähennetä pisteitä tyypeiltä, jotka ovat luottaneet kysymykseen omana supertärppinään (3) ei myöskään palkita "tuulituloksella" niitä, jotka eivät ole osanneet vastata suuntaan saati toiseen. Toimintamalliehdotusta saa kommentoida. Lopullinen arvostelu tapahtuu automaattisesti; tieto perustelun olemassaolosta kirjataan arvosteluskriptiin. (sanoinko skripti? juu, samalla python-skriptillä tullaan arvostelemaan, millä kysymykset on generoitu kysymyspankista... pittää vaan liittää tietorakenteisiin vielä lippuattribuutti, oliko kysymys havaittu huonoksi.. kysymys.isBadQuestionOMG()) *** Tentin osallistujien esitykset monitulkintaisiksi kysymyksiksi: Mahdollisesti tai todennäköisesti arvosteluun vaikuttavia huomioita: - Tehtävä 1: Tapahtui reaalimaailman "off-by-one" -virhe.. [luennolla sanoin muuten "one-off", joka on tietysti väärä sana tähän tarkoitukseen. Off-by-one on oikea termi...] olin heti niin tyytyväinen ensimmäiseen kysymykseen, että sitä en juurikaan ajatellut enää uudempaan kertaan, vaan tarkka läpikäynti lähti kysymyksestä 2, koska "se ensimmäinenhän on jo varmasti OK, kyllä mä sen tiedän". No ei se ihan ollut. Opiskelijoiden havaintoja: + "moniselitteinen, koska ei voida tietää puhutaanko koko lähdekoodista vai tarkoitetaanko vain sitä, että prosessin omat säikeet toimivat prosessin koodin sisällä, sillä ne eivät välttämättä käytä koko koodia" + "A, jos siis tarkoitetaan sitä koodia ohjelmoijan kirjoittamana tekstipötkönä, ei sitä, ettäkö säikeet suorittaisivat aina samaa kohtaa koodista. Tässä mahdollinen monitulkinnallisuus?" + "Valtavan epämääräinen sana 'koodi'" Mielessäni tarkoitin koko ajan "prosessin koodialue on sen säikeille yhteinen", enkä tulkinnut tehtävänantoon päätynyttä tekstiä siten kuin se oli ("prosessin koodi on sen kaikille säikeille yhteinen"). Siis tuo "koodi" voi olla paljon kaikkea: lähdekoodi (hyvin todennäköisesti eri lähdekoodi jokaisella säikeellä), käännetty binäärikoodi (jossa todennäköisesti eri osio jokaisella säikeellä), prosessin virhekoodi, salauskoodi.. - Tehtävä 7: Kysymyksenasettelu meni pieleen, joten arvostelu vaatii tältä osin jonkin oikeudenmukaisen korjauksen. Havaintojen yleiskuva: + Esimerkissä menin ja sanoin että skenaariossa on 10 intensiivisesti laskevaa sovellusta. Nämähän pyörähtää 50Hz kellolla läpi 5 kertaa sekunnissa jokainen. Väliin mahtuu myös satunnainen muu prosessi viimeistään 0.2 sekunnin sisällä, vaikka se tulisi kiertojonon perältä. Ei tämä nyt ihan megaluokan viive olisi ihmisen näkökulmasta. Eri asia olisi reaaliaikajärjestelmä, jossa on pakko kelata jonoa nopeammin. Mutta tällaista ei nyt ollut spesifioitu tehtävän esimerkkiskenaariossa. + lisäksi sanamuoto voisi olla "painottaa vähän" tai "vähän laskentaa vaativia". Luonnollinen kieli on ikävästi moniselitteistä; onneksi on ohjelmointikielet syntakseineen :) Alustava suunnitelma siis, että A, B ja "perusteltu tyhjä" hyväksytään kaikki oikeina vastauksina (+0.5p). Tyhjä ilman perustelua normaali 0.0p - tehtävät 21--22: Tässä on muutaman opiskelijan kanssa keskustelu / väittely kesken, että oliko kyseessä oikeasti osaamistavoitteita mittaava kysymys vai "liian paha kompa" tiedostopäätteestä .tex tai sen puuttumisesta johtuen. Jonkinlainen ratkaisu tästä tulee, mutta toistaiseksi auki. Mahdollisesti on höllennettävä väärän vastauksen miinuspisteitä tämän osalta. Mutta tyhjäksi tätä ei varmasti ole jättänyt kukaan, jolla oikea osaaminen löytyy. Huolimattomuus on sitten asia erikseen, ja pittää pohtia, kuinka paljon sitä sitten saisi sallia. - Tehtävä 28: Tapahtui perinteinen "viime hetken tarkennus", joka ei ollut loppuun asti harkittu. Note to self: älä tee viime hetken tarkennuksia. Tarkkaavaisen opiskelijan havainto: + "Mahdollinen monitulkinta: ohjelmakoodissa sem.arvo on kurssin mallin mukaan kokonaisluku (joka siis voi olla etumerkillinen kuten koodissa on 'if (sem.arvo <= 0))', mutta todellisuudessa ei arvo koskaan laske pakkasen puolelle. Ei voi olla vaikkapa '-2' vapaata tai täyttä paikkaa. Näin se on. Toteutus voisi antaa semaforin arvon mennä pakkasen puolelle, jolloin sen itseisarvo tarkoittaisi jonottavien prosessien määrää.. Tämä ajatus nyt ei ollut itsellä mielessä, kun "tarkensin" tehtävänantoa viime hetkellä. Uusinnoissa tämä väite tulee muotoon, jossa etumerkistä ei puhuta. Tällä kertaa tässäkin hyväksyttävä A ja B sekä kommentoitu tyhjä. - Tehtävä 29: Edellisen kohdan vuoksi mahdollisesti myös moniselitteinen. Tutkitaan ennen kuin hutkitaan. - Tehtävä 45: En vielä tiedä toimintamallia, ennen kuin nähdään kaikki vastaukset. Opiskelijan havainto: + "B, koska käyttäjä voi itse määrittää tiedoston nimen" Nythän on niin, että voi määrittää.. mutta tiedostoon voi määrittää useita nimiä ns. kovina linkkeinä. Asia on mielestäni kyllä kirjoitettu auki aika hyvin monisteen nykyiseen versioon. Samoin se, että nimi ei ole osa tiedoston sisältöä eikä myöskään i-solmun sisältöä. Itse asiassa monisteen lopullisessa versiossa on suorastaan kursiivilla (harvoissa ja valituissa paikoissa käytetty tehokeino!) seuraava täsmällinen ilmaisu: "tiedoston nimi määräytyy hakemistotiedostoon kirjatun merkkijonon perusteella!" Voi olla, että evidenssi ei tule riittämään tämän tehtävän arvostelun muuttamiseen. Havaintoja, jotka eivät välttämättä aiheuta toimenpiteitä: - Lukuisia yksittäisiä havaintoja; erityisesti sellaisten ääritapausten pohdintaa, joihin asti johdantokurssilla ei päästä. Olin jo aikeissa ennen tenttiä meilata, että "elvistely on sallittua, jos sille on oikea osaamispohja olemassa". Tulen käymään näiden muutamien "Agoran elvisten" tiuhaan kommentoidut vastauspaperit läpi erikseen, ja jos kommentit ovat tarkoin analysoituna valideja niin antaa mennä vain... Vastauspaperien yleiskuva (ilman tarkempaa tarkastelua) voisi viitata siihen, että nämä ovat osaamisensa aiemmin hankkineita, joiden arvosanat painottuvat yläpäähän joka tapauksessa. Tämä sinänsä miellyttävä "gurujen" kanssa operointi ei vaikuta johdantokurssin tietojen pohjalta tehtyihin vastauksiin. *** "Vapaaehtoinen vapaa sana" -kysymyksen vastaukset: - "Varsin selkeä kurssi. Osaamistavoitteet selkeytti ja mallitentti helpotti varsinaiseen tenttiin lukua, kun näki vähän sokeita pisteitään. Lisäksi se, että näki kysymystyypit ennakolta helpotti ja nopeutti tenttiä. Ihana tavoite: opiskelija *uskaltaa* ja osaa käyttää selliä. Siinä on pieni kynnys, kyllä." Kiitos positiivisesta palautteesta. Voin kertoa, että mietin tavoitteita tarkoin, ja tuo "uskaltaa" on olennainen osa, vaikka mielestäni tärkeintä kyseisessä tavoitteessa onkin "aiheuttamatta vaaraa omille tiedoille tai häiriötä muille käyttäjille tai järjestelmälle" :) - "Harmi kun kaikki mielenkiintoinen ja tärkeä tiivistyi n. 5 viimeiseen luentoon. Pehmojohdanto oli parasta viihdettä vähään aikaan. Luennot aina yhtäaikaa eikä jaksanut käydä siksi paikalla. Kiva kun demoilla ei kovaa kiirettä." Kiitos rakentavasta palautteesta, jossa oli positiivisiakin osioita :). Itse olen sitä mieltä, että alusta lähtien kaikki oli tärkeää. Mielenkiintoisuus on subjektiivista. Omasta mielestäni alkupuolen asia on huikean mielenkiintoista, mutta kuten monisteen johdannossakin totean, henkilökohtaiset mielenkiinnon kohteet vaihtelevat varmasti. Tarkoitus oli, että alkupuolella tulisi tekninen pohja ymmärtää ilman suurempaa käsienheiluttelua loppupuolen asiat, joissa ns. "korjataan hedelmät" (termi, jota joku matematiikan luennoitsija aikoinaan käytti siitä, kun alkupuolen teoreettisilla tuloksilla aletaan viimeisillä luennoilla tehdä jotakin hyödyllistä :)) Pehmojohdanto ilmaantui viimevuotisen yksittäisen palautteen perusteella, ja sen on tosiaan tarkoitus olla viihteellinen. Tulevaisuudessa siirrän sen ehkä kuitenkin liitteeksi, jolloin pääteksti menisi ensimmäisillä sivuilla suoraan tekniseen asiaan. - "Vaikeata on, kun tulee miinuspisteitä. Kurssin alussa olleet demot olivat liian helppoja, niin kuljin vähän löysin rantein. Pistä seuraavalla kerralla assembler-jutut heti ja skriptit lopuksi, niin lähtee oikeammalle raiteelle. Kurssin asiasisältö on kokonaisuutena OK ja materiaali oli hyvää. Sellaista toivoisin, että jos keräsin nyt vahingossa liikaa miinuksia, enkä pääsekään läpi, niin voisitkohan tiedottaa epäonnistumisesta heti? Muuten en ennätä valmistautua uusintaankaan. Mukavaa oli, että tenttitilaisuudessa on kunnolla aikaa." Kiitos jäsennellystä palautteesta, hyvistä huomioista ja kohteliaista lisäyksistä :). Miinuspisteiden osalta on ehkä katsottava kaikkien 113 tenttijän tulokset ja tehtäväkohtaiset pisteet, ja mietittävä, onko se -0.5 pistettä liikaa arvaamisen kitkemiseksi. Väittämätehtävissä odotusarvo arvaamalla olisi 0, ja nyt kun on myös "yhdistä lauseita" ym., joissa oikean vastauksen arvaustodennäköisyys on mallia 25%, niin arvaamisen odotusarvo oikeastaan on negatiivinen. Voi olla, että pienemmälläkin miinustuksella saataisiin minimaaliseksi riski päästä arvaamalla läpi. Maito on tietysti jo maassa siinä mielessä, että arvosteluperuste (-0.5 väärästä) oli tiedossa tenttiä tehtäessä, joten jokainen tenttijä on tehnyt oman riskiarvionsa sen tiedon varassa. Tällä perusteella tätä ei ehkä uskalla jälkikäteen enää muuttaa tämän kurssikerran osalta. Katsotaan ja analysoidaan tulokset, ja tehdään sitten toimenpiteitä. Erityisesti katsotaan, että arvosanajakauma käy järkeen. 113 hengen populaatio on uskoakseni riittävän suuri arvioiden tekemiseen ja vertaamiseen aiempiin kurssikertoihin, vaikka kysymykset nyt erityyppisiä olivatkin. - "GNU/Linux; kernel ja käyttis ovat eri asia, kernel ei yritä toteuttaa POSIXia" Hyvä täsmennys. Asiahan on selvä, mutta on saattanut jäädä sanomatta juuri noilla sanoin. Kirjataan se jatkossa materiaaliin noilla sanoin. Uskon kuitenkin, että tällä kurssikerralla saatiin riittävän useaan otteeseen käsiteltyä kirjastojen kerroksia ja ytimen kutsurajapintaa, joten kokonaisuuden jälkeen pitäisi olla kyllä selvää, mihin kirjasto loppuu ja ydin alkaa, ja mihin kerrokseen POSIXin toteuttaminen sijoittuu. HUOM: Jos muistat laittaneesi tenttipaperiin jotakin, mitä tähän ei ollut kaivettu, niin ilmoita!! Koska olen mielestäni ottanut kaikki papereissa olleet kommentit tähän. [Seuraavat löytyivät tarkemmassa läpikäynnissä luennon jälkeen]: - "Tulin tähän tenttiin koska olin unohtanut poistaa ilmoittautumiseni ajoissa. Tarkoitus oli tulla tekemään koe vasta 12.6., eli tähän tilaisuuteen ei oltu valmistuttu. Ompas käsiala huonontunut kun tässä opinahjossa on vuoden viettänyt." Propsit siitä, että tulit paikalle tenttitilaisuuteen, johon olit ilmoittautunut! Onnea ja osaamista seuraavaan yritykseen 12.6. Käsiala kannattaa pitää kunnossa. Pidemmän päälle joutuu melko todennäköisesti draftailemaan suunnittelukaavioita, mindmappeja ynnä muuta, joista kavereiden täytyy saada selvää. Alussa ei vielä ehditä tuohon opinahjossa, kun on niin paljon koodattavaa :). - "Tentti oli hyvä." Noh.. kiva että ainakin joku tykkäsi :) Katsotaan onko tilanne sama vielä arvostelun jälkeen... - "Unohdin lukea tenttiin :)" - "Täytyy vielä vähän treenata..." - "Valitettavasti tälle kurssille ei jäänyt aikaa, mutta opiskelen varmaan kesällä ja tentin heinäkuussa :) Uusinnassapa sitten! - "Hyvä kurssi. Haastava verrattuna moneen ja taitaa uusintaan tentti mennä. You are not prepared!" Kiitos positiivisesta palautteesta. Haastaviahan kaikkien kurssien pitäisi olla, eihän niissä muuten oppisi uutta :). Next time you'll be prepared! - "Tuuletetaan! (toivottavasti tarkastuksen jälkeenkin on syytä siihen) Tutkitaan ennen kuin hutkitaan. Kyseisen palautteen antaja voi kylläkin tuulettaa vähintään selkeää läpipääsyä vastausrivinsä yleiskuvan perusteella. Mallia monta oikein, eikä yritelty arvailla liikaa. - "Ei voi mennä läpi. :)" Hyvä, jos tilanne kuitenkin hymyilyttää hymiön verran :). Uusinnassa sitten! - "Monivalinta on yllättävän hyvä tenttimuoto; vääristä vastauksista tosin rokotetaan ehkä turhan ankarasti, vaikka virhe ajattelussa voi olla pieni. Kiitokset hyvästä kurssista!" Kiitos positiivisesta palautteesta sekä perustellusta kritiikistä! Kyllähän se näin jälkiviisaasti ajatellen on rankka rokotus tuo -0.5 pistettä. Nyt kun sitä ei etukäteen osattu arvata, niin tämän kanssa on elettävä vielä kesän kaksi uusintaa (ks. perustelut yllä). Populaation tasolla skaalataan kokonaispisteytystä kaikkien osalta tarvittaessa, jos tarvetta ilmenee. - "Mukava kurssi, paljon asioita jotka on hyvä tietää. Tavallaan hyötyy ja tavallaan kärsii demojen vapaammasta aikataulusta (soveltuu kyllä hyvin kiireisemmän opiskelijan aikatauluun). Kiitos positiivisesta palautteesta ja rehellisestä mielipiteestä aikataulutuksesta. Deadlinet ovat pohdituttaneet paljon vuosien varrella, ja jokaisessa ratkaisussa on hyviä ja huonoja puolia. - "Muistutti niin paljon mallitenttiä, että tuntui helpolta. Kohta 28 meni arvailuksi, muut kuvittelen tietäväni." Näin oli tarkoitukseni, että malliin tutustutaan ja sitten tuntuisi helpolta. Mutta toivottavasti olit myös tarkkana, koska tehtäviä oli muutettu malliin nähden! Automaatti sen aikanaan kertoo. Tehtävää 28 ei olisi kylläkään välttämättä kannattanut arvata :) Katsotaan nyt, miten kyseisen tehtävän arvostelun kanssa käy ylipäätään (ks. palauteluennolla läpikäydyt huomiot ylempänä). - "Kurssi oli loistava, mutta Ohjelmointi 2 ja vaihtoon hakeminen söivät voimavaroja suoritukselta. Tehtävät olivat paras osa. Erityisen selkeä opastus ja harjoitteet vähensivät pelkoa uudelta unixkäyttäjältä" Kiitos positiivisesta palautteesta. Olen tehnyt paljon töitä mm. mainitsemiasi piirteitä kohti eli selkeää opastusta ja pelkokertoimien pienentämistä uusien teknisten asioiden lähestymistä kohtaan. Toivottavasti vaihtokohde löytyy! Vaihtoon lähteminen on erittäin suositeltavaa. Muista sopia vaihdossa tehtävistä kursseista *etukäteen* oman opintoneuvojan kanssa :) - "Pitäisi katsoa luentotallenteet ainakin kaksi kertaa lisää ennen kuin tuntisi osaavansa." Niitä voi onneksi kotona kelailla tylsien osien yli ja katsoa tuplanopeudella tai hidastettuna tarpeen mukaan :) *** Yleistä palautetta demoista Nämä löytyvät demosivustolta (ei varsinaisa spoilereita niille, joilla demot on vielä kesken): http://itka203.it.jyu.fi/pages/geneerinen_palaute_opiskelijoille_2015.rst Käydään läpi luennolla, jos ehditään.