Hyrje në sistemet operative
Përshëndetje, Habr! Dëshiroj t'ju prezantoj një seri artikujsh-përkthime mbi një literaturë që e konsideroj interesante — OSTEP. Ky material shqyrton në mënyrë të thellë funksionimin e sistemeve operative të ngjashme me Unix, sidomos — menaxhimin e proceseve, planifikuesit e ndryshëm, memorjen dhe komponentë të tjerë të tillë që përbëjnë një sistem operativ modern. Origjinali i të gjitha materialeve mund ta shihni këtu . Ju lutem, mbani në mend se përkthimi është bërë në mënyrë jo profesionale (mjaft e lirë), por shpresoj se e kam ruajtur kuptimin e përgjithshëm.
Laboratorët për këtë lëndë mund t'i gjeni këtu:
- origjinali:
- origjinali:
- adaptimi im personal:
Pjesë të tjera:
Po ashtu mund të dëshironi të vizitoni kanalin tim në =)
Le të shqyrtojmë abstraksionin më themelor që OS i ofron përdoruesve: procesi. Definimi i procesit është mjaft i thjeshtë — kjo është një program në punë. Programi vetë është një gjë e pajetë, që ndodhet në disk — ajo është një grup instruksionesh dhe ndoshta disa të dhënash statike, që presin momentin e aktivizimit. Pikërisht OS merr këto byte dhe i aktivizon, duke i transformuar programin në diçka të dobishme.
Shumica e përdoruesve dëshirojnë të drejtojnë më shumë se një program njëkohësisht, për shembull, mund të hapni në laptop tuaj një shfletues, një lojë, një player multimedia, një redaktues teksti dhe gjëra të ngjashme. Në të vërtetë, një sistem tipik mund të drejtojë dhjetëra dhe qindra procese njëkohësisht. Ky fakt e bën sistemin më të lehtë për t'u përdorur, kurrë nuk keni për të shqetësuar nëse CPU është e lirë, thjesht hapni programet.
Këtu lind problemi: si të krijoni iluzionin e shumë CPU-ve? Si mund të krijojë OS iluzionin e një numri praktikisht të pafund CPU-sh, edhe nëse keni vetëm një CPU fizik?
OS-ja krijon këtë iluzion përmes virtualizimit të CPU-së. Duke drejtuar një proces, pastaj duke e ndaluar atë, duke hapur një proces tjetër dhe kështu me radhë, OS-ja mund të mbajë iluzionin që ekzistojnë shumë CPU virtuale, edhe pse në të vërtetë do të jetë një ose disa procese fizike. Kjo teknikë quhet ndarja e burimeve të CPU-së sipas kohës. Kjo teknologji u lejon përdoruesve të nisin sa më shumë procese të njëkohshme sa të duan. Çmimi i kësaj zgjidhjeje është performanca – pasi nëse CPU ndan disa procese, çdo proces do të përpunojë më ngadalë.
Për të realizuar virtualizimin e CPU-së, veçanërisht për ta bërë këtë mirë, sistemi operativ ka nevojë për mbështetje të ulët dhe të lartë. Mbështetje e ulët quhet mekanizmat — këto janë metoda apo protokolle të ulëta që realizojnë pjesën e nevojshme të funksionalitetit. Një shembuj i tillë funksionaliteti është ndryshimi i konteksteve, i cili i duhët sistemit operativ për të ndaluar një program dhe për të nisur një program tjetër në procesor. Ky ndarje në kohë është realizuar në të gjitha sistemet operativ moderne.
Në majë të këtyre mekanizmave ka disa logjikë, e vendosur në sistemin operativ, në formën e “politikave”. Politika — është një algoritëm i caktimit të vendimeve nga sistemi operativ. Këto politika, për shembull, vendosin se cilin program duhet të nisë (nga lista e komandave) më parë. Kështu, për shembull, këtë detyrë do ta zgjidhë një politikë që quhet politika e caktimit (scheduling policy) dhe gjatë zgjedhjes së zgjidhjes do të udhëhiqet nga të dhëna të tilla si: historia e përgatitjes (cila program ka qenë e ekzekutuar më gjatë gjatë minutës së fundit), çfarë ngarkese përmbush ky proces (çfarë lloj programesh janë ekzekutuar), metrikat e performancës (nëse sistema është optimizuar për ndërveprimin interaktiv ose për kapacitetin e kalimit) dhe kështu me radhë.
Abstraksioni: procesi
Abstraksioni i një programi në ekzekutim, i realizuar nga sistemi operacional, është ajo që ne e quajmë proces. Siç është thënë më parë, procesi është thjesht një program në ekzekutim, në çdo moment të caktuar të kohës. Programi me anë të të cilit ne mund të marrim informacion të përmbledhur nga burime të ndryshme të sistemit, dhe që i referohet ose që preken nga ky program gjatë ekzekutimit të tij.
Për të kuptuar përbërësit e procesit, duhet të kuptojmë gjendjet e sistemit: çfarë mund të lexojë ose ndryshojë programi gjatë punës së tij. Në çdo moment të caktuar, duhet të kuptojmë se cilat elemente të sistemit janë të rëndësishme për ekzekutimin e programit.
Një nga elementët e dukshëm të gjendjes së sistemit, të cilat procesi përfshin — është память. Instruksionet vendosen në memorie. Të dhënat që programi lexon ose shkruan gjithashtu, janë të vendosura në memorie. Pra, memoria që procesi mund të adresojë (e ashtuquajtur hapësirë adresimi) është një pjesë e procesit.
Gjithashtu, një pjesë e gjendjes së sistemit janë regjistrat. Shumë instruksione kanë për qëllim të ndryshojnë vlerën e regjistrave ose të lexojnë vlerën e tyre dhe kështu regjistrat bëhen gjithashtu një pjesë e rëndësishme e funksionimit të procesit.
Duhet të theksohet se gjendja e makinës formohet edhe nga disa regjistra specialë. Për shembull, IP — treguesi i instrukcioni — tregon për instrukcionin që programi po ekzekuton në këtë moment. Ka gjithashtu treguesin e stack dhe të lidhur me të treguesin e kornizës, të cilat përdoren për menaxhimin: parametrave të funksioneve, variablave lokalë dhe adresave të kthimit.
Më në fund, programet shpesh i referohen ROM (memorisë së përhershme). Kjo informacion në lidhje me “I/O” (hyrje-dalje) duhet të përfshijë një listë të skedarëve që procesi ka hapur në këtë moment.
Process API
Për të përmirësuar kuptimin e funksionit të procesit, le të shqyrtojmë shembuj të thirrjeve sistemore që duhet të përfshihen në çdo ndërfaqe operative. Këto API janë në formë të caktuar të disponueshme në çdo OS.
● Create (krijimi): Një metodë e tillë duhet të jetë e pranishme në OS që lejon krijimin e proceseve të reja. Kur vendosni një komandë në terminal ose hapni një aplikacion duke dyfishuar klikimin në ikonë, dërgohet një kërkesë në OS për të krijuar një proces të ri dhe për të nisur programin e specifikuar.
● Fshirja: Duke qenë se ka një ndërfaqe për krijimin e proceseve, OS duhet gjithashtu të ofrojë mundësinë për të fshirë me forcë një proces. Shumica e programeve pritet të ekzekutohen dhe të mbyllen vetvetiu gjatë funksionimit të tyre. Në të kundërt, përdoruesi do të dojë të ketë mundësinë për t'i përfunduar ato, kështu që një ndërfaqe për ndalimin e procesit do të ishte e dobishme.
● Wait (pritja): Ndonjëherë është e dobishme të prisni për përfundimin e një procesi, ndaj ofrohen disa ndërfaqe që ofrojnë mundësi pritjeje.
● Misc Control (menaxhimi i ndryshëm): Përveç vrasjes dhe pritjes së procesit, ekzistojnë edhe metoda të tjera të ndryshme kontrolluese. Për shembull, shumica e OS-ve ofrojnë mundësinë për të ngrirë një proces (ndalimi i ekzekutimit të tij për një periudhë të caktuar) dhe pastaj për ta rinisur (vazhdimi i ekzekutimit).
● Statusi (gjendja): Ekzistojnë ndërfaqe të ndryshme për të marrë disa informata mbi statusin e procesit, siç janë koha e punës së tij ose në cilën gjendje ndodhet tani.

Krijimi i procesit: detajet
Një nga gjërat interesante është se si programet transformohen në procese. Veçanërisht, si OS e ngre dhe e nis programin. Si krijohet konkretisht një proces.
Së pari, OS duhet të ngarkojë kodin e programit dhe të dhënat statike në memorie (në hapësirën adresore të procesit). Programet zakonisht ndodhen në disk ose në një ruajtës të ngurtë në një format ekzekutues të caktuar. Prandaj, procesi i ngarkimit të programit dhe të dhënave statike në memorie kërkon nga OS mundësinë për të lexuar këto byte nga disku dhe për t’i vendosur ato diku në memorie.
Në sistemet operative të hershme, procesi i ngarkesës realizohej me padurim, që do të thotë se kodi ngarkohej në memorie në tërësi para se të fillonte programi. Sistemet moderne bëjnë këtë në mënyrë të ngadaltë, ngjashëm me ngarkimin e copave të kodit ose të dhënave vetëm kur ato kërkohen nga programi gjatë ekzekutimit të tij.
PasiKodi dhe të dhënat statike ngarkohet në memorie, sistemi operativ duhet të kryejë disa gjëra përpara se të nisë procesin. Një sasi memorie duhet të ndahet për stek. Programet përdorin stek për variablat lokalë, parametrat e funksioneve dhe adresat e rikthimit.. Sistemi operativ e ndan këtë memorie dhe ia jep procesit. Steku gjithashtu mund të ndarë disa argumente, posaçërisht mbush parametrat e funksionit main(), siç janë masat argc dhe argv.
Sistemi operativ gjithashtu mund të ndarë një sasi memorie për grumbullin e programit. Grumbulli përdoret nga programet për të dhëna dinamike që kërkohen shprehimisht.. Programet kërkojnë këtë hapësirë duke thirrur funksionin malloc() dhe e çliron atë duke thirrur funksionin free(). Koshat nevojitet për strukturat e tillë të të dhënave si: lista të lidhura, tabela të hash-it, pemë dhe të tjera. Fillimisht, hapsira e nevojshme e alokuar për koshin është e vogël, por me kalimin e kohës, gjatë funksionimit të programit, koshat mund të kërkojnë më shumë hapsirë përmes thirrjes API të bibliotekës malloc(). Sistemi operativ është i përfshirë në procesin e alokimit të më shumë hapsirës për të ndihmuar në kënaqjen e këtyre thirrjeve.
Sistemi operativ gjithashtu do të kryejë detyra inicializimi, veçanërisht ato që lidhen me hyrjen dhe daljen. Për shembull, në sistemet UNIX, çdo proces ka për default 3 deshkrime të hapura të skedarëve për rrjedhën standarde të hyrjes, daljes dhe gabimeve. Këto deshkrime lejojnë programet të lexojnë hyrjen nga terminali dhe gjithashtu të nxjerrin informacion në ekran.
Kështu, duke ngarkuar kodin dhe të dhënat statike në memories, duke krijuar dhe inicializuar stekun, si dhe duke kryer punë të tjera që lidhen me ekzekutimin e detyrave të hyrjes dhe daljes, sistemi operativ përgatit terrenin për ekzekutimin e procesit. Në fund të fundit, mbetet detyra e fundit: të nisni programin për ekzekutim nëpërmjet pikës së tij të hyrjes, e quajtur funksioni main(). Duke u kaluar në ekzekutimin e funksionit main(), sistemi operativ i kalon kontrollin CPU-së procesit të sapo krijuar, kështu që programi fillon të ekzekutohet.
Gjendja e procesit
Tani, kur kemi një kuptim të caktuar se çfarë është një proces dhe si krijohet ai, le të rendisim gjendjet e procesit në të cilat ai mund të ndodhet. Në formën më të thjeshtë, procesi mund të ndodhet në njërën nga këto gjendje:
● Running. Në gjendjen e ekzekutimit, procesi po ekzekutohet në procesor. Kjo do të thotë se po ndodh ekzekutimi i instrukcioneve.
● Gati. Në gjendjen e gatshme, procesi është gati të fillojë, por për disa arsye sistemi operativ nuk e ekzekuton atë në momentin e caktuar.
● Blokuar. Në gjendje të bllokuar, procesi kryen disa operacione që nuk e lejojnë atë të jetë i gatshëm për ekzekutim deri sa të ndodhi një ngjarje. Një nga shembujt e zakonshëm është kur procesi inicializon një operacion IO, ai bëhet i bllokuar dhe kështu një proces tjetër mund ta përdorë procesorin.

Të imagjinojmë këto gjendje si një graf. Siç mund të shohim në figurë, gjendja e procesit mund të ndryshojë mes RUNNING dhe READY sipas vendimit të OS. Kur gjendja e procesit fillon nga READY në RUNNING, kjo do të thotë se procesi është planifikuar. Në anën tjetër, është larguar nga planifikimi. Në momentin kur procesi bëhet BLOCKED, për shembull, duke inicializuar një operacion IO, OS do ta mbajë atë në këtë gjendje deri sa të ndodhi një ngjarje, si përfundimi i IO. Në këtë moment, ndodh kalimi në gjendjen READY dhe ndoshta menjëherë në gjendjen RUNNING, nëse kështu vendos OS.
Le të shohim një shembull se si dy procese kalojnë përmes këtyre gjendjeve. Së pari, le të imagjinojmë se të dy proceset janë të aktivizuar, dhe secili përdor vetëm CPU. Në këtë rast, gjendjet e tyre do të duken si më poshtë.

Në shembullin tjetër, procesi i parë pas një kohe pune kërkon IO dhe kalon në gjendjen BLOCKED, duke i dhënë mundësinë procesit tjetër të fillojë (SHK 1.4). OS sheh se procesi 0 nuk po përdor CPU dhe fillon procesin 1. Gjatë ekzekutimit të procesit 1 — IO përfundon dhe statusi i procesit 0 ndryshon në READY. Së fundi, procesi 1 përfundon dhe pas përfundimit të tij, procesi 0 fillohet, ekzekutohet dhe përfundon punën e tij.

Struktura e të dhënave
OS vetë është një program, dhe si çdo program tjetër, ka disa struktura kyçe të të dhënave që ndjekin pjesë të ndryshme relevante informacioni. Për të mbajtur nën kontroll gjendjen e çdo procesi, OS do të mbajë një listë procesesh për të gjitha proceset në gjendjen READY dhe disa informacione shtesë për të ndjekur proceset që po kryhen tani. Gjithashtu, sistemi operativ duhet të ndjekë edhe proceset e bllokuara. Pasi të përfundojë IO, sistemi operativ është i detyruar të zgjojë procesin e duhur dhe ta çojë atë në gjendjen e gatishmërisë për të filluar.
Kështu, për shembull, sistemi operativ duhet të ruajë gjendjen e regjistrave të procesorit. Në momentin e ndalimit të procesit, gjendja e regjistrave ruhet në hapësirën adresore të procesit, dhe në momentin e vazhdueshëm të punës së tij — rikthehen vlerat e regjistrave dhe kështu vazhdohet kryerja e këtij procesi.
Përveç gjendjeve ready, blocked, running ekzistojnë edhe disa gjendje të tjera. Ndonjëherë në momentin e krijimit, procesi mund të ketë gjendjen INIT. Në fund, procesi mund të vendoset në gjendjen FINAL, kur ai tashmë është përfunduar, por informacioni rreth tij nuk është pastruar ende. Në sistemet UNIX, kjo gjendje quhet proces-zombi. Ky kyç fuqon për rastet kur procesi prind dëshiron të dijë kodin e kthimit të procesit fëmijë, për shembull, zakonisht 0 tregon përfundimin e suksesshëm, ndërsa 1 për një gabim, megjithatë programuesit mund të krijojnë kode të tjera të daljes, duke sinjalizuar për probleme të ndryshme. Kur përfundon, procesi prind bën thirjen e fundit të sistemit, për shembull wait(), për të pritur përfundimin e punës së procesit fëmijë dhe për të sinjalizuar OS-në që të pastrojë çdo të dhënë të lidhur me procesin e përfunduar.

Pikat kryesore të leksionit:
● Procesi — është abstraksioni kryesor i një programi në funksionim në OS. Në çdo moment, procesi mund të përshkruhet përmes gjendjes së tij: përmbajtja e memories në hapësirën e tij adresore, përmbajtja e regjistrave të procesorit, duke përfshirë pointer-in e udhëzimeve dhe pointer-in e stack-ut, si dhe informacione për IO, për shembull, skedarët e hapur që po lexohen ose shkruhen.
● Process API përbëhet nga thirrjet që programet mund të bëjnë në lidhje me proceset. Zakonisht, këto janë thirrje për krijimin, fshirjen ose të tjerat.
● Procesi ndodhet në një nga shumë gjendje, duke përfshirë running, ready, blocked. Ngjarje të ndryshme, si planifikimi, përjashtimi nga planifikimi ose pritja, mund të shndërrojnë gjendjen e procesit nga njëra në tjetrën.
● Lista e proceseve përmban informacion rreth të gjitha proceseve në sistem. Çdo rekord në të quhet blloku i kontrollit të procesit, i cili në realitet është një strukturë që përmban të gjitha informacionet e nevojshme për një proces të veçantë.
Burimi: habr.com
