-*- coding:utf-8 ; mode:org -*- Käyttöjärjestelmät, kevät 2018. 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 2018: ** Luento 1: Aloitus, yleisinfo ja suoritusvaatimukset Luennon päätavoite on kuvailla kurssin tekniset vaatimukset ja muu perusinfo. Varsinaiseen asiaankin ehdittiin alustavalla tasolla aivan lopuksi. - Esittelyt: opettajat, opiskelijat, opiskelijoiden pääaineet (Millainen jakauma 2018? Valtaosa tietotekniikka. TJT hyvänä kakkosena. Löytyy myös ainakin fyysikoita. Opiskelijoiden pääasialliset käyttöjärjestelmät omassa käytössä (pöytäkoneet, tabletit, älypuhelimet)? - Perinteinen ryhmäkuva vuosia harjoitellulla koreografialla... Kaikki, mitä "koreografiassa" nähdään, liittyy 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ä: Demot on julkaistu toistaiseksi HTML-muodossa (linkki kurssin etusivulta). Seuraavalla luennolla tulee tarkempi 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! Palautusjärjestelmää ei ole vielä ehditty testata tälle vuodelle, joten teknisestikään tänään ei ole vielä hyvä päivä palauttaa. 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!] * "Palopuhe" demojen tekemisestä. Olennaisimmat kohdat aiemmilta vuosilta havaittuna: + 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ä monesta syystä, (mukaanlukien puoliautomaattinen rekisteröinti Korppiin), joten ohjeet on tosiaankin luettava, jos mielii saada tehtävät läpi! * Aikataulut ja salit: Korpissa. (Päivittyy kurssin alkuvaiheessa.) Ryhmäohjauksia mikroluokissa kenties ainakin käyntiin pääsemiseksi. Aikatauluista tiedotetaan. Luennot ovat iltapäivästä - tehdään yhteinen ratkaisu, pidetäänkö niissä tauko vai jätetäänkö tauko pois ja lopetetaan aiemmin: TODO * 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ä. - Etenkin etäopiskelijoille, mutta myös muille, meillä on käytössä kaksi vertaistukikanavaa: yksi virallinen ja yksi epävirallinen: * Sähköpostilista itka203_kevat2018_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 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. (IRC-palvelu ei ole Jyväskylän yliopiston tukema palvelu, eikä se ole kurssin tiedotuskanavana virallinen. Hyödyllinen vertaistukikanava se on, ja irc.cc.tut.fi -palvelin ottaa vastaan yhteyksiä niistä JY:n koneista, joilla meidän demot tehdään) 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/ Hieman ehdittiin jopa itse asiaankin luennon lopussa: - Demo1:n ohje, tavoitteet sekä tarpeelliset varoitukset ohjeen alussa. - Tekemisen saa aloittaa, kun on sisäistänyt varoitukset!! ** Luento 2: Luentomuoto, 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: - Demojärjestelmän käyttöönotto etenee, ilmoitetaan kun on online. - "Open labrapäivä" -konseptin selitys; ensimmäinen sessio torstaina 8:30-12 mikroluokassa MaD206. Pääteyhteys ja siihen liittyvät asiat: - Luentomuoto ja kurssin työkalut alusta alkaen ja esimerkit näyttäen: pääteyhteys, bash-shell ja tekstipohjaiset työkaluohjelmat. - Näytään, mitä tapahtuu kulissien takana ennen luentoa: pääteyhteys, KiTTY-asetukset, screen, komentojen antaminen. - UNIX-käyttäjätunnuksen aktivointi salasana.jyu.fi -palvelussa. - Miten lähdetään tekemään demoa 1: Alkuvaroitukset (uudestaan) ja toisaalta rohkaisu. - KiTTY -pääteohjelma (asennettava itselle, jos haluaa tehdä kotoa käsin; tehtävien palauttaminen kotoa käsin tulee vaatimaan lisukkeen, josta infoa ensimmäisen demotehtävän palautusohjeessa). - 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 - Komento alussa, sitten argumentit. Kaiken näytetyn tulee sujua viikon päästä jokaiselta mikroluokassa tai kotona ilman pienintäkään vaikeutta. Demot 1&2 opastavat alusta lähtien. - Screen-ohjelman käyttöesimerkki - Lopussa spoileria demo 1:een, useless use of echo ym. - kill ja kuinka selvitä "nolosta ikuisesta silmukasta". - Ja sitten vaan tekemään! ** Luento 3: Yleiskuvaa, tavoitteita, esitietoja Päivän päätavoite on saada omatoiminen lukeminen ja tehtävien tekeminen käyntiin. Seuraava luento on vasta kahden viikon päästä (välissä pääsiäistauko). - Tilanne demojärjestelmän suhteen: Näyttää hyvälle, alustavat kokeilut ovat osoittaneet järjestelmän toimivaksi ainakin, kun sitä käyttää nätisti. Demotehtäville tulee vielä luoda palautusmekanismi, puhdistaa kokeilut ja sitten järjestelmä julkaistaan. HUOM: Palautuslaatikon puute ei edelleenkään vaikuta mitenkään demojen tekemiseen - ainoastaan palauttamiseen ja tarkistamiseen. On tärkeää aloittaa demot, jos ei vielä ole sitä tehnyt!! - Huomatkaa open labrapäivä ja Koodaamo - Ohjeellinen "deadline" noin 1 tehtävä / viikko. Sitten kohti itse asiaa: - Mainintoja oppikirjoista, esim. OSTEP http://pages.cs.wisc.edu/~remzi/OSTEP/ - Kurssimonisteen luonne. HUOM: Nyt alkakkee sukeltaa monisteeseen! - Ensimmäinen vilkaisu "jyrkempään" taustamateriaaliin: AMD64-manuaalit, POSIX, C99 spesifikaatio. Mitä ihmettä ja miksi? - Miten homma jatkuu demossa 2: Screen-ohjelman käyttely. Demoissa tulee paljon muutakin. Ajatuksella kannattaa tehdä, mutta aloittaa pian. 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. - Esitietojen varmistaminen: Mitä ohjelmointi 1 -kurssilta pitäisi muistaa ( ks. https://trac.cc.jyu.fi/projects/ohj1/wiki/sisallys ) - 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ä). HUOM: Hetimiten demon 1 & 2 ääreen ja lukemaan monistetta, jos ei olla jo näissä menossa!! ** Luento 4: Tietokonelaitteisto, tiedosto, kääntäminen, konekieli, debugger *** Infoa keväälle 2018: - Demojen palautusjärjestelmä viivästyy pienen tietoturvateknisen syyn vuoksi. Demoja saa ja pitää edelleen tehdä - seuraavaksi demo 3. Jonnen ja minun YPE15-opetuskokeilut ("save-the-date"): - Mikroluokassa tiistaina 17.4.2018; teemana C-kieli. - Osallistumalla kuittaantuu pakollinen demo 4 - Keskenään identtiset sessiot - voit ilmoittautua Korpissa vaikka heti. - Muoto on parityö. Parit ratkotaan paikan päällä siten, että jokaiselle tulee mahdollisimman vähän ennalta tuttu pari. - Jos et pysty tulemaan paikalle tai suoritat kurssia eri aikaan, tarjolle tulee korvaava itsenäinen tehtävä demo 4:n suorittamiseksi. Tehtävä julkaistaan lähisession jälkeen. - Demo 4:n tehtäväohjeen teksti olisi syytä sisäistää ennen mikroluokkasessiota. - Luennoilla 16.4.2018, 18.4.2018, 23.4.2018 saattaa tapahtua lisää kokeiluja. - Kurssikaverimme muista oppiaineista ovat tarkkailemassa kokeiluja. - Kysymme osallistujilta palautetta ja toivomme aktiivista osallistumista tältäkin osin. *** Esitietoja - Pintapuolisia esi- tai ennakkotietoja kurssien Algoritmit 1&2. -puolelta. Arkihavaintoja abstrakteista tietorakenteista: tietue/olio, taulukko, lista, jono, pino, puu. Lukujärjestelmistä: - lukujärjestelmät ovat 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. - Tarkentava kysymys yleisöstä (2017): Negatiivisten kokonaislukujen esittäminen? Tyypillistä on kahden komplementtiesitys... palataan tähän varmasti myöhemmin. Heksana kirjoittaisin koodiin esim. -0x7B, jos tarkoittaisin kymmenjärjestelmän lukua -123. MUTTA, jos haluaisin ihan kirjoittaa 8 bittiä, jotka tarkoittais esim. etumerkillistä -1:tä kahden komplementtiesityksessä 8-bittisessä tallennustilassa, niin voisin kirjoittaa 0xff. -2 == 0xfe jne. 0xff + 1 (8-bittisenä) = 0x00 0xff + 3 (8-bittisenä) = 0x02 Jos olisi 16-bittinen tallennustila, niin -1 olisi 0xffff jne. Aina jos kaikki bitit on ykkösiä, niin kahden komplementtiesitys tulkitaan luvuksi -1. Heksalukuja tarvitaankin yleisimmin juuri silloin, kun nimenomaan bittiesityksellä on väliä. Näin ollen "-0x7B" on luultavasti aika harvinainen tapa kirjoittaa koodiin vakio "-123" - Googletellaan löytyisikö aihepiiriin liittyvä video edelleen haulla "Ariane 5 test launch". Kurssin asiat eivät ole rakettitiedettä, mutta rakettienkin kanssa toimittaessa ne täytyy ymmärtää, mm. lukujärjestelmät ja tallennustilan rajallisuus laitteistossa. Videolla paukahtaa puolisen miljardia euroa nätisti, koska 16 bitin mittaiseen tallennustilaan yritettiin laittaa luku, joka olisi tarvinnut useampia bittejä. Oli siinä muutakin, alkaen muuttuneista vaatimuksista (tavanomaista ohjelmistoissa) ja puuttuvista esitarkistuksista (tavanomainen paikka, josta säästetään, kun painotetaan aikatauluja). Lisätietoa, jos kiinnostaa: http://sunnyday.mit.edu/accidents/Ariane5accidentreport.html - Kerratkaa tai opetelkaa ensimmäistä kertaa binääriluvut, heksaluvut ja oktaaliluvut!! Jatkossa katsotaan heksoja paljon! Nyt vaelletaan johdannon kerroskuvan matalimmilla tasoilla, lähellä tietokonetta ja prosessorin rajapintaa. *** Tietokonelaitteistosta 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. Jäi hyvin alustavalle tasolle; palattava aiheeseen myöhemmin tarkemmin! - Lisää viimeistään demossa 2 vastaan tulevia termejä: Prosessi, prosessi-ID. lapsiprosessi, vanhempiprosessi, prosessipuu. *** POSIX-vartti: - Mikä on POSIX? Kuka sen on tehnyt? Mitä se sanoo esimerkiksi tällä luennolla tai aiemmin nähdyistä asioista? + Suositellaan iltalukemiseksi alun yleiskuvaukset ja rajaukset - POSIX ei ota kantaa laitteistorajapintaan eikä käyttöjärjestelmän sisäiseen rakenteeseen; kyseessä siis nimenomaan rajapintadokumentaatio käyttöjärjestelmäkerroksen ja sovellusohjelmakerroksen välissä. C, minimalistiset kirjastot, shell-komentokieli ja tietty minimijoukko apuohjelmia / komentoja. Vain tekstiä; ei mitään grafiikkaan liittyvää. + Base definitions Intro: (mm. XBD Sec. 1.7 "Portability"), Modulaarinen rakenne, laajennukset ja marginaalihuomioiden formaatti. *** C-kieli ja demo 3 Pyöritään luennoilla kuitenkin hetken verran laitteistorajapinnassa niin konkreettisesti kuin pystytään. Käytetään apuna mahdollisimman matalatasoista käyttäjärajapintaa (shell, C-kieli). 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.. Nämä ehdittiin käydä luennon lopussa: - Esimerkkiohjelmien nouto wgetillä - (Vielä kerran) editointi yhdessä screen-ikkunassa ja kokeilut toisessa. - C-ohjelman kääntäminen POSIXin määräämällä c99 -komennolla. - Lähdekooditiedoston sisällön katselua hexdumpilla. Normaali tekstitiedostohan se vain on.. - Ääkkösen "ä" UTF-8 -koodaus kahtena tavuna, heksoina 0xc3 0xa4 ** Luento 5: Debuggeri, konekieli. Ohjelman argumentit ja virhekoodi Viime kerralla jäi nämä pois suhteessa vuoteen 2017: - 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 tarkemmin mm. rivinvaihtojen ja skandinaavisten kirjaimien kuvaamista tekstitiedostossa. Mainittakoon UTF-8 -merkistökoodaus (yksi Unicoden koodaus). Ehkä myöhemmin: 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ä. Huvin vuoksi ja löytämisen ilon kannalta: - Tarkastellaan erilaisia tiedostoja heksavedoksena.. vaikkapa kuvatiedostoja (JPG, PNG) ... - Entäpäs tämä: http://users.jyu.fi/~nieminen/kj18/mystery2 Sitten jatketaan "Hei maailma" -ohjelmasta. Edelleen huvin vuoksi ja löytämisen ilon kannalta... - 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 esim. POSIX _ei_ ota kantaa; niinpä työkalut ovat sidoksissa GNU-tuotoksiin, tiedostoformaatit Linuxiin, ja konekieli AMD64 prosessoriarkkitehtuuriin, jotka meillä yliopiston palvelimelta löytyvät. Huolellisesti POSIXin mukaiseksi tehty C99 -kielinen ohjelma kuitenkin voitaisiin kääntää mihin tahansa POSIX-yhteensopivaan järjestelmään, eli se "kelluu" abstraktin rajapinnan päällä!) + katsottin AMD64-manuaalia: * Idea konekielisten tavujen muodostumisesta * Esimerkki käskyn esittelystä, "PUSH" .. erityisesti löytyi rajapintadokumentaatio sille, miksi "push %rbp" on konekielellä nimenomaan heksa 0x55 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.) - 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". Ohjelman kytköksiä toimintaympäristöönsä: argumentit ja virhekoodi - Lavennetaan "hei maailmaa" käyttämään argumenttejaan. - Tehdään jotain myös virhekoodilla - TODO tarkista syntymäaikavuosiluku-tehtävä, onko tarkoitus käyttää koko vuotta vai paria alkua - TODO jatka selittämällä rakenne, ABI, yms ** Luento 6: Prosessi, virtuaalimuistiavaruus Ensin tiedotus: demopalautusjärjestelmä on käytössä! Ohjelman kytköksiä toimintaympäristöönsä: Aiemmin nähty argumentit ja virhekoodi. Katsotaan vielä seuraavat: - standardiulostulo (C:n stdout, vastaa esim. Javan System.out'ia), standardivirheulostulo (C:n stderr) - ympäristömuuttujat (demo 3:n asiaa), voi asettaa shellissä (myös skriptissä), exportatut ympäristömuuttujat periytyvät lapsiprosesseille eli ohjelmille, jotka kyseinen shell käynnistää. - samalla metataitoja: kun unohtuu, miten joku juttu toimii jossakin kielessä tai alustassa, niin nopein Googlettaja (joka osaa vielä soveltaa netin pirstaleisia ohjeita omaan työn alla olevaan ongelmaan) on voittaja. Löytyi helposti getenv() -kutsun manuaalisivu. Totuus on esim. POSIX-standardissa, mutta nettisivukin vaikutti tässä tapauksessa luotettavalta. - NULL-osoittimen luonne: tarkoittaa "osoitetta ei ole olemassa", mutta koodataan kokonaislukuna kuten muutkin muistiosoitteet. Saattaa olla kääntäjästä riippuen esim. 0, mutta on silti syytä kirjoittaa isoilla kirjaimilla vakiona NULL. Sitten eteenpäin: - Askeltaminen konekäsky kerrallaan, "stepi" (step instruction). - Askelletaan esimerkkikoodia konekielinen 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. ** Luento 7: Osoitteen tulkinta, MMU, käyttöjärjestelmäkutsu Nämä jäi edelliseltä kerralta: - 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. - Vilkaistaan luentomonisteen listaa x86-64 -prosessorin yleisrekistereistä. - Todettiin RIP eli käskyosoiterekisterin muuttuminen peräkkäissuoritteisissa käskyissä ja jopa JG (jump if greater) ehdollisessa hyppykäskyssä. Ts. prosessorin nouto-suoritus-syklin toteaminen. - Virtuaalimuistiavaruus on syytä käsitellä alustavasti: * 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. Tietyn käyttöjärjestelmän osalta on sovittu ABI (Application Binary Interface). Esim. AMD64-prosessorin päällä Linuxissa on sovittu käytettäväksi kyseiselle prosessorille adaptoitua "SysV ABIa". Edellinen loppuun: - Virtuaalimuistiosoitteiden tulkinta alustavasti. C:llä, assemblerilla ja debuggerilla vielä hetki: - ohjelman jäljitys strace -apuohjelmalla, joka näyttää kaikki tehdyt järjestelmäkutsut. - 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. + Puhdas Assembler-ohjelma. Motivoidaan kerroksittaisten abstraktioiden käyttöä. [Tässä kohtaa luento loppui..] ** Luento 8: C-kieli, linkitys. Mitkä tunnelmat salissa? A=huippua! B=OK C=ei niinkään D=hirvittää. Mini-info keväälle 2018: - kiitos 55 eilisessä "laboratoriotyössä" käyneelle. Korvaava itsenäinen suoritustapa määritellään pian - oletettavasti vaaditaan viimeistelty kirjallinen vastaus (ja ohjelmakoodi) kysymyksiin, jotka labrassakin aiheuttivat pohdintaa. - YPE-kokeilut jatkuvat: Paavo ja Jonne vetävät edelleen pariluennointina, ja tällä luennolla olisi tarkoitus kokeilla Socrative -välinettä. - Seuraava open labrapäivä ma 23.5.2018 klo 8:30-11:45 luokassa Ag B112.2 (Latin). Perjantaina koodaamo normaalisti. Tarkkaavainen huomio: Monisteen kuvassa 14 pitäisi olla 48-bittisiä osoitteita, mutta oli 56. Hups. Korjaus aiempaan ohjeeseen VPN:stä.. Ciscon VPN-softa tarvitaan Windowsissa, mutta ei Linuxilla eikä Macillä. VPN:n käyttö hyvä opetella joka tapauksessa, mm. verovaroilla teille maksetut artikkelitietokannat toimivat yliopiston verkosta käsin! (luentovideolla tässä lyhyt IRC-demo) Poimitaan ajatus, johon jäätiin viime kerralla. Eli katsotaan konekielistä Hello worldiä ja käyttöjärjestelmäkutsun tapahtumista sovellusohjelmassa: - 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. + 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ä.. Nyt silmäiltiin päällisin puolin käyttöjärjestelmäkutsun eli SYSCALL-käskyn selitys pseudokoodeineen. Kuten mainittu, manuaalit ovat hyvää, unettavaa, mutta sivistävää iltalukemista. + 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. Tsekattiin vähän näitä: - ELF-tiedoston formaatti (vilautettiin speksiä PDF:stä) - 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ä! - selväkielisempi listaus ELFin sisällöstä: objdump -x a.out tmv. - muistin tarkastelu debuggerissa.. lisäesimerkki 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'. 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. Lopussa YPE-kokeiluna Socrative-kysely. TODO: Täsmennä. ** Luento 9: käyttäjätila, käyttöjärjestelmätila, C-kieli, Aktivaatio, kutsupino, Mini-info: - demo 4 itsenäinen palautustapa on nyt määritelty. Löytyy demo-ohjeista (lopussa linkki C-koodiin). - Palautusjärjestelmässä laatikko auki. 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ä vuonna 2016. cURL on POSIXin määrittämä [EIKÄ ole POSIXin määrittämä, mistä lie joskus tullut opettajalle moinen aivotuhnu? Yleisesti käytetty ja alustariippumaton se toki on] 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. Tärkeä tilannekatsaus: - Varmistetaan luentomonisteen sisältö ja tilanne, missä ollaan nyt. Tilanne: Jotakuinkin nyt tulisi olla luettu ja ymmärretty sivulle 84 asti. Täydennystä edellisiin aiheisiin: - 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#L107 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. Sitten jälleen mukavasti "tutuksi ja turvalliseksi tulleen" demo4:n mallikoodin ja samalla tapaa tutun tekstimuotoisen debuggerin parissa: Isompi ohjelma, jossa on vaikkapa aliohjelmakutsuja ja silmukoita: - Askelletaan demo 4:n esimerkkikoodia lähdekoodirivi kerrallaan debuggerilla. Havainnoidaan kutsupinoa, jonka tilanteen saa gdb:ssä näkyviin komennolla "backtrace" tai lyhennettynä "bt". Muita nimiä ainakin aktivaatiopino, suorituspino. - Katsotaan vähän vinkkiä demo4:n palautustehtävän aloittamiseksi. Entä jos tulee vahingossa "ikuinen silmukka"? (Helposti käy...) Ctrl-C, debuggeri ja tarkkaavaisuus koodaamisessa auttavat. Älä unohda kynää ja paperia! - aliohjelmakutsu, kutsupino - debuggerin näkymä kutsupinoon, 'backtrace'-komento näyttää pinoon kullakin hetkellä kertyneet aliohjelma-aktivaatiot. - askeltaminen konekielikäsky kerrallaan erityisesti rekursion päättymisen kohdalla. ** Luento 10: Ohjelman jälki, kutsupino konekielessä, ABI Infoja: - Demojärjestelmä on kokeellinen (ja se on kivaa). Yleisohje: Sivun uudelleen lataaminen (refresh, esim. F5 tmv.) voi auttaa, jos näyttää kummalliselta. Lipun klikkaamisesta voi ilmiantaa pahiksen. Toivottavasti ei ole todellista tarvetta klikata sitä :) - Vappuaaton ohjelmaa: 8:30-12:00 Open labrapäivä mikroluokassa (Europe) 16:15 Käyttöjärjestelmien luento 17:45 luento päättyy. Ehtii vielä patsaalle vappua viettämään. - Open labrapäivät myös seuraavana maanantaina. Ja seuraavana. - Demo4 työn alla. Tämän päivän jälkeen toivottavasti demo5. Jatketaan demo4:n esimerkkikoodeilla ja luentomonisteen pinokehyssarjakuvasta. Esimerkkejä C-kielellä (HUOM: osin kertaavaa!): - Demo4:n palautustehtävään vähän sommittelua alkuun, esim. seuraavan luvun laskeminen (ei spoilata kokonaan kuitenkaan!) - Mitä tapahtuu, ja mitä voi tehdä, jos vahingossa tulee ikuinen silmukka? ("Ctrl-C" painallus, "killall ohjelmanimi" -komento) - Muistetaan perinteinen "kaikenlaskija" -esimerkki demonstroimaan aikakatkaisun tarvetta. Aliohjelmien ja pinon käyttö (osin jo myös demon 5 aihepiiriä): - 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. Demo 5:n olennainen sisältö, eli aliohjelma-aktivaatio ja konekielinen ohjelman suoritus. - 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. ** Luento 11: Historiakatsaus, Aikakatkaisu/keskeytys Ennakoiva havainto: - 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äjätilan ohjelmalla täytyy olla mahdollisuus pyytää siirtymää käyttöjärjestelmän palveluun ("system call") jolloin prosessorin tilan on vaihduttava. 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. - pakollinen maininta: http://www.cs.utexas.edu/users/EWD/ewd01xx/EWD196.PDF eli Dijkstran "The structure of the THE-multiprocessing system", josta käyttöjärjestelmien jakaminen kerroksiin (julkaisussa 'System hierachy', nykyään 'layers'), sivutetun virtuaalimuistin esiversiot ja semaforit ovat peräisin. (lisämateriaalia) Sitten periaatteessa luentomonisteen järjestyksessä etteenpäin... Yhteenveto käyttöjärjestelmän tehtävistä, tavoitemittareista ja kompromisseista. Prosessorin suoritussykli, tarkempi kuva: - 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. Yleisön kysymys 2017: "Blue screen" (win), "kernel panic" (linux) tulosteista.. kyseessä käyttöjärjestelmän virhe, josta ei ole paluuta. kyllä näissä virheilmoituksissa nimenomaan viitataan käyttöjärjestelmän muistialueisiin (koodiosoite RIP, kernel stack pino-osoite RSP) ** Luento 12: Prosessi, säie. Tilakaavio, fork(), exec(), shellin perustoiminta Moniajo, prosessi, "säie", resurssit, haaroitus ja käynnistys. Esim. vuoron vaihto prosessien välillä sisältää hukka-aikaa: P1 |------| |------| P2 |------| kj |---| |---| |---| Tiheämpi kellokeskeytys: P1 |---| |---| P2 |---| |---| kj |---| |---| |---| Prosessi? Kertausta aiemmista havainnoista: - POSIXin Base Definitions -osion termimäärittely "Process": "An address space with one or more threads executing within that address space, and the required system resources for those threads." Vautsi... Pystytään jo ymmärtämään suurin osa tästä kuvailusta! 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ä. Lisähuomio POSIXin termimäärittelyssä: "Many of the system resources defined by POSIX.1-2008 are shared among all of the threads within a process. These include the process ID, the parent process ID, process group ID, session membership, real, effective, and saved set-user-ID, real, effective, and saved set-group-ID, supplementary group IDs, current working directory, root directory, file mode creation mask, and file descriptors." - 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 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 käyttöjärjestelmäkutsujen tehostamiseksi. 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). Tämä ``task_struct`` 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. Tässä kohtaa tilakaavio. Ja jumppa. Jatketaan suoraan prosessin olemuksesta: - 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ä. - 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. (ks. esimerkkikuva tämän luennon alussa) ** Luento 13: Säikeet. Kilpa-ajo, lukot, deadlock. Muistutus ekasta tentistä: - ke 16.5.2018 klo 16:15-20:15. Ei tarvitse ilmoittautua. Ikään kuin luento. Uusinnat heinäkuu, elokuu. Näihin ilmoittautuminen Korpissa. - kurssi lähestyy loppuhuipennusta. Demot 1-5 pitäis alkaa olla sisäistetty. - Hmm... Tässä kohtaa pittäis alkaa olla demo6 speksattu... Tulee keskiviikkona. Assemblerilla tehdään siinä itse. Säie vs. prosessi: - Säie on yksi ajassa etenevä suorituskohta prosessin koodissa, joka muodostaa konekielisten suoritusten "jäljen" ja vaikutuksia dataan. Pieni tenttitärppi luennolla tässä kohtaa (paperin käyttö jäljityksessä pääkopan tukena). - 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ä; suurten tiedostojen lataamiset ja tallentamiset), seinäkelloajan minimointi rinnakkaislaskennalla. - Laskentatehtävien nopeuttaminen säikeistämällä vaatii 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 2018/l13/ -hakemistossa: saikeiden_tarve.c saikeet.c - katsottiinpa myös Googlella Java Thread API ja C# vastaava. - "kilpa-ajotilanne" eli race condition: vuoronnus voi milloin vain keskeyttää säikeen (tai prosessin) ja antaa suoritusvuoron toiselle: koodi 2018/l13/ -hakemistossa: race.c - lukitus auttaa: keskinäinen poissulku race_fixed_mutex.c - deadlock -tilanne, esimerkki huolimattomasta resurssilukituksesta: huonon kahvihuoneen simulaattori kahvihuone_deadlock.c ja toimivamman kahvihuone_ei_lukkiudu.c ** Luento 14: IPC: signaalit, viestijono. Semafori. Kuluttaja-tuottaja. Demo 6 esittely. Vilkaistaan mallitenttiä (sama kuin viime vuonna). Tästä jatketaan viimeinen viikko tiukasti siihen asti kuin vaan ehditään: Prosessien (ja säikeiden) välinen kommunikointi eli IPC: - engl. Inter-process communication. Yksi tärkeistä tehtävistä, joihin käyttöjärjestelmää tarvitaan. Esimerkkejä: + signaalin lähettäminen pääteyhteyden näppäilyllä "päällimmäiselle" ohjelmalle, jolle syötteet ohjautuvat. + signaalin nappaaminen C-kielisessä ohjelmassa: koodi 2018/l14/sigesim.c + 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 repossa: 2018/l14/chattomyself.c (tässä oli "demoefekti" luennolla 15.. todellinen efekti siis se, että luennoitsija luuli varoitusta virheeksi ja ettei koodi kääntynyt.. vaikka se kääntyikin. Esimerkistä korjattu nyt myös varoitukset pois.) Semafori: - esimerkki: tuottaja-kuluttaja -probleemi sekä sen ratkaisu kolmella semaforilla koodi repossa: 2018/l14/tuottaja_kuluttaja.c "ASCII-sarjakuva" repossa: 2018/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! Miksi? Tulee älyttömästi hukka-aikaa lukituksia hoitavista käyttöjärjestelmäkutsuista!! 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. Tarkkana suunnittelussa ja toteutuksessa! + Säikeitä kannattaa alkaa käyttämään omissa ohjelmissa tarpeen mukaan, muistaen tarkkaavaisuuden ja potentiaaliset ongelmatilanteet! ** Luento 15: Virtuaalimuisti, sivutaulut, swap. I/O. Unixin erikoistiedostot. Loppusuoralle / lopputaisteluun... Niin monta tuntia aikaa ekaan tenttiin, että kyllä me siihenkin mennessä vielä paljon hyviä asioita ehditään oppia. 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ä. - 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: 2018/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 - Katsotaan jotain oikean ohjelman karttaa, esim. emacs-tekstieditorin. Havaitaan mm. lukuisa joukko kirjastoja, joiden tarvitsee olla ladattuna fyysiseen muistiin vain yhtenä kopiona, vaikka emacs olisi käynnissä vaikka kuinka monena prosessina. Pari lisäesimerkkiä Unix-tyyppisestä "kaikki ilmenee tiedostona" -lähestymisestä (näitä on ehditty nähdä jo aiemminkin, kun signaaliluennolla juteltiin dd -ohjelmasta): + /dev/urandom -"tiedostosta" voi lukea loputtomiin satunnaislukuja + /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. + 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ä. + /dev/sda -"tiedostosta" voi lukea (käyttöoikeuksien salliessa) kovalevyn koko sisällön bitti bitiltä esimerkiksi koko järjestelmän kattavaa varmuuskopiointia varten. Lisää tiedostonhallinnan käyttäjänäkökulmaa: Esimerkki: - Tiedostojen käyttöoikeudet rwx / ugo. Shell-ohjelma chmod nähty jo aiemmin. (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ä...) 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 (ajurit). - I/O -kutsun kulku ohjelmistokerrosten läpi (karkea yleiskuva). Lopussa vielä http://www.pouet.net/prod.php?which=67941 Sitä nyt vaan ei voi estää. * Ja se oli sitten siinä vuodelta 2018! Tähän ehdittiin 2018. Loput ei tule tenttiin. Vuoden 2018 mukaista kurssia voi suorittaa helmikuuhun 2019 saakka. Virallisten tenttikertojen (3 kpl) jälkeen kysy erillistä tenttimahdollisuutta. * 2018 pois jätettyä: ** C-kielestä "pienoisgallup" Alkuun "YPE-hype" (eli omien yliopistopedagogisten opintojeni hurmoksen herättämä interaktiohetki): - Muodosta lähimpänä istuvien 2-3 henkilön kanssa keskusteluryhmä; keskustelkaa seuraavasta kysymyksestä demo4:n ja tähän asti luennoilla käsitellyn valossa: + Mikä tällä hetkellä askarruttaa eniten C-kielessä? (esim. suhteessa aiemmilta kursseilta tuttuihin kieliin, muihin aiempiin ohjelmointikokemuksiin tai ennakko-odotuksiin? Keskustelu saa rönsyillä muihinkin suuntiin, kunhan pyörii C:n ympärillä.) - Keskustelun löydöksiä (luentovideo alkaa tästä kohtaa): + "viitemuuttujat", ts. viedään aliohjelmalle **muistiosoite**. + miksi Windowsin ja Linuxin (tai ylipäätään eri käyttöjärjestelmien) C-ohjelmat eivät ole yhteensopivia keskenään? HUOM: Ne *ovat* yhteensopivia, jos niissä (1) ei kutsuta käyttöjärjestelmäriippuvaisia aliohjelmia ja (2) ohjelmat käännetään uudelleen (ABI määrää mm. miten aliohjelmia kutsutaan konekielessä; ABI on käyttöjärjestelmän tekijän valinta ja riippuu aina prosessoriarkkitehtuurista.) + (on ihan OK, jos tässä vaiheessa "ei osaa vielä muodostaa kysymystä". Toivottavasti se on pian mahdollista!) + C:n "listat"? HUOM: Lista on teknisesti eri asia kuin taulukko (ks. esitietoluku monisteesta!) Kysymyksessä tarkoitettiin taulukkoa ``int taulukko[3]`` - miksi se sallii kirjoittaa ``taulukko[1000] = 42`` Noh.. C yrittää tehdä mahdollisimman "vähän" ja jättää loput ohjelmoijan vastuulle. HUOM: käännösvaiheessa voi olla vaikea tietää, mihin sijoitetaan. Esim. ``taulukko[i] = 42``. Itse pitää ohjelmoida esim. ``if (lkm > maximi) error("") else ...`` Voi aina tehdä kirjaston, joka hoitaa esim. tarkistukset. ``turvallinen_taulukko_lisaa(taulukko, maksimi, indeksi, arvo);`` HUOM: C:n taulukko on erilainen (yksinkertaisempi) kuin modernimpien kielien automaattisesti skaalautuvat ja rajat tarkistavat tietorankenteet. + "Eikö ne 1970-luvulla 'tajunneet' tehdä taulukosta turvallisempaa"? Historiikeista voi selvitä. Joka tapauksessa voi olla suorituskykykysymys. - vuosi 2018 tässä moi, ja Jonne: Kyllä tajusivat. Taulukoiden rajojen tarkistus (ainakin 1960-luvulta https://en.wikipedia.org/wiki/Bounds_checking#Index_checking), poikkeukset (LISP ja PL/I 1960-luvulla) ja roskien keruu (LISP 1950-luvun lopussa) oli keksitty jo tuolloin, mutta valitettavasti K&R C:tä tehdessään halusivat tehdä vain "makroassemblerin", joten moiset höpötykset saivat jäädä kielestä pois. Tämä sama pätee seuraavaan kysymykseen. + Miksi muistivuotojen hallinta ja muu resurssien vapautus on ohjelmoijan vastuulla C:ssä? Vastaus on kysymyksessä: Milloin pitäisi vapauttaa? Vaatii ajonaikaisen järjestelmän, joka tarkkailee resurssin tarvetta. Uskomukseni on, että ainakin osittain tavoite on ollut vähentää alustan monimutkaisuutta. Myöskin tutkimus kielten toteutuksessa on elänyt omaa raidettaan 1970-luvun jälkeen, kun C syntyi. + Mikä on .c, .h ja .o -tiedostojen suhde toisiinsa? Ks. demo3 ja demo4 tehtäväohjeet. Tästä jatkuu itse asia sitten: - Tavujärjestys (byte order), jos jotakuta on ihmetyttänyt (parhaimmillaan on ihmetyttänyt!)? AMD64:ssä on "little-endian" -järjestys. Kokeillaan luvulla 0x0123456789abcdef, jonka tavujärjestys on helppo varmistaa vaikkapa debuggerin tulosteesta. ** Lisuketta edelliseen - Näkökulmia viime luennon keskusteluhuomioihin: + C on lähtökohtaisesti suunniteltu "laiteläheiseksi" - esimerkiksi lähdekoodissa näkyvät rakenteet vastaavat datan sijoittumista tietokoneen muistiin niin, että mitään ei ole tai tapahdu "piilossa". Mm. tämän lähtökohdan vuoksi C (ja sittemmin C++) soveltuvat käyttöjärjestelmien ja muun laitehallinnan toteuttamiseen: datan sijainti tietokoneen muistiavaruudessa nähdään suoraan, koska struct-rakenteet ja taulukot (mukaanlukien merkkijonot) ovat kiinteitä, peräkkäin sijaitsevia pötköjä. + Mitä muuta C:n yksinkertaisuudesta seuraa? Mahdollisimman pieni määrä ajonaikaista alustakoodia - mm. siksi C soveltuu sellaisten pienten prosessorien ja mikrokontrollereiden ohjelmointiin, joissa ohjelmalle tai datalle ei yksinkertaisesti ole kovin paljon tilaa. Tällaisten valmistus ja siten käyttäminen tuotteiden osana on luonnollisesti halvempaa (=tarkoituksenmukaista) kuin isompien. + Miksei C:ssä olisi edes käännösaikana estetty taulukoiden tilan ylittämistä? Itse asiassa kääntäjät osaa varoittaa aika hyvin. Käytä oikeassa ohjelmassa -Werror argumenttia gcc:ssä ** Ehkä vielä takas? [Siirtynyt aiemmasta..] Alkuun 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ä. ** alkupuolen luennoilta.. + (ei pilata kaunista speksiä vuonna 2018 tällä:) 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). Viime vuoden "opettajan pääsiäisläksy" eli pääohjelma, jossa ei ole eksplisiittistä return-lausetta lopussa... tämähän se tuotti hämmennystä ja "huonon esimerkin", kun en saanut kääntäjää varoittamaan ja kieltäytymään omaan silmääni vaaralliselta näyttävästä koodista... No.. läksy oli helppo, koska pääsiäisläksyn tehtävä eli nollasta poikkeavan virhekoodin jättävä ohjelma olisi ollut faktisesti mahdoton tehdä: C99-standardi määrittelee seuraavaa main()-aliohjelman loppumisesta (luku 5.1.2.2.3):: 5.1.2.2.3 Program termination If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified. Siellähän se standardissa luvataan: "reaching the } that terminates the main function returns a value of 0". Tältä osin kaikki kunnossa, ja itsekin olen yhtä asiaa viisaampi. Ja esimerkistä tulikin hyvä :) sovitaan vaan, että se käsitteli asioiden tarkistamista standardista, jos joku alkaa käytännössä ihmetyttämään. Silti suosittelen kirjoittamaan lähdekoodiin "return 0":n niin ei tule ihmetystä eteen niillekään, jotka eivät ole yhtä tarkkaan lukeneet speksiä. Tämä löytyi ensin Googlettamalla ja sitten varmistamalla itse C99-standardista (ISO/IEC 9899:1999), että näin se on komitea mennyt sopimaan. Ehkä tämä määritelmä auttaa keskimäärin vähentämään ohjelmointivirheitä, kun porukka kumminkin unohtaa sen return 0:nsa kirjoittaa, eikä tajuaisi muuttaa kääntäjän varoituksia virheiksi :). Vastaus luennolla esitettyyn tarkennukseen kirjastofunktioiden linkittämisestä käynnistysvaiheessa, eikä enää varsinaisen ajon aikana: Ainakin GNU:n työkaluilla ELF-muotoiseen ohjelmatiedostoon voi laittaa pyynnön kirjastojen linkittämisestä heti ohjelman latauksen yhteydessä seuraavalla komennolla (osio "-Wl,-z,now"):: c99 -Wl,-z,now -Werror -g -O0 -o omaecho omaecho.c Merkintä tulee luonnollisesti aivan viimeisessä työkaluketjun vaiheessa eli linkitysohjelmassa "ld". Vastaus löytyi kuin löytyikin helpoiten selaamalla ld:n manuaalia ja tarkistamalla c99-komennolla käynnistyvän julkisivuohjelman manuaalista, miten ld-vaiheelle saadaan tuupattua argumentteja. "-Wl,-z,now" johtaa siihen, että ohjelmatiedoston kasaamisvaiheessa konepellin alla ajettava komento "ld" saa mm. peräkkäiset argumentit "-z" ja "now". Oletusarvoisesti ld:n ajo tulkitaan kuten "-z lazy" eli jaetut kirjastot ladataan laiskasti vain tarvittaessa, eli kun jotakin kirjastossa sijaitsevaa aliohjelmaa faktisesti kutsutaan. * 2017 pois jätettyä: Semaforin käyttö kuluttaja-tuottaja -ongelman ratkaisussa. (Semafori tietorakenteena käytiin läpi, ja se on muistettava, ts. resurssien määrää kuvaava kokonaisluku ja jono/joukko prosesseja, jotka jonottavat siinä tapauksessa, että vapaana on 0 kpl resurssia). TODO: Hyvä tietää -osastolle 2017: *** 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: 2017/esimerkit/l17/hellofile.c Esimerkki: - Oman "cat -apuohjelman" raakile; tiedoston avaaminen, lukeminen ja kirjoittaminen tavu kerrallaan, sulkeminen C:n alustakirjaston kutsuilla. koodi repossa: 2017/esimerkit/l17/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. *** Lisää esimerkkejä erikoistiedostoista /dev/ -hakemistossa 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/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ä *** 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. - 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. *** 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. *** Muita ohitettuja 2017 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... *** I/O:sta ja laitteista ohitettua 2017: - DMA. - RAID *** Vuoronnusmenettelyjä, RT, skriptit. Vuoden 2016 luennoilta 9-10: 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. * Vuoden 2015 toteumaa: ** 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!! ** Palauteluento ekan tentin jälkeen 2015 (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.