Računarski softver se može, na grubo, podeliti u dva tipa:
Najbitniji sistemski program je operativni sistem, čiji je posao da kontroliše sve računarske resurse i obezbedi osnovu na kojoj se može razvijati aplikacioni softver. Operativni sistem se ponaša kao posrednik između korisnika računara i računarskog hardvera.
Računarski sistem se može podeliti na četri komponente: hardver, operativni sistem, aplikacioni program i korisnik.
Operativni sistem obavlja posao sličan državnoj upravi. Kao i državna uprava, on nema korisnu funkciju sam po sebi, već obezbeđuje okruženje u kome drugi programi mogu da rade korisne stvari.
Operativni sistem sakriva hardverske detalje od korisnika i obezbeđuje prikladan interfejs za korišćenje sistema. Ako ovako posmatramo operativni sistem onda je njegova funkcija da obezbedi korisniku “prihvatljiviji” oblik komunikacije sa hardverskim komponentama tj. da se ponaša kao proširenje hardvera (virtuelna mašina). Mesto operativnog sistema je prikazano na slici ispod.
Računarski sistem ima mnoge resurse. Moderan računar se sastoji od procesora, memorije, tajmera, diska, miša, mrežnog interfejsa, štampača i mnogih drugih uređaja. Ako posmatramo OS kao upravljač resursa, onda je njegova funkcija da obezbedi uređeno i kontrolisano dodeljivanje procesora, memorije i ulazno / izlaznih (I/O) uređaja između više programa koji se takmiče za njihovo korišćenje.
Deo operativnog sistema se nalazi u radnoj memoriji. Ovo je jezgro operativnog sistema. Ostatak glavne memorije sadrži korisničke programe i podatke. Dodeljivanje resorsa (glavne memorije) je kontrolisano od strane OS i hardvera za upravljanje memorijom u procesoru.
Moderan računarski sistem, opšte upotrebe, se sastoji od jednog ili više centralnih procesorskih jedinica i većeg broja kontrolora uređaja povezanih preko magistrale koja obezbeđuje i pristup deljenoj memoriji.
Računarski poziv je način na koji program zahteva usluge od jezgra operativnog sistema. Ovo uključuje usluge vezane za hardver (npr. pristup hdd-u), kreiranje i startovanje novog procesa i komunikaciju sa servisima jezgra. Sistemski poziv obezbeđuje interfejs između procesa i operativnog sistema. Savremeni operativni sistemi imaju na stotine sistemskih poziva. Linux ima preko 300 različitih poziva. Sistemski pozivi se na grubo mogu podeliti u pet glavnih kategorija:
Uniprogramski sistemi - računarski sistemi koji u jednom trenutku mogu da izvršavaju samo jedan korisnički program.
Multiprogramski sistemi - računarski sistemi koji mogu simultano da izvrše više korisničkih programa. Korisnički programi su po pravilu nezavisni, a koriste zajedničke resurse (procesor(e), memorije, I/O uređaje, datoteke, biblioteke…).
Multiprogramski sistemi su se razvili iz potrebe da se optimizuje korišćenje procesorskog vremena.
Rani multiprogramski sistemi nisu obezbedili interakciju korisnika sa računarskim sistemom. Vremenska podela procesora je logična nadogradnja multiprogramskih sistema koja obezbeđuje interakciju sa korisnicima. Postoji više od jednog korisnika koji komunicira sa sistemom. Promena poseda CPU između korisnika je toliko brza da korisnik stiče utisak da samo on komunicira sa sistemom, ali u stvari on se deli između više korisnika. Svaki korisnik naizvmenično dobija kratak interval procesorskog vremena. Vremenska podela procesora je kompleksnija od multiprogramiranja zato što mora da obezbedi mehanizme za sinhronizaciju i komunikaciju između poslova različitih korisnika.
Proces predstavlja instancu programa pri izvršavanju. Program nije proces i predstavlja pasivni entitet, fajl koji sadrži spisak instrukcija i koji se nalazi na hdd-u (najčešće se naziva izvršni fajl). Proces je aktivni entitet sa brojačem instrukcija postavljenim na sledeću instrukciju koja treba da se izvrši u kodu i skupom potrebnih resursa. Program postaje proces kada se izvršni fajl učita u glavnu memoriju.
Primer koji ilustruje razliku između procesa i programa:
Program sadrži jedan izraz množenja (prod = prod * i), ali proces će izvršiti 100 množenja, po jednom u svakoj iteraciji “for” petlje.
Proces roditelj kreira decu procese, koji mogu da kreiraju nove procese i tako formiraju stablo procesa.
Kada se pokrene operativni sistem, najčešće se kreira nekoliko procesa. Neki od tih procesa su prednji - mogu da komuniciraju sa korisnikom i obavljaju poslove za njih. Drugi su pozadinski procesi - nisu povezani sa korisnicima već imaju neku specifičnu funkciju. Takvi procesi ostaju u pozadini, aktiviraju se po potrebi i obavljaju funkcije kao što je npr. sinhronicacija sistemskog časovnika, štampanje itd. Ovi procesori se nazivaju demoni (deamons).
Pored procesa koji se kreiraju pri pokretanju operativnog sistema, novi procesi mogu da se kreiraju i kasnije. Najčešće se kreiraju tako što aktivan proces izdaje sistemski poziv za kreiranje jednog ili više novih procesa.
U interaktivnim sistemima korisnik pokreće program kucanjem odgovarajuće komande u terminalu ili duplim klikom na ikonu. Na Unix sistemima postoji samo jedan sistemski poziv za kreiranje procesa: fork. Ovaj poziv klonira pozivajući proces. Na primer, kada korisnik otkuca komandu u terminalu, recimo pstree, terminal forkuje proces dete i to dete izvrši program pstree.
Da bi smo u programskom jeziku C kreirali novi proces potrebno je pozvati funkciju pid_t fork(void) standardne biblioteke unistd. Dete proces se u odnosu na proces roditelj razlikuje, između ostalog, i po tome što dobija novi identifikator procesa. Nakon poziva funkcije fork() oba procesa (i roditelj i dete) imaju iste kopije podataka i nastavljaju da izvršavaju isti kod.
pid_t je generički tip procesa. Na Unix sistemima je short. fork() može da vrati samo tri stvari:
Iako ovo deluje prilično jednostavno, da bi i stvarno bilo jednostavno potrebno je znati nekoliko stvari. Pre svega, kada se na Unix sistemu proces “završi”, on se više ne izvršava, ali mali ostatak podataka ostaje u memoriji i čeka da ga proces roditelj pokupi. Ovaj ostatak, između ostalog, sadrži i povratnu vrednost procesa. To znači da proces roditelj, nakon što pozove fork(), mora da sačeka da proces dete izađe (pozivom funkcije exit()). Pozivom funkcije wait() čeka bilo koje dete, a funkcijom waitpid() čeka neko konkretno dete. Ovaj čin čekanja dozvoljava da ostatak procesa deteta nestane. Funkcija void exit(int status) je definisana u biblioteci stdlib, a funkcije pid_t wait(int *status) i pid_t waitpid(pid_t pid, int *status, int options) u bibliotekama sys/types i sys/wait.
Naravno, postoji izuzetak od pravila da roditelj mora da sačeka da dete izađe. Roditelj može da ignoriše signal SIGCHLD i onda ne mora da poziva funkciju wait(). Ovo može da se postigne na sledeći način:
Kada proces dete izađe, a nije sačekan (wait()), najčešće se u ps listi prikazuje kao “<defunct>”. Takav status ima sve dok roditelj ne pozove wait(). Ako roditelj završi pre nego što pozove wait() za dete (pod pretpostavkom da ne ignoriše SIGCHLD), dete dobija novog roditelja. Taj roditelj je init proces (PID 1). Ovo nije problem ako dete još uvek nije završilo. Ako je dete već defunct onda ono postaje zombi proces. Na nekim sistemima init proces periodično uništava zombi procese. Na drugim sistemima init proces odbija da postane roditelj defunc procesima i odmah ih uništava.
U operativnom sistemu svaki proces je predstavljen kontrolnim blokom procesa (PCB) ili zadataka. PCB je struktura podataka jezgra operativnog sistema koja fizički predstavlja proces u memoriji računara. Sadrži mnoge informacije povezane sa specifičnim procesom od kojih su najznačajnije:
Svaki proces može biti u jednom od sledećih stanja: