Úvod do operačných systémov
Ahoj, Habr! Chcem vám predstaviť sériu článkov-prekladu zaujímavej literatúry, ktorú považujem za zaujímavú — OSTEP. V tomto materiáli sa podrobne zaoberá fungovaním unixových operačných systémov, konkrétne prácou s procesmi, rôznymi plánovačmi, pamäťou a inými podobnými komponentmi, ktoré tvoria moderný OS. Originál všetkých materiálov si môžete pozrieť tu: . Prosím berte na vedomie, že preklad bol vykonaný neprofesionálne (dosť voľne), ale dúfam, že som zachoval celkový zmysel.
Laboratórne práce na tomto predmete nájdete tu:
Ďalšie časti:
A môžete sa pozerať aj na môj kanál v =)
Poplach! k tej prednáške je labka! pozri
API procesu
Pozrime sa na príklad vytvorenia procesu v UNIX systéme. Tento proces vzniká prostredníctvom dvoch systémových volaní. fork() a exec().
Volanie fork()

Pozrime sa na program, ktorý vykonáva volanie fork(). Výsledok jeho vykonania bude nasledujúci.

Najprv vstúpime do funkcie main() a vykonáme výstup reťazca na obrazovku. Tento reťazec obsahuje identifikátor procesu, ktorý sa pôvodne nazýva PID alebo identifikátor procesu. Tento identifikátor sa v UNIX-e používa na to, aby sme mohli odkazovať na proces. Nasledujúci príkaz spustí volanie fork(). V tomto momente sa vytvára prakticky presná kópia procesu. Pre operačný systém to vyzerá tak, akoby sa v systéme spustili ako keby 2 kópie tej istej programy, ktoré sa následne odhlásia z vykonávania funkcie fork(). Novovytvorený proces-potomok (v porovnaní so svojím procesom-rodičom) už nebude vykonávať so začiatkom funkcie main(). Je potrebné pamätať na to, že proces-potomok nie je presnou kópiou procesu-rodiča, konkrétne má vlastný adresný priestor, vlastné registre, svoj ukazovateľ na vykonávané inštrukcie a podobne. Tým pádom sa hodnota, ktorá sa vracia volateľovi funkcie fork(), bude líšiť. Konkrétne, proces-rodič získa ako návratovú hodnotu PID procesu dieťaťa, zatiaľ čo dieťa získa hodnotu rovnu 0. Na základe týchto návratových kódov je možné následne oddeľovať procesy a nútiť každý z nich vykonávať svoju prácu. Pri tom však vykonávanie tejto programy nie je striktne definované. Po rozdelení na 2 procesy operačný systém začína sledovať ich, ako aj plánovať ich prácu. V prípade vykonávania na jednojadrovom procesore bude pokračovať práca jedného z procesov, v tomto prípade — rodičovského, a potom prevzme riadenie proces-potomok. Pri opätovnom spustení situácia môže byť iná.
Volanie wait()

Pozrime sa na nasledujúci program. V tomto programe, vďaka prítomnosti volania wait() proces-rodič vždy počká na ukončenie činnosti procesu-potomka. V tomto prípade dostaneme striktne definovaný výstup textu na obrazovke.

Volanie exec()

Pozrime sa na volanie exec(). Toto systémové volanie je užitočné, keď chceme spustiť úplne inú program. Tu budeme vykonávať volanie execvp() na spustenie programu wc, ktorý je program na počítanie slov. Čo sa teda deje pri volaní exec()? Tento príkaz prijíma ako argumenty názov vykonávateľného súboru a niektoré parametre. Po tom sa načíta kód a statické údaje z tohto vykonávateľného súboru a prepisuje sa vlastný segment s kódom. Ostatné časti pamäte, ako je zásobník a halda, sa preinicializujú. Potom operačný systém jednoducho vykoná program a prenesie mu súbor argumentov. Takto sme nevytvorili nový proces, len sme transformovali aktuálne spustený program na iný spustený program. Po vykonaní volania exec() v potomkovi nastáva dojem, že pôvodný program akoby sa vôbec nespustil.
Toto komplikovanie spustenia je úplne normálne pre shell prostredie Unix, a umožňuje tomuto shellu vykonávať kód po volaní fork(), ale pred volaním exec(). Príkladom takéhoto kódu môže byť prispôsobenie prostredia shellu potrebám spusteného programu pred jeho bezprostredným spustením.
Shell — to je len používateľský program. Zobrazuje vám riadok príkazu a čaká, kým do neho niečo napíšete. V väčšine prípadov, ak do neho napíšete názov programu, shell nájde jeho umiestnenie, zavolá metódu fork(), a potom na vytvorenie nového procesu zavolá niektorý z typov exec() a čaká na jeho vykonanie pomocou volania wait(). Keď sa proces-potomok dokončí, shell sa vráti z volania wait() a opäť zobrazí riadok príkazu a bude čakať na zadanie nasledujúceho príkazu.
Rozdelenie fork() & exec() umožňuje shellu robiť nasledujúce veci, napríklad:
wc file > new_file.
V tomto príklade je výstup programu wc presmerovaný do súboru. Spôsob, akým to shell dosahuje, je dosť jednoduchý — pri vytváraní procesu-dieťaťa pred volaním exec(), shell uzavrie štandardný výstupný prúd a otvorí súbor new_file, týmto spôsobom bude celý výstup z následne spusteného programu wc presmerovaný do súboru namiesto na obrazovku.
Unix pipe sú implementované podobným spôsobom, s výnimkou, že používajú volanie pipe(). V tomto prípade bude výstupný prúd procesu pripojený k frontu pipe, ktorý je umiestnený v jadre, ku ktorému bude tiež pripojený vstupný prúd iného procesu.
Zdroj: habr.com
