4.3. Proces-management

Unix-operativsystemer er multi-programming og multi-user-systemer. Det betyder at flere programmer kan køre på én computer samtidig, og dermed også at flere personer kan bruge én computer som server samtidig. For brugeren ser det ud som om programmerne kører parallelt, og at flere processer dermed har CPU'en samtidig. Dette fungerer i praksis ved, at hver proces har CPU'en i et bestemt tidsrum, hvorefter den ryger bag i en kø og næste proces hentes ind (multi-tasking).

Linux understøtter, ligesom Unix, ægte multi-tasking. Alle processer kører helt uafhængigt af hinanden, så ingen processer behøver at tage højde for at give processor-tid til andre processer. Hver proces har et hukommelses-område, som er beskyttet mod ændringer fra andre processer.

http://www-106.ibm.com/developerworks/linux/library/l-rt7/?Open&t=grl,l=252,p=mgth findes en interessant artikel om Linux i forhold til Windows 2000 og XP med hensyn til proces og tråd-håndtering.

4.3.1. Proces-struktur

Det vigtigste og mest specielle ved et multi-tasking-system er processerne og proces-strukturen. En proces er et program, som er under udførelse.

x86-arkitekturen understøtter 4 privilegieniveauer (eng. »privilege levels«), hvor niveau 0 er det mest privilegerede, og 3 det mindst privilegerede. Et kørende program vil altid være på et af disse niveauer.

Linux bruger kun 2 niveauer, nemlig kerneniveau (eng. »kernel mode«) og brugerniveau (eng. »user mode«). Ved at skelne mellem brugerniveau og kerneniveau kan man forhindre, at brugeren har direkte adgang til de forskellige I/O-enheder.

Der er kun adgang til disse fra kerneniveau, og alle brugerprogrammer kører på brugerniveau. Brugerprogrammer har derved kun adgang til I/O-enheder igennem et på forhånd specificeret systemkald, som resulterer i et skift fra brugerniveau til kerneniveau. Derved slipper programmøren af brugerprogrammer for at bekymre sig om detaljerne omkring f.eks. I/O. Hardwarens kompleksitet skjules derved for brugeren og udvikleren.

Et brugerprogram kan således bruge operativsystemet til at få udført forskellige instruktioner, ved at lave et systemkald. Et brugerprogram, der kører under Linux, vil derfor se Linux-kernen som en udbyder af servicefunktioner.

Når en proces kører i systemtilstand, kan den være i en af følgende tilstande:

4.3.2. Opstart af Linux

Når kernen er loadet starter den én enkeltbruger-proces, nemlig /sbin/init. Som parameter får init-programmet det "run-level" som man angiver ved lilo-prompten, f.eks. "single" der normalt fortolkes som "run-level 1".

init kigger så i /etc/inittab, og udfører de kommandoer der står som aktive for run-level 1, eller alle run-levels. På min Red Hat er det f.eks.

# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
l1:1:wait:/etc/rc.d/rc 1

rc.sysinit bliver altså kørt uanset run-level, mens /etc/rc.d/rc 1 – som starter alle de kommandoer der ligger i /etc/rc.d/rc1.d/-kataloget – kun kører i run-level 1.

Det er formentlig i rc.sysinit at du finder et kald til f.eks. sulogin, der spørger dig efter "root"s adgangskode førend den starter en kommandofortolker.

Det er forresten ikke nogen naturlov, at kernen starter /sbin/init som det første program. Man kan faktisk angive hvilket program der skal startes med en lilo-parameter, f.eks. vil init=/bin/bash starte en root-shell helt uden om opstarts-scripts osv.

4.3.3. Procesrelationer

Proces-hierarkiet i Linux er et forælder-barn-hierarki. En ny proces kan kun skabes med systemkaldet fork(). Den nye proces bliver barn-proces til den proces, der udførte fork().

Den nye proces bliver oprettet ved at lave en næsten identisk kopi af den proces der kaldte fork(). Ofte er det første, en ny proces gør, at udføre et execve-kald, som overskriver den arvede kode, stak, registre mv., så den ikke længere er en kopi af forælderprocessen, men en ny proces.

Det kan være meget ressourcekrævende at oprette en ny proces, da der kan være mange data fra forælderprocessen, som skal kopieres. Derfor bruges der i Linux "copy-on-write"-teknikken. Tanken bag denne teknik er, at et antal processer kan have adgang til den samme hukommelse, så længe der ikke er nogen af processerne, der laver ændringer i data. Således bliver de relevante pages af hukommelse ikke kopieret ved systemkaldet fork(), men den fælles hukommelse bliver skrivebeskyttet. Hvis en af processerne forsøger at skrive til hukommelsen, bliver processen afbrudt, og kernen laver en kopi af den relevante page. Herefter kan der tildeles en kopi til hver proces. Den store fordel ved denne metode er, at data kun bliver kopieret hvis det er nødvendigt.

4.3.4. Proces-ID

Alle processer har deres eget ID-nummer (pid) og er i en gruppe og en session. I Linux kan en proces være tilknyttet flere grupper.

Når en ny proces bliver genereret, får den et nyt pid-nummer, og fork() returnerer 0 til barn-processen og barn-processens pid til forælder-processen. Derved kan de to processer se, hvilken proces der er barn-proces, og hvilken der er forælder-proces.

For at kunne bestemme hvor en proces har adgang, har hver proces et bruger-ID (userid = uid) og et gruppe-ID (gid). Disse ID-numre har børne-processerne arvet efter deres forældre-processer. Når en adgangskontrol skal foretages, er det dog den effektive bruger-ID (euid) og gruppe-ID (egid) der bliver brugt. Generelt er uid = euid og gid = egid, undtagen for set-UID programmer.

I disse programmer bliver euid og egid sat til bruger-ID og gruppe-ID for ejeren af den kørbare fil. På denne måde er det muligt for superuseren at give almindelige brugere adgang til brug af systemadministrative programmer på en kontrolleret måde. Et set-UID program er et program hvor set-UID-bitten er sat. Af sikkerhedsårsager understøtter Linux kun set-UID på binære filer, ikke på shell scripts.