Operativsystem: Tre enkla delar. Del 3: Process API (översättning)

Introduktion till operativsystem

Hej Habr! Jag skulle vilja uppmärksamma dig på en serie artiklar-översättningar av en intressant litteratur enligt min mening - OSTEP. Detta material diskuterar ganska djupt arbetet med unix-liknande operativsystem, nämligen arbete med processer, olika schemaläggare, minne och andra liknande komponenter som utgör ett modernt operativsystem. Du kan se originalet av allt material här här. Observera att översättningen gjordes oprofessionellt (ganska fritt), men jag hoppas att jag behöll den allmänna innebörden.

Labbarbete i detta ämne finns här:

Övriga delar:

Du kan också kolla in min kanal på telegram =)

Larm! Det finns ett labb för denna föreläsning! Se github

Process API

Låt oss titta på ett exempel på att skapa en process i ett UNIX-system. Det sker genom två systemsamtal gaffel() и exec ().

Call fork()

Operativsystem: Tre enkla delar. Del 3: Process API (översättning)

Tänk på ett program som gör ett fork()-anrop. Resultatet av dess utförande blir följande.

Operativsystem: Tre enkla delar. Del 3: Process API (översättning)

Först och främst går vi in ​​i main()-funktionen och skriver ut strängen på skärmen. Raden innehåller processidentifieraren som i originalet kallas PID eller processidentifierare. Denna identifierare används i UNIX för att referera till en process. Nästa kommando kommer att anropa fork(). Vid denna tidpunkt skapas en nästan exakt kopia av processen. För operativsystemet ser det ut som att det finns två kopior av samma program som körs på systemet, vilket i sin tur kommer att avsluta fork()-funktionen. Den nyskapade underordnade processen (i relation till den överordnade processen som skapade den) kommer inte längre att exekveras, med början från main()-funktionen. Man bör komma ihåg att en underordnad process inte är en exakt kopia av den överordnade processen; i synnerhet har den sitt eget adressutrymme, sina egna register, sin egen pekare till körbara instruktioner och liknande. Således kommer värdet som returneras till anroparen av fork()-funktionen att vara annorlunda. I synnerhet kommer den överordnade processen att få PID-värdet för den underordnade processen som en retur, och barnet kommer att få ett värde lika med 2. Med dessa returkoder kan du sedan separera processer och tvinga var och en av dem att göra sitt eget arbete . Utförandet av detta program är dock inte strikt definierat. Efter uppdelning i 0 processer börjar operativsystemet övervaka dem och planera deras arbete. Om den körs på en enkärnig processor kommer en av processerna, i det här fallet föräldern, att fortsätta att fungera, och sedan kommer den underordnade processen att få kontroll. Vid omstart kan situationen vara annorlunda.

Samtal vänta()

Operativsystem: Tre enkla delar. Del 3: Process API (översättning)

Tänk på följande program. I detta program, på grund av närvaron av ett samtal vänta() Föräldraprocessen väntar alltid på att den underordnade processen ska slutföras. I det här fallet kommer vi att få en strikt definierad textutmatning på skärmen

Operativsystem: Tre enkla delar. Del 3: Process API (översättning)

exec() anrop

Operativsystem: Tre enkla delar. Del 3: Process API (översättning)

Tänk på utmaningen exec (). Detta systemanrop är användbart när vi vill köra ett helt annat program. Här ska vi ringa execvp() att köra wc-programmet som är ett ordräkningsprogram. Vad händer när exec() anropas? Detta anrop skickas med namnet på den körbara filen och några parametrar som argument. Varefter koden och statiska data från denna körbara fil laddas och dess eget segment med koden skrivs över. De återstående minnesområdena, såsom stacken och heapen, återinitieras. Därefter kör operativsystemet helt enkelt programmet och skickar det en uppsättning argument. Så vi skapade inte en ny process, vi förvandlade helt enkelt det program som körs för närvarande till ett annat program som körs. Efter exekvering av exec()-anropet i efterkommande verkar det som om det ursprungliga programmet inte kördes alls.

Denna startkomplikation är helt normal för ett Unix-skal och låter det skalet exekvera kod efter anrop gaffel(), men innan samtalet exec (). Ett exempel på sådan kod skulle vara att anpassa skalmiljön till behoven hos programmet som lanseras, innan det startas.

Shell - bara ett användarprogram. Hon visar dig inbjudningsraden och väntar på att du ska skriva något i den. I de flesta fall, om du skriver namnet på ett program där, kommer skalet att hitta sin plats, anropa metoden fork() och sedan anropa någon typ av exec() för att skapa en ny process och vänta på att den ska slutföras med en wait() samtal. När den underordnade processen avslutas kommer skalet att återvända från wait()-anropet och skriva ut prompten igen och vänta på att nästa kommando ska matas in.

Fork() & exec() split tillåter skalet att göra följande saker, till exempel:
wc-fil > ny_fil.

I det här exemplet omdirigeras utdata från wc-programmet till en fil. Sättet som skalet uppnår detta på är ganska enkelt - genom att skapa en underordnad process innan du ringer exec (), stänger skalet standardutdata och öppnar filen ny fil, alltså all utmatning från det vidare pågående programmet wc kommer att omdirigeras till en fil istället för en skärm.

Unix-rör implementeras på liknande sätt, med skillnaden att de använder ett pipe()-anrop. I det här fallet kommer processens utström att kopplas till en rörkö som finns i kärnan, till vilken ingångsströmmen från en annan process kommer att kopplas.

Källa: will.com

Lägg en kommentar