Ako ne znate šta su sistemski pozivi, poznati i kao sistemski poziviOvdje ću objasniti sve što trebate znati o njima i kako funkcioniraju, kao i razloge zašto ovi mehanizmi operativnog sistema postoje i zašto su toliko korisni za ispravan rad aplikacija.
Šta je jezgro operativnog sistema?
Prva stvar koju trebate znati, da biste bolje razumjeli šta je sistemski poziv, jeste da Šta je kernel operativnog sistema. Jezgro je jezgro operativnog sistema, odnosno najvažniji dio, onaj koji pruža osnovne usluge potrebne ostalim dijelovima operativnog sistema, uključujući aplikacije.
Jezgro je najniži sloj, onaj koji je najviše usko povezan s hardverom i upravljanje svojim resursima. Na primjer, može upravljati procesima koji će biti učitani u RAM, vršiti zamjenu u virtualnoj memoriji, kontrolirati različite uređaje, omogućiti kreiranje i manipulaciju datotekama na disku za pohranu podataka itd.
Kada se računar pokrene, prvo se pokreće BIOS/UEFI firmver ili slično, i nakon nekoliko preliminarnih koraka, provjerit će na kojem mediju je operativni sistem instaliran kako bi predao kontrolu. Nakon što se to učini, bootloader će učitati kernel operativnog sistema u RAM memoriju tako da sve počne raditi, a također će predati kontrolu ovom kernelu.
U redu, to je ono što trebate razumjeti na osnovnom nivou o tome šta je kernel.
Funkcije jezgra
Što se tiče funkcija jezgra operativnog sistema, ono mora obezbijediti niz interfejsa. neophodno i za korisnika i za aplikacije također može koristiti hardverske resurse kojima upravlja. Ukratko, osnovne funkcije jezgra su sljedeće:
Svi operativni sistemi imaju kernel, kao što GNU/Linux distribucije imaju Linux kernel, Windows 11 ima Windows NT, macOS ima XNU, itd.
- Učitava upravljačke programe i firmver uređaja. Oni su neophodni za komunikaciju i korištenje hardvera.
- Upravljajte procesima i podprocesima (nitima) koje generiraju različiti pokrenuti programi.
- Također je odgovoran za nadzor i kontrolu pristupa aplikacijama, sa svim što to podrazumijeva, kao što je alokacija memorije koju korisnički prostor može koristiti. Da bi to postiglo, kernel radi u nadzorničkom režimu ili kernel režimu, kao što ćemo kasnije vidjeti.
- Rješava konflikte i greške uzrokovane alokacijom hardverskih resursa.
- Pored CPU-a i memorije, može upravljati i pristupati I/O uređajima.
- I, što je najvažnije, ima interfejs koji obrađuje sistemske pozive ili sistemske pozive koji se vrše.
Naravno, kernel nije sam. Često ga prate i drugi elementi koji čine kompletan operativni sistem. Jedan od njih je interfejs za interakciju korisnika s računarom. To uključuje korištenje, na primjer, CLI ili GUI.
Upravljački programi uređaja
Još jedan od fundamentalnih dijelova kernela su upravljački programi uređaja ili upravljački programi, kako su obično poznati. Drajveri mogu biti ugrađeni u sam kernel, tretirani kao moduli ili samostalni. U stvari, na osnovu toga se može klasifikovati o kojoj vrsti kernela se radi, iako se time ovdje nećemo baviti.
Drajveri su fundamentalni dio, jer predstavljaju kod ili program koji će biti odgovoran za direktnu interakciju sa hardverom na niskom nivou. Na taj način, kernel će moći komunicirati s hardverom putem drajvera. To jest, svrha drajvera je jednostavno dodavanje podrške kernelu za određeni uređaj, kao što je GPU, tastatura, štampač itd.
Mnogi od ovih drajvera već dolaze sa samim operativnim sistemom, da bi hardver ispravno radio od trenutka instalacije operativnog sistema. Međutim, drugi se moraju instalirati nakon instalacije operativnog sistema kako bi se u potpunosti iskoristile prednosti komponente koju kontrolišu, kao što su drajveri za grafičku karticu.
S druge strane, može se reći da postoji nekoliko vrsta upravljačkih programa uređaja, svaki s različitim metodama prijenosa informacija. Na primjer:
- Karakter: Ovi drajveri uređaja mogu otvarati, zatvarati, čitati ili pisati podatke kako bi ovu mogućnost omogućili i korisničkom prostoru.
- Blok: Ovi uređaji omogućavaju pristup uređajima za pohranu podataka ili uređajima koji koriste fiksne blokove informacija.
- Mreža: To su oni koji upravljaju paketima mrežnih podataka. To jest, omogućavaju komunikaciju mrežnih interfejsa.
Ovo izgleda prilično dobro na Unix-sličnim sistemima, kao što je Linux, budući da oni i dalje održavaju ovaj način odvajanja tipova uređaja.
S druge strane, važno je napraviti razliku između drajvera koji rade u kernel ili privilegovanom režimu i u korisničkom ili neprivilegovanom režimu:
- Kernel mod: Ovo je generički drajver koji se učitava s operativnim sistemom i kontrolira kritične hardverske uređaje za pokretanje kao što su CPU, matična ploča, RAM itd.
- Korisnički način rada: Ovo su kontroleri koji mogu ad-hoc kontrolirati širok raspon perifernih uređaja i dodataka svih vrsta, kao što su štampači, miševi, tastature, zvučni sistemi i drugi Plug and Play uređaji. Ovo su uređaji koji nisu neophodni za pokretanje računara.
Opet, na sistemima poput Linuxa, ovo se također može vrlo jasno vidjeti kod drajvera koji se dodaju monolitnom kernelu ili onih koji se izdvajaju kao moduli koji se dinamički učitavaju kada je uređaj povezan ili kada je to potrebno.
U redu, malo po malo, počinjemo shvaćati funkcije kernela i drajvera, a sada prelazimo na ono što smo govorili o kernelu ili privilegovanom režimu i korisničkom režimu, što je također vrlo važno da biste razumjeli šta je sistemski poziv i za šta se koristi...
Načini rada
Šta je kernel ili privilegovani režim?
Računarski dizajneri, ovisno o arhitekturi, kreirali su niz slojeva ili sigurnosni prstenovi koji su veoma važni. Kada govorimo o kernel modu ili privilegovanom modu, mislimo na centralni prsten na gornjoj slici, odnosno onaj crvenog lika. Prsten 0 je onaj koji ima potpuni pristup svim kritičnim aspektima, kao što su upravljanje hardverskim resursima, kontrola datotečnog sistema (FS) itd. To jest, taj nivo privilegija bi bio neophodan za dodjeljivanje prostora u RAM memoriji bilo kojem programu koji namjeravate pokrenuti, čak i za kreiranje datoteke na disku za pohranu, bilo kojem I/O zadatku koji izvršavate, uključujući umrežavanje itd.
Iako se drajveri pojavljuju u drugim, manje privilegovanim prstenovima od kernela, treba napomenuti, kao što sam već spomenuo, da postoje i neki kritični drajveri integrirani u kernel.
Šta je korisnički režim?
El korisnički način rada je neprivilegirani način rada Kao što se može vidjeti na slici, to bi bio zeleni prsten (Prsten 3), koji koriste sve aplikacije i korisnički prostor. Stoga, budući da nema privilegije, ne bi mogao kontrolirati bitne zadatke poput upravljanja hardverom.
Dakle, možda se pitate kako videoigra može koristiti GPU ili se pokrenuti, ili kako program za obradu teksta može sačuvati datoteku ako nema privilegije za obavljanje ovih zadataka. Pa, evo ga. ključ sistemskog poziva ili poziva sistema.
Šta je povreda kičmene moždine (SCI)?
Kao što možete vidjeti na gornjoj slici, najniži sloj koji imamo je hardver. Iznad hardvera, u ovom slučaju, imamo kernel operativnog sistema. LinuxI u njemu, drajveri koji će moći direktno komunicirati s tim hardverom, između ostalih bitnih elemenata.
Tada jezgro ima "površinski" sloj, da tako kažemo, koji Zove se SCI ili Interfejs sistemskih poziva. Interfejs sistemskih poziva To nije ništa više od interfejsa koji omogućava korisničkom prostoru da vrši pozive koje kernel mora obraditi kako bi aplikacije mogle, na neki način, čak i indirektno, pristupiti tim resursima kojima se može pristupiti samo s privilegijama.
Na SCI-ju, kao što se može vidjeti na slici, imamo elementarne biblioteke operativnog sistema, koje se mogu razlikovati od jednog OS-a do drugog. Ove biblioteke ili API-ji Oni služe za isporuku svega što je potrebno korisničkim aplikacijama ili programima. Međutim, to nas ovdje ne zanima. Jedino važno što treba zaključiti je da su iznad svega toga aplikacije ili korisnički prostor, što je neprivilegovani režim.
Šta je sistemski poziv?

A sada dolazimo do zaista važnog dijela, a to je šta je to sistemski poziv ili sistemski poziv koje smo već spomenuli. Pa, sistemski poziv je jednostavno funkcija koju SCI pruža kako bi aplikacije ili kod korisničkog prostora mogli zatražiti pristup onim instancama koje su ograničene zbog nedostatka privilegija. Drugim riječima, to je način poboljšanja sigurnosti, tako da aplikacija ne može direktno pristupiti tim resursima.
Ali naravno, kao što možda mislite, da bi se ovi pozivi zaista i ostvarili, nešto se mora dogoditi, i nešto se mora dogoditi u operativnom sistemu da bi se na njih odgovorilo. Pa, to ćemo objasniti u sljedećim odjeljcima...
Kako funkcioniše sistemski poziv?
Pa, Zamislite da koristite tekstualni editorOtvorite tekstualni editor i kada ga otvorite, on radi. To jest, operativni sistem je učitao proces u RAM memoriju koji ga je ugasio, a CPU je pristupio ovom procesu kako bi izvršio instrukcije i podatke koje je pronašao u tom procesu kako bi tekstualni editor mogao raditi.
Sada, ukucate nešto u tekstualni editor i želite sačuvati datoteku. Date joj ime i sačuvate je. Datoteka je sačuvana kao example.txt. Ali ako je tekstualni editor aplikacija korisničkog prostora i nije privilegovana... kako je mogao pristupiti datotečnom sistemu diska za pohranu podataka da bi sačuvao tekstualnu datoteku? Pa, to je učinio putem sistemskog poziva, sistemskog poziva koji je poslao SCI-ju, a kernel je izvršio određeni kod kako bi omogućio kreiranje i spremanje datoteke.
To ću pokušati objasniti u nastavku na tehničkiji način.
Tipovi sistemskih poziva
Ne postoji samo jedan vrsta sistemskog poziva ili sistemskog poziva, ali ih ima nekoliko. Neki od glavnih tipova sistemskih poziva su:
- Kontrola procesa: Ovo su pozivi koji vam omogućavaju kreiranje, brisanje, promjenu prioriteta, stavljanje procesa na čekanje itd. U ovom slučaju, oni su usko povezani sa planerom operativnog sistema i upravljanjem korištenjem memorije i CPU-a.
- Upravljanje datotekamaU ovom slučaju, to su sistemski pozivi koji su posebno namijenjeni manipulaciji datotekama, kao što su kreiranje nove datoteke, čitanje, pisanje, brisanje itd. U ovom slučaju, oni su usko povezani s kontrolom datotečnih sistema (FS) različitih dostupnih jedinica za pohranu, kako internih tako i eksternih ili prenosivih.
- Upravljanje uređajimaOvo su sistemski pozivi odgovorni za upravljanje uređajima i omogućavanje njihovog korištenja, kao što su povezivanje, isključivanje, otpuštanje itd. Oni su usko povezani s perifernim uređajima ili uređajima kojima se može upravljati.
- Održavanje informacija: je vrsta sistemskog poziva koji se koristi za održavanje osnovnih informacija o operativnom sistemu, kao što su vrijeme, datum itd., koje su važne za neke aplikacije.
- KomunikacijeOvi sistemski pozivi, kao što im i samo ime govori, odgovorni su za komunikaciju između procesa. To jest, oni upravljaju porukama ili signalima koje procesi šalju jedni drugima radi prenosa informacija.
Sada kada smo obradili osnovne tipove sistemskih poziva, vrijeme je da naučimo kako i šta su ovi sistemski pozivi u operativnim sistemima, jer nisu isti na svim operativnim sistemima. Na primjer, evo tabele s nekim primjerima za Windows NT i Linux (važi i za Unix):
| Tipovi sistemskih poziva | Windows | Linux |
|---|---|---|
| KreirajProces() | viljuška() | |
| Kontrola procesa | ExitProcess() | Izlaz () |
| ČekajNaJedanObjekat() | čekaj() | |
| KreirajDatoteku() | otvori() | |
| ReadFile() | pročitaj () | |
| Upravljanje datotekama | WriteFile() | pisati() |
| ZatvoriRučku() | zatvori () | |
| PostaviKonzolniNačin() | ioctl() | |
| Upravljanje uređajima | ReadConsole() | pročitaj () |
| WriteConsole() | pisati() | |
| DohvatiTrenutniIDProcesa() | getpid() | |
| Održavanje informacija | PostaviTajmer() | alarm() |
| spavaj() | spavaj() | |
| KreirajCijev() | cijev() | |
| Komunikacija | CreateFileMapping() | shmget() |
| PrikazMapeDatoteke() | mmap() |
Kao što možete vidjeti, nisu isti na jednom sistemu nego na drugom, čak i ako imaju iste funkcije. Ovo se mora uzeti u obzir prilikom programiranja za jednu ili drugu platformu. To jest, morate biti upoznati sa ABI-jem i bibliotekama dostupnim na operativnom sistemu za koji pišete kod, jer ako trebate koristiti bilo koji od ovih sistemskih poziva, morat ćete ih poznavati i ne koristiti one iz drugog operativnog sistema.
por ejemploZamislite Linuxov poziv read(), koji je poziv za upravljanje datotekama i koristi se za čitanje datoteke, kao što možete pretpostaviti iz njenog imena. Na primjer, zamislite program koji čita sadržaj datoteke, kao što je ovaj C izvorni kod:
#uključi #uključi #uključi int main() { DATOTEKA* ptr; char ch; // Otvara datoteku u načinu čitanja ptr = fopen("primjer.txt", "r"); if (NULL == ptr) { printf("Datoteka se ne može otvoriti \n"); } printf("Sadržaj ove datoteke je: \n"); // Prikazuje sadržaj do { ch = fgetc(ptr); printf("%c", ch); // Provjerava EOF i zaustavlja } while (ch != EOF); // Zatvara datoteku fclose(ptr); return 0; }
Ovaj izvorni kod također koristi druge sistemske pozive, kao što je zatvaranje datoteke, u ovom slučaju close(). Ali fokusirajmo se samo na funkciju read(). Pa, ako se ovaj izvorni kod kompajlira i izvrši, procedura koja bi se dogodila bila bi sljedeća:
- Ovaj mali program nema privilegije; izvršava se u korisničkom prostoru. Međutim, potrebno mu je otvoriti, pročitati i zatvoriti datoteku. Stoga će izvršiti sistemski poziv, koji će u ovom slučaju dosegnuti SCI Linux kernela.
- Kernel će obraditi ovaj poziv u privilegovanom prostoru, pokrećući rutinu koja odgovara traženom pozivu, u ovom slučaju poziv za čitanje. To jest, učitat će proces korišten za izvršavanje poziva u memoriju, koju će obraditi CPU.
- Kada se rutina izvrši, kontrola se prenosi na kernel putem prekida ili zamke. Pozivu će biti dodijeljen jedinstveni kod u zapisniku radi njegove identifikacije, budući da se istovremeno može obavljati mnogo drugih poziva, pa čak i identičnih (čitanje).
- Kernel, putem svoje kontrole nad datotečnim sistemom, će izvršiti čitanje tražene datoteke.
- Nakon što se ova rutina read() završi, kernel vraća kontrolu u korisnički način rada. Također će vratiti izlaz procesa programu koji ga je pozvao, u ovom slučaju našem primjeru programa.
- Nakon prijema izlaza, programski proces će nastaviti s izvršavanjem tamo gdje je stao.
Rezultat bi bio da prilikom pokretanja našeg programa, uprkos tome što nemamo privilegije za pristup kontroli datotečnog sistema, on može izvršiti ovaj zadatak bez problema i dobiti sadržaj tražene datoteke. U ovom primjeru koda, to bi bila datoteka pod nazivom example.txt.
U ovom slučaju, funkcija "fopen" u izvornom kodu programskog jezika C bit će odgovorna za pokretanje svega ovoga. Ova funkcija koristi C biblioteku. Kao što vidite, zato je važno znati sve što sam gore spomenuo o kernelu, bibliotekama, modovima itd. U suprotnom, ovo ne biste razumjeli.
A kako kernel zna šta da radi? Pa, u ovom slučaju, Linux ima odgovarajuću funkciju za čitanje. Na primjer, evo izvornog koda za read() u Linuxu, implementiranog u GNU C biblioteci u ovom slučaju:
/* Implementacija sistemskog poziva za čitanje Linuxa. Autorska prava (C) 2017-2022 Free Software Foundation, Inc. Ova datoteka je dio GNU C biblioteke. GNU C biblioteka je besplatan softver; možete je distribuirati i/ili mijenjati pod uslovima GNU Manje opšte javne licence kako je objavila Free Software Foundation; bilo verzija 2.1 licence ili (po vašem izboru) bilo koja kasnija verzija. GNU C biblioteka se distribuira u nadi da će biti korisna, ali BEZ IKAKVE GARANCIJE; čak i bez implicitne garancije PRODAJNOSTI ili POGODNOSTI ZA ODREĐENU NAMJENU. Pogledajte GNU Manju opštu javnu licencu za više detalja. Trebali ste dobiti kopiju GNU Manje opšte javne licence zajedno s GNU C bibliotekom; ako ne, pogledajte . */ #uključi #uključi /* Učitava NBYTES u BUF iz FD-a. Vraća broj pročitanih podataka ili -1. */ ssize_t __libc_read (int fd, void *buf, size_t nbytes) { return SYSCALL_CANCEL (read, fd, buf, nbytes); } libc_hidden_def (__libc_read) libc_hidden_def (__read) weak_alias (__libc_read, __read) libc_hidden_def (read) weak_alias (__libc_read, read)
Također vrijedi napomenuti da će se prekid, ovisno o arhitekturi ili korištenom ISA-u, obrađivati drugačije. Na primjer, u ASM-u ili x86 asembleru, rezultirajući kod iz gornjeg C programa bi bio:
.LC0: .string "r" .LC1: .string "example.txt" .LC2: .string "Datoteka se ne može otvoriti" .LC3: .string "Sadržaj ove datoteke je:" main: push rbp mov rbp, rsp sub rsp, 16 mov esi, OFFSET FLAT:.LC0 mov edi, OFFSET FLAT:.LC1
poziv fopen
mov QWORD PTR [rbp-8], rax cmp QWORD PTR [rbp-8], 0 i više .L2 mov edi, OFFSET FLAT:.LC2 poziv puts .L2: mov edi, OFFSET FLAT:.LC3 poziv puts .L3: mov rax, QWORD PTR [rbp-8] mov rdi, rax poziv fgetc mov BYTE PTR [rbp-9], al movsx eax, BYTE PTR [rbp-9] mov edi, eax poziv putchar cmp BYTE PTR [rbp-9], -1 i više .L3 mov rax, QWORD PTR [rbp-8] mov rdi, rax poziv fclose mov eax, 0 ostavi ret
Kao što vidite, istaknuo sam liniju call fopen, jer je to instrukcija koja će se izvršiti na CPU-u da bi se uputio taj sistemski poziv. U ovom slučaju, call je instrukcija prisutna u x86-64 ISA i služi upravo toj svrsi.
Najvažniji pozivi
Također je potrebno istaknuti neke važne pozive koji su neophodni za izvršavanje programa u računarskim sistemima, a to su:
- čekaj(): Ovaj poziv omogućava stavljanje procesa na čekanje kako bi se drugi proces s višim prioritetom mogao prvo završiti. Nakon obrade, ovaj proces se može vratiti na izvršenje. U ovom slučaju, može se dogoditi nekoliko stvari:
- Ako se proces nalazio u RAM-u i nije započeo s izvršavanjem, ali u RAM-u ima dovoljno prostora za drugi prioritetni proces, prioritetni proces će također biti učitan u RAM, ali će prvi biti stavljen u red čekanja za izvršenje od strane CPU-a.
- Ako imamo isti scenario kao gore, ali nema dovoljno RAM memorije za učitavanje prioritetnog procesa, operativni sistem će koristiti virtuelnu memoriju, premještajući proces čekanja na disk, a prioritetni proces u RAM.
- Ako je proces koji se stavlja u red čekanja već započeo obradu od strane CPU-a, kontekst će se promijeniti i PCB će biti pohranjen. Prioritetni proces će se zatim izvršiti, a ovaj PCB će biti preuzet iz memorije s detaljima kako bi se utvrdilo gdje se prethodni proces izvršavao.
- viljuška(): Ovaj sistemski poziv kreira fork ili derivat glavnog procesa. To jest, program kreira kopiju sebe, koja zatim djeluje kao "podređeni proces" originalnog procesa, koji se sada naziva "roditelj".
- izvršavanje(): Ovaj sistemski poziv se koristi kada pokrenuti proces želi pokrenuti drugu izvršnu datoteku. ID procesa ostaje isti, dok se ostali resursi koje proces koristi zamjenjuju novokreiranim procesom.
- ubiti(): Ponekad, tokom rada, prekinemo određeni proces. Tada se poziva sistemski poziv kill(), koji šalje signal za prekid procesu. Drugim riječima, završava ga. To se može vidjeti, na primjer, kada se koristi naredba kill za prekid programa u Linuxu.
- izlaz(): Kada zaista trebamo prekinuti program, koristimo izlazni sistemski poziv. Resursi koje je proces zauzeo oslobađaju se nakon pozivanja izlaznog sistemskog poziva.
Međutim, iako bi ovo bila druga tema, može se desiti da se proces ne završi kako treba i ostane kao zombi..., bez oslobađanja resursa koje je "oteo", ali bez da mu oni zapravo i trebaju, budući da je "mrtav".
Inače, prilikom programiranja možete kreirati i poznate niti, tj. podprocese. U ovom slučaju, proces se može podijeliti na nekoliko osnovnijih zadataka poznatih kao podprocesi. Stoga, CPU može da ih obrađuje nezavisno, kao da su nezavisni procesi. Na primjer, u C-u možete koristiti funkciju pthread_create da kreira ove niti. Sve dok se sve niti u procesu ne završe, proces se ne završava.
zaključak
Šta bismo radili bez sistemskih poziva, ili syscallova? Aplikacije ne bi mogle ispravno funkcionirati, a to bi značilo pisanje aplikacija u privilegovanom prostoru, što bi predstavljalo značajan sigurnosni rizik.
Nadam se da vam je ovaj članak bio koristan i da sada dobro razumijete šta je sistemski poziv...