Operativni sustavi: Tri jednostavna dijela. Dio 3: API procesa (prijevod)

Uvod u operacijske sustave

Pozdrav, Habr! Želim predstaviti seriju članaka-prijevoda jedne zanimljive literature po mom mišljenju — OSTEP. U ovom materijalu duboko se razmatra rad unix-sličnih operacijskih sustava, a posebno — rad s procesima, raznim planerima, memorijom i drugim sličnim komponentama koji čine moderni OS. Original svih materijala možete pogledati ovdje ovdje. Molim vas, imajte na umu da je prijevod izveden neprofesionalno (dovoljno slobodno), ali se nadam da sam zadržao opći smisao.

Laboratorijske vježbe vezane uz ovu temu možete pronaći ovdje:

Ostali dijelovi:

A također možete zaviriti na moj kanal u telegramu =)

Alarm! ima laboratorijska vježba za ovu lekciju! pogledaj GitHub

API procesa

Razmotrit ćemo primjer stvaranja procesa u UNIX sustavu. To se događa putem dva sustavna poziva. fork() i exec().

Poziv fork()

Operativni sustavi: Tri jednostavna dijela. Dio 3: API procesa (prijevod)

Razmotrit ćemo program koji izvršava poziv fork(). Rezultat njegove izvedbe bit će sljedeći.

Operativni sustavi: Tri jednostavna dijela. Dio 3: API procesa (prijevod)

Prvo ulazimo u funkciju main() i izvršavamo ispis stringa na ekran. String sadrži identifikator procesa koji se u izvornom nazivlje zove PID ili identifikator procesa. Ovaj identifikator se u UNIX-u koristi za adresiranje procesa. Sljedeća naredba bit će poziv fork(). U tom trenutku se stvara gotovo točna kopija procesa. Za OS to izgleda kao da su u sustavu pokrenute kao da postoje 2 kopije iste programa, koje će na kraju izvršenja funkcije fork() završiti. Novo stvoreni proces-dijete (u odnosu na roditeljski proces koji ga je stvorio) više neće izvršavati, počevši od funkcije main(). Treba imati na umu da proces-dijete nije točna kopija procesa-roditelja, posebno jer ima vlastiti adresni prostor, vlastite registre, vlastitu oznaku na izvršne upute i slično. Tako će vrijednost koju vraća pozivaocu funkcije fork() biti različita. Konkretno, proces-roditelj će primiti kao povratnu vrijednost PID procesa djeteta, a dijete će dobiti vrijednost jednaku 0. S obzirom na te kodove povratka kasnije se mogu razdvojiti procesi i prisiliti svaki od njih da izvršava svoj posao. U tom slučaju, izvršenje ovog programa nije strogo definirano. Nakon razdvajanja na 2 procesa, OS počinje pratiti njih, kao i planirati njihov rad. U slučaju izvršavanja na jednogrjadnom procesoru, rad će nastaviti jedan od procesa, u ovom slučaju - roditeljski, a zatim će kontrolu preuzeti proces-dijete. Pri ponovnom pokretanju situacija se može promijeniti.

Poziv wait()

Operativni sustavi: Tri jednostavna dijela. Dio 3: API procesa (prijevod)

Razmotrit ćemo sljedeći program. U ovom programu zahvaljujući prisustvu poziva wait() proces-roditelj uvijek će čekati završetak rada procesa-dijete. U tom slučaju dobivamo strogo definiran ispis teksta na ekran.

Operativni sustavi: Tri jednostavna dijela. Dio 3: API procesa (prijevod)

Poziv exec()

Operativni sustavi: Tri jednostavna dijela. Dio 3: API procesa (prijevod)

Razmotrit ćemo poziv exec(). Ovaj sistemski poziv je koristan kada želimo pokrenuti potpuno drugi program. Ovdje ćemo pozvati execvp() za pokretanje programa wc, koji je program za brojanje riječi. Što se događa prilikom poziva exec()? Ovom pozivu se prosljeđuju kao argumenti ime izvršne datoteke i neki parametri. Nakon toga dolazi do učitavanja koda i statičkih podataka iz te izvršne datoteke i prepisivanja vlastitog segmenta s kodom. Ostali dijelovi memorije, poput stoga i hrpe, ponovo se inicijaliziraju. Nakon čega OS jednostavno izvršava program, prosljeđujući mu skup argumenata. Dakle, nismo stvarali novi proces, već smo jednostavno transformirali trenutno pokrenuti program u drugi pokrenuti program. Nakon izvršavanja poziva exec() u potomku se stvara dojam da izvorni program kao da uopće nije bio pokrenut.

Ovo komplikovanje pokretanja je potpuno normalno za Unix shell, i omogućava ovom shellu da izvrši kod nakon poziva fork(), ali prije poziva exec(). Primjer takvog koda može biti prilagođavanje okruženja shella potrebama pokretane aplikacije, prije njenog direktnog pokretanja.

Shell je samo korisnički program. On vam pokazuje liniju pozivnog znaka i čeka da nešto napišete. U većini slučajeva, ako tamo upišete ime programa, shell će pronaći njegovu lokaciju, pozvati metodu fork(), a zatim, kako bi stvorio novi proces, pozvati neki od tipova exec() i čekati njegovu izvršenost pomoću poziva wait(). Kada potomak završi, shell se vraća iz poziva wait() i ponovo prikazuje liniju pozivnog znaka te čeka unos sljedeće komande.

Razdvajanje fork() & exec() omogućava shellu da radi sljedeće stvari, na primjer:
wc file > new_file.

U ovom primjeru, izlaz programa wc preusmjeren je u datoteku. Način na koji shell to postiže je prilično jednostavan — prilikom stvaranja procesa-djeteta prije poziva exec(), shell zatvara standardni izlazni tok i otvara datoteku new_file, na taj način će cijeli izlaz iz dalje pokrenutog programa wc biti preusmjeren u datoteku umjesto na ekran.

Unix cijev realizirane na sličan način, s razlikom da koriste poziv pipe(). U ovom slučaju, izlazni tok procesa bit će spojen na cijevni red smješten u jezgru koja će također biti povezana s ulaznim tokom drugog procesa.

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster