Uvod u operacijske sustave
Hej Habr! Predstavljam vam seriju članaka-prijevoda jedne po meni zanimljive literature - OSTEP. Ovaj materijal prilično duboko raspravlja o radu operativnih sustava nalik unixu, naime o radu s procesima, raznim planerima, memorijom i drugim sličnim komponentama koje čine moderan OS. Izvornike svih materijala možete vidjeti ovdje
Laboratorijske radove iz ove teme možete pronaći ovdje:
Ostali dijelovi:
Također možete pogledati moj kanal na
Alarm! Za ovo predavanje postoji laboratorij! Izgled
API procesa
Pogledajmo primjer kreiranja procesa u UNIX sustavu. To se događa kroz dva sistemska poziva vilica () и exec().
Call fork()
Razmotrite program koji upućuje fork() poziv. Rezultat njegovog izvršenja bit će sljedeći.
Prije svega, ulazimo u funkciju main() i ispisujemo string na ekran. Redak sadrži identifikator procesa koji se u originalu zove PID ili identifikator procesa. Ovaj se identifikator koristi u UNIX-u za označavanje procesa. Sljedeća naredba će pozvati fork(). U ovom trenutku stvara se gotovo točna kopija procesa. Za OS, izgleda da postoje 2 kopije istog programa koji se izvode na sustavu, koji će izaći iz funkcije fork(). Novostvoreni podređeni proces (u odnosu na nadređeni proces koji ga je kreirao) više se neće izvršavati, počevši od funkcije main(). Treba imati na umu da proces dijete nije točna kopija procesa roditelja, posebno ima svoj vlastiti adresni prostor, svoje registre, svoj pokazivač na izvršne instrukcije i slično. Stoga će vrijednost vraćena pozivatelju funkcije fork() biti drugačija. Konkretno, nadređeni proces će primiti PID vrijednost procesa djeteta kao povrat, a dijete će dobiti vrijednost jednaku 0. Koristeći ove povratne kodove, možete zatim odvojiti procese i natjerati svakog od njih da radi svoj posao . Međutim, izvođenje ovog programa nije strogo definirano. Nakon podjele na 2 procesa, OS ih počinje nadzirati, kao i planirati njihov rad. Ako se izvrši na jednojezgrenom procesoru, jedan od procesa, u ovom slučaju roditelj, nastavit će raditi, a potom će proces dijete dobiti kontrolu. Prilikom ponovnog pokretanja situacija može biti drugačija.
Poziv na čekanju()
Razmotrite sljedeći program. U ovom programu, zbog prisutnosti poziva čekati() Roditeljski proces će uvijek čekati da se dijete završi. U ovom slučaju dobit ćemo strogo definiran izlaz teksta na zaslonu
exec() poziv
Razmotrite izazov exec(). Ovaj sistemski poziv koristan je kada želimo pokrenuti potpuno drugačiji program. Ovdje ćemo nazvati execvp() za pokretanje wc programa koji je program za brojanje riječi. Što se događa kada se pozove exec()? Ovom se pozivu prosljeđuje ime izvršne datoteke i neki parametri kao argumenti. Nakon toga se učitavaju kod i statički podaci iz ove izvršne datoteke i prepisuje se vlastiti segment s kodom. Preostala područja memorije, kao što su stog i hrpa, ponovno se inicijaliziraju. Nakon toga OS jednostavno izvršava program, prosljeđujući mu skup argumenata. Dakle, nismo stvorili novi proces, jednostavno smo transformirali trenutno pokrenuti program u drugi pokrenuti program. Nakon izvršavanja exec() poziva u potomku, čini se kao da se izvorni program uopće nije pokrenuo.
Ova komplikacija pri pokretanju potpuno je normalna za Unix ljusku i dopušta toj ljusci da izvrši kod nakon poziva vilica (), ali prije poziva exec(). Primjer takvog koda bilo bi prilagođavanje okruženja ljuske potrebama programa koji se pokreće, prije njegovog pokretanja.
Ljuska - samo korisnički program. Pokazuje vam pozivnicu i čeka da u njoj nešto napišete. U većini slučajeva, ako ondje napišete naziv programa, ljuska će pronaći njegovu lokaciju, pozvati metodu fork(), a zatim pozvati neku vrstu exec() za stvaranje novog procesa i pričekati da završi pomoću čekaj() poziv. Kada podređeni proces izađe, ljuska će se vratiti s poziva wait() i ponovno ispisati upit i čekati da se unese sljedeća naredba.
Fork() & exec() split omogućuje ljusci da radi sljedeće stvari, na primjer:
wc datoteka > nova_datoteka.
U ovom primjeru, izlaz wc programa je preusmjeren na datoteku. Način na koji ljuska to postiže prilično je jednostavan - stvaranjem procesa djeteta prije poziva exec(), ljuska zatvara standardni izlaz i otvara datoteku nova_datoteka, dakle, sav izlaz iz programa koji se dalje izvodi wc bit će preusmjeren na datoteku umjesto na zaslon.
Unix cijev implementiraju se na sličan način, s tom razlikom što koriste poziv pipe(). U ovom slučaju, izlazni tok procesa bit će spojen na red čekanja cijevi koji se nalazi u kernelu, na koji će biti povezan ulazni tok drugog procesa.
Izvor: www.habr.com