PB173 - Ovladače jádra - Linux IX. Přerušení Jiri Slabý Fakulta informatiky Masarykova univerzita 15. 11. 2016 Jiri Slabý (Fakulta informatiky, MU) PB173/04 15. 11. 2016 1 /17 Přerušení LDD3 kap. 7 a 10 Q „Měkká" přerušení 9 Časovače • Pozdržení vykonávání kódu (spánek) • Odložené vykonání kódu Q „Tvrdá" přerušení (z HW) O Změny v kontextu přerušení • Zámky Alokace, apod. Jiri Slabý (Fakulta informatiky, MU) PB173/04 15.11.2016 2/17 Sekce 1 „Měkká" přerušení Jiri Slabý (Fakulta informatiky, MU) PB173/04 15. 11. 2016 3/17 Časovače • Documentation/timers/* • Činnost v nastavených časech (i periodicky) • Kód je volán v kontextu přerušení (nelze spát) • /proc/timer_iist (mimo historická jádra) Obyčejné časovače o Fungují na každé architektuře Založené na jif f ies • Proměnná zvyšující se o 1 s frekvencí HZ • Rozlišení: 1-10 ms (pro HZ: 1000-100) High-res časovače o usleep_range (linux/hrtimer.h) • Rozlišení: ~ fis Jiri Slabý (Fakulta informatiky, MU) PB173/04 15.11.2016 4/17 Obyčejné časovače API • linux/timer.h, struct timer_list • DEFINE_TIMERS, setup_timerD • Načasování: mod_timer (=del_timer+add_timer) • Zrušení: del_timer_sync (POZOR) Příklad static void myjun (unsigned long data); static DEFINE_TIMER(my_timer, myjun, 0, 30); static void my fun(unsigned long data) { my_timer.data *= 2; mod_timer(&my_timer, jiffies + msecs_toJiffies (data)); } mod_timer(&my_timer, jiffies + msecs_toJiffies(100)); del_timer_sync(&my_timer); Úkol: Každou vteřinu, kdy je modul v systému, vypište HZ (°/,u) a I jiffies (°/.lu) I _I Jiri Slabý (Fakulta informatiky, MU) PB173/04 15. 11. 2016 5/17 Pozdržení vykonávání kódu Čekání na událost trvající pevně danou dobu (linux/delay .h) O Spánek • Zapojení časovače (tikni za ...) a plánovače (... a vzbuď mě) • Rozlišení: ^ 10 jus až 10 ms (HW-závislé) • ssleep, msleep, usleep_range O Busy-waiting • Smyčka - spotřeba času CPU a energie! • Rozlišení: ns • mdelay, udelay, ndelay V jádře lze pobývat (čekat) jen omezenou dobu v řádu jednotek až desítek vteřin Úkol: spěte 3 vteřiny v module.init a vyzkoušejte vložením modulu Jiri Slabý (Fakulta informatiky, MU) PB173/04 15. 11. 2016 6/17 Odložené vykonání kódu Při potřebě vykonat kód, který nelze vykonat teď • Držím zámek, jsem v přerušení, ... 9 Není nutno specifikovat pevně daný moment • (Narozdíl od časovačů) • Ale je to možné 2 druhy O Workqueue Q Tasklet Rozdíly • Rychlost zavolání (tasklet dřív) • Kontext zavolání (tasklet z přerušení, workqueue z procesu) • Množství kódu (tj. rychlost vykonání) Jiri Slabý (Fakulta informatiky, MU) PB173/04 15. 11. 2016 7/17 Workqueue • Documentation/workqueue.txt • Speciální procesy volající funkce řazené do fronty • Globální, společné pro všechny - většinou stačí • Vlastní - pro speciální případy • Lze v nich spát 9 Spustí se, až se plánovač rozhodne • Lze specifikovat minimální prodlevu Jiri Slabý (Fakulta informatiky, MU) PB173/04 15.11.2016 8/17 Workqueue API • linux/workqueue.h, struct work_struct • Definice práce: declare_works, init_workd 9 Globální proces: • Zařazení do fronty: scheduie_work • Vyřazení z fronty (předčasně): cancei_work_sync • Vlastní proces: • Vytvoření procesu: create_workqueue, destroy_workqueue • Zařazení do fronty: queue_work • Vyřazení z fronty: cancei_work_sync (tj. stejně) • Delayed (s garantovanou prodlevou): *_deiayed_work Úkol: V module.init nahrajte modul ieee80211 nebo mac80211 (request.module). request_moduie nelze volat přímo v moduie_init a je nutný i vlastní workqueue proces. Jiri Slabý (Fakulta informatiky MU) PB 173/04 15. 11. 2016 9/17 Tasklet • Běží v kontextu přerušení (jako časovače) a Nelze spát • Musí být rychlý • Spustí se po příštím přerušení API • linux/interrupt. h, struct tasklet_struct Definice taskletu: declare_tasklets, taskiet_initD Zařazení do fronty: taskiet.schedule • Vyřazení z fronty: taskiet.kili Úkol: vytvořte tasklet, spusťte a vypište posloupnost volání pomocí dump.stack Jiri Slabý (Fakulta informatiky MU) PB173/04 15. 11. 2016 10/17 Sekce 2 „Tvrdá" přerušení (z HW) Jiri Slabý (Fakulta informatiky MU) PB173/04 15. 11. 2016 11/17 Přerušení HW • HW informuje o změně stavu • Časovač tiknul, přišel paket, přečten blok z disku, ... • CPU přeruší chod programu/jádra a zavolá jádro • Ví, koho volat, má tabulku (IDT) o Cyklus? Priority přerušení! • OS musí obsloužit přerušení • Zjistí zdroj a zavolá odpovídající ovladač (jeho obsluhu přerušení) • Přerušení je identifikováno číslem (IRQ) • Vynuluje přerušení na řadiči přerušení Nutná podpora HW (CPU, řadiče, sběrnice, zařízení) Jiri Slabý (Fakulta informatiky MU) PB173/04 15. 11. 2016 12/17 Přerušení v Linuxu • 1inux/int errupt.h • request_irq, free_irq • Flags: hlavně irqf.shared • Návratová hodnota z obsluhy: irq.none, irq.handled • /proc/interrupts Příklad static irqreturn_t my_handler(int irq, void *data) { /* data == my_data */ return my_device_raised_interrupt ? IRQ_HANDLED : IRQNONE; } static int my_probe(struct pci_dev *pdev,...) { /* here: enable device etc. */ my_data = kmalloc(...); ret = request_irq(pdev->irq, myjiandler, IRQF_SHARED, "my", my_data); } Jiri Slabý (Fakulta informatiky, MU) PB173/04 15. 11. 2016 13/17 Sekce 3 Změny v kontextu přerušení Jiri Slabý (Fakulta informatiky MU) PB173/04 15. 11. 2016 14/17 Přerušení a spinlocky Vlákno spin_lock(&addr_lock); < interrupt > spin_unlock(&addr_lock); Přerušení spin_lock(&addr_lock); // AAA deadlock AAA spin_unlock(&addr_lock); irq* varianty Zákaz přerušení, poté spinlock Vlákno Přerušení spin_lock_irq(&addr_lock); // interrupt cannot trigger spin_unlock_irq(&addr_lock); spin_lock(&addr_lock); spin_unlock(&addr_lock); Jiri Slabý (Fakulta informatiky MU) PB 173/04 15. 11. 2016 15/17 Kontext přerušení Další změny o Alokace • GFP_ATOMIC A tedy nevelké alokace 9 Kód • Rychlý, krátký o (Víc kódu později v taskletu, ještě víc třeba ve workqueue) Jiri Slabý (Fakulta informatiky MU) PB173/04 15. 11. 2016 16/17 Úkol Práce s přerušením (součást domácího) O Vytvořte pojmenování (makra) pro registry (viz tabulku dole) O Spusťte 100ms periodický časovač (pro každé EDU zařízení) • Nechte počítat faktoriál a po výpočtu generovat přerušení (r. 0x20) • Můžete občas nechat EDU vyvolat i jiné přerušení (r. 0x60) O Navažte se v probe na přerušení (request.irq) O Implementujte obsluhu • Přečtěte stav (r. 0x24), vypište stav - limitované Nenula: odsouhlaste přerušení (r. 0x64), vraťte irq_handled • Jinak: vraťte irq_none Specifikace baru 0 (pokračování z minula) Offset Len R/W Contents Meaning 0x0024 4B R bitmap Raised interrupts 0x0060 4B W bitmap Raise interrupts 0x0064 4B W bitmap Acknowledge interrupts Jiri Slabý (Fakulta informatiky MU) PB173/04 15. 11. 2016 17/17