2. cvičenie – systémové volania

Systémové volania

Na minulom cvičení ste napísali niekoľko utilít, ktoré používali systémové volania. V tomto cvičení napíšete dvojicu systémových volaní, ktoré vám pomôžu lepšie pochopiť interné mechanizmy jadra xv6 a ako samotné systémové volania fungujú. S pridávaním systémových volaní sa stretnete aj v niektorých ďalších cvičeniach.

Než začnete programovať, preštudujte si kapitolu 2 z xv6 knižky, sekcie 4.3 a 4.4 kapitoly 4 a príslušné zdrojové súbory.

  • Kód užívateľského módu pre systémové volania je v user/user.h a user/usys.pl.
  • Kód jadra pre užívateľské volania je v kernel/syscall.h a kernel/syscall.c.
  • Kód týkajúci sa procesov nájdete v kernel/proc.h a kernel/proc.c.

Na začiatok sa prepnite do vetvy syscall:

Ak spustíte make grade, zistíte, že hodnotiaci skript nemôže spustiť (execnúť) trace and sysinfotest. Vašou úlohou je pridať potrebné systémové volania a podporný kód, aby testy prešli.

Trasovanie systémových volaní (stredná)

V tomto zadaní pridáte do jadra funkcionalitu trasovania systémových volaní, ktorá vám môže byť nápomocná v neskorších cvičeniach. Vytvoríte systémové volanie trace(), ktorým bude možné riadiť trasovanie. Bude mať jeden argument, celočíselnú „masku“, ktorej bity určia, ktoré systémové volania budú trasované. Napríklad, na trasovanie systémového volania fork() program zavolá trace(1 << SYS_fork), kde SYS_fork je číslo systémového volania definované v kernel/syscall.h. Vaším cieľom je modifikovať jadro xv6 tak, aby tesne pred ukončením systémového volania jadro skontrolovalo, či je v maske nastavené číslo prebiehajúceho systémového volania. V takom prípade jadro vypíše riadok s id procesu, názvom systémového volania a jeho návratovou hodnotou. Systémové volanie trace() by malo povoliť trasovanie pre proces, ktorý ho zavolal a pre jeho detské procesy, ktoré neskôr vytvorí zavolaním fork(), ale nie pre ostatné procesy.

V repozitári nájdete užívateľský program trace, ktorý spustí iný program so zapnutým trasovaním (viď user/trace.c). Ak ste volanie správne naimplementovali, mali by ste vidieť niečo takéto:

V prvom príklade trace spustí trasovanie programu grep, konkrétne systémového volania read. Číslo 1<<SYS_read je rovné 32. V druhom príklade sa jedná o ten istý proces, ale trasujú sa všetky systémové volania. Číslo 2147583647 má nastavených všetkých 31 dolných bitov. V treťom príklade program nie je trasovaný, takže nie je ani vypísaný žiadny výstup. V štvrtom príklade sú trasovaní všetci potomkovia testu forkforkfork zo sady testov usertests. Vaše riešenie je korektné, ak program má rovnaké správanie ako je uvedené vyššie (ID procesov môžu byť rozdielne).

Pomôcky:

  • Pridajte $U/_trace do premennej UPROGS v súbore Makefile.

  • Spustite make qemu a uvidíte, že kompilátor nemôže skompilovať súbor user/trace.c, pretože užívateľské útržky kódu pre systémové volanie ešte neexistujú: pridajte prototyp systémového volania do user/user.h, útržok do user/usys.pl, a číslo systémového volania do kernel/syscall.h. Súbor Makefile spustí perl skript user/usys.pl, ktorý vytvorí user/usys.S, kde sú uložené skutočné útržky systémových volaní, ktoré obsahujú inštrukciu ecall architektúry RISC-V, ktorá slúži na prechod do jadra. Potom, ako opravíte kompilačné problémy, spustite trace 32 grep hello README. Uvidíte, že zlyhá, lebo samotné systémové volanie v jadre ešte nie je implementované.

  • Pridajte funkciu sys_trace() do kernel/sysproc.c. Jej úloha je uložiť argument systémového volania do novej premennej v štruktúre proc (viď kernel/proc.h). Funkcie na prevzatie argumentov systémového volania nájdete v kernel/syscall.c a príklady ich použitia nájdete v kernel/sysproc.c.

  • Upravte fork() (viď. kernel/proc.c), aby skopíroval trasovaciu masku z rodiča do detského procesu.

  • Upravte funkciu syscall() v kernel/syscall.c, aby vypísala trasovací výstup. Musíte pridať pole názvov systémových volaní, ktoré sa budú vypisovať.

Sysinfo (stredná)

V tomto zadaní pridáte systémové volanie sysinfo(), ktoré zbiera informácie o bežiacom systéme. Má jeden argument: smerník na štruktúru struct sysinfo (viď kernel/sysinfo.h). Jadro by malo naplniť položky tejto štruktúry: položka freemem by mala obsahovať počet bajtov voľnej pamäte a položka nproc by mala obsahovať počet procesov, ktorých state nie je UNUSED. Úlohu ste úspešne zvládli ak testovací program sysinfotest vypíše sysinfotest: OK.

Pomôcky:

  • Pridajte $U/_sysinfotest do premennej UPROGS v súbore Makefile.

  • Po spustení make qemu zlyhá kompilácia súboru user/sysinfotest.c. Pridajte systémové volanie sysinfo podobným postupom ako v predchádzajúcej úlohe. Aby ste mohli deklarovať prototyp sysinfo() v user/user.h, musíte deklarovať existenciu štruktúry struct sysinfo:

    Keď opravíte problémy s kompiláciou, spustite sysinfotest. Zlyhá, pretože ste ešte neimplementovali systémové volanie v jadre.

  • sysinfo musí skopírovať štruktúru struct sysinfo do užívateľského priestoru. Pozrite sa ako na to vo funkciách sys_fstat() (kernel/sysfile.c) a filestat() (kernel/file.c). Bude vás zaujímať funkcia copyout().

  • Aby ste získali množstvo voľnej pamäte, pridajte funkciu do kernel/kalloc.c.

  • Na získanie počtu procesov pridajte funkciu do kernel/proc.c.

Týmto je cvičenie hotové. Skontrolujte, či vaše riešenie prejde všetkými testami make grade. Aby ste prešli posledným testom time, musíte vytvoriť nový súbor time.txt, v ktorom uvediete počet hodín, ktorý ste strávili nad zadaním ako celé číslo. Na záver nezabudnite svoje zmeny commitnúť do repozitára.

Voliteľné úlohy

  • Vypíšte argumenty trasovaných systémových volaní. (ľahká)
  • Vypočítajte priemernú záťaž procesora a vypíšte ju cez sysinfo() (stredná)