GLAVA 7. UPRAVLENIE PROCESSAMI
V predydushchej glave byl rassmotren kontekst processa i opisany algoritmy
dlya raboty s nim; v dannoj glave rech' pojdet ob ispol'zovanii i realizacii
sistemnyh funkcij, upravlyayushchih kontekstom processa. Sistemnaya funkciya fork
sozdaet novyj process, funkciya exit zavershaet vypolnenie processa, a wait
daet vozmozhnost' roditel'skomu processu sinhronizirovat' svoe prodolzhenie s
zaversheniem porozhdennogo processa. Ob asinhronnyh sobytiyah processy informi-
ruyutsya pri pomoshchi signalov. Poskol'ku yadro sinhroniziruet vypolnenie funkcij
exit i wait pri pomoshchi signalov, opisanie mehanizma signalov predvaryaet so-
boj rassmotrenie funkcij exit i wait. Sistemnaya funkciya exec daet processu
vozmozhnost' zapuskat' "novuyu" programmu, nakladyvaya ee adresnoe prostranstvo
na ispolnyaemyj obraz fajla. Sistemnaya funkciya brk pozvolyaet dinamicheski vy-
delyat' dopolnitel'nuyu pamyat'; temi zhe samymi sredstvami yadro dinamicheski na-
rashchivaet stek zadachi, vydelyaya v sluchae neobhodimosti dopolnitel'noe prost-
ranstvo. V zaklyuchitel'noj chasti glavy daetsya kratkoe opisanie osnovnyh grupp
operacij komandnogo processora shell i nachal'nogo processa init.
Na Risunke 7.1 pokazana vzaimosvyaz' mezhdu sistemnymi funkciyami, rassmat-
rivaemymi v dannoj glave, s odnoj storony, i algoritmami, opisannymi v pre-
dydushchej glave, s drugoj. Pochti vo vseh funkciyah ispol'zuyutsya algoritmy sleep
i wakeup, otsutstvuyushchie na risunke. Funkciya exec, krome togo, vzaimodejstvu-
et s algoritmami raboty s fajlovoj sistemoj, rech' o kotoryh shla v glavah 4 i
5.
+-----------------------------+---------------------+------------+
| Sistemnye funkcii, imeyushchie | Sistemnye funkcii, | Funkcii |
| yushchie delo s upravleniem pa- | svyazannye s sinhro- | smeshannogo |
| myat'yu | nizaciej | tipa |
+-------+-------+-------+-----+--+----+------+----+-+-----+------+
| fork | exec | brk | exit |wait|signal|kill|setrgrr|setuid|
+-------+-------+-------+--------+----+------+----+-------+------+
|dupreg |detach-|growreg| detach-| |
|attach-| reg | | reg | |
| reg |alloc- | | | |
| | reg | | | |
| |attach-| | | |
| | reg | | | |
| |growreg| | | |
| |loadreg| | | |
| |mapreg | | | |
+-------+-------+-------+--------+-------------------------------+
Risunok 7.1. Sistemnye funkcii upravleniya processom i ih
svyaz' s drugimi algoritmami
Edinstvennym sposobom sozdaniya pol'zovatelem novogo processa v operaci-
onnoj sisteme UNIX yavlyaetsya vypolnenie sistemnoj funkcii fork. Process, vy-
zyvayushchij funkciyu fork, nazyvaetsya roditel'skim (process-roditel'), vnov'
sozdavaemyj process nazyvaetsya porozhdennym (process-potomok). Sintaksis vy-
zova funkcii fork:
179
pid = fork();
V rezul'tate vypolneniya funkcii fork pol'zovatel'skij kontekst i togo, i
drugogo processov sovpadaet vo vsem, krome vozvrashchaemogo znacheniya peremennoj
pid. Dlya roditel'skogo processa v pid vozvrashchaetsya identifikator porozhdenno-
go processa, dlya porozhdennogo - pid imeet nulevoe znachenie. Nulevoj process,
voznikayushchij vnutri yadra pri zagruzke sistemy, yavlyaetsya edinstvennym proces-
som, ne sozdavaemym s pomoshch'yu funkcii fork.
V hode vypolneniya funkcii yadro proizvodit sleduyushchuyu posledovatel'nost'
dejstvij:
1. Otvodit mesto v tablice processov pod novyj process.
2. Prisvaivaet porozhdaemomu processu unikal'nyj kod identifikacii.
3. Delaet logicheskuyu kopiyu konteksta roditel'skogo processa. Poskol'ku te
ili inye sostavlyayushchie processa, takie kak oblast' komand, mogut razde-
lyat'sya drugimi processami, yadro mozhet inogda vmesto kopirovaniya oblasti
v novyj fizicheskij uchastok pamyati prosto uvelichit' znachenie schetchika
ssylok na oblast'.
4. Uvelichivaet znacheniya schetchika chisla fajlov, svyazannyh s processom, kak v
tablice fajlov, tak i v tablice indeksov.
5. Vozvrashchaet roditel'skomu processu kod identifikacii porozhdennogo proces-
sa, a porozhdennomu processu - nulevoe znachenie.
Realizaciyu sistemnoj funkcii fork, pozhaluj, nel'zya nazvat' trivial'noj,
tak kak porozhdennyj process nachinaet svoe vypolnenie, voznikaya kak by iz
vozduha. Algoritm realizacii funkcii dlya sistem s zameshcheniem stranic po zap-
rosu i dlya sistem s podkachkoj processov imeet lish' neznachitel'nye razlichiya;
vse izlozhennoe nizhe v otnoshenii etogo algoritma kasaetsya v pervuyu ochered'
tradicionnyh sistem s podkachkoj processov, no s nepremennym akcentirovaniem
vnimaniya na teh momentah, kotorye v sistemah s zameshcheniem stranic po zaprosu
realizuyutsya inache. Krome togo, konechno, predpolagaetsya, chto v sisteme imeet-
sya svobodnaya operativnaya pamyat', dostatochnaya dlya razmeshcheniya porozhdennogo
processa. V glave 9 budet otdel'no rassmotren sluchaj, kogda dlya porozhdennogo
processa ne hvataet pamyati, i tam zhe budut dany raz®yasneniya otnositel'no re-
alizacii algoritma fork v sistemah s zameshcheniem stranic.
Na Risunke 7.2 priveden algoritm sozdaniya processa. Snachala yadro dolzhno
udostoverit'sya v tom, chto dlya uspeshnogo vypolneniya algoritma fork est' vse
neobhodimye resursy. V sisteme s podkachkoj processov dlya razmeshcheniya porozhda-
emogo processa trebuetsya mesto libo v pamyati, libo na diske; v sisteme s za-
meshcheniem stranic sleduet vydelit' pamyat' dlya vspomogatel'nyh tablic (v chast-
nosti, tablic stranic). Esli svobodnyh resursov net, algoritm fork zaversha-
etsya neudachno. YAdro ishchet mesto v tablice processov dlya konstruirovaniya kon-
teksta porozhdaemogo processa i proveryaet, ne prevysil li pol'zovatel', vy-
polnyayushchij fork, ogranichenie na maksimal'no-dopustimoe kolichestvo parallel'no
zapushchennyh processov. YAdro takzhe podbiraet dlya novogo processa unikal'nyj
identifikator, znachenie kotorogo prevyshaet na edinicu maksimal'nyj iz sushches-
tvuyushchih identifikatorov. Esli predlagaemyj identifikator uzhe prisvoen drugo-
mu processu, yadro beret identifikator, sleduyushchij po poryadku. Kak tol'ko bu-
det dostignuto maksimal'no-dopustimoe znachenie, otschet identifikatorov opyat'
nachnetsya s 0. Poskol'ku bol'shinstvo processov imeet korotkoe vremya zhizni,
pri perehode k nachalu otscheta znachitel'naya chast' identifikatorov okazyvaetsya
svobodnoj.
Na kolichestvo odnovremenno vypolnyayushchihsya processov nakladyvaetsya ograni-
chenie (konfiguriruemoe), otsyuda ni odin iz pol'zovatelej ne mozhet zanimat' v
tablice processov slishkom mnogo mesta, meshaya tem samym drugim pol'zovatelyam
sozdavat' novye processy. Krome togo, prostym pol'zovatelyam ne razreshaetsya
sozdavat' process, zanimayushchij poslednee svobodnoe mesto v tablice processov,
v protivnom sluchae sistema zashla by v tupik. Drugimi slovami, poskol'ku v
tablice processov net svobodnogo mesta, to yadro ne mozhet garantirovat', chto
vse sushchestvuyushchie processy zavershatsya estestvennym obrazom, poetomu novye
180
+------------------------------------------------------------+
| algoritm fork |
| vhodnaya informaciya: otsutstvuet |
| vyhodnaya informaciya: dlya roditel'skogo processa - identifi-|
| kator (PID) porozhdennogo processa |
| dlya porozhdennogo processa - 0 |
| { |
| proverit' dostupnost' resursov yadra; |
| poluchit' svobodnoe mesto v tablice processov i unikal'- |
| nyj kod identifikacii (PID); |
| proverit', ne zapustil li pol'zovatel' slishkom mnogo |
| processov; |
| sdelat' pometku o tom, chto porozhdaemyj process nahoditsya|
| v sostoyanii "sozdaniya"; |
| skopirovat' informaciyu v tablice processov iz zapisi, |
| sootvetstvuyushchej roditel'skomu processu, v zapis', soot-|
| vetstvuyushchuyu porozhdennomu processu; |
| uvelichit' znacheniya schetchikov ssylok na tekushchij katalog i|
| na kornevoj katalog (esli on byl izmenen); |
| uvelichit' znachenie schetchika otkrytij fajla v tablice |
| fajlov; |
| sdelat' kopiyu konteksta roditel'skogo processa (adresnoe|
| prostranstvo, komandy, dannye, stek) v pamyati; |
| pomestit' v stek fiktivnyj uroven' sistemnogo konteksta |
| nad urovnem sistemnogo konteksta, sootvetstvuyushchim po- |
| rozhdennomu processu; |
| fiktivnyj kontekstnyj uroven' soderzhit informaciyu, |
| neobhodimuyu porozhdennomu processu dlya togo, chtoby |
| znat' vse o sebe i buduchi vybrannym dlya ispolneniya |
| zapuskat'sya s etogo mesta; |
| esli (v dannyj moment vypolnyaetsya roditel'skij process) |
| { |
| perevesti porozhdennyj process v sostoyanie "gotovnosti|
| k vypolneniyu"; |
| vozvratit' (identifikator porozhdennogo processa); |
| /* iz sistemy pol'zovatelyu */ |
| } |
| v protivnom sluchae /* vypolnyaetsya porozhdennyj |
| process */ |
| { |
| zapisat' nachal'nye znacheniya v polya sinhronizacii ad- |
| resnogo prostranstva processa; |
| vozvratit' (0); /* pol'zovatelyu */ |
| } |
| } |
+------------------------------------------------------------+
Risunok 7.2. Algoritm fork
processy sozdavat'sya ne budut. S drugoj storony, superpol'zovatelyu nuzhno
dat' vozmozhnost' ispolnyat' stol'ko processov, skol'ko emu potrebuetsya, ko-
nechno, uchityvaya razmer tablicy processov, pri etom process, ispolnyaemyj su-
perpol'zovatelem, mozhet zanyat' v tablice i poslednee svobodnoe mesto. Pred-
polagaetsya, chto superpol'zovatel' mozhet pribegat' k reshitel'nym meram i za-
puskat' process, pobuzhdayushchij ostal'nye processy k zaversheniyu, esli eto vyzy-
vaetsya neobhodimost'yu (sm. razdel 7.2.3, gde govoritsya o sistemnoj funkcii
kill).
Zatem yadro prisvaivaet nachal'nye znacheniya razlichnym polyam zapisi tablicy
181
processov, sootvetstvuyushchej porozhdennomu processu, kopiruya v nih znacheniya po-
lej iz zapisi roditel'skogo processa. Naprimer, porozhdennyj process "nasle-
duet" u roditel'skogo processa kody identifikacii pol'zovatelya (real'nyj i
tot, pod kotorym ispolnyaetsya process), gruppu processov, upravlyaemuyu rodi-
tel'skim processom, a takzhe znachenie, zadannoe roditel'skim processom v fun-
kcii nice i ispol'zuemoe pri vychislenii prioriteta planirovaniya. V sleduyushchih
razdelah my pogovorim o naznachenii etih polej. YAdro peredaet znachenie polya
identifikatora roditel'skogo processa v zapis' porozhdennogo, vklyuchaya posled-
nij v drevovidnuyu strukturu processov, i prisvaivaet nachal'nye znacheniya raz-
lichnym parametram planirovaniya, takim kak prioritet planirovaniya, ispol'zo-
vanie resursov central'nogo processora i drugie znacheniya polej sinhroniza-
cii. Nachal'nym sostoyaniem processa yavlyaetsya sostoyanie "sozdaniya" (sm. Risu-
nok 6.1).
Posle togo yadro ustanavlivaet znacheniya schetchikov ssylok na fajly, s ko-
torymi avtomaticheski svyazyvaetsya porozhdaemyj process. Vo-pervyh, porozhdennyj
process razmeshchaetsya v tekushchem kataloge roditel'skogo processa. CHislo proces-
sov, obrashchayushchihsya v dannyj moment k katalogu, uvelichivaetsya na 1 i, sootvet-
stvenno, uvelichivaetsya znachenie schetchika ssylok na ego indeks. Vo-vtoryh,
esli roditel'skij process ili odin iz ego predkov uzhe vypolnyal smenu korne-
vogo kataloga s pomoshch'yu funkcii chroot, porozhdennyj process nasleduet i no-
vyj koren' s sootvetstvuyushchim uvelicheniem znacheniya schetchika ssylok na indeks
kornya. Nakonec, yadro prosmatrivaet tablicu pol'zovatel'skih deskriptorov dlya
roditel'skogo processa v poiskah otkrytyh fajlov, izvestnyh processu, i uve-
lichivaet znachenie schetchika ssylok, associirovannogo s kazhdym iz otkrytyh
fajlov, v global'noj tablice fajlov. Porozhdennyj process ne prosto nasleduet
prava dostupa k otkrytym fajlam, no i razdelyaet dostup k fajlam s roditel'-
skim processom, tak kak oba processa obrashchayutsya v tablice fajlov k odnim i
tem zhe zapisyam. Dejstvie fork v otnoshenii otkrytyh fajlov podobno dejstviyu
algoritma dup: novaya zapis' v tablice pol'zovatel'skih deskriptorov fajla
ukazyvaet na zapis' v global'noj tablice fajlov, sootvetstvuyushchuyu otkrytomu
fajlu. Dlya dup, odnako, zapisi v tablice pol'zovatel'skih deskriptorov fajla
otnosyatsya k odnomu processu; dlya fork - k raznym processam.
Posle zaversheniya vseh etih dejstvij yadro gotovo k sozdaniyu dlya porozhden-
nogo processa pol'zovatel'skogo konteksta. YAdro vydelyaet pamyat' dlya adresno-
go prostranstva processa, ego oblastej i tablic stranic, sozdaet s pomoshch'yu
algoritma dupreg kopii vseh oblastej roditel'skogo processa i prisoedinyaet s
pomoshch'yu algoritma attachreg kazhduyu oblast' k porozhdennomu processu. V siste-
me s podkachkoj processov yadro kopiruet soderzhimoe oblastej, ne yavlyayushchihsya
oblastyami razdelyaemoj pamyati, v novuyu zonu operativnoj pamyati. Vspomnim iz
razdela 6.2.4 o tom, chto v prostranstve processa hranitsya ukazatel' na soot-
vetstvuyushchuyu zapis' v tablice processov. Za isklyucheniem etogo polya, vo vsem
ostal'nom soderzhimoe adresnogo prostranstva porozhdennogo processa v nachale
sovpadaet s soderzhimym prostranstva roditel'skogo processa, no mozhet rasho-
dit'sya posle zaversheniya algoritma fork. Roditel'skij process, naprimer, pos-
le vypolneniya fork mozhet otkryt' novyj fajl, k kotoromu porozhdennyj process
uzhe ne poluchit dostup avtomaticheski.
Itak, yadro zavershilo sozdanie staticheskoj chasti konteksta porozhdennogo
processa; teper' ono pristupaet k sozdaniyu dinamicheskoj chasti. YAdro kopiruet
v nee pervyj kontekstnyj uroven' roditel'skogo processa, vklyuchayushchij v sebya
sohranennyj registrovyj kontekst zadachi i stek yadra v moment vyzova funkcii
fork. Esli v dannoj realizacii stek yadra yavlyaetsya chast'yu prostranstva pro-
cessa, yadro v moment sozdaniya prostranstva porozhdennogo processa avtomati-
cheski sozdaet i sistemnyj stek dlya nego. V protivnom sluchae roditel'skomu
processu pridetsya skopirovat' v prostranstvo pamyati, associirovannoe s po-
rozhdennym processom, svoj sistemnyj stek. V lyubom sluchae stek yadra dlya po-
rozhdennogo processa sovpadaet s sistemnym stekom ego roditelya. Dalee yadro
sozdaet dlya porozhdennogo processa fiktivnyj kontekstnyj uroven' (2), v koto-
rom soderzhitsya sohranennyj registrovyj kontekst iz pervogo kontekstnogo
urovnya. Znacheniya schetchika komand (registr PC) i drugih registrov, sohranyae-
182
mye v registrovom kontekste, ustanavlivayutsya takim obrazom, chtoby s ih po-
moshch'yu mozhno bylo "vosstanavlivat'" kontekst porozhdennogo processa, pust' da-
zhe poslednij eshche ni razu ne ispolnyalsya, i chtoby etot process pri zapuske
vsegda pomnil o tom, chto on porozhdennyj. Naprimer, esli programma yadra pro-
veryaet znachenie, hranyashcheesya v registre 0, dlya togo, chtoby vyyasnit', yavlyaetsya
li dannyj process roditel'skim ili zhe porozhdennym, to eto znachenie perepisy-
vaetsya v registrovyj kontekst porozhdennogo processa, sohranennyj v sostave
pervogo urovnya. Mehanizm sohraneniya ispol'zuetsya tot zhe, chto i pri pereklyu-
chenii konteksta (sm. predydushchuyu glavu).
Roditel'skij process
+---------------------------------------------+ Tablica
| +---------+ CHastnaya Adresnoe prostran- | fajlov
| | Oblast' | tablica stvo processa | +---------+
| | dannyh | oblastej +------------------+| | - |
| +---------+ processa | Otkrytye fajly --||-- + | - |
| | +------+ | || - | - |
| -- - - + | + +| Tekushchij katalog -||+ | +---------+
| - +------+ -| ||- -- -| |
| +---------+ + + | || Izmenennyj koren'||| | | |
| | Stek | +------+ -+------------------+|- - +---------+
| | zadachi + - + | |+------------------+|| | | - |
| +---------+ +------+ -| - ||- - | - |
| || - ||| | | - |
| -| - ||- - +---------+
| -- - - - - - - - -+| Stek yadra ||| + - + |
| | +------------------+|- - | |
+---------------------------------------------+| | +---------+
- - - | - |
+----+----+ | | | - |
|Razdelyae-| - - | - |
| maya | | | +---------+
| oblast' | - -- -| |
| komand | | | | |
+----+----+ - - +---------+
- | | +---------+
+ - - - - - - - - + - -
+---------------------------------------------++ -|+ Tablica
| +---------+ CHastnaya | Adresnoe prostran- | -- fajlov
| | Oblast' | tablica - stvo processa | || +---------+
| | dannyh | oblastej |+------------------+| -- | - |
| +---------+ processa -| Otkrytye fajly --||-- +| | - |
| | +------+ || || - | - |
| -- - - + | +--| Tekushchij katalog -||+ | +---------+
| - +------+ | ||- -- + |
| +---------+ + + | | Izmenennyj koren'||+ - - -| |
| | Stek | +------+ +------------------+| +---------+
| | zadachi + - + | +------------------+| | - |
| +---------+ +------+ | - || | - |
| | - || +---------+
| | Stek yadra || | |
| +------------------+| | |
+---------------------------------------------+ +---------+
Porozhdennyj process | - |
| - |
+---------+
Risunok 7.3. Sozdanie konteksta novogo processa pri vypolne-
nii funkcii fork
183
Esli kontekst porozhdennogo processa gotov, roditel'skij process zaversha-
et svoyu rol' v vypolnenii algoritma fork, perevodya porozhdennyj process v
sostoyanie "gotovnosti k zapusku, nahodyas' v pamyati" i vozvrashchaya pol'zovatelyu
ego identifikator. Zatem, ispol'zuya obychnyj algoritm planirovaniya, yadro vy-
biraet porozhdennyj process dlya ispolneniya i tot "doigryvaet" svoyu rol' v al-
goritme fork. Kontekst porozhdennogo processa byl zadan roditel'skim proces-
som; s tochki zreniya yadra kazhetsya, chto porozhdennyj process vozobnovlyaetsya
posle priostanova v ozhidanii resursa. Porozhdennyj process pri vypolnenii
funkcii fork realizuet tu chast' programmy, na kotoruyu ukazyvaet schetchik ko-
mand, vosstanavlivaemyj yadrom iz sohranennogo na urovne 2 registrovogo kon-
teksta, i po vyhode iz funkcii vozvrashchaet nulevoe znachenie.
Na Risunke 7.3 predstavlena logicheskaya shema vzaimodejstviya roditel'sko-
go i porozhdennogo processov s drugimi strukturami dannyh yadra srazu posle
zaversheniya sistemnoj funkcii fork. Itak, oba processa sovmestno pol'zuyutsya
fajlami, kotorye byli otkryty roditel'skim processom k momentu ispolneniya
funkcii fork, pri etom znachenie schetchika ssylok na kazhdyj iz etih fajlov v
tablice fajlov na edinicu bol'she, chem do vyzova funkcii. Porozhdennyj process
imeet te zhe, chto i roditel'skij process, tekushchij i kornevoj katalogi, znache-
nie zhe schetchika ssylok na indeks kazhdogo iz etih katalogov tak zhe stanovitsya
na edinicu bol'she, chem do vyzova funkcii. Soderzhimoe oblastej komand, dannyh
i steka (zadachi) u oboih processov sovpadaet; po tipu oblasti i versii sis-
temnoj realizacii mozhno ustanovit', mogut li processy razdelyat' samu oblast'
komand v fizicheskih adresah.
Rassmotrim privedennuyu na Risunke 7.4 programmu, kotoraya predstavlyaet
soboj primer razdeleniya dostupa k fajlu pri ispolnenii funkcii fork. Pol'zo-
vatelyu sleduet peredavat' etoj programme
dva parametra - imya sushchestvuyushchego fajla i imya sozdavaemogo fajla. Process
otkryvaet sushchestvuyushchij fajl, sozdaet novyj fajl i - pri uslovii otsutstviya
oshibok - porozhdaet novyj process. Vnutri programmy yadro delaet kopiyu kontek-
sta roditel'skogo processa dlya porozhdennogo, pri etom roditel'skij process
ispolnyaetsya v odnom adresnom prostranstve, a porozhdennyj - v drugom. Kazhdyj
iz processov mozhet rabotat' so svoimi sobstvennymi kopiyami global'nyh pere-
mennyh fdrd, fdwt i c, a takzhe so svoimi sobstvennymi kopiyami stekovyh pere-
mennyh argc i argv, no ni odin iz nih ne mozhet obrashchat'sya k peremennym dru-
gogo processa. Tem ne menee, pri vypolnenii funkcii fork yadro delaet kopiyu
adresnogo prostranstva pervogo processa dlya vtorogo, i porozhdennyj process,
takim obrazom, nasleduet dostup k fajlam roditel'skogo (to est' k fajlam, im
ranee otkrytym i sozdannym) s pravom ispol'zovaniya teh zhe samyh desk-
riptorov.
Roditel'skij i porozhdennyj processy nezavisimo drug ot druga, konechno,
vyzyvayut funkciyu rdwrt i v cikle schityvayut po odnomu bajtu informaciyu iz is-
hodnogo fajla i perepisyvayut ee v fajl vyvoda. Funkciya rdwrt vozvrashchaet up-
ravlenie, kogda pri schityvanii obnaruzhivaetsya konec fajla. YAdro pered tem
uzhe uvelichilo znacheniya schetchikov ssylok na ishodnyj i rezul'tiruyushchij fajly v
tablice fajlov, i deskriptory, ispol'zuemye v oboih processah, adresuyut k
odnim i tem zhe strokam v tablice. Takim obrazom, deskriptory fdrd v tom i v
drugom processah ukazyvayut na zapis' v tablice fajlov, sootvetstvuyushchuyu is-
hodnomu fajlu, a deskriptory, podstavlyaemye v kachestve fdwt, - na zapis',
sootvetstvuyushchuyu rezul'tiruyushchemu fajlu (fajlu vyvoda). Poetomu oba processa
nikogda ne obratyatsya vmeste na chtenie ili zapis' k odnomu i tomu zhe adresu,
vychislyaemomu s pomoshch'yu smeshcheniya vnutri fajla, poskol'ku yadro smeshchaet vnutri-
fajlovye ukazateli posle kazhdoj operacii chteniya ili zapisi. Nesmotrya na to,
chto, kazalos' by, iz-za togo, chto processy raspredelyayut mezhdu soboj rabochuyu
nagruzku, oni kopiruyut ishodnyj fajl v dva raza bystree, soderzhimoe rezul'-
tiruyushchego fajla zavisit ot ocherednosti, v kotoroj yadro zapuskaet processy.
Esli yadro zapuskaet processy tak, chto oni ispolnyayut sistemnye funkcii pope-
remenno (chereduya i sparennye vyzovy funkcij read-write), soderzhimoe rezul'-
184
+------------------------------------------------------------+
| #include |
| int fdrd, fdwt; |
| char c; |
| |
| main(argc, argv) |
| int argc; |
| char *argv[]; |
| { |
| if (argc != 3) |
| exit(1); |
| if ((fdrd = open(argv[1],O_RDONLY)) == -1) |
| exit(1); |
| if ((fdwt = creat(argv[2],0666)) == -1) |
| exit(1); |
| |
| fork(); |
| /* oba processa ispolnyayut odnu i tu zhe programmu */ |
| rdwrt(); |
| exit(0); |
| } |
| |
| rdwrt(); |
| { |
| for(;;) |
| { |
| if (read(fdrd,&c,1) != 1) |
| return; |
| write(fdwt,&c,1); |
| } |
| } |
+------------------------------------------------------------+
Risunok 7.4. Programma, v kotoroj roditel'skij i porozhdennyj
processy razdelyayut dostup k fajlu
tiruyushchego fajla budet sovpadat' s soderzhimym ishodnogo fajla. Rassmotrim,
odnako, sluchaj, kogda processy sobirayutsya schitat' iz ishodnogo fajla posle-
dovatel'nost' iz dvuh simvolov "ab". Predpolozhim, chto roditel'skij process
schital simvol "a", no ne uspel zapisat' ego, tak kak yadro pereklyuchilos' na
kontekst porozhdennogo processa. Esli porozhdennyj process schityvaet simvol
"b" i zapisyvaet ego v rezul'tiruyushchij fajl do vozobnovleniya roditel'skogo
processa, stroka "ab" v rezul'tiruyushchem fajle budet imet' vid "ba". YAdro ne
garantiruet soglasovanie tempov vypolneniya processov.
Teper' perejdem k programme, predstavlennoj na Risunke 7.5, v kotoroj
process-potomok nasleduet ot svoego roditelya fajlovye deskriptory 0 i 1 (so-
otvetstvuyushchie standartnomu vvodu i standartnomu vyvodu). Pri kazhdom vypolne-
nii sistemnoj funkcii pipe proizvoditsya naznachenie dvuh fajlovyh deskripto-
rov v massivah to_par i to_chil. Process vyzyvaet funkciyu fork i delaet ko-
piyu svoego konteksta: kazhdyj iz processov imeet dostup tol'ko k svoim sobst-
vennym dannym, tak zhe kak i v predydushchem primere. Roditel'skij process zak-
ryvaet fajl standartnogo vyvoda (deskriptor 1) i dubliruet deskriptor zapi-
si, vozvrashchaemyj v kanal to_chil. Poskol'ku pervoe svobodnoe mesto v tablice
deskriptorov roditel'skogo processa obrazovalos' v rezul'tate tol'ko chto vy-
polnennoj operacii zakrytiya (close) fajla vyvoda, yadro perepisyvaet tuda
deskriptor zapisi v kanal i etot deskriptor stanovitsya deskriptorom fajla
standartnogo vyvoda dlya to_chil. Te zhe samye dejstviya roditel'skij process
vypolnyaet v otnoshenii deskriptora fajla standartnogo vvoda, zamenyaya ego des-
185
kriptorom chteniya iz kanala to_par. I porozhdennyj process zakryvaet fajl
standartnogo vvoda (deskriptor 0) i tak zhe dubliruet deskriptor chteniya iz
kanala to_chil. Poskol'ku pervoe svobodnoe mesto v tablice deskriptorov faj-
lov prezhde bylo zanyato fajlom standartnogo vvoda, ego deskriptorom stanovit-
sya deskriptor chteniya iz kanala to_chil. Analogichnye dejstviya vypolnyayutsya i v
otnoshenii deskriptora fajla standartnogo vyvoda, zamenyaya ego deskriptorom
zapisi v kanal to_par. I tot, i drugoj processy zakryvayut fajly, deskriptory
+------------------------------------------------------------+
| #include |
| char string[] = "hello world"; |
| main() |
| { |
| int count,i; |
| int to_par[2],to_chil[2]; /* dlya kanalov roditelya i |
| potomka */ |
| char buf[256]; |
| pipe(to_par); |
| pipe(to_chil); |
| if (fork() == 0) |
| { |
| /* vypolnenie porozhdennogo processa */ |
| close(0); /* zakrytie prezhnego standartnogo vvoda */ |
| dup(to_chil[0]); /* dublirovanie deskriptora chteniya |
| iz kanala v poziciyu standartnogo |
| vvoda */ |
| close(1); /* zakrytie prezhnego standartnogo vyvoda */|
| dup(to_par[0]); /* dublirovanie deskriptora zapisi |
| v kanal v poziciyu standartnogo |
| vyvoda */ |
| close(to_par[1]); /* zakrytie nenuzhnyh deskriptorov |
| close(to_chil[0]); kanala */ |
| close(to_par[0]); |
| close(to_chil[1]); |
| for (;;) |
| { |
| if ((count = read(0,buf,sizeof(buf))) == 0) |
| exit(); |
| write(1,buf,count); |
| } |
| } |
| /* vypolnenie roditel'skogo processa */ |
| close(1); /* perenastrojka standartnogo vvoda-vyvoda */|
| dup(to_chil[1]); |
| close(0); |
| dup(to_par[0]); |
| close(to_chil[1]); |
| close(to_par[0]); |
| close(to_chil[0]); |
| close(to_par[1]); |
| for (i = 0; i < 15; i++) |
| { |
| write(1,string,strlen(string)); |
| read(0,buf,sizeof(buf)); |
| } |
| } |
+------------------------------------------------------------+
Risunok 7.5. Ispol'zovanie funkcij pipe, dup i fork
186
kotoryh vozvratila funkciya pipe - horoshaya tradiciya, v chem nam eshche predstoit
ubedit'sya. V rezul'tate, kogda roditel'skij process perepisyvaet dannye v
standartnyj vyvod, zapis' vedetsya v kanal to_chil i dannye postupayut k po-
rozhdennomu processu, kotoryj schityvaet ih cherez svoj standartnyj vvod. Kogda
zhe porozhdennyj process pishet dannye v standartnyj vyvod, zapis' vedetsya v
kanal to_par i dannye postupayut k roditel'skomu processu, schityvayushchemu ih
cherez svoj standartnyj vvod. Tak cherez dva kanala oba processa obmenivayutsya
soobshcheniyami.
Rezul'taty etoj programmy ne zavisyat ot togo, v kakoj ocherednosti pro-
cessy vypolnyayut svoi dejstviya. Takim obrazom, net nikakoj raznicy, vozvrashcha-
etsya li upravlenie roditel'skomu processu iz funkcii fork ran'she ili pozzhe,
chem porozhdennomu processu. I tak zhe bezrazlichen poryadok, v kotorom processy
vyzyvayut sistemnye funkcii pered tem, kak vojti v svoj sobstvennyj cikl, ibo
oni ispol'zuyut identichnye struktury yadra. Esli process-potomok ispolnyaet
funkciyu read ran'she, chem ego roditel' vypolnit write, on budet priostanovlen
do teh por, poka roditel'skij process ne proizvedet zapis' v kanal i tem sa-
mym ne vozobnovit vypolnenie potomka. Esli roditel'skij process zapisyvaet v
kanal do togo, kak ego potomok pristupit k chteniyu iz kanala, pervyj process
ne smozhet v svoyu ochered' schitat' dannye iz standartnogo vvoda, poka vtoroj
process ne prochitaet vse iz svoego standartnogo vvoda i ne proizvedet zapis'
dannyh v standartnyj vyvod. S etogo mesta poryadok raboty zhestko fiksirovan:
kazhdyj process zavershaet vypolnenie funkcij read i write i ne mozhet vypol-
nit' sleduyushchuyu operaciyu read do teh por, poka drugoj process ne vypolnit pa-
ru read-write. Roditel'-
skij process posle 15 iteracij zavershaet rabotu; porozhdennyj process natal-
kivaetsya na konec fajla ("end-of-file"), poskol'ku kanal ne svyazan bol'she ni
s odnim iz zapisyvayushchih processov, i tozhe zavershaet rabotu. Esli porozhdennyj
process popytaetsya proizvesti zapis' v kanal posle zaversheniya roditel'skogo
processa, on poluchit signal o tom, chto kanal ne svyazan ni s odnim iz proces-
sov chteniya.
My upomyanuli o tom, chto horoshej tradiciej v programmirovanii yavlyaetsya
zakrytie nenuzhnyh fajlovyh deskriptorov. V pol'zu etogo govoryat tri dovoda.
Vo-pervyh, deskriptory fajlov postoyanno nahodyatsya pod kontrolem sistemy, ko-
toraya nakladyvaet ogranichenie na ih kolichestvo. Vo-vtoryh, vo vremya ispolne-
niya porozhdennogo processa prisvoenie deskriptorov v novom kontekste sohranya-
etsya (v chem my eshche ubedimsya). Zakrytie nenuzhnyh fajlov do zapuska processa
otkryvaet pered programmami vozmozhnost' ispolneniya v "steril'nyh" usloviyah,
svobodnyh ot lyubyh neozhidannostej, imeya otkrytymi tol'ko fajly standartnogo
vvoda-vyvoda i oshibok. Nakonec, funkciya read dlya kanala vozvrashchaet priznak
konca fajla tol'ko v tom sluchae, esli kanal ne byl otkryt dlya zapisi ni od-
nim iz processov. Esli schityvayushchij process budet derzhat' deskriptor zapisi v
kanal otkrytym, on nikogda ne uznaet, zakryl li zapisyvayushchij process rabotu
na svoem konce kanala ili net. Vysheprivedennaya programma ne rabotala by nad-
lezhashchim obrazom, esli by pered vhodom v cikl vypolneniya processom-potomkom
ne byli zakryty deskriptory zapisi v kanal.
7.2 SIGNALY
Signaly soobshchayut processam o vozniknovenii asinhronnyh sobytij. Posylka
signalov proizvoditsya processami - drug drugu, s pomoshch'yu funkcii kill, - ili
yadrom. V versii V (vtoraya redakciya) sistemy UNIX sushchestvuyut 19 razlichnyh
signalov, kotorye mozhno klassificirovat' sleduyushchim obrazom:
* Signaly, posylaemye v sluchae zaversheniya vypolneniya processa, to est'
togda, kogda process vypolnyaet funkciyu exit ili funkciyu signal s para-
metrom death of child (gibel' potomka);
* Signaly, posylaemye v sluchae vozniknoveniya vyzyvaemyh processom osobyh
situacij, takih kak obrashchenie k adresu, nahodyashchemusya za predelami virtu-
187
al'nogo adresnogo prostranstva processa, ili popytka zapisi v oblast'
pamyati, otkrytuyu tol'ko dlya chteniya (naprimer, tekst programmy), ili po-
pytka ispolneniya privilegirovannoj komandy, a takzhe razlichnye apparatnye
oshibki;
* Signaly, posylaemye vo vremya vypolneniya sistemnoj funkcii pri voznikno-
venii neispravimyh oshibok, takih kak ischerpanie sistemnyh resursov vo
vremya vypolneniya funkcii exec posle osvobozhdeniya ishodnogo adresnogo
prostranstva (sm. razdel 7.5);
* Signaly, prichinoj kotoryh sluzhit vozniknovenie vo vremya vypolneniya sis-
temnoj funkcii sovershenno neozhidannyh oshibok, takih kak obrashchenie k ne-
sushchestvuyushchej sistemnoj funkcii (process peredal nomer sistemnoj funkcii,
kotoryj ne sootvetstvuet ni odnoj iz imeyushchihsya funkcij), zapis' v kanal,
ne svyazannyj ni s odnim iz processov chteniya, a takzhe ispol'zovanie nedo-
pustimogo znacheniya v parametre "reference" sistemnoj funkcii lseek. Ka-
zalos' by, bolee logichno v takih sluchayah vmesto posylki signala vozvra-
shchat' kod oshibki, odnako s prakticheskoj tochki zreniya dlya avarijnogo za-
versheniya processov, v kotoryh voznikayut podobnye oshibki, bolee predpoch-
titel'nym yavlyaetsya imenno ispol'zovanie signalov (*);
* Signaly, posylaemye processu, kotoryj vypolnyaetsya v rezhime zadachi, nap-
rimer, signal trevogi (alarm), posylaemyj po istechenii opredelennogo pe-
rioda vremeni, ili proizvol'nye signaly, kotorymi obmenivayutsya processy,
ispol'zuyushchie funkciyu kill;
* Signaly, svyazannye s terminal'nym vzaimodejstviem, naprimer, s "zavisa-
niem" terminala (kogda signal-nositel' na terminal'noj linii prekrashchaet-
sya po lyuboj prichine) ili s nazhatiem klavish "break" i "delete" na klavia-
ture terminala;
* Signaly, s pomoshch'yu kotoryh proizvoditsya trassirovka vypolneniya processa.
Usloviya primeneniya signalov kazhdoj gruppy budut rassmotreny v etoj i
posleduyushchih glavah.
Koncepciya signalov imeet neskol'ko aspektov, svyazannyh s tem, kakim ob-
razom yadro posylaet signal processu, kakim obrazom process obrabatyvaet sig-
nal i upravlyaet reakciej na nego. Posylaya signal processu, yadro ustanavliva-
et v edinicu razryad v pole signala zapisi tablicy processov, sootvetstvuyushchij
tipu signala. Esli process nahoditsya v sostoyanii priostanova s prioritetom,
dopuskayushchim preryvaniya, yadro vozobnovit ego vypolnenie. Na etom rol' otpra-
vitelya signala (processa ili yadra) ischerpyvaetsya. Process mozhet zapominat'
signaly razlichnyh tipov, no ne imeet vozmozhnosti zapominat' kolichestvo polu-
chaemyh signalov kazhdogo tipa. Naprimer, esli process poluchaet signal o "za-
visanii" ili ob udalenii processa iz sistemy, on ustanavlivaet v edinicu so-
otvetstvuyushchie razryady v pole signalov tablicy processov, no ne mozhet ska-
zat', skol'ko ekzemplyarov signala kazhdogo tipa on poluchil.
YAdro proveryaet poluchenie signala, kogda process sobiraetsya perejti iz
rezhima yadra v rezhim zadachi, a takzhe kogda on perehodit v sostoyanie priosta-
nova ili vyhodit iz etogo sostoyaniya s dostatochno nizkim prioritetom planiro-
vaniya (sm. Risunok 7.6). YAdro obrabatyvaet signaly tol'ko togda, kogda pro-
cess vozvrashchaetsya iz rezhima yadra v rezhim zadachi. Takim obrazom, signal ne
okazyvaet nemedlennogo vozdejstviya na povedenie processa, ispolnyaemogo v re-
zhime yadra. Esli process ispolnyaetsya v rezhime zadachi, a yadro tem vremenem ob-
rabatyvaet preryvanie, posluzhivshee povodom dlya posylki processu signala, yad-
ro raspoznaet i obrabotaet signal po vyhode iz preryvaniya. Takim obrazom,
process ne budet ispolnyat'sya v rezhime zadachi, poka kakie-to signaly ostayutsya
neobrabotannymi.
Na Risunke 7.7 predstavlen algoritm, s pomoshch'yu kotorogo yadro opredelyaet,
---------------------------------------
(*) Ispol'zovanie signalov v nekotoryh obstoyatel'stvah pozvolyaet obnaruzhit'
oshibki pri vypolnenii programm, ne proveryayushchih kod zaversheniya vyzyvaemyh
sistemnyh funkcij (soobshchil D.Richi).
188
Vypolnyaetsya v
rezhime zadachi
+-------+
| | Proverka
| 1 | i
Vyzov funk- | | + - obrabotka
cii, prery- ++------+ -+ - signalov
vanie | ^ ^- -+-
Prery- +-----+ +-------+ |- -|- - +
vanie, | | | +-------+ +---+ Vozvrat v
vozvrat| | | | Vozvrat | rezhim zadachi
iz pre-| | | | |
ryva-| v v | Vypolnyaet- |
+-------+ niya | +------++sya v rezhi- ++------+
| | +-->| |me yadra | |
| 9 |<-----------+ 2 +------------>| 7 |
| | Vyhod | | Rezerviruet-| |
+-------+ ++------+ sya +-------+
Prekrashchenie | ^ - Zarezer-
sushchestvovaniya |- - -|- - - - - - - - + - virovan
| |- - - - - - - + + -- -+
+---------------+ +------+ -------- Proverka
| Priostanov Zapusk | - + - - - signalov
v | -
Pri-+-------+ +-+-----+ Gotov k
os- | | Vozobnovlenie | | zapusku
ta- | 4 +----------------------->| 3 | v pamyati
nov-| | | |
len +---+---+ ++------+
v pa- | | ^ ^
myati | | | | Dostatochno
| | | | pamyati
| | | +---+
| Vy- Vy- | | |
| gruzka gruzka | | | Sozdan
| | |Za- ++------+
| | |gruz-| | fork
| | |ka | 8 |<-----
| | | | |
| | | ++------+
| | | |
| | | | Nedosta-
| | | +---+ tochno
| | | | pamyati
| | | | (tol'ko sistema
| | | | podkachki)
v v | v
+-------+ +---+---+
| | Vozobnovlenie | |
| 6 +----------------------->| 5 |
| | | |
+-------+ +-------+
Priostanovlen, Gotov k zapusku,
vygruzhen vygruzhen
Risunok 7.6. Diagramma perehodov processa iz sostoyanie v sostoyanie s
ukazaniem momentov proverki i obrabotki signalov
189
poluchil li process signal ili net. Usloviya, v kotoryh formiruyutsya signaly
tipa "gibel' potomka", budut rassmotreny pozzhe. My takzhe uvidim, chto process
mozhet ignorirovat' otdel'nye signaly, esli vospol'zuetsya funkciej signal. V
algoritme issig yadro prosto gasit indikaciyu teh signalov, na kotorye process
ne zhelaet obrashchat' vnimanie, i privlekaet vnimanie processa ko vsem ostal'-
nym signalam.
+------------------------------------------------------------+
| algoritm issig /* proverka polucheniya signalov */ |
| vhodnaya informaciya: otsutstvuet |
| vyhodnaya informaciya: "istina", esli process poluchil signa- |
| ly, kotorye ego interesuyut |
| "lozh'" - v protivnom sluchae |
| { |
| vypolnit' poka (pole v zapisi tablicy processov, soder- |
| zhashchee indikaciyu o poluchenii signala, hranit nenulevoe |
| znachenie) |
| { |
| najti nomer signala, poslannogo processu; |
| esli (signal tipa "gibel' potomka") |
| { |
| esli (signaly dannogo tipa ignoriruyutsya) |
| osvobodit' zapisi tablicy processov, kotorye |
| sootvetstvuyut potomkam, prekrativshim sushchestvo-|
| vanie; |
| v protivnom sluchae esli (signaly dannogo tipa pri-|
| nimayutsya) |
| vozvratit' (istinu); |
| } |
| v protivnom sluchae esli (signal ne ignoriruetsya) |
| vozvratit' (istinu); |
| sbrosit' (pogasit') signal'nyj razryad, ustanovlennyj |
| v sootvetstvuyushchem pole tablicy processov, hranyashchem |
| indikaciyu polucheniya signala; |
| } |
| vozvratit' (lozh'); |
| } |
+------------------------------------------------------------+
Risunok 7.7. Algoritm opoznaniya signalov
YAdro obrabatyvaet signaly v kontekste togo processa, kotoryj poluchaet
ih, poetomu chtoby obrabotat' signaly, nuzhno zapustit' process. Sushchestvuet
tri sposoba obrabotki signalov: process zavershaetsya po poluchenii signala, ne
obrashchaet vnimanie na signal ili vypolnyaet osobuyu (pol'zovatel'skuyu) funkciyu
po ego poluchenii. Reakciej po umolchaniyu so storony processa, ispolnyaemogo v
rezhime yadra, yavlyaetsya vyzov funkcii exit, odnako s pomoshch'yu funkcii signal
process mozhet ukazat' drugie special'nye dejstviya, prinimaemye po poluchenii
teh ili inyh signalov.
Sintaksis vyzova sistemnoj funkcii signal:
oldfunction = signal(signum,function);
gde signum - nomer signala, pri poluchenii kotorogo budet vypolneno dejstvie,
svyazannoe s zapuskom pol'zovatel'skoj funkcii, function - adres funkcii,
oldfunction - vozvrashchaemoe funkciej znachenie. Vmesto adresa funkcii process
mozhet peredavat' vyzyvaemoj procedure signal chisla 1 i 0: esli function = 1,
process budet ignorirovat' vse posleduyushchie postupleniya signala s nomerom
190
signum (osobyj sluchaj, svyazannyj s ignorirovaniem signala "gibel' potomka",
rassmatrivaetsya v razdele 7.4), esli = 0 (znachenie po umolchaniyu), process po
poluchenii signala v rezhime yadra zavershaetsya. V prostranstve processa podder-
zhivaetsya massiv polej dlya obrabotki signalov, po odnomu polyu na kazhdyj opre-
delennyj v sisteme signal. V pole, sootvetstvuyushchem signalu s ukazannym nome-
rom, yadro sohranyaet adres pol'zovatel'skoj funkcii, vyzyvaemoj po poluchenii
signala processom. Sposob obrabotki signalov odnogo tipa ne vliyaet na obra-
botku signalov drugih tipov.
+------------------------------------------------------------+
| algoritm psig /* obrabotka signalov posle proverki ih |
| sushchestvovaniya */ |
| vhodnaya informaciya: otsutstvuet |
| vyhodnaya informaciya: otsutstvuet |
| { |
| vybrat' nomer signala iz zapisi tablicy processov; |
| ochistit' pole s nomerom signala; |
| esli (pol'zovatel' ranee vyzyval funkciyu signal, s po- |
| moshch'yu kotoroj sdelal ukazanie ignorirovat' signal dan- |
| nogo tipa) |
| vozvratit' upravlenie; |
| esli (pol'zovatel' ukazal funkciyu, kotoruyu nuzhno vypol- |
| nit' po poluchenii signala) |
| { |
| iz prostranstva processa vybrat' pol'zovatel'skij |
| virtual'nyj adres funkcii obrabotki signala; |
| /* sleduyushchij operator imeet nezhelatel'nye pobochnye |
| effekty */ |
| ochistit' pole v prostranstve processa, soderzhashchee |
| adres funkcii obrabotki signala; |
| vnesti izmeneniya v pol'zovatel'skij kontekst: |
| iskusstvenno sozdat' v steke zadachi zapis', imi- |
| tiruyushchuyu obrashchenie k funkcii obrabotki signala; |
| vnesti izmeneniya v sistemnyj kontekst: |
| zapisat' adres funkcii obrabotki signala v pole |
| schetchika komand, prinadlezhashchee sohranennomu re- |
| gistrovomu kontekstu zadachi; |
| vozvratit' upravlenie; |
| } |
| esli (signal trebuet dampirovaniya obraza processa v pa- |
| myati) |
| { |
| sozdat' v tekushchem kataloge fajl s imenem "core"; |
| perepisat' v fajl "core" soderzhimoe pol'zovatel'sko-|
| go konteksta; |
| } |
| nemedlenno zapustit' algoritm exit; |
| } |
+------------------------------------------------------------+
Risunok 7.8. Algoritm obrabotki signalov
Obrabatyvaya signal (Risunok 7.8), yadro opredelyaet tip signala i ochishchaet
(gasit) razryad v zapisi tablicy processov, sootvetstvuyushchij dannomu tipu sig-
nala i ustanovlennyj v moment polucheniya signala processom. Esli funkcii ob-
rabotki signala prisvoeno znachenie po umolchaniyu, yadro v otdel'nyh sluchayah
pered zaversheniem processa sbrasyvaet na vneshnij nositel' (dampiruet) obraz
processa v pamyati (sm. uprazhnenie 7.7). Dampirovanie udobno dlya programmis-
191
tov tem, chto pozvolyaet ustanovit' prichinu zaversheniya processa i posredstvom
etogo vesti otladku programm. YAdro dampiruet sostoyanie pamyati pri postuple-
nii signalov, kotorye soobshchayut o kakih-nibud' oshibkah v vypolnenii proces-
sov, kak naprimer, popytka ispolneniya zapreshchennoj komandy ili obrashchenie k
adresu, nahodyashchemusya za predelami virtual'nogo adresnogo prostranstva pro-
cessa. YAdro ne dampiruet sostoyanie pamyati, esli signal ne svyazan s programm-
noj oshibkoj. Naprimer, preryvanie, vyzvannoe nazhatiem klavish "delete" ili
"break" na terminale, imeet svoim rezul'tatom posylku signala, kotoryj soob-
shchaet o tom, chto pol'zovatel' hochet ran'she vremeni zavershit' process, v to
vremya kak signal o "zavisanii" yavlyaetsya svidetel'stvom narusheniya svyazi s re-
gistracionnym terminalom. |ti signaly ne svyazany s oshibkami v protekanii
processa. Signal o vyhode (quit), odnako, vyzyvaet sbros sostoyaniya pamyati,
nesmotrya na to, chto on voznikaet za predelami vypolnyaemogo processa. |tot
signal, obychno vyzyvaemyj odnovremennym nazhatiem klavish , daet prog-
rammistu vozmozhnost' poluchat' damp sostoyaniya pamyati v lyuboj moment posle za-
puska processa, chto byvaet neobhodimo, esli process popadaet v beskonechnyj
cikl vypolneniya odnih i teh zhe komand (zaciklivaetsya).
Esli process poluchaet signal, na kotoryj bylo resheno ne obrashchat' vnima-
nie, vypolnenie processa prodolzhaetsya tak, slovno signala i ne bylo. Pos-
kol'ku yadro ne sbrasyvaet znachenie sootvetstvuyushchego polya, svidetel'stvuyushchego
o neobhodimosti ignorirovaniya signala dannogo tipa, to kogda signal postupit
vnov', process opyat' ne obratit na nego vnimanie. Esli process poluchaet sig-
nal, reagirovanie na kotoryj bylo priznano neobhodimym, srazu po vozvrashchenii
processa v rezhim zadachi vypolnyaetsya zaranee uslovlennoe dejstvie, odnako
prezhde chem perevesti process v rezhim zadachi, yadro eshche dolzhno predprinyat'
sleduyushchie shagi:
1. YAdro obrashchaetsya k sohranennomu registrovomu kontekstu zadachi i vybiraet
znacheniya schetchika komand i ukazatelya vershiny steka, kotorye budut vozv-
rashcheny pol'zovatel'skomu processu.
2. Sbrasyvaet v prostranstve processa prezhnee znachenie polya funkcii obra-
botki signala i prisvaivaet emu znachenie po umolchaniyu.
3. Sozdaet novuyu zapis' v steke zadachi, v kotoruyu, pri neobhodimosti vyde-
lyaya dopolnitel'nuyu pamyat', perepisyvaet znacheniya schetchika komand i uka-
zatelya vershiny steka, vybrannye ranee iz sohranennogo registrovogo kon-
teksta zadachi. Stek zadachi budet vyglyadet' tak, kak budto process proiz-
vel obrashchenie k pol'zovatel'skoj funkcii (obrabotki signala) v toj toch-
ke, gde on vyzyval sistemnuyu funkciyu ili gde yadro prervalo ego vypolne-
nie (pered opoznaniem signala).
4. Vnosit izmeneniya v sohranennyj registrovyj kontekst zadachi: ustanavliva-
et znachenie schetchika komand ravnym adresu funkcii obrabotki signala, a
znachenie ukazatelya vershiny steka ravnym glubine steka zadachi.
Takim obrazom, po vozvrashchenii iz rezhima yadra v rezhim zadachi process
pristupit k vypolneniyu funkcii obrabotki signala; posle ee zaversheniya uprav-
lenie budet peredano na to mesto v programme pol'zovatelya, gde bylo proizve-
deno obrashchenie k sistemnoj funkcii ili proizoshlo preryvanie, tem samym kak
by imitiruetsya vyhod iz sistemnoj funkcii ili preryvaniya.
V kachestve primera mozhno privesti programmu (Risunok 7.9), kotoraya pri-
nimaet signaly o preryvanii (SIGINT) i sama posylaet ih (v rezul'tate vypol-
neniya funkcii kill). Na Risunke 7.10 predstavleny fragmenty programmnogo ko-
da, poluchennye v rezul'tate disassemblirovaniya zagruzochnogo modulya v opera-
cionnoj srede VAX 11/780. Pri vypolnenii processa obrashchenie k bibliotechnoj
procedure kill imeet adres (shestnadcatirichnyj) ee; eta procedura v svoyu oche-
red', prezhde chem vyzvat' sistemnuyu funkciyu kill, ispolnyaet komandu chmk (pe-
revesti process v rezhim yadra) po adresu 10a. Adres vozvrata iz sistemnoj
funkcii - 10c. Vo vremya ispolneniya sistemnoj funkcii yadro posylaet processu
signal o preryvanii. YAdro obrashchaet vnimanie na etot signal togda, kogda pro-
cess sobiraetsya vernut'sya v rezhim zadachi, vybiraya iz sohranennogo registro-
vogo konteksta adres vozvrata 10c i pomeshchaya ego v stek zadachi. Pri etom ad-
192
res funkcii obrabotki signala, 104, yadro pomeshchaet v sohranennyj registrovyj
kontekst zadachi. Na Risunke 7.11 pokazany razlichnye sostoyaniya steka zadachi i
sohranennogo registrovogo konteksta.
V rassmotrennom algoritme obrabotki signalov imeyutsya nekotorye nesoot-
vetstviya. Pervoe iz nih i naibolee vazhnoe svyazano s ochistkoj pered vozvrashche-
niem processa v rezhim zadachi togo polya v prostranstve processa, kotoroe so-
derzhit adres pol'zovatel'skoj funkcii obrabotki signala. Esli processu snova
ponadobitsya obrabotat' signal, emu opyat' pridetsya pribegnut' k pomoshchi sis-
temnoj funkcii signal. Pri etom mogut vozniknut' nezhelatel'nye posleds-
+-------------------------------------------+
| #include |
| main() |
| { |
| extern catcher(); |
| signal(SIGINT,catcher); |
| kill(0,SIGINT); |
| } |
| |
| catcher() |
| { |
| } |
+-------------------------------------------+
Risunok 7.9. Ishodnyj tekst programmy priema signalov
+--------------------------------------------------------+
| **** VAX DISASSEMBLER **** |
| |
| _main() |
| e4: |
| e6: pushab Ox18(pc) |
| ec: pushl $Ox2 |
| # v sleduyushchej stroke vyzyvaetsya funkciya signal |
| ee: calls $Ox2,Ox23(pc) |
| f5: pushl $Ox2 |
| f7: clrl -(sp) |
| # v sleduyushchej stroke vyzyvaetsya bibliotechnaya procedu-|
| ra kill |
| f9: calls $Ox2,Ox8(pc) |
| 100: ret |
| 101: halt |
| 102: halt |
| 103: halt |
| _catcher() |
| 104: |
| 106: ret |
| 107: halt |
| _kill() |
| 108: |
| # v sleduyushchej stroke vyzyvaetsya vnutrennee preryvanie|
| operacionnoj sistemy |
| 10a: chmk $Ox25 |
| 10c: bgequ Ox6 |
| 10e: jmp Ox14(pc) |
| 114: clrl r0 |
| 116: ret |
+--------------------------------------------------------+
Risunok 7.10. Rezul'tat disassemblirovaniya programmy priema signalov
193
Do Posle
| | | |
| | +-->+--------------------+
| | Vershina | | Novaya zapis' s vy- |
| | +-- steka --+ | zovom funkcii |
| | | zadachi | |
| | | ---->|Adres vozvrata (10c)|
+--------------------+<--+ - +--------------------+
| Stek zadachi | - | Stek zadachi |
| do | - | do |
| polucheniya signala | - | polucheniya signala |
+--------------------+ - +--------------------+
Stek zadachi - Stek zadachi
-
+--------------------+ - +--------------------+
| Adres vozvrata | - | Adres vozvrata |
| v processe (10c) -|---------------- | v processe (104) |
+--------------------+ +--------------------+
| Sohranennyj regist-| | Sohranennyj regist-|
| rovyj kontekst za- | | rovyj kontekst za- |
| dachi | | dachi |
+--------------------+ +--------------------+
Sistemnyj kontekstnyj Sistemnyj kontekstnyj
uroven' 1 uroven' 1
Oblast' sohraneniya Oblast' sohraneniya
registrov registrov
Risunok 7.11. Stek zadachi i oblast' sohraneniya struktur yadra
do i posle polucheniya signala
tviya: naprimer, mogut sozdast'sya usloviya dlya konkurencii, esli vtoroj raz
signal postupit do togo, kak process poluchit vozmozhnost' zapustit' sistemnuyu
funkciyu. Poskol'ku process vypolnyaetsya v rezhime zadachi, yadru sledovalo by
proizvesti pereklyuchenie konteksta, chtoby uvelichit' tem samym shansy processa
na poluchenie signala do momenta sbrosa znacheniya polya funkcii obrabotki sig-
nala.
|tu situaciyu mozhno razobrat' na primere programmy, predstavlennoj na Ri-
sunke 7.12. Process obrashchaetsya k sistemnoj funkcii signal dlya togo, chtoby
dat' ukazanie prinimat' signaly o preryvaniyah i ispolnyat' po ih poluchenii
funkciyu sigcatcher. Zatem on porozhdaet novyj process, zapuskaet sistemnuyu
funkciyu nice, pozvolyayushchuyu sdelat' prioritet zapuska processa-roditelya nizhe
prioriteta ego potomka (sm. glavu 8), i vhodit v beskonechnyj cikl. Porozhden-
nyj process zaderzhivaet svoe vypolnenie na 5 sekund, chtoby dat' roditel'sko-
mu processu vremya ispolnit' sistemnuyu funkciyu nice i snizit' svoj prioritet.
Posle etogo porozhdennyj process vhodit v cikl, v kazhdoj iteracii kotorogo on
posylaet roditel'skomu processu signal o preryvanii (posredstvom obrashcheniya k
funkcii kill). Esli v rezul'tate oshibki, naprimer, iz-za togo, chto roditel'-
skij process bol'she ne sushchestvuet, kill zavershaetsya, to zavershaetsya i porozh-
dennyj process. Vsya ideya sostoit v tom, chto roditel'skomu processu sleduet
zapuskat' funkciyu obrabotki signala pri kazhdom poluchenii signala o preryva-
nii. Funkciya obrabotki signala vyvodit soobshchenie i snova obrashchaetsya k funk-
cii signal pri ocherednom poyavlenii signala o preryvanii, roditel'skij zhe
process prodolzhaet
194
+------------------------------------------------------------+
| #include |
| sigcatcher() |
| { |
| printf("PID %d prinyal signal\n",getpid()); /* pechat' |
| PID */ |
| signal(SIGINT,sigcatcher); |
| } |
| |
| main() |
| { |
| int ppid; |
| |
| signal(SIGINT,sigcatcher); |
| |
| if (fork() == 0) |
| { |
| /* dat' processam vremya dlya vypolneniya ustanovok */ |
| sleep(5); /* bibliotechnaya funkciya priostanova na|
| 5 sekund */ |
| ppid = getppid(); /* poluchit' identifikator rodite- |
| lya */ |
| for (;;) |
| if (kill(ppid,SIGINT) == -1) |
| exit(); |
| } |
| |
| /* chem nizhe prioritet, tem vyshe shansy vozniknoveniya kon-|
| kurencii */ |
| nice(10); |
| for (;;) |
| ; |
| } |
+------------------------------------------------------------+
Risunok 7.12. Programma, demonstriruyushchaya vozniknovenie sopernichestva
mezhdu processami v hode obrabotki signalov
ispolnyat' ciklicheskij nabor komand.
Odnako, vozmozhna i sleduyushchaya ocherednost' nastupleniya sobytij:
1. Porozhdennyj process posylaet roditel'skomu processu signal o preryvanii.
2. Roditel'skij process prinimaet signal i vyzyvaet funkciyu obrabotki sig-
nala, no rezerviruetsya yadrom, kotoroe proizvodit pereklyuchenie konteksta
do togo, kak funkciya signal budet vyzvana povtorno.
3. Snova zapuskaetsya porozhdennyj process, kotoryj posylaet roditel'skomu
processu eshche odin signal o preryvanii.
4. Roditel'skij process poluchaet vtoroj signal o preryvanii, no pered tem
on ne uspel sdelat' nikakih rasporyazhenij otnositel'no sposoba obrabotki
signala. Kogda vypolnenie roditel'skogo processa budet vozobnovleno, on
zavershitsya.
V programme opisyvaetsya imenno takoe povedenie processov, poskol'ku vy-
zov roditel'skim processom funkcii nice privodit k tomu, chto yadro budet chashche
zapuskat' na vypolnenie porozhdennyj process.
Po slovam Richi (eti svedeniya byli polucheny v chastnoj besede), signaly
byli zadumany kak sobytiya, kotorye mogut byt' kak fatal'nymi, tak i prohodya-
shchimi nezametno, kotorye ne vsegda obrabatyvayutsya, poetomu v rannih versiyah
sistemy konkurenciya processov, svyazannaya s posylkoj signalov, ne fiksirova-
las'. Tem ne menee, ona predstavlyaet ser'eznuyu problemu v teh programmah,
gde osushchestvlyaetsya priem signalov. |ta problema byla by ustranena, esli by
195
pole opisaniya signala ne ochishchalos' po ego poluchenii. Odnako, takoe reshenie
porodilo by novuyu problemu: esli postupayushchij signal prinimaetsya, a pole ochi-
shcheno, vlozhennye obrashcheniya k funkcii obrabotki signala mogut perepolnit'
stek. S drugoj storony, yadro moglo by sbrosit' znachenie funkcii obrabotki
signala, tem samym delaya rasporyazhenie ignorirovat' signaly dannogo tipa do
teh por, poka pol'zovatel' vnov' ne ukazhet, chto nuzhno delat' po poluchenii
podobnyh signalov. Takoe reshenie predpolagaet poteryu informacii, tak kak
process ne v sostoyanii uznat', skol'ko signalov im bylo polucheno. Odnako,
informacii pri etom teryaetsya ne bol'she, chem v tom sluchae, kogda process po-
luchaet bol'shoe kolichestvo signalov odnogo tipa do togo, kak poluchaet vozmozh-
nost' ih obrabotat'. V sisteme BSD, nakonec, process imeet vozmozhnost' blo-
kirovat' poluchenie signalov i snimat' blokirovku pri novom obrashchenii k sis-
temnoj funkcii; kogda process snimaet blokirovku signalov, yadro posylaet
processu vse signaly, otlozhennye (povisshie) s momenta ustanovki blokirovki.
Kogda process poluchaet signal, yadro avtomaticheski blokiruet poluchenie sledu-
yushchego signala do teh por, poka funkciya obrabotki signala ne zakonchit rabotu.
V etih dejstviyah yadra nablyudaetsya analogiya s tem, kak yadro reagiruet na ap-
paratnye preryvaniya: ono blokiruet poyavlenie novyh preryvanij na vremya obra-
botki predydushchih.
Vtoroe nesootvetstvie v obrabotke signalov svyazano s priemom signalov,
postupayushchih vo vremya ispolneniya sistemnoj funkcii, kogda process priostanov-
len s dopuskayushchim preryvaniya prioritetom. Signal pobuzhdaet process vyjti iz
priostanova (s pomoshch'yu longjump), vernut'sya v rezhim zadachi i vyzvat' funkciyu
obrabotki signala. Kogda funkciya obrabotki signala zavershaet rabotu, prois-
hodit to, chto process vyhodit iz sistemnoj funkcii s oshibkoj, soobshchayushchej o
preryvanii ee vypolneniya. Uznav ob oshibke, pol'zovatel' zapuskaet sistemnuyu
funkciyu povtorno, odnako bolee udobno bylo by, esli by eto dejstvie avtoma-
ticheski vypolnyalos' yadrom, kak v sisteme BSD.
Tret'e nesootvetstvie proyavlyaetsya v tom sluchae, kogda process ignoriruet
postupivshij signal. Esli signal postupaet v to vremya, kogda process nahodit-
sya v sostoyanii priostanova s dopuskayushchim preryvaniya prioritetom, process vo-
zobnovlyaetsya, no ne vypolnyaet longjump. Drugimi slovami, yadro uznaet o tom,
chto process proignoriroval postupivshij signal tol'ko posle vozobnovleniya ego
vypolneniya. Logichnee bylo by ostavit' process v sostoyanii priostanova. Odna-
ko, v moment posylki signala k prostranstvu processa, v kotorom yadro hranit
adres funkcii obrabotki signala, mozhet otsutstvovat' dostup. |ta problema
mozhet byt' reshena putem zapominaniya adresa funkcii obrabotki signala v zapi-
si tablicy processov, obrashchayas' k kotoroj, yadro poluchalo by vozmozhnost' re-
shat' vopros o neobhodimosti vozobnovleniya processa po poluchenii signala. S
drugoj storony, process mozhet nemedlenno vernut'sya v sostoyanie priostanova
(po algoritmu sleep), esli obnaruzhit, chto v ego vozobnovlenii ne bylo neob-
hodimosti. Odnako, pol'zovatel'skie processy ne imeyut vozmozhnosti osoznavat'
sobstvennoe vozobnovlenie, poskol'ku yadro raspolagaet tochku vhoda v algoritm
sleep vnutri cikla s usloviem prodolzheniya (sm. glavu 2), perevodya process
vnov' v sostoyanie priostanova, esli ozhidaemoe processom sobytie v dejstvi-
tel'nosti ne imelo mesta.
Ko vsemu skazannomu vyshe sleduet dobavit', chto yadro obrabatyvaet signaly
tipa "gibel' potomka" ne tak, kak drugie signaly. V chastnosti, kogda process
uznaet o poluchenii signala "gibel' potomka", on vyklyuchaet indikaciyu signala
v sootvetstvuyushchem pole zapisi tablicy processov i po umolchaniyu dejstvuet
tak, slovno nikakogo signala i ne postupalo. Naznachenie signala "gibel' po-
tomka" sostoit v vozobnovlenii vypolneniya processa, priostanovlennogo s do-
puskayushchim preryvaniya prioritetom. Esli process prinimaet takoj signal, on,
kak i vo vseh ostal'nyh sluchayah, zapuskaet funkciyu obrabotki signala. Dejst-
viya, predprinimaemye yadrom v tom sluchae, kogda process ignoriruet postupiv-
shij signal etogo tipa, budut opisany v razdele 7.4. Nakonec, kogda process
vyzval funkciyu signal s parametrom "gibel' potomka" (death of child), yadro
posylaet emu sootvetstvuyushchij signal, esli on imeet potomkov, prekrativshih
sushchestvovanie. V razdele 7.4 na etom momente my ostanovimsya bolee podrobno.
196
Nesmotrya na to, chto v sisteme UNIX processy identificiruyutsya unikal'nym
kodom (PID), sisteme inogda prihoditsya ispol'zovat' dlya identifikacii pro-
cessov nomer "gruppy", v kotoruyu oni vhodyat. Naprimer, processy, imeyushchie ob-
shchego predka v lice registracionnogo shell'a, vzaimosvyazany, i poetomu kogda
pol'zovatel' nazhimaet klavishi "delete" ili "break", ili kogda terminal'naya
liniya "zavisaet", vse eti processy poluchayut sootvetstvuyushchie signaly. YAdro
ispol'zuet kod gruppy processov dlya identifikacii gruppy vzaimosvyazannyh
processov, kotorye pri nastuplenii opredelennyh sobytij dolzhny poluchat' ob-
shchij signal. Kod gruppy zapominaetsya v tablice processov; processy iz odnoj
gruppy imeyut odin i tot zhe kod gruppy.
Dlya togo, chtoby prisvoit' kodu gruppy processov nachal'noe znachenie, pri-
ravnyav ego kodu identifikacii processa, sleduet vospol'zovat'sya sistemnoj
funkciej setpgrp. Sintaksis vyzova funkcii:
grp = setpgrp();
gde grp - novyj kod gruppy processov. Pri vypolnenii funkcii fork pro-
cess-potomok nasleduet kod gruppy svoego roditelya. Ispol'zovanie funkcii
setpgrp pri naznachenii dlya processa operatorskogo terminala imeet vazhnye
osobennosti, na kotorye stoit obratit' vnimanie (sm. razdel 10.3.5).
7.2.3 Posylka signalov processami
Dlya posylki signalov processy ispol'zuyut sistemnuyu funkciyu kill. Sintak-
sis vyzova funkcii:
kill(pid,signum)
gde v pid ukazyvaetsya adresat posylaemogo signala (oblast' dejstviya signa-
la), a v signum - nomer posylaemogo signala. Svyaz' mezhdu znacheniem pid i so-
vokupnost'yu vypolnyayushchihsya processov sleduyushchaya:
* Esli pid - polozhitel'noe celoe chislo, yadro posylaet signal processu s
identifikatorom pid.
* Esli znachenie pid ravno 0, signal posylaetsya vsem processam, vhodyashchim v
odnu gruppu s processom, vyzvavshim funkciyu kill.
* Esli znachenie pid ravno -1, signal posylaetsya vsem processam, u kotoryh
real'nyj kod identifikacii pol'zovatelya sovpadaet s tem, pod kotorym is-
polnyaetsya process, vyzvavshij funkciyu kill (ob etih kodah bolee podrobno
sm. v razdele 7.6). Esli process, poslavshij signal, ispolnyaetsya pod ko-
dom identifikacii superpol'zovatelya, signal rassylaetsya vsem processam,
krome processov s identifikatorami 0 i 1.
* Esli pid - otricatel'noe celoe chislo, no ne -1, signal posylaetsya vsem
processam, vhodyashchim v gruppu s nomerom, ravnym absolyutnomu znacheniyu pid.
Vo vseh sluchayah, esli process, poslavshij signal, ispolnyaetsya pod kodom
identifikacii pol'zovatelya, ne yavlyayushchegosya superpol'zovatelem, ili esli kody
identifikacii pol'zovatelya (real'nyj i ispolnitel'nyj) u etogo processa ne
sovpadayut s sootvetstvuyushchimi kodami processa, prinimayushchego signal, kill za-
vershaetsya neudachno.
V programme, privedennoj na Risunke 7.13, glavnyj process sbrasyvaet us-
tanovlennoe ranee znachenie nomera gruppy i porozhdaet 10 novyh processov. Pri
rozhdenii kazhdyj process-potomok nasleduet nomer gruppy processov svoego ro-
ditelya, odnako, processy, sozdannye v nechetnyh iteraciyah cikla, sbrasyvayut
eto znachenie. Sistemnye funkcii getpid i getpgrp vozvrashchayut znacheniya koda
identifikacii vypolnyaemogo processa i nomera gruppy, v kotoruyu on vhodit, a
funkciya pause priostanavlivaet vypolnenie processa do momenta polucheniya sig-
nala. V konechnom itoge roditel'skij process zapuskaet funkciyu kill i posyla-
et signal o preryvanii vsem processam, vhodyashchim v odnu s nim gruppu. YAdro
197
+------------------------------------------------------------+
| #include |
| main() |
| { |
| register int i; |
| |
| setpgrp(); |
| for (i = 0; i < 10; i++) |
| { |
| if (fork() == 0) |
| { |
| /* porozhdennyj process */ |
| if (i & 1) |
| setpgrp(); |
| printf("pid = %d pgrp = %d\n",getpid(),getpgrp());|
| pause(); /* sistemnaya funkciya priostanova vy- |
| polneniya */ |
| } |
| } |
| kill(0,SIGINT); |
| } |
+------------------------------------------------------------+
Risunok 7.13. Primer ispol'zovaniya funkcii setpgrp
posylaet signal pyati "chetnym" processam, ne sbrosivshim unasledovannoe znache-
nie nomera gruppy, pri etom pyat' "nechetnyh" processov prodolzhayut svoe vypol-
nenie.
7.3 ZAVERSHENIE VYPOLNENIYA PROCESSA
V sisteme UNIX process zavershaet svoe vypolnenie, zapuskaya sistemnuyu
funkciyu exit. Posle etogo process perehodit v sostoyanie "prekrashcheniya sushchest-
vovaniya" (sm. Risunok 6.1), osvobozhdaet resursy i likvidiruet svoj kontekst.
Sintaksis vyzova funkcii:
exit(status);
gde status - znachenie, vozvrashchaemoe funkciej roditel'skomu processu. Proces-
sy mogut vyzyvat' funkciyu exit kak v yavnom, tak i v neyavnom vide (po okoncha-
nii vypolneniya programmy: nachal'naya procedura (startup), komponuemaya so vse-
mi programmami na yazyke Si, vyzyvaet funkciyu exit na vyhode programmy iz
funkcii main, yavlyayushchejsya obshchej tochkoj vhoda dlya vseh programm). S drugoj
storony, yadro mozhet vyzyvat' funkciyu exit po svoej iniciative, esli process
ne prinyal poslannyj emu signal (ob etom my uzhe govorili vyshe). V etom sluchae
znachenie parametra status ravno nomeru signala.
Sistema ne nakladyvaet nikakogo ogranicheniya na prodolzhitel'nost' vypol-
neniya processa, i zachastuyu processy sushchestvuyut v techenie dovol'no dlitel'no-
go vremeni. Nulevoj process (programma podkachki) i process 1 (init), k pri-
meru, sushchestvuyut na protyazhenii vsego vremeni zhizni sistemy. Prodolzhitel'nymi
processami yavlyayutsya takzhe getty-processy, kontroliruyushchie rabotu terminal'noj
linii, ozhidaya registracii pol'zovatelej, i processy obshchego naznacheniya, vy-
polnyaemye pod rukovodstvom administratora.
Na Risunke 7.14 priveden algoritm funkcii exit. Snachala yadro otmenyaet
obrabotku vseh signalov, posylaemyh processu, poskol'ku ee prodolzhenie sta-
novitsya bessmyslennym. Esli process, vyzyvayushchij funkciyu exit, vozglavlyaet
198
+------------------------------------------------------------+
| algoritm exit |
| vhodnaya informaciya: kod, vozvrashchaemyj roditel'skomu pro- |
| cessu |
| vyhodnaya informaciya: otsutstvuet |
| { |
| ignorirovat' vse signaly; |
| esli (process vozglavlyaet gruppu processov, associiro- |
| vannuyu s operatorskim terminalom) |
| { |
| poslat' vsem processam, vhodyashchim v gruppu, signal o |
| "zavisanii"; |
| sbrosit' v nol' kod gruppy processov; |
| } |
| zakryt' vse otkrytye fajly (vnutrennyaya modifikaciya algo-|
| ritma close); |
| osvobodit' tekushchij katalog (algoritm iput); |
| osvobodit' oblasti i pamyat', associirovannuyu s processom|
| (algoritm freereg); |
| sozdat' zapis' s uchetnoj informaciej; |
| prekratit' sushchestvovanie processa (perevesti ego v soot-|
| vetstvuyushchee sostoyanie); |
| naznachit' vsem processam-potomkam v kachestve roditelya |
| process init (1); |
| esli kto-libo iz potomkov prekratil sushchestvovanie, |
| poslat' processu init signal "gibel' potomka"; |
| poslat' signal "gibel' potomka" roditelyu dannogo proces-|
| sa; |
| pereklyuchit' kontekst; |
| } |
+------------------------------------------------------------+
Risunok 7.14. Algoritm funkcii exit
gruppu processov, associirovannuyu s operatorskim terminalom (sm. razdel
10.3.5), yadro delaet predpolozhenie o tom, chto pol'zovatel' prekrashchaet rabo-
tu, i posylaet vsem processam v gruppe signal o "zavisanii". Takim obrazom,
esli pol'zovatel' v registracionnom shell'e nazhmet posledovatel'nost' kla-
vish, oznachayushchuyu "konec fajla" (Ctrl-d), pri etom s terminalom ostalis' svya-
zannymi nekotorye iz sushchestvuyushchih processov, process, vypolnyayushchij funkciyu
exit, poshlet im vsem signal o "zavisanii". Krome togo, yadro sbrasyvaet v
nol' znachenie koda gruppy processov dlya vseh processov, vhodyashchih v dannuyu
gruppu, poskol'ku ne isklyuchena vozmozhnost' togo, chto pozdnee tekushchij kod
identifikacii processa (processa, kotoryj vyzval funkciyu exit) budet prisvo-
en drugomu processu i togda poslednij vozglavit gruppu s ukazannym kodom.
Processy, vhodivshie v staruyu gruppu, v novuyu gruppu vhodit' ne budut. Posle
etogo yadro prosmatrivaet deskriptory otkrytyh fajlov, zakryvaet kazhdyj iz
etih fajlov po algoritmu close i osvobozhdaet po algoritmu iput indeksy teku-
shchego kataloga i kornya (esli on izmenyalsya).
Nakonec, yadro osvobozhdaet vsyu vydelennuyu zadache pamyat' vmeste s sootvet-
stvuyushchimi oblastyami (po algoritmu detachreg) i perevodit process v sostoyanie
prekrashcheniya sushchestvovaniya. YAdro sohranyaet v tablice processov kod vozvrata
funkcii exit (status), a takzhe summarnoe vremya ispolneniya processa i ego po-
tomkov v rezhime yadra i rezhime zadachi. V razdele 7.4 pri rassmotrenii funkcii
wait budet pokazano, kakim obrazom process poluchaet informaciyu o vremeni vy-
polneniya svoih potomkov. YAdro takzhe sozdaet v global'nom uchetnom fajle za-
pis', kotoraya soderzhit razlichnuyu statisticheskuyu informaciyu o vypolnenii pro-
cessa, takuyu kak kod identifikacii pol'zovatelya, ispol'zovanie resursov cen-
tral'nogo processora i pamyati, ob®em potokov vvoda-vyvoda, svyazannyh s pro-
199
cessom. Pol'zovatel'skie programmy mogut v lyuboj moment obratit'sya k uchetno-
mu fajlu za statisticheskimi dannymi, predstavlyayushchimi interes s tochki zreniya
slezheniya za funkcionirovaniem sistemy i organizacii raschetov s pol'zovatelya-
mi. YAdro udalyaet process iz dereva processov, a ego potomkov peredaet pro-
cessu 1 (init). Takim obrazom, process 1 stanovitsya zakonnym roditelem vseh
prodolzhayushchih sushchestvovanie potomkov zavershayushchegosya processa. Esli kto-libo
iz potomkov prekrashchaet sushchestvovanie, zavershayushchijsya process posylaet proces-
su init signal "gibel' potomka" dlya togo, chtoby process nachal'noj zagruzki
mog udalit' zapis' o potomke iz tablicy processov (sm. razdel 7.9); krome
togo, zavershayushchijsya process posylaet etot signal svoemu roditelyu. V tipichnoj
situacii roditel'skij process sinhroniziruet svoe vypolnenie s zavershayushchimsya
potomkom s pomoshch'yu sistemnoj funkcii wait. Prekrashchaya sushchestvovanie, process
pereklyuchaet kontekst i yadro mozhet teper' vybirat' dlya ispolneniya sleduyushchij
process; yadro s etih por uzhe ne budet ispolnyat' process, prekrativshij sushches-
tvovanie.
V programme, privedennoj na Risunke 7.15, process sozdaet novyj process,
kotoryj pechataet svoj kod identifikacii i vyzyvaet sistemnuyu funkciyu pause,
priostanavlivayas' do polucheniya signala. Process-roditel' pechataet PID svoego
potomka i zavershaetsya, vozvrashchaya tol'ko chto vyvedennoe znachenie cherez para-
metr status. Esli by vyzov funkcii exit otsutstvoval, nachal'naya procedura
sdelala by ego po vyhode processa iz funkcii main. Porozhdennyj process pro-
dolzhaet ozhidat' polucheniya signala, dazhe esli ego roditel' uzhe zavershilsya.
7.4 OZHIDANIE ZAVERSHENIYA VYPOLNENIYA PROCESSA
Process mozhet sinhronizirovat' prodolzhenie svoego vypolneniya s momentom
zaversheniya potomka, esli vospol'zuetsya sistemnoj funkciej wait. Sintaksis
vyzova funkcii:
+------------------------------------------------------------+
| main() |
| { |
| int child; |
| |
| if ((child = fork()) == 0) |
| { |
| printf("PID potomka %d\n",getpid()); |
| pause(); /* priostanov vypolneniya do polucheniya |
| signala */ |
| } |
| /* roditel' */ |
| printf("PID potomka %d\n",child); |
| exit(child); |
| } |
+------------------------------------------------------------+
Risunok 7.15. Primer ispol'zovaniya funkcii exit
pid = wait(stat_addr);
gde pid - znachenie koda identifikacii (PID) prekrativshego svoe sushchestvovanie
potomka, stat_addr - adres peremennoj celogo tipa, v kotoruyu budet pomeshcheno
vozvrashchaemoe funkciej exit znachenie, v prostranstve zadachi.
Algoritm funkcii wait priveden na Risunke 7.16. YAdro vedet poisk potom-
kov processa, prekrativshih sushchestvovanie, i v sluchae ih otsutstviya vozvrashcha-
et oshibku. Esli potomok, prekrativshij sushchestvovanie, obnaruzhen, yadro pereda-
et ego kod identifikacii i znachenie, vozvrashchaemoe cherez parametr funkcii
exit, processu, vyzvavshemu funkciyu wait. Takim obrazom, cherez parametr funk-
200
cii exit (status) zavershayushchijsya process mozhet peredavat' razlichnye znacheniya,
v zakodirovannom vide soderzhashchie informaciyu o prichine zaversheniya processa,
odnako na praktike etot parametr ispol'zuetsya po naznacheniyu dovol'no redko.
YAdro peredaet v sootvetstvuyushchie polya, prinadlezhashchie prostranstvu roditel'-
skogo processa, nakoplennye znacheniya prodolzhitel'nosti ispolneniya proces-
sa-potomka v rezhime yadra i v rezhime zadachi i, nakonec, osvobozhdaet v tablice
processov mesto, kotoroe v nej zanimal prezhde prekrativshij sushchestvovanie
process. |to mesto budet predostavleno novomu processu.
Esli process, vypolnyayushchij funkciyu wait, imeet potomkov, prodolzhayushchih su-
shchestvovanie, on priostanavlivaetsya do polucheniya ozhidaemogo signala. YAdro ne
vozobnovlyaet po svoej iniciative process, priostanovivshijsya s pomoshch'yu funk-
cii wait: takoj process mozhet vozobnovit'sya tol'ko v sluchae polucheniya signa-
la. Na vse signaly, krome signala "gibel' potomka", process reagiruet ranee
rassmotrennym obrazom. Reakciya processa na signal "gibel' potomka" proyavlya-
etsya po-raznomu v zavisimosti ot obstoyatel'stv:
* Po umolchaniyu (to est' esli special'no ne ogovoreny nikakie drugie dejst-
viya) process vyhodit iz sostoyaniya ostanova, v kotoroe on voshel s pomoshch'yu
funkcii wait, i zapuskaet algoritm issig dlya opoznaniya tipa postupivshego
signala. Algoritm issig (Risunok 7.7) rassmatrivaet osobyj sluchaj pos-
tupleniya signala tipa "gibel' potomka" i vozvrashchaet "lozh'". Poetomu yadro
ne vypolnyaet longjump iz funkcii sleep, a vozvrashchaet upravlenie funkcii
wait. Ono perezapuskaet funkciyu wait, nahodit potomkov, prekrativshih su-
shchestvovanie (po krajnej mere, odnogo), osvobozhdaet mesto v tablice pro-
cessov, zanimaemoe etimi potomkami, i vyhodit iz funkcii wait, vozvrashchaya
+------------------------------------------------------------+
| algoritm wait |
| vhodnaya informaciya: adres peremennoj dlya hraneniya znacheniya|
| status, vozvrashchaemogo zavershayushchimsya |
| processom |
| vyhodnaya informaciya: identifikator potomka i kod vozvrata |
| funkcii exit |
| { |
| esli (process, vyzvavshij funkciyu wait, ne imeet potom- |
| kov) |
| vozvratit' (oshibku); |
| |
| dlya (;;) /* cikl s vnutrennim ciklom */ |
| { |
| esli (process, vyzvavshij funkciyu wait, imeet potom-|
| kov, prekrativshih sushchestvovanie) |
| { |
| vybrat' proizvol'nogo potomka; |
| peredat' ego roditelyu informaciyu ob ispol'zova-|
| nii potomkom resursov central'nogo processora;|
| osvobodit' v tablice processov mesto, zanimae- |
| moe potomkom; |
| vozvratit' (identifikator potomka, kod vozvrata|
| funkcii exit, vyzvannoj potomkom); |
| } |
| esli (u processa net potomkov) |
| vozvratit' oshibku; |
| priostanovit'sya s prioritetom, dopuskayushchim preryva-|
| niya (do zaversheniya potomka); |
| } |
| } |
+------------------------------------------------------------+
Risunok 7.16. Algoritm funkcii wait
201
upravlenie processu, vyzvavshemu ee.
* Esli processy prinimaet signaly dannogo tipa, yadro delaet vse neobhodi-
mye ustanovki dlya zapuska pol'zovatel'skoj funkcii obrabotki signala,
kak i v sluchae postupleniya signala lyubogo drugogo tipa.
* Esli process ignoriruet signaly dannogo tipa, yadro perezapuskaet funkciyu
wait, osvobozhdaet v tablice processov mesto, zanimaemoe potomkami, prek-
rativshimi sushchestvovanie, i issleduet ostavshihsya potomkov.
Naprimer, esli pol'zovatel' zapuskaet programmu, privedennuyu na Risunke
7.17, s parametrom i bez parametra, on poluchit raznye rezul'taty. Snachala
rassmotrim sluchaj, kogda pol'zovatel' zapuskaet programmu bez parametra
(edinstvennyj parametr - imya programmy, to est' argc ravno 1). Roditel'skij
process porozhdaet 15 potomkov, kotorye v konechnom itoge zavershayut svoe vy-
polnenie s kodom vozvrata i, nomerom processa v poryadke ocherednosti sozda-
niya. YAdro, ispolnyaya funkciyu wait dlya roditelya, nahodit potomka, prekrativshe-
go sushchestvovanie, i peredaet roditelyu ego identifikator i kod vozvrata funk-
cii exit. Pri etom zaranee ne izvestno, kakoj iz potomkov budet obnaruzhen.
Iz teksta programmy, realizuyushchej sistemnuyu funkciyu exit, napisannoj na yazyke
Si i vklyuchennoj v biblioteku standartnyh podprogramm, vidno, chto programma
zapominaet kod vozvrata funkcii exit v bitah 8-15 polya ret_code i vozvrashchaet
funkcii wait identifikator processa-potomka. Takim obrazom, v ret_code hra-
nitsya znachenie, ravnoe 256*i, gde i - nomer potomka, a v ret_val zanositsya
znachenie identifikatora potomka.
Esli pol'zovatel' zapuskaet programmu s parametrom (to est' argc > 1),
roditel'skij process s pomoshch'yu funkcii signal delaet rasporyazhenie ignoriro-
vat' signaly tipa "gibel' potomka". Predpolozhim, chto roditel'skij process,
vypolnyaya funkciyu wait, priostanovilsya eshche do togo, kak ego potomok proizvel
obrashchenie k funkcii exit: kogda process-potomok perehodit k vypolneniyu funk-
cii exit, on posylaet svoemu roditelyu signal "gibel' potomka"; roditel'skij
process vozobnovlyaetsya, poskol'ku on byl priostanovlen s prioritetom, dopus-
kayushchim preryvaniya. Kogda tak ili inache roditel'skij process prodolzhit svoe
+------------------------------------------------------------+
| #include |
| main(argc,argv) |
| int argc; |
| char *argv[]; |
| { |
| int i,ret_val,ret_code; |
| |
| if (argc >= 1) |
| signal(SIGCLD,SIG_IGN); /* ignorirovat' gibel' |
| potomkov */ |
| for (i = 0; i < 15; i++) |
| if (fork() == 0) |
| { |
| /* process-potomok */ |
| printf("process-potomok %x\n",getpid()); |
| exit(i); |
| } |
| ret_val = wait(&ret_code); |
| printf("wait ret_val %x ret_code %x\n",ret_val,ret_code);|
| } |
+------------------------------------------------------------+
Risunok 7.17. Primer ispol'zovaniya funkcii wait i ignorirova-
niya signala "gibel' potomka"
202
vypolnenie, on obnaruzhit, chto signal soobshchal o "gibeli" potomka; odnako,
poskol'ku on ignoriruet signaly
etogo tipa i ne obrabatyvaet ih, yadro udalyaet iz tablicy processov zapis',
sootvetstvuyushchuyu prekrativshemu sushchestvovanie potomku, i prodolzhaet vypolnenie
funkcii wait tak, slovno signala i ne bylo. YAdro vypolnyaet eti dejstviya vsya-
kij raz, kogda roditel'skij process poluchaet signal tipa "gibel' potomka",
do teh por, poka cikl vypolneniya funkcii wait ne budet zavershen i poka ne
budet ustanovleno, chto u processa bol'she potomkov net. Togda funkciya wait
vozvrashchaet znachenie, ravnoe -1. Raznica mezhdu dvumya sposobami zapuska prog-
rammy sostoit v tom, chto v pervom sluchae process-roditel' zhdet zaversheniya
lyubogo iz potomkov, v to vremya kak vo vtorom sluchae on zhdet, poka zavershatsya
vse ego potomki.
V rannih versiyah sistemy UNIX funkcii exit i wait ne ispol'zovali i ne
rassmatrivali signal tipa "gibel' potomka". Vmesto posylki signala funkciya
exit vozobnovlyala vypolnenie roditel'skogo processa. Esli roditel'skij pro-
cess pri vypolnenii funkcii wait priostanovilsya, on vozobnovlyaetsya, nahodit
potomka, prekrativshego sushchestvovanie, i vozvrashchaet upravlenie. V protivnom
sluchae vozobnovleniya ne proishodit; process-roditel' obnaruzhit "pogibshego"
potomka pri sleduyushchem obrashchenii k funkcii wait. Tochno tak zhe i process na-
chal'noj zagruzki (init) mozhet priostanovit'sya, ispol'zuya funkciyu wait, i za-
vershayushchiesya po exit processy budut vozobnovlyat' ego, esli on imeet usynov-
lennyh potomkov, prekrashchayushchih sushchestvovanie.
V takoj realizacii funkcij exit i wait imeetsya odna nereshennaya problema,
svyazannaya s tem, chto processy, prekrativshie sushchestvovanie, nel'zya ubirat' iz
sistemy do teh por, poka ih roditel' ne ispolnit funkciyu wait. Esli process
sozdal mnozhestvo potomkov, no tak i ne ispolnil funkciyu wait, mozhet proizoj-
ti perepolnenie tablicy processov iz-za nalichiya potomkov, prekrativshih su-
shchestvovanie s pomoshch'yu funkcii exit. V kachestve primera rassmotrim tekst
programmy planirovshchika processov, privedennyj na Risunke 7.18. Process pro-
izvodit schityvanie dannyh iz fajla standartnogo vvoda do teh por, poka ne
budet obnaruzhen konec fajla, sozdavaya pri kazhdom ispolnenii funkcii read no-
vogo potomka. Odnako, process-roditel' ne dozhidaetsya zaversheniya kazhdogo po-
tomka, poskol'ku on stremitsya zapuskat' processy na vypolnenie kak mozhno
bystree, tem bolee, chto mozhet projti dovol'no mnogo vremeni, prezhde chem pro-
cess-potomok zavershit svoe vypolnenie. Esli, obrativshis' k
+------------------------------------------------------------+
| #include |
| main(argc,argv) |
| { |
| char buf[256]; |
| |
| if (argc != 1) |
| signal(SIGCLD,SIG_IGN); /* ignorirovat' gibel' |
| potomkov */ |
| while (read(0,buf,256)) |
| if (fork() == 0) |
| { |
| /* zdes' process-potomok obychno vypolnyaet |
| kakie-to operacii nad buferom (buf) */ |
| exit(0); |
| } |
| } |
+------------------------------------------------------------+
Risunok 7.18. Primer ukazaniya prichiny poyavleniya signala "gi-
bel' potomkov"
203
funkcii signal, process rasporyadilsya ignorirovat' signaly tipa "gibel' po-
tomka", yadro budet ochishchat' zapisi, sootvetstvuyushchie prekrativshim sushchestvova-
nie processam, avtomaticheski. Inache v konechnom itoge iz-za takih processov
mozhet proizojti perepolnenie tablicy.
7.5 VYZOV DRUGIH PROGRAMM
Sistemnaya funkciya exec daet vozmozhnost' processu zapuskat' druguyu prog-
rammu, pri etom sootvetstvuyushchij etoj programme ispolnyaemyj fajl budet raspo-
lagat'sya v prostranstve pamyati processa. Soderzhimoe pol'zovatel'skogo kon-
teksta posle vyzova funkcii stanovitsya nedostupnym, za isklyucheniem peredava-
emyh funkcii parametrov, kotorye perepisyvayutsya yadrom iz starogo adresnogo
prostranstva v novoe. Sintaksis vyzova funkcii:
execve(filename,argv,envp)
gde filename - imya ispolnyaemogo fajla, argv - ukazatel' na massiv paramet-
rov, kotorye peredayutsya vyzyvaemoj programme, a envp - ukazatel' na massiv
parametrov, sostavlyayushchih sredu vypolneniya vyzyvaemoj programmy. Vyzov sis-
temnoj funkcii exec osushchestvlyayut neskol'ko bibliotechnyh funkcij, takih kak
execl, execv, execle i t.d. V tom sluchae, kogda programma ispol'zuet para-
metry komandnoj stroki
main(argc,argv) ,
+------------------------------------------------------------+
| algoritm exec |
| vhodnaya informaciya: (1) imya fajla |
| (2) spisok parametrov |
| (3) spisok peremennyh sredy |
| vyhodnaya informaciya: otsutstvuet |
| { |
| poluchit' indeks fajla (algoritm namei); |
| proverit', yavlyaetsya li fajl ispolnimym i imeet li pol'- |
| zovatel' pravo na ego ispolnenie; |
| prochitat' informaciyu iz zagolovkov fajla i proverit', |
| yavlyaetsya li on zagruzochnym modulem; |
| skopirovat' parametry, peredannye funkcii, iz starogo |
| adresnogo prostranstva v sistemnoe prostranstvo; |
| dlya (kazhdoj oblasti, prisoedinennoj k processu) |
| otsoedinit' vse starye oblasti (algoritm detachreg);|
| dlya (kazhdoj oblasti, opredelennoj v zagruzochnom module) |
| { |
| vydelit' novye oblasti (algoritm allocreg); |
| prisoedinit' oblasti (algoritm attachreg); |
| zagruzit' oblast' v pamyat' po gotovnosti (algoritm |
| loadreg); |
| } |
| skopirovat' parametry, peredannye funkcii, v novuyu ob- |
| last' steka zadachi; |
| special'naya obrabotka dlya setuid-programm, trassirovka; |
| proinicializirovat' oblast' sohraneniya registrov zadachi |
| (v ramkah podgotovki k vozvrashcheniyu v rezhim zadachi); |
| osvobodit' indeks fajla (algoritm iput); |
| } |
+------------------------------------------------------------+
Risunok 7.19. Algoritm funkcii exec
204
massiv argv yavlyaetsya kopiej odnoimennogo parametra, peredavaemogo funkcii
exec. Simvol'nye stroki, opisyvayushchie sredu vypolneniya vyzyvaemoj programmy,
imeyut vid "imya=znachenie" i soderzhat poleznuyu dlya programm informaciyu, takuyu
kak nachal'nyj katalog pol'zovatelya i put' poiska ispolnyaemyh programm. Pro-
cessy mogut obrashchat'sya k parametram opisaniya sredy vypolneniya, ispol'zuya
global'nuyu pere-
mennuyu environ, kotoruyu zavodit nachal'naya procedura Si-interpretatora.
Na Risunke 7.19 predstavlen algoritm vypolneniya sistemnoj funkcii exec.
Snachala funkciya obrashchaetsya k fajlu po algoritmu namei, proveryaya, yavlyaetsya li
fajl ispolnimym i otlichnym ot kataloga, a takzhe proveryaya nalichie u pol'zova-
telya prava ispolnyat' programmu. Zatem yadro, schityvaya zagolovok fajla, opre-
delyaet razmeshchenie informacii v fajle (format fajla).
Na Risunke 7.20 izobrazhen logicheskij format ispolnyaemogo fajla v fajlo-
voj sisteme, obychno generiruemyj translyatorom ili zagruzchikom. On razbivaet-
sya na chetyre chasti:
1. Glavnyj zagolovok, soderzhashchij informaciyu o tom, na skol'ko razdelov de-
litsya fajl, a takzhe soderzhashchij nachal'nyj adres ispolneniya processa i ne-
kotoroe "magicheskoe chislo", opisyvayushchee tip ispolnyaemogo fajla.
2. Zagolovki razdelov, soderzhashchie informaciyu, opisyvayushchuyu kazhdyj razdel v
fajle: ego razmer, virtual'nye adresa, v kotoryh on raspolagaetsya, i dr.
3. Razdely, soderzhashchie sobstvenno "dannye" fajla (naprimer, tekstovye), ko-
torye zagruzhayutsya v adresnoe prostranstvo processa.
4. Razdely, soderzhashchie smeshannuyu informaciyu, takuyu kak tablicy identifika-
torov i drugie dannye, ispol'zuemye v processe otladki.
+---------------------------+
| Tip fajla |
Glavnyj zagolovok | Kolichestvo razdelov |
| Nachal'noe sostoyanie regis-|
| trov |
+---------------------------+
| Tip razdela |
Zagolovok 1-go razdela | Razmer razdela |
| Virtual'nyj adres |
+---------------------------+
| Tip razdela |
Zagolovok 2-go razdela | Razmer razdela |
- | Virtual'nyj adres |
- +---------------------------+
- | - |
- | - |
- +---------------------------+
- | Tip razdela |
Zagolovok n-go razdela | Razmer razdela |
| Virtual'nyj adres |
+---------------------------+
Razdel 1 | Dannye (naprimer, tekst) |
+---------------------------+
Razdel 2 | Dannye |
- +---------------------------+
- | - |
- | - |
- +---------------------------+
Razdel n | Dannye |
+---------------------------+
| Drugaya informaciya |
+---------------------------+
Risunok 7.20. Obraz ispolnyaemogo fajla
205
Ukazannye sostavlyayushchie s razvitiem samoj sistemy vidoizmenyayutsya, odnako
vo vseh ispolnyaemyh fajlah obyazatel'no prisutstvuet glavnyj zagolovok s po-
lem tipa fajla.
Tip fajla oboznachaetsya korotkim celym chislom (predstavlyaetsya v mashine
poluslovom), kotoroe identificiruet fajl kak zagruzochnyj modul', davaya tem
samym yadru vozmozhnost' otslezhivat' dinamicheskie harakteristiki ego vypolne-
niya. Naprimer, v mashine PDP 11/70 opredelenie tipa fajla kak zagruzochnogo
modulya svidetel'stvuet o tom, chto process, ispolnyayushchij fajl, mozhet ispol'zo-
vat' do 128 Kbajt pamyati vmesto 64 Kbajt (**), tem ne menee v sistemah s za-
meshcheniem stranic tip fajla vse eshche igraet sushchestvennuyu rol', v chem nam pred-
stoit ubedit'sya vo vremya znakomstva s glavoj 9.
Vernemsya k algoritmu. My ostanovilis' na tom, chto yadro obratilos' k in-
deksu fajla i ustanovilo, chto fajl yavlyaetsya ispolnimym. YAdru sledovalo by
osvobodit' pamyat', zanimaemuyu pol'zovatel'skim kontekstom processa. Odnako,
poskol'ku v pamyati, podlezhashchej osvobozhdeniyu, raspolagayutsya peredavaemye no-
voj programme parametry, yadro pervym delom kopiruet ih iz adresnogo prost-
ranstva v promezhutochnyj bufer na vremya, poka ne budut otvedeny oblasti dlya
novogo prostranstva pamyati.
Poskol'ku parametrami funkcii exec vystupayut pol'zovatel'skie adresa
massivov simvol'nyh strok, yadro po kazhdoj stroke snachala kopiruet v sistem-
nuyu pamyat' adres stroki, a zatem samu stroku. Dlya hraneniya stroki v raznyh
versiyah sistemy mogut byt' vybrany razlichnye mesta. CHashche prinyato hranit'
stroki v steke yadra (lokal'naya struktura dannyh, prinadlezhashchaya programme yad-
ra), na neraspredelyaemyh uchastkah pamyati (takih kak stranicy), kotorye mozhno
zanimat' tol'ko vremenno, a takzhe vo vneshnej pamyati (na ustrojstve vygruz-
ki).
S tochki zreniya realizacii proshche vsego dlya kopirovaniya parametrov v novyj
pol'zovatel'skij kontekst obratit'sya k steku yadra. Odnako, poskol'ku razmer
steka yadra, kak pravilo, ogranichivaetsya sistemoj, a takzhe poskol'ku paramet-
ry funkcii exec mogut imet' proizvol'nuyu dlinu, etot podhod sleduet sochetat'
s drugimi podhodami. Pri rassmotrenii drugih variantov obychno ostanavlivayut-
sya na sposobe hraneniya, obespechivayushchem naibolee bystryj dostup k strokam.
Esli dostup k stranicam pamyati v sisteme realizuetsya dovol'no prosto, stroki
sleduet razmeshchat' na stranicah, poskol'ku obrashchenie k operativnoj pamyati
osushchestvlyaetsya bystree, chem k vneshnej (ustrojstvu vygruzki).
Posle kopirovaniya parametrov funkcii exec v sistemnuyu pamyat' yadro otsoe-
dinyaet oblasti, ranee prisoedinennye k processu, ispol'zuya algoritm
detachreg. Neskol'ko pozzhe my eshche pogovorim o special'nyh dejstviyah, vypol-
nyaemyh v otnoshenii oblastej komand. K rassmatrivaemomu momentu process uzhe
lishen pol'zovatel'skogo konteksta i poetomu vozniknovenie v dal'nejshem lyuboj
oshibki neizbezhno budet privodit' k zaversheniyu processa po signalu. Takimi
oshibkami mogut byt' obrashchenie k prostranstvu, ne opisannomu v tablice oblas-
tej yadra, popytka zagruzit' programmu, imeyushchuyu nedopustimo bol'shoj razmer
ili ispol'zuyushchuyu oblasti s peresekayushchimisya adresami, i dr. YAdro vydelyaet i
prisoedinyaet k processu oblasti komand i dannyh, zagruzhaet v operativnuyu pa-
myat' soderzhimoe ispolnyaemogo fajla (algoritmy allocreg, attachreg i loadreg,
sootvetstvenno). Oblast' dannyh processa iznachal'no podelena na dve chasti:
---------------------------------------
(**) V PDP 11 "magicheskie chisla" imeyut znacheniya, sootvetstvuyushchie komandam
perehoda; pri vypolnenii etih komand v rannih versiyah sistemy upravle-
nie peredavalos' v raznye mesta programmy v zavisimosti ot razmera za-
golovka i ot tipa ispolnyaemogo fajla. |ta osobennost' bol'she ne ispol'-
zuetsya s teh por, kak sistema stala razrabatyvat'sya na yazyke Si.
206
dannye, inicializaciya kotoryh byla vypolnena vo vremya kompilyacii, i dannye,
ne opredelennye kompilyatorom ("bss"). Oblast' pamyati pervonachal'no vydelyaet-
sya dlya proinicializirovannyh dannyh. Zatem yadro uvelichivaet razmer oblasti
dannyh dlya razmeshcheniya dannyh tipa "bss" (algoritm growreg) i obnulyaet ih
znacheniya. Naposledok yadro vydelyaet i prisoedinyaet k processu oblast' steka i
otvodit prostranstvo pamyati dlya hraneniya parametrov funkcii exec. Esli para-
metry funkcii razmeshchayutsya na stranicah, te zhe stranicy mogut byt' ispol'zo-
vany pod stek. V protivnom sluchae parametry funkcii razmeshchayutsya v steke za-
dachi.
V prostranstve processa yadro stiraet adresa pol'zovatel'skih funkcij ob-
rabotki signalov, poskol'ku v novom pol'zovatel'skom kontekste oni teryayut
svoe znachenie. Odnako i v novom kontekste rekomendacii po ignorirovaniyu teh
ili inyh signalov ostayutsya v sile. YAdro ustanavlivaet v registrah dlya rezhima
zadachi znacheniya iz sohranennogo registrovogo konteksta, v chastnosti pervona-
chal'noe znachenie ukazatelya vershiny steka (sp) i schetchika komand (pc): pervo-
nachal'noe znachenie schetchika komand bylo zaneseno zagruzchikom v zagolovok
fajla. Dlya setuid-programm i dlya trassirovki processa yadro predprinimaet
osobye dejstviya, na kotoryh my eshche ostanovimsya vo vremya rassmotreniya glav 8
i 11, sootvetstvenno. Nakonec, yadro zapuskaet algoritm iput, osvobozhdaya in-
deks, vydelennyj po algoritmu namei v samom nachale vypolneniya funkcii exec.
Algoritmy namei i iput v funkcii exec vypolnyayut rol', podobnuyu toj, kotoruyu
oni vypolnyayut pri otkrytii i zakrytii fajla; sostoyanie fajla vo vremya vypol-
neniya funkcii exec pohozhe na sostoyanie otkrytogo fajla, esli ne prinimat' vo
vnimanie otsutstvie zapisi o fajle v tablice fajlov. Po vyhode iz funkcii
process ispolnyaet tekst novoj programmy. Tem ne menee, process ostaetsya tem
zhe, chto i do vypolneniya funkcii; ego identifikator ne izmenilsya, kak ne iz-
menilos' i ego mesto v ierarhii processov. Izmeneniyu podvergsya tol'ko pol'-
zovatel'skij kontekst processa.
+-------------------------------------------------------+
| main() |
| { |
| int status; |
| if (fork() == 0) |
| execl("/bin/date","date",0); |
| wait(&status); |
| } |
+-------------------------------------------------------+
Risunok 7.21. Primer ispol'zovaniya funkcii exec
V kachestve primera mozhno privesti programmu (Risunok 7.21), v kotoroj
sozdaetsya process-potomok, zapuskayushchij funkciyu exec. Srazu po zavershenii
funkcii fork process-roditel' i process-potomok nachinayut ispolnyat' nezavisi-
mo drug ot druga kopii odnoj i toj zhe programmy. K momentu vyzova proces-
som-potomkom funkcii exec v ego oblasti komand nahodyatsya instrukcii etoj
programmy, v oblasti dannyh raspolagayutsya stroki "/bin/date" i "date", a v
steke - zapisi, kotorye budut izvlecheny po vyhode iz exec. YAdro ishchet fajl
"/bin/date" v fajlovoj sisteme, obnaruzhiv ego, uznaet, chto ego mozhet ispol-
nit' lyuboj pol'zovatel', a takzhe to, chto on predstavlyaet soboj zagruzochnyj
modul', gotovyj dlya ispolneniya. Po usloviyu pervym parametrom funkcii exec,
vklyuchaemym v spisok parametrov argv, yavlyaetsya imya ispolnyaemogo fajla (pos-
lednyaya komponenta imeni puti poiska fajla). Takim obrazom, process imeet
dostup k imeni programmy na pol'zovatel'skom urovne, chto inogda mozhet oka-
zat'sya poleznym (***). Zatem yadro kopiruet stroki "/bin/date" i "date" vo
vnutrennyuyu strukturu hraneniya i osvobozhdaet oblasti komand, dannyh i steka,
zanimaemye processom. Processu vydelyayutsya novye oblasti komand, dannyh i
steka, v oblast' komand perepisyvaetsya komandnaya sekciya fajla "/bin/date", v
207
---------------------------------------
(***) Naprimer, v versii V standartnye programmy pereimenovaniya fajla (mv),
kopirovaniya fajla (cp) i komponovki fajla (ln), poskol'ku ispolnyayut
pohozhie dejstviya, vyzyvayut odin i tot zhe ispolnyaemyj fajl. Po imeni
vyzyvaemoj programmy process uznaet, kakie dejstviya v nastoyashchij moment
trebuyutsya pol'zovatelyu.
oblast' dannyh - sekciya dannyh fajla. YAdro vosstanavlivaet pervonachal'nyj
spisok parametrov (v dannom sluchae eto stroka simvolov "date") i pomeshchaet
ego v oblast' steka. Vyzvav funkciyu exec, process-potomok prekrashchaet vypol-
nenie staroj programmy i perehodit k vypolneniyu programmy
"date"; kogda programma "date" zavershitsya, process-roditel', ozhidayushchij etogo
momenta, poluchit kod zaversheniya funkcii exit.
Vplot' do nastoyashchego momenta my predpolagali, chto komandy i dannye raz-
meshchayutsya v raznyh sekciyah ispolnyaemoj programmy i, sledovatel'no, v raznyh
oblastyah tekushchego processa. Takoe razmeshchenie imeet dva osnovnyh preimushchest-
va: prostota organizacii zashchity ot nesankcionirovannogo dostupa i vozmozh-
nost' razdeleniya oblastej razlichnymi processami. Esli by komandy i dannye
nahodilis' v odnoj oblasti, sistema ne smogla by predotvratit' zatiranie ko-
mand, poskol'ku ej ne byli by izvestny adresa, po kotorym oni raspolagayutsya.
Esli zhe komandy i dannye nahodyatsya v raznyh oblastyah, sistema imeet vozmozh-
nost' pol'zovat'sya mehanizmami apparatnoj zashchity oblasti komand processa.
Kogda process sluchajno popytaetsya chto-to zapisat' v oblast', zanyatuyu koman-
dami, on poluchit otkaz, porozhdennyj sistemoj zashchity i privodyashchij obychno k
avarijnomu zaversheniyu processa.
+------------------------------------------------------------+
| #include |
| main() |
| { |
| int i,*ip; |
| extern f(),sigcatch(); |
| |
| ip = (int *)f; /* prisvoenie peremennoj ip znacheniya ad-|
| resa funkcii f */ |
| for (i = 0; i < 20; i++) |
| signal(i,sigcatch); |
| *ip = 1; /* popytka zateret' adres funkcii f */ |
| printf("posle prisvoeniya znacheniya ip\n"); |
| f(); |
| } |
| |
| f() |
| { |
| } |
| |
| sigcatch(n) |
| int n; |
| { |
| printf("prinyat signal %d\n",n); |
| exit(1); |
| } |
+------------------------------------------------------------+
Risunok 7.22. Primer programmy, vedushchej zapis' v oblast' komand
V kachestve primera mozhno privesti programmu (Risunok 7.22), kotoraya
prisvaivaet peremennoj ip znachenie adresa funkcii f i zatem delaet rasporya-
208
zhenie prinimat' vse signaly. Esli programma skompilirovana tak, chto komandy
i dannye raspolagayutsya v raznyh oblastyah, process, ispolnyayushchij programmu,
pri popytke zapisat' chto-to po adresu v ip vstretit porozhdennyj sistemoj za-
shchity otkaz, poskol'ku oblast' komand zashchishchena ot zapisi. Pri rabote na
komp'yutere AT&T 3B20 yadro posylaet processu signal SIGBUS, v drugih sistemah
vozmozhna posylka drugih signalov. Process prinimaet signal i zavershaetsya, ne
dojdya do vypolneniya komandy vyvoda na pechat' v procedure main. Odnako, esli
programma skompilirovana tak, chto komandy i dannye raspolagayutsya v odnoj ob-
lasti (v oblasti dannyh), yadro ne pojmet, chto process pytaetsya zateret' ad-
res funkcii f. Adres f stanet ravnym 1. Process ispolnit komandu vyvoda na
pechat' v procedure main, no kogda zapustit funkciyu f, proizojdet oshibka,
svyazannaya s popytkoj vypolneniya zapreshchennoj komandy. YAdro poshlet processu
signal SIGILL i process zavershitsya.
Raspolozhenie komand i dannyh v raznyh oblastyah oblegchaet poisk i predot-
vrashchenie oshibok adresacii. Tem ne menee, v rannih versiyah sistemy UNIX ko-
mandy i dannye razreshalos' raspolagat' v odnoj oblasti, poskol'ku na mashinah
PDP razmer processa byl sil'no ogranichen: programmy imeli men'shij razmer i
sushchestvenno men'shuyu segmentaciyu, esli komandy i dannye zanimali odnu i tu zhe
oblast'. V poslednih versiyah sistemy takih strogih ogranichenij na razmer
processa net i v dal'nejshem vozmozhnost' zagruzki komand i dannyh v odnu ob-
last' kompilyatorami ne budet podderzhivat'sya.
Vtoroe preimushchestvo razdel'nogo hraneniya komand i dannyh sostoit v voz-
mozhnosti sovmestnogo ispol'zovaniya oblastej processami. Esli process ne mo-
zhet vesti zapis' v oblast' komand, komandy processa ne preterpevayut nikakih
izmenenij s togo momenta, kak yadro zagruzilo ih v oblast' komand iz komand-
noj sekcii ispolnyaemogo fajla. Esli odin i tot zhe fajl ispolnyaetsya neskol'-
kimi processami, v celyah ekonomii pamyati oni mogut imet' odnu oblast' komand
na vseh. Takim obrazom, kogda yadro pri vypolnenii funkcii exec otvodit ob-
last' pod komandy processa, ono proveryaet, imeetsya li vozmozhnost' sovmestno-
go ispol'zovaniya processami komand ispolnyaemogo fajla, chto opredelyaetsya "ma-
gicheskim chislom" v zagolovke fajla. Esli da, to s pomoshch'yu algoritma xalloc
yadro ishchet sushchestvuyushchuyu oblast' s komandami fajla ili naznachaet novuyu v slu-
chae ee otsutstviya (sm. Risunok 7.23).
Ispolnyaya algoritm xalloc, yadro prosmatrivaet spisok aktivnyh oblastej v
poiskah oblasti s komandami fajla, indeks kotorogo sovpadaet s indeksom is-
polnyaemogo fajla. V sluchae ee otsutstviya yadro vydelyaet novuyu oblast' (algo-
ritm allocreg), prisoedinyaet ee k processu (algoritm attachreg), zagruzhaet
ee v pamyat' (algoritm loadreg) i zashchishchaet ot zapisi (read-only). Poslednij
shag predpolagaet, chto pri popytke processa zapisat' chto-libo v oblast' ko-
mand budet poluchen otkaz, vyzvannyj sistemoj zashchity pamyati. V sluchae obnaru-
zheniya oblasti s komandami fajla v spiske aktivnyh oblastej osushchestvlyaetsya
proverka ee nalichiya v pamyati (ona mozhet byt' libo zagruzhena v pamyat', libo
vygruzhena iz pamyati) i prisoedinenie ee k processu. V zavershenie vypolneniya
algoritma xalloc yadro snimaet s oblasti blokirovku, a pozdnee, sleduya algo-
ritmu detachreg pri vypolnenii funkcij exit ili exec, umen'shaet znachenie
schetchika oblastej. V tradicionnyh realizaciyah sistemy podderzhivaetsya tablica
komand, k kotoroj yadro obrashchaetsya v sluchayah, podobnyh opisannomu. Takim ob-
razom, sovokupnost' oblastej komand mozhno rassmatrivat' kak novuyu versiyu
etoj tablicy.
Napomnim, chto esli oblast' pri vypolnenii algoritma allocreg (Razdel
6.5.2) vydelyaetsya vpervye, yadro uvelichivaet znachenie schetchika ssylok na in-
deks, associirovannyj s oblast'yu, pri etom znachenie schetchika ssylok nami uzhe
bylo uvelicheno v samom nachale vypolneniya funkcii exec (algoritm namei). Pos-
kol'ku yadro umen'shaet znachenie schetchika tol'ko odin raz v zavershenie vypol-
neniya funkcii exec (po algoritmu iput), znachenie schetchika ssylok na indeks
fajla, associirovannogo s razdelyaemoj oblast'yu komand i ispolnyaemogo v nas-
toyashchij moment, ravno po men'shej mere 1. Poetomu kogda process razryvaet
svyaz' s fajlom (funkciya unlink), soderzhimoe fajla ostaetsya netronutym (ne
preterpevaet izmenenij). Posle zagruzki v pamyat' sam fajl yadru stanovitsya
209
nenuzhen, yadro interesuet tol'ko ukazatel' na kopiyu indeksa fajla v pamyati,
soderzhashchijsya v tablice oblastej; etot ukazatel' i budet identificirovat'
+------------------------------------------------------------+
| algoritm xalloc /* vydelenie i inicializaciya oblasti |
| komand */ |
| vhodnaya informaciya: indeks ispolnyaemogo fajla |
| vyhodnaya informaciya: otsutstvuet |
| { |
| esli (ispolnyaemyj fajl ne imeet otdel'noj oblasti komand)|
| vernut' upravlenie; |
| esli (uzhe imeetsya oblast' komand, associirovannaya s in- |
| deksom ispolnyaemogo fajla) |
| { |
| /* oblast' komand uzhe sushchestvuet ... podklyuchit'sya k |
| nej */ |
| zablokirovat' oblast'; |
| vypolnit' poka (soderzhimoe oblasti eshche ne dostupno) |
| { |
| /* operacii nad schetchikom ssylok, predohranyayushchie |
| ot global'nogo udaleniya oblasti |
| */ |
| uvelichit' znachenie schetchika ssylok na oblast'; |
| snyat' s oblasti blokirovku; |
| priostanovit'sya (poka soderzhimoe oblasti ne stanet|
| dostupnym); |
| zablokirovat' oblast'; |
| umen'shit' znachenie schetchika ssylok na oblast'; |
| } |
| prisoedinit' oblast' k processu (algoritm attachreg);|
| snyat' s oblasti blokirovku; |
| vernut' upravlenie; |
| } |
| /* interesuyushchaya nas oblast' komand ne sushchestvuet -- soz- |
| dat' novuyu */ |
| vydelit' oblast' komand (algoritm allocreg); /* oblast' |
| zabloki- |
| rovana */|
| esli (oblast' pomechena kak "neot®emlemaya") |
| otklyuchit' sootvetstvuyushchij flag; |
| podklyuchit' oblast' k virtual'nomu adresu, ukazannomu v |
| zagolovke fajla (algoritm attachreg); |
| esli (fajl imeet special'nyj format dlya sistemy s zameshche-|
| niem stranic) |
| /* etot sluchaj budet rassmotren v glave 9 */ |
| v protivnom sluchae /* fajl ne imeet special'nogo for-|
| mata */ |
| schitat' komandy iz fajla v oblast' (algoritm |
| loadreg); |
| izmenit' rezhim zashchity oblasti v zapisi chastnoj tablicy |
| oblastej processa na "read-only"; |
| snyat' s oblasti blokirovku; |
| } |
+------------------------------------------------------------+
Risunok 7.23. Algoritm vydeleniya oblastej komand
fajl, svyazannyj s oblast'yu. Esli by znachenie schetchika ssylok stalo ravnym 0,
210
yadro moglo by peredat' kopiyu indeksa v pamyati drugomu fajlu, tem samym delaya
somnitel'nym znachenie ukazatelya na indeks v zapisi tablicy oblastej: esli by
pol'zovatelyu prishlos' ispolnit' novyj fajl, ispol'zuya funkciyu exec, yadro po
oshibke svyazalo by ego s oblast'yu komand starogo fajla. |ta problema ustranya-
etsya blagodarya tomu, chto yadro pri vypolnenii algoritma allocreg uvelichivaet
znachenie schetchika ssylok na indeks, preduprezhdaya tem samym perenaznachenie
indeksa v pamyati drugomu fajlu. Kogda process vo vremya vypolneniya funkcij
exit ili exec otsoedinyaet oblast' komand, yadro umen'shaet znachenie schetchika
ssylok na indeks (po algoritmu freereg), esli tol'ko svyaz' indeksa s ob-
last'yu ne pomechena kak "neot®emlemaya".
Tablica indeksov Tablica oblastej
+----------------+ chto moglo by proi- +----------------+
| - | zojti, esli by schet- | - |
| - | chik ssylok na indeks | - |
| - | fajla /bin/date byl | - |
| - | raven 0 +----------------+
| - | | oblast' komand |
| - | -- - - - - -|- dlya fajla |
| - | | | /bin/who |
+----------------+ - +----------------+
| kopiya indeksa -|- - - - - -+ | - |
| fajla /bin/date| | - |
| v pamyati <+-----------+ | - |
+----------------+ | +----------------+
| - | | | oblast' komand |
| - | +-----------+- dlya fajla |
| - | ukazatel' na| /bin/date |
| - | kopiyu indek-+----------------+
| - | sa v pamyati | - |
| - | | - |
+----------------+ +----------------+
Risunok 7.24. Vzaimosvyaz' mezhdu tablicej indeksov i tablicej
oblastej v sluchae sovmestnogo ispol'zovaniya
processami odnoj oblasti komand
Rassmotrim v kachestve primera situaciyu, privedennuyu na Risunke 7.21, gde
pokazana vzaimosvyaz' mezhdu strukturami dannyh v processe vypolneniya funkcii
exec po otnosheniyu k fajlu "/bin/date" pri uslovii raspolozheniya komand i dan-
nyh fajla v raznyh oblastyah. Kogda process ispolnyaet fajl "/bin/date" pervyj
raz, yadro naznachaet dlya komand fajla tochku vhoda v tablice oblastej (Risunok
7.24) i po zavershenii vypolneniya funkcii exec ostavlyaet schetchik ssylok na
indeks ravnym 1. Kogda fajl "/bin/date" zavershaetsya, yadro zapuskaet algorit-
my detachreg i freereg, sbrasyvaya znachenie schetchika ssylok v 0. Odnako, esli
yadro v pervom sluchae ne uvelichilo znachenie schetchika, ono po zavershenii funk-
cii exec ostanetsya ravnym 0 i indeks na vsem protyazhenii vypolneniya processa
budet nahodit'sya v spiske svobodnyh indeksov. Predpolozhim, chto v eto vremya
svobodnyj indeks ponadobilsya processu, zapustivshemu s pomoshch'yu funkcii exec
fajl "/bin/who", togda yadro mozhet vydelit' etomu processu indeks, ranee pri-
nadlezhavshij fajlu "/ bin/date". Prosmatrivaya tablicu oblastej v poiskah in-
deksa fajla "/bin/who", yadro vmesto nego vybralo by indeks fajla
"/bin/date". Schitaya, chto oblast' soderzhit komandy fajla "/bin/who", yadro is-
polnilo by sovsem ne tu programmu. Poetomu znachenie schetchika ssylok na in-
deks aktivnogo fajla, svyazannogo s razdelyaemoj oblast'yu komand, dolzhno byt'
ne men'she edinicy, chtoby yadro ne moglo perenaznachit' indeks drugomu fajlu.
Vozmozhnost' sovmestnogo ispol'zovaniya razlichnymi processami odnih i teh
zhe oblastej komand pozvolyaet ekonomit' vremya, zatrachivaemoe na zapusk prog-
rammy s pomoshch'yu funkcii exec. Administratory sistemy mogut s pomoshch'yu sistem-
211
noj funkcii (i komandy) chmod ustanavlivat' dlya chasto ispolnyaemyh fajlov re-
zhim "sticky-bit", sushchnost' kotorogo zaklyuchaetsya v sleduyushchem. Kogda process
ispolnyaet fajl, dlya kotorogo ustanovlen rezhim "sticky-bit", yadro ne osvobozh-
daet oblast' pamyati, otvedennuyu pod komandy fajla, otsoedinyaya oblast' ot
processa vo vremya vypolneniya funkcij exit ili exec, dazhe esli znachenie schet-
chika ssylok na indeks stanovitsya ravnym 0. YAdro ostavlyaet oblast' komand v
pervonachal'nom vide, pri etom znachenie schetchika ssylok na indeks ravno 1,
pust' dazhe oblast' ne podklyuchena bol'she ni k odnomu iz processov. Esli zhe
fajl budet eshche raz zapushchen na vypolnenie (uzhe drugim processom), yadro v tab-
lice oblastej obnaruzhit zapis', sootvetstvuyushchuyu oblasti s komandami fajla.
Process zatratit na zapusk fajla men'she vremeni, tak kak emu ne pridetsya chi-
tat' komandy iz fajlovoj sistemy. Esli komandy fajla vse eshche nahodyatsya v pa-
myati, v ih peremeshchenii ne budet neobhodimosti; esli zhe komandy vygruzheny vo
vneshnyuyu pamyat', budet gorazdo bystree zagruzit' ih iz vneshnej pamyati, chem iz
fajlovoj sistemy (sm. ob etom v glave 9).
YAdro udalyaet iz tablicy oblastej zapisi, sootvetstvuyushchie oblastyam s ko-
mandami fajla, dlya kotorogo ustanovlen rezhim "sticky-bit" (inymi slovami,
kogda oblast' pomechena kak "neot®emlemaya" chast' fajla ili processa), v sle-
duyushchih sluchayah:
1. Esli process otkryl fajl dlya zapisi, v rezul'tate sootvetstvuyushchih opera-
cij soderzhimoe fajla izmenitsya, pri etom budet zatronuto i soderzhimoe
oblasti.
2. Esli process izmenil prava dostupa k fajlu (chmod), otmeniv rezhim
"sticky-bit", fajl ne dolzhen ostavat'sya v tablice oblastej.
3. Esli process razorval svyaz' s fajlom (unlink), on ne smozhet bol'she is-
polnyat' etot fajl, poskol'ku u fajla ne budet tochki vhoda v fajlovuyu
sistemu; sledovatel'no, i vse ostal'nye processy ne budut imet' dostupa
k zapisi v tablice oblastej, sootvetstvuyushchej fajlu. Poskol'ku oblast' s
komandami fajla bol'she ne ispol'zuetsya, yadro mozhet osvobodit' ee vmeste
s ostal'nymi resursami, zanimaemymi fajlom.
4. Esli process demontiruet fajlovuyu sistemu, fajl perestaet byt' dostupnym
i ni odin iz processov ne mozhet ego ispolnit'. V ostal'nom - vse kak v
predydushchem sluchae.
5. Esli yadro ispol'zovalo uzhe vse prostranstvo vneshnej pamyati, otvedennoe
pod vygruzku zadach, ono pytaetsya osvobodit' chast' pamyati za schet oblas-
tej, imeyushchih pometku "sticky-bit", no ne ispol'zuemyh v nastoyashchij mo-
ment. Nesmotrya na to, chto eti oblasti mogut vskore ponadobit'sya drugim
processam, potrebnosti yadra yavlyayutsya bolee srochnymi.
V pervyh dvuh sluchayah oblast' komand s pometkoj "sticky-bit" dolzhna byt'
osvobozhdena, poskol'ku ona bol'she ne otrazhaet tekushchee sostoyanie fajla. V os-
tal'nyh sluchayah eto delaetsya iz prakticheskih soobrazhenij. Konechno zhe yadro
osvobozhdaet oblast' tol'ko pri tom uslovii, chto ona ne ispol'zuetsya ni odnim
iz vypolnyayushchihsya processov (schetchik ssylok na nee imeet nulevoe znachenie); v
protivnom sluchae eto privelo by k avarijnomu zaversheniyu vypolneniya sistemnyh
funkcij open, unlink i umount (sluchai 1, 3 i 4, sootvetstvenno).
Esli process zapuskaet s pomoshch'yu funkcii exec samogo sebya, algoritm vy-
polneniya funkcii neskol'ko uslozhnyaetsya. Po komande
sh script
komandnyj processor shell porozhdaet novyj process (novuyu vetv'), kotoryj
iniciiruet zapusk shell'a (s pomoshch'yu funkcii exec) i ispolnyaet komandy fajla
"script". Esli process zapuskaet samogo sebya i pri etom ego oblast' komand
dopuskaet sovmestnoe ispol'zovanie, yadru pridetsya sledit' za tem, chtoby pri
obrashchenii vetvej processa k indeksam i oblastyam ne voznikali vzaimnye bloki-
rovki. Inache govorya, yadro ne mozhet, ne snimaya blokirovki so "staroj" oblasti
komand, popytat'sya zablokirovat' "novuyu" oblast', poskol'ku na samom dele
eto odna i ta zhe oblast'. Vmesto etogo yadro prosto ostavlyaet "staruyu" ob-
212
last' komand prisoedinennoj k processu, tak kak v lyubom sluchae ej predstoit
povtornoe ispol'zovanie.
Obychno processy vyzyvayut funkciyu exec posle funkcii fork; takim obrazom,
vo vremya vypolneniya funkcii fork process-potomok kopiruet adresnoe prostran-
stvo svoego roditelya, no sbrasyvaet ego vo vremya vypolneniya funkcii exec i
po sravneniyu s roditelem ispolnyaet obraz uzhe drugoj programmy. Ne bylo by
bolee estestvennym ob®edinit' dve sistemnye funkcii v odnu, kotoraya by zag-
ruzhala programmu i ispolnyala ee pod vidom novogo processa ? Richi vyskazal
predpolozhenie, chto vozniknovenie fork i exec kak otdel'nyh sistemnyh funkcij
obyazano tomu, chto pri sozdanii sistemy UNIX funkciya fork byla dobavlena k
uzhe sushchestvuyushchemu obrazu yadra sistemy (sm. [Ritchie 84a], str.1584). Odnako,
razdelenie fork i exec vazhno i s funkcional'noj tochki zreniya, poskol'ku v
etom sluchae processy mogut rabotat' s deskriptorami fajlov standartnogo vvo-
da-vyvoda nezavisimo, povyshaya tem samym "elegantnost'" ispol'zovaniya kana-
lov. Primer, pokazyvayushchij ispol'zovanie etoj vozmozhnosti, privoditsya v raz-
dele 7.8.
7.6 KOD IDENTIFIKACII POLXZOVATELYA PROCESSA
YAdro svyazyvaet s processom dva koda identifikacii pol'zovatelya, ne zavi-
syashchih ot koda identifikacii processa: real'nyj (dejstvitel'nyj) kod identi-
fikacii pol'zovatelya i ispolnitel'nyj kod ili setuid (ot "set user ID" - us-
tanovit' kod identifikacii pol'zovatelya, pod kotorym process budet ispol-
nyat'sya). Real'nyj kod identificiruet pol'zovatelya, nesushchego otvetstvennost'
za vypolnyayushchijsya process. Ispolnitel'nyj kod ispol'zuetsya dlya ustanovki prav
sobstvennosti na vnov' sozdavaemye fajly, dlya proverki prav dostupa k fajlu
i razresheniya na posylku signalov processam cherez funkciyu kill. Processy mo-
gut izmenyat' ispolnitel'nyj kod, zapuskaya s pomoshch'yu funkcii exec programmu
setuid ili zapuskaya funkciyu setuid v yavnom vide.
Programma setuid predstavlyaet soboj ispolnyaemyj fajl, imeyushchij v pole re-
zhima dostupa ustanovlennyj bit setuid. Kogda process zapuskaet programmu
setuid na vypolnenie, yadro zapisyvaet v polya, soderzhashchie real'nye kody iden-
tifikacii, v tablice processov i v prostranstve processa kod identifikacii
vladel'ca fajla. CHtoby kak-to razlichat' eti polya, nazovem odno iz nih, koto-
roe hranitsya v tablice processov, sohranennym kodom identifikacii pol'zova-
telya. Rassmotrim primer, illyustriruyushchij raznicu v soderzhimom etih polej.
Sintaksis vyzova sistemnoj funkcii setuid:
setuid(uid)
gde uid - novyj kod identifikacii pol'zovatelya. Rezul'tat vypolneniya funkcii
zavisit ot tekushchego znacheniya real'nogo koda identifikacii. Esli real'nyj kod
identifikacii pol'zovatelya processa, vyzyvayushchego funkciyu, ukazyvaet na su-
perpol'zovatelya, yadro zapisyvaet znachenie uid v polya, hranyashchie real'nyj i
ispolnitel'nyj kody identifikacii, v tablice processov i v prostranstve pro-
cessa. Esli eto ne tak, yadro zapisyvaet uid v kachestve znacheniya ispolnitel'-
nogo koda identifikacii v prostranstve processa i to tol'ko v tom sluchae,
esli znachenie uid ravno znacheniyu real'nogo koda ili znacheniyu sohranennogo
koda. V protivnom sluchae funkciya vozvrashchaet vyzyvayushchemu processu oshibku.
Process nasleduet real'nyj i ispolnitel'nyj kody identifikacii u svoego ro-
ditelya (v rezul'tate vypolneniya funkcii fork) i sohranyaet ih znacheniya posle
vyzova funkcii exec.
Na Risunke 7.25 privedena programma, demonstriruyushchaya ispol'zovanie funk-
cii setuid. Predpolozhim, chto ispolnyaemyj fajl, poluchennyj v rezul'tate tran-
slyacii ishodnogo teksta programmy, imeet vladel'ca s imenem "maury" (kod
identifikacii 8319) i ustanovlennyj bit setuid; pravo ego ispolneniya predos-
tavleno vsem pol'zovatelyam. Dopustim takzhe, chto pol'zovateli "mjb" (kod
identifikacii 5088) i "maury" yavlyayutsya vladel'cami fajlov s temi zhe imenami,
kazhdyj iz kotoryh dostupen tol'ko dlya chteniya i tol'ko svoemu vladel'cu. Vo
vremya ispolneniya programmy pol'zovatelyu "mjb" vyvoditsya sleduyushchaya informa-
213
ciya:
uid 5088 euid 8319
fdmjb -1 fdmaury 3
after setuid(5088): uid 5088 euid 5088
fdmjb 4 fdmaury -1
after setuid(8319): uid 5088 euid 8319
Sistemnye funkcii getuid i geteuid vozvrashchayut znacheniya real'nogo i ispolni-
tel'nogo kodov identifikacii pol'zovatelej processa, dlya
+------------------------------------------------------------+
| #include |
| main() |
| { |
| int uid,euid,fdmjb,fdmaury; |
| |
| uid = getuid(); /* poluchit' real'nyj UID */ |
| euid = geteuid(); /* poluchit' ispolnitel'nyj UID */|
| printf("uid %d euid %d\n",uid,euid); |
| |
| fdmjb = open("mjb",O_RDONLY); |
| fdmaury = open("maury",O_RDONLY); |
| printf("fdmjb %d fdmaury %d\n",fdmjb,fdmaury); |
| |
| setuid(uid); |
| printf("after setuid(%d): uid %d euid %d\n",uid, |
| getuid(),geteuid()); |
| |
| fdmjb = open("mjb",O_RDONLY); |
| fdmaury = open("maury",O_RDONLY); |
| printf("fdmjb %d fdmaury %d\n",fdmjb,fdmaury); |
| |
| setuid(uid); |
| printf("after setuid(%d): uid %d euid %d\n",euid, |
| getuid(),geteuid()); |
| } |
+------------------------------------------------------------+
Risunok 7.25. Primer vypolneniya programmy setuid
pol'zovatelya "mjb" eto, sootvetstvenno, 5088 i 8319. Poetomu process ne mo-
zhet otkryt' fajl "mjb" (ibo on imeet ispolnitel'nyj kod identifikacii pol'-
zovatelya (8319), ne razreshayushchij proizvodit' chtenie fajla), no mozhet otkryt'
fajl "maury". Posle vyzova funkcii setuid, v rezul'tate vypolneniya kotoroj v
pole ispolnitel'nogo koda identifikacii pol'zovatelya ("mjb") zanositsya zna-
chenie real'nogo koda identifikacii, na pechat' vyvodyatsya znacheniya i togo, i
drugogo koda identifikacii pol'zovatelya "mjb": oba ravny 5088. Teper' pro-
cess mozhet otkryt' fajl "mjb", poskol'ku on ispolnyaetsya pod kodom identifi-
kacii pol'zovatelya, imeyushchego pravo na chtenie iz fajla, no ne mozhet otkryt'
fajl "maury". Nakonec, posle zaneseniya v pole ispolnitel'nogo koda identifi-
kacii znacheniya, sohranennogo funkciej setuid (8319), na pechat' snova vyvo-
dyatsya znacheniya 5088 i 8319. My pokazali, takim obrazom, kak s pomoshch'yu prog-
rammy setuid process mozhet izmenyat' znachenie koda identifikacii pol'zovate-
lya, pod kotorym on ispolnyaetsya.
Vo vremya vypolneniya programmy pol'zovatelem "maury" na pechat' vyvoditsya
sleduyushchaya informaciya:
uid 8319 euid 8319
fdmjb -1 fdmaury 3
after setuid(8319): uid 8319 euid 8319
fdmjb -1 fdmaury 4
214
after setuid(8319): uid 8319 euid 8319
Real'nyj i ispolnitel'nyj kody identifikacii pol'zovatelya vo vremya vypolne-
niya programmy ostayutsya ravny 8319: process mozhet otkryt' fajl "maury", no ne
mozhet otkryt' fajl "mjb". Ispolnitel'nyj kod, hranyashchijsya v prostranstve pro-
cessa, zanesen tuda v rezul'tate poslednego ispolneniya funkcii ili programmy
setuid; tol'ko ego znacheniem opredelyayutsya prava dostupa processa k fajlu. S
pomoshch'yu funkcii setuid ispolnitel'nomu kodu mozhet byt' prisvoeno znachenie
sohranennogo koda (iz tablicy processov), t.e. to znachenie, kotoroe ispolni-
tel'nyj kod imel v samom nachale.
Primerom programmy, ispol'zuyushchej vyzov sistemnoj funkcii setuid, mozhet
sluzhit' programma registracii pol'zovatelej v sisteme (login). Parametrom
funkcii setuid pri etom yavlyaetsya kod identifikacii superpol'zovatelya, takim
obrazom, programma login ispolnyaetsya pod kodom superpol'zovatelya iz kornya
sistemy. Ona zaprashivaet u pol'zovatelya razlichnuyu informaciyu, naprimer, imya
i parol', i esli eta informaciya prinimaetsya sistemoj, programma zapuskaet
funkciyu setuid, chtoby ustanovit' znacheniya real'nogo i ispolnitel'nogo kodov
identifikacii v sootvetstvii s informaciej, postupivshej ot pol'zovatelya (pri
etom ispol'zuyutsya dannye fajla "/etc/passwd"). V zaklyuchenie programma login
iniciiruet zapusk komandnogo processora shell, kotoryj budet ispolnyat'sya pod
ukazannymi pol'zovatel'skimi kodami identifikacii.
Primerom setuid-programmy yavlyaetsya programma, realizuyushchaya komandu mkdir.
V razdele 5.8 uzhe govorilos' o tom, chto sozdat' katalog mozhet tol'ko pro-
cess, vypolnyayushchijsya pod upravleniem superpol'zovatelya. Dlya togo, chtoby pre-
dostavit' vozmozhnost' sozdaniya katalogov prostym pol'zovatelyam, komanda
mkdir byla vypolnena v vide setuid-programmy, prinadlezhashchej kornyu sistemy i
imeyushchej prava superpol'zovatelya. Na vremya ispolneniya komandy mkdir process
poluchaet prava superpol'zovatelya, sozdaet katalog, ispol'zuya funkciyu mknod,
i predostavlyaet prava sobstvennosti i dostupa k katalogu istinnomu pol'zova-
telyu processa.
7.7 IZMENENIE RAZMERA PROCESSA
S pomoshch'yu sistemnoj funkcii brk process mozhet uvelichivat' i umen'shat'
razmer oblasti dannyh. Sintaksis vyzova funkcii:
brk(endds);
gde endds - starshij virtual'nyj adres oblasti dannyh processa (adres verhnej
granicy). S drugoj storony, pol'zovatel' mozhet obratit'sya k funkcii sleduyu-
shchim obrazom:
oldendds = sbrk(increment);
gde oldendds - tekushchij adres verhnej granicy oblasti, increment - chislo
bajt, na kotoroe izmenyaetsya znachenie oldendds v rezul'tate vypolneniya funk-
cii. Sbrk - eto imya standartnoj bibliotechnoj podprogrammy na Si, vyzyvayushchej
funkciyu brk. Esli razmer oblasti dannyh processa v rezul'tate vypolneniya
funkcii uvelichivaetsya, vnov' vydelyaemoe prostranstvo imeet virtual'nye adre-
sa, smezhnye s adresami uvelichivaemoj oblasti; takim obrazom, virtual'noe ad-
resnoe prostranstvo processa rasshiryaetsya. Pri etom yadro proveryaet, ne prevy-
shaet li novyj razmer processa maksimal'no-dopustimoe znachenie, prinyatoe dlya
nego v sisteme, a takzhe ne nakladyvaetsya li novaya oblast' dannyh processa na
virtual'noe adresnoe prostranstvo, otvedennoe ranee dlya drugih celej (Risu-
nok 7.26). Esli vse v poryadke, yadro zapuskaet algoritm growreg, prisoedinyaya
k oblasti dannyh vneshnyuyu pamyat' (naprimer, tablicy stranic) i uvelichivaya
znachenie polya, opisyvayushchego razmer processa. V sisteme s zameshcheniem stranic
yadro takzhe otvodit pod novuyu oblast' prostranstvo osnovnoj pamyati i obnulyaet
ego soderzhimoe; esli svobodnoj pamyati net, yadro osvobozhdaet pamyat' putem
vygruzki processa (bolee podrobno ob etom my pogovorim v glave 9). Esli s
pomoshch'yu funkcii brk process umen'shaet razmer oblasti dannyh, yadro osvobozhda-
et chast' ranee vydelennogo adresnogo prostranstva; kogda process popytaetsya
obratit'sya k dannym po virtual'nym adresam, prinadlezhashchim osvobozhdennomu
215
prostranstvu, on stolknetsya s oshibkoj adresacii.
+------------------------------------------------------------+
| algoritm brk |
| vhodnaya informaciya: novyj adres verhnej granicy oblasti |
| dannyh |
| vyhodnaya informaciya: staryj adres verhnej granicy oblasti |
| dannyh |
| { |
| zablokirovat' oblast' dannyh processa; |
| esli (razmer oblasti uvelichivaetsya) |
| esli (novyj razmer oblasti imeet nedopustimoe zna-|
| chenie) |
| { |
| snyat' blokirovku s oblasti; |
| vernut' (oshibku); |
| } |
| izmenit' razmer oblasti (algoritm growreg); |
| obnulit' soderzhimoe prisoedinyaemogo prostranstva; |
| snyat' blokirovku s oblasti dannyh; |
| } |
+------------------------------------------------------------+
Risunok 7.26. Algoritm vypolneniya funkcii brk
Na Risunke 7.27 priveden primer programmy, ispol'zuyushchej funkciyu brk, i
vyhodnye dannye, poluchennye v rezul'tate ee progona na mashine AT&T 3B20.
Vyzvav funkciyu signal i rasporyadivshis' prinimat' signaly o narushenii segmen-
tacii (segmentation violation), process obrashchaetsya k podprogramme sbrk i vy-
vodit na pechat' pervonachal'noe znachenie adresa verhnej granicy oblasti dan-
nyh. Zatem v cikle, ispol'zuya schetchik simvolov, process zapolnyaet oblast'
dannyh do teh por, poka ne obratitsya k adresu, raspolozhennomu za predelami
oblasti, tem samym davaya povod dlya signala o narushenii segmentacii. Poluchiv
signal, funkciya obrabotki signala vyzyvaet podprogrammu sbrk dlya togo, chtoby
prisoedinit' k oblasti dopolnitel'no 256 bajt pamyati; process prodolzhaetsya s
tochki preryvaniya, zapolnyaya informaciej vnov' vydelennoe prostranstvo pamyati
i t.d. Na mashinah so stranichnoj organizaciej pamyati, takih kak 3B20, nablyu-
daetsya interesnyj fenomen. Stranica yavlyaetsya naimen'shej edinicej pamyati, s
kotoroj rabotayut mehanizmy apparatnoj zashchity, poetomu apparatnye sredstva ne
v sostoyanii ustanovit' oshibku v granichnoj situacii, kogda process pytaetsya
zapisat' informaciyu po adresam, prevyshayushchim verhnyuyu granicu oblasti dannyh,
no prinadlezhashchim t.n. "polulegal'noj" stranice (stranice, ne polnost'yu zanya-
toj oblast'yu dannyh processa). |to vidno iz rezul'tatov vypolneniya program-
my, vyvedennyh na pechat' (Risunok 7.27): pervyj raz podprogramma sbrk vozv-
rashchaet znachenie 140924, to est' adres, ne dotyagivayushchij 388 bajt do konca
stranicy, kotoraya na mashine 3B20 imeet razmer 2 Kbajta. Odnako process polu-
chit oshibku tol'ko v tom sluchae, esli obratitsya k sleduyushchej stranice pamyati,
to est' k lyubomu adresu, nachinaya s 141312. Funkciya obrabotki signala pribav-
lyaet k adresu verhnej granicy oblasti 256, delaya ego ravnym 141180 i, takim
obrazom, ostavlyaya ego v predelah tekushchej stranicy. Sledovatel'no, process
tut zhe snova poluchit oshibku, vydav na pechat' adres 141312. Ispolniv podprog-
rammu sbrk eshche raz, yadro vydelyaet pod dannye processa novuyu stranicu pamyati,
tak chto process poluchaet vozmozhnost' adresovat' dopolnitel'no 2 Kbajta pamya-
ti, do adresa 143360, dazhe esli verhnyaya granica oblasti raspolagaetsya nizhe.
Poluchiv oshibku, process dolzhen budet vosem' raz obratit'sya k podprogramme
sbrk, prezhde chem smozhet prodolzhit' vypolnenie osnovnoj programmy. Takim ob-
razom, process mozhet inogda vyhodit' za oficial'nuyu verhnyuyu granicu oblasti
dannyh, hotya eto i nezhelatel'nyj moment v praktike programmirovaniya.
216
Kogda stek zadachi perepolnyaetsya, yadro avtomaticheski uvelichivaet ego raz-
mer, vypolnyaya algoritm, pohozhij na algoritm funkcii brk. Pervonachal'no stek
zadachi imeet razmer, dostatochnyj dlya hraneniya parametrov funkcii exec, odna-
ko pri vypolnenii processa
+-------------------------------------------------------+
| #include |
| char *cp; |
| int callno; |
| |
| main() |
| { |
| char *sbrk(); |
| extern catcher(); |
| |
| signal(SIGSEGV,catcher); |
| cp = sbrk(0); |
| printf("original brk value %u\n",cp); |
| for (;;) |
| *cp++ = 1; |
| } |
| |
| catcher(signo); |
| int signo; |
| { |
| callno++; |
| printf("caught sig %d %dth call at addr %u\n", |
| signo,callno,cp); |
| sbrk(256); |
| signal(SIGSEGV,catcher); |
| } |
+-------------------------------------------------------+
+-------------------------------------------+
| original brk value 140924 |
| caught sig 11 1th call at addr 141312 |
| caught sig 11 2th call at addr 141312 |
| caught sig 11 3th call at addr 143360 |
| ...(tot zhe adres pechataetsya do 10-go |
| vyzova podprogrammy sbrk) |
| caught sig 11 10th call at addr 143360 |
| caught sig 11 11th call at addr 145408 |
| ...(tot zhe adres pechataetsya do 18-go |
| vyzova podprogrammy sbrk) |
| caught sig 11 18th call at addr 145408 |
| caught sig 11 19th call at addr 145408 |
| - |
| - |
+-------------------------------------------+
Risunok 7.27. Primer programmy, ispol'zuyushchej funkciyu brk, i
rezul'taty ee kontrol'nogo progona
etot stek mozhet perepolnit'sya. Perepolnenie steka privodit k oshibke adresa-
cii, svidetel'stvuyushchej o popytke processa obratit'sya k yachejke pamyati za pre-
delami otvedennogo adresnogo prostranstva. YAdro ustanavlivaet prichinu voz-
niknoveniya oshibki, sravnivaya tekushchee znachenie ukazatelya vershiny steka s raz-
merom oblasti steka. Pri rasshirenii oblasti steka yadro ispol'zuet tochno ta-
koj zhe mehanizm, chto i dlya oblasti dannyh. Na vyhode iz preryvaniya process
217
+------------------------------------------------------------+
| /* chtenie komandnoj stroki do simvola konca fajla */ |
| while (read(stdin,buffer,numchars)) |
| { |
| /* sintaksicheskij razbor komandnoj stroki */ |
| if (/* komandnaya stroka soderzhit & */) |
| amper = 1; |
| else |
| amper = 0; |
| /* dlya komand, ne yavlyayushchihsya konstrukciyami komandnogo |
| yazyka shell */ |
| if (fork() == 0) |
| { |
| /* pereadresaciya vvoda-vyvoda ? */ |
| if (/* pereadresaciya vyvoda */) |
| { |
| fd = creat(newfile,fmask); |
| close(stdout); |
| dup(fd); |
| close(fd); |
| /* stdout teper' pereadresovan */ |
| } |
| if (/* ispol'zuyutsya kanaly */) |
| { |
| pipe(fildes); |
| |
+------------------------------------------------------------+
Risunok 7.28. Osnovnoj cikl programmy shell
imeet oblast' steka neobhodimogo dlya prodolzheniya raboty razmera.
7.8 KOMANDNYJ PROCESSOR SHELL
Teper' u nas est' dostatochno materiala, chtoby perejti k ob®yasneniyu prin-
cipov raboty komandnogo processora shell. Sam komandnyj processor namnogo
slozhnee, chem to, chto my o nem zdes' budem izlagat', odnako vzaimodejstvie
processov my uzhe mozhem rassmotret' na primere real'noj programmy. Na Risunke
7.28 priveden fragment osnovnogo cikla programmy shell, demonstriruyushchij
asinhronnoe vypolnenie processov, perenaznachenie vyvoda i ispol'zovanie ka-
nalov.
Shell schityvaet komandnuyu stroku iz fajla standartnogo vvoda i interpre-
tiruet ee v sootvetstvii s ustanovlennym naborom pravil. Deskriptory fajlov
standartnogo vvoda i standartnogo vyvoda, ispol'zuemye registracionnym
shell'om, kak pravilo, ukazyvayut na terminal, s kotorogo pol'zovatel' regis-
triruetsya v sisteme (sm. glavu 10). Esli shell uznaet vo vvedennoj stroke
konstrukciyu sobstvennogo komandnogo yazyka (naprimer, odnu iz komand cd, for,
while i t.p.), on ispolnyaet komandu svoimi silami, ne pribegaya k sozdaniyu
novyh processov; v protivnom sluchae komanda interpretiruetsya kak imya ispol-
nyaemogo fajla.
Komandnye stroki prostejshego vida soderzhat imya programmy i neskol'ko pa-
rametrov, naprimer:
who
grep -n include *.c
ls -l
218
+------------------------------------------------------------+
| if (fork() == 0) |
| { |
| /* pervaya komponenta komandnoj stroki */|
| close(stdout); |
| dup(fildes[1]); |
| close(fildes[1]); |
| close(fildes[0]); |
| /* standartnyj vyvod napravlyaetsya v ka- |
| nal */ |
| /* komandu ispolnyaet porozhdennyj pro- |
| cess */ |
| execlp(command1,command1,0); |
| } |
| /* vtoraya komponenta komandnoj stroki */ |
| close(stdin); |
| dup(fildes[0]); |
| close(fildes[0]); |
| close(fildes[1]); |
| /* standartnyj vvod budet proizvodit'sya iz|
| kanala */ |
| } |
| execve(command2,command2,0); |
| } |
| /* s etogo mesta prodolzhaetsya vypolnenie roditel'skogo |
| * processa... |
| * process-roditel' zhdet zaversheniya vypolneniya potomka,|
| * esli eto vytekaet iz vvedennoj stroki |
| * / |
| if (amper == 0) |
| retid = wait(&status); |
| } |
+------------------------------------------------------------+
Risunok 7.28. Osnovnoj cikl programmy shell (prodolzhenie)
Shell "vetvitsya" (fork) i porozhdaet novyj process, kotoryj i zapuskaet prog-
rammu, ukazannuyu pol'zovatelem v komandnoj stroke. Roditel'skij process
(shell) dozhidaetsya zaversheniya potomka i povtoryaet cikl schityvaniya sleduyushchej
komandy.
Esli process zapuskaetsya asinhronno (na fone osnovnoj programmy), kak v
sleduyushchem primere
nroff -mm bigdocument &
shell analiziruet nalichie simvola ampersand (&) i zanosit rezul'tat proverki
vo vnutrennyuyu peremennuyu amper. V konce osnovnogo cikla shell obrashchaetsya k
etoj peremennoj i, esli obnaruzhivaet v nej priznak nalichiya simvola, ne vy-
polnyaet funkciyu wait, a tut zhe povtoryaet cikl schityvaniya sleduyushchej komandy.
Iz risunka vidno, chto process-potomok po zavershenii funkcii fork polucha-
et dostup k komandnoj stroke, prinyatoj shell'om. Dlya togo, chtoby pereadreso-
vat' standartnyj vyvod v fajl, kak v sleduyushchem primere
nroff -mm bigdocument > output
process-potomok sozdaet fajl vyvoda s ukazannym v komandnoj stroke imenem;
219
esli fajl ne udaetsya sozdat' (naprimer, ne razreshen dostup k katalogu), pro-
cess-potomok tut zhe zavershaetsya. V protivnom sluchae process-potomok zakryva-
et staryj fajl standartnogo vyvoda i perenaznachaet s pomoshch'yu funkcii dup
deskriptor etogo fajla novomu fajlu. Staryj deskriptor sozdannogo fajla zak-
ryvaetsya i sohranyaetsya dlya zapuskaemoj programmy. Podobnym zhe obrazom shell
perenaznachaet i standartnyj vvod i standartnyj vyvod oshibok.
+-----------+
| Shell |
+-----+-----+ wait
| ^
| |
+-----+-----+ exit
| wc |
+-----+-----+ read
| ^
| |
+-----+-----+ write
| ls - l |
+-----------+
Risunok 7.29. Vzaimosvyaz' mezhdu processami, ispolnyayushchimi ko-
mandnuyu stroku ls -l|wc
Iz privedennogo teksta programmy vidno, kak shell obrabatyvaet komandnuyu
stroku, ispol'zuya odin kanal. Dopustim, chto komandnaya stroka imeet vid:
ls -l|wc
Posle sozdaniya roditel'skim processom novogo processa process-potomok sozda-
et kanal. Zatem process-potomok sozdaet svoe otvetvlenie; on i ego potomok
obrabatyvayut po odnoj komponente komandnoj stroki. "Vnuchatyj" process ispol-
nyaet pervuyu komponentu stroki (ls): on sobiraetsya vesti zapis' v kanal, poe-
tomu on zakryvaet staryj fajl standartnogo vyvoda, peredaet ego deskriptor
kanalu i zakryvaet staryj deskriptor zapisi v kanal, v kotorom (v deskripto-
re) uzhe net neobhodimosti. Roditel' (wc) "vnuchatogo" processa (ls) yavlyaetsya
potomkom osnovnogo processa, realizuyushchego programmu shell'a (sm. Risunok
7.29). |tot process (wc) zakryvaet svoj fajl standartnogo vvoda i peredaet
ego deskriptor kanalu, v rezul'tate chego kanal stanovitsya fajlom standartno-
go vvoda. Zatem zakryvaetsya staryj i uzhe ne nuzhnyj deskriptor chteniya iz ka-
nala i ispolnyaetsya vtoraya komponenta komandnoj stroki. Oba porozhdennyh pro-
cessa vypolnyayutsya asinhronno, prichem vyhod odnogo processa postupaet na vhod
drugogo. Tem vremenem osnovnoj process dozhidaetsya zaversheniya svoego potomka
(wc), posle chego prodolzhaet svoyu obychnuyu rabotu: po zavershenii processa, vy-
polnyayushchego komandu wc, vsya komandnaya stroka yavlyaetsya obrabotannoj. Shell
vozvrashchaetsya v cikl i schityvaet sleduyushchuyu komandnuyu stroku.
7.9 ZAGRUZKA SISTEMY I NACHALXNYJ PROCESS
Dlya togo, chtoby perevesti sistemu iz neaktivnoe sostoyanie v aktivnoe,
administrator vypolnyaet proceduru "nachal'noj zagruzki". Na raznyh mashinah
eta procedura imeet svoi osobennosti, odnako vo vseh sluchayah ona realizuet
odnu i tu zhe cel': zagruzit' kopiyu operacionnoj sistemy v osnovnuyu pamyat'
mashiny i zapustit' ee na ispolnenie. Obychno procedura nachal'noj zagruzki
vklyuchaet v sebya neskol'ko etapov. Pereklyucheniem klavish na pul'te mashiny ad-
ministrator mozhet ukazat' adres special'noj programmy apparatnoj zagruzki, a
mozhet, nazhav tol'ko odnu klavishu, dat' komandu mashine zapustit' proceduru
zagruzki, ispolnennuyu v vide mikroprogrammy. |ta programma mozhet sostoyat' iz
neskol'kih komand, podgotavlivayushchih zapusk drugoj programmy. V sisteme UNIX
220
procedura nachal'noj zagruzki zakanchivaetsya schityvaniem s diska v pamyat' blo-
ka nachal'noj zagruzki (nulevogo bloka). Programma, soderzhashchayasya v etom blo-
ke, zagruzhaet iz fajlovoj sistemy yadro OS (naprimer, iz fajla s imenem
"/unix" ili s drugim imenem, ukazannym administratorom). Posle zagruzki yadra
sistemy v pamyat' upravlenie peredaetsya po startovomu adresu yadra i yadro za-
puskaetsya na vypolnenie (algoritm start, Risunok 7.30).
YAdro inicializiruet svoi vnutrennie struktury dannyh. Sredi prochih
struktur yadro sozdaet svyaznye spiski svobodnyh buferov i indeksov, hesh-oche-
redi dlya buferov i indeksov, inicializiruet struktury oblastej, tochki vhoda
v tablicy stranic i t.d. Po okonchanii etoj fazy yadro montiruet kornevuyu faj-
lovuyu sistemu i formiruet sredu vypolneniya nulevogo processa, sredi vsego
prochego sozdavaya prostranstvo processa, inicializiruya nulevuyu tochku vhoda v
tablice processa i delaya kornevoj katalog tekushchim dlya processa.
Kogda formirovanie sredy vypolneniya processa zakanchivaetsya, sistema is-
polnyaetsya uzhe v vide nulevogo processa. Nulevoj process "vetvitsya", zapuskaya
algoritm fork pryamo iz yadra, poskol'ku sam process ispolnyaetsya v rezhime yad-
+------------------------------------------------------------+
| algoritm start /* procedura nachal'noj zagruzki sistemy */|
| vhodnaya informaciya: otsutstvuet |
| vyhodnaya informaciya: otsutstvuet |
| { |
| proinicializirovat' vse struktury dannyh yadra; |
| psevdo-montirovanie kornya; |
| sformirovat' sredu vypolneniya processa 0; |
| sozdat' process 1; |
| { |
| /* process 1 */ |
| vydelit' oblast'; |
| podklyuchit' oblast' k adresnomu prostranstvu processa|
| init; |
| uvelichit' razmer oblasti dlya kopirovaniya v nee is- |
| polnyaemogo koda; |
| skopirovat' iz prostranstva yadra v adresnoe prost- |
| ranstvo processa kod programmy, ispolnyaemoj proces-|
| som; |
| izmenit' rezhim vypolneniya: vernut'sya iz rezhima yadra |
| v rezhim zadachi; |
| /* process init dalee vypolnyaetsya samostoyatel'no -- |
| * v rezul'tate vyhoda v rezhim zadachi, |
| * init ispolnyaet fajl "/etc/init" i stanovitsya |
| * "obychnym" pol'zovatel'skim processom, proizvodya- |
| * shchim obrashcheniya k sistemnym funkciyam |
| */ |
| } |
| /* prodolzhenie nulevogo processa */ |
| porodit' processy yadra; |
| /* nulevoj process zapuskaet programmu podkachki, uprav- |
| * lyayushchuyu raspredeleniem adresnogo prostranstva proces- |
| * sov mezhdu osnovnoj pamyat'yu i ustrojstvami vygruzki. |
| * |to beskonechnyj cikl; nulevoj process obychno priosta-|
| * navlivaet svoyu rabotu, esli neobhodimosti v nem bol'-|
| * she net. |
| */ |
| ispolnit' programmu, realizuyushchuyu algoritm podkachki; |
| } |
+------------------------------------------------------------+
Risunok 7.30. Algoritm zagruzki sistemy
221
ra. Porozhdennyj nulevym novyj process, process 1, zapuskaetsya v tom zhe rezhi-
me i sozdaet svoj pol'zovatel'skij kontekst, formiruya oblast' dannyh i pri-
soedinyaya ee k svoemu adresnomu prostranstvu. On uvelichivaet razmer oblasti
do nadlezhashchej velichiny i perepisyvaet programmu zagruzki iz adresnogo prost-
ranstva yadra v novuyu oblast': eta programma teper' budet opredelyat' kontekst
processa 1. Zatem process 1 sohranyaet registrovyj kontekst zadachi, "vozvra-
shchaetsya" iz rezhima yadra v rezhim zadachi i ispolnyaet tol'ko chto perepisannuyu
programmu. V otlichie ot nulevogo processa, kotoryj yavlyaetsya processom sis-
temnogo urovnya, vypolnyayushchimsya v rezhime yadra, process 1 otnositsya k pol'zova-
tel'skomu urovnyu. Kod, ispolnyaemyj processom 1, vklyuchaet v sebya vyzov sis-
temnoj funkcii exec, zapuskayushchej na vypolnenie programmu iz fajla
"/etc/init". Obychno process 1 imenuetsya processom init, poskol'ku on otvecha-
et za inicializaciyu novyh processov.
Kazalos' by, zachem yadru kopirovat' programmu, zapuskaemuyu s pomoshch'yu fun-
kcii exec, v adresnoe prostranstvo processa 1 ? On mog by obratit'sya k vnut-
rennemu variantu funkcii pryamo iz yadra, odna-
ko, po sravneniyu s uzhe opisannym algoritmom eto bylo by gorazdo trudnee rea-
lizovat', ibo v etom sluchae funkcii exec prishlos' by proizvodit' analiz imen
fajlov v prostranstve yadra, a ne v prostranstve zadachi. Podobnaya detal',
trebuyushchayasya tol'ko dlya processa init, uslozhnila by programmu realizacii fun-
kcii exec i otricatel'no otrazilas' by na skorosti vypolneniya funkcii v bo-
lee obshchih sluchayah.
Process init (Risunok 7.31) vystupaet dispetcherom processov, kotoryj po-
rozhdaet processy, sredi vsego prochego pozvolyayushchie pol'zovatelyu registriro-
vat'sya v sisteme. Instrukcii o tom, kakie processy nuzhno sozdat', schityvayut-
sya processom init iz fajla "/etc/inittab". Stroki fajla vklyuchayut v sebya
identifikator sostoyaniya "id" (odnopol'zovatel'skij rezhim, mnogopol'zovatel'-
skij i t. d.), predprinimaemoe dejstvie (sm. uprazhnenie 7.43) i specifikaciyu
programmy, realizuyushchej eto dejstvie (sm. Risunok 7.32). Process init pros-
matrivaet stroki fajla do teh por, poka ne obnaruzhit identifikator sostoya-
niya, sootvetstvuyushchego tomu sostoyaniyu, v kotorom nahoditsya process, i sozdaet
process, ispolnyayushchij programmu s ukazannoj specifikaciej. Naprimer, pri za-
puske v mnogopol'zovatel'skom rezhime (sostoyanie 2) process init obychno po-
rozhdaet getty-processy, upravlyayushchie funkcionirovaniem terminal'nyh linij,
vhodyashchih v sostav sistemy. Esli registraciya pol'zovatelya proshla uspeshno,
getty-process, projdya cherez proceduru login, zapuskaet na ispolnenie regist-
racionnyj shell (sm. glavu 10). Tem vremenem process init nahoditsya v sosto-
yanii ozhidaniya (wait), nablyudaya za prekrashcheniem sushchestvovaniya svoih potomkov,
a takzhe "vnuchatyh" processov, ostavshihsya "sirotami" posle gibeli svoih rodi-
telej.
Processy v sisteme UNIX mogut byt' libo pol'zovatel'skimi, libo upravlya-
yushchimi, libo sistemnymi. Bol'shinstvo iz nih sostavlyayut pol'zovatel'skie pro-
cessy, svyazannye s pol'zovatelyami cherez terminaly. Upravlyayushchie processy ne
svyazany s konkretnymi pol'zovatelyami, oni vypolnyayut shirokij spektr sistemnyh
funkcij, takih kak administrirovanie i upravlenie setyami, razlichnye periodi-
cheskie operacii, buferizaciya dannyh dlya vyvoda na ustrojstvo postrochnoj pe-
chati i t.d. Process init mozhet porozhdat' upravlyayushchie processy, kotorye budut
sushchestvovat' na protyazhenii vsego vremeni zhizni sistemy, v razlichnyh sluchayah
oni mogut byt' sozdany samimi pol'zovatelyami. Oni pohozhi na pol'zovatel'skie
processy tem, chto oni ispolnyayutsya v rezhime zadachi i pribegayut k uslugam sis-
temy putem vyzova sootvetstvuyushchih sistemnyh funkcij.
Sistemnye processy vypolnyayutsya isklyuchitel'no v rezhime yadra. Oni mogut
porozhdat'sya nulevym processom (naprimer, process zameshcheniya stranic vhand),
kotoryj zatem stanovitsya processom podkachki. Sistemnye processy pohozhi na
upravlyayushchie processy tem, chto oni vypolnyayut sistemnye funkcii, pri etom oni
obladayut bol'shimi vozmozhnostyami prioritetnogo vypolneniya, poskol'ku lezhashchie
v ih osnove programmnye kody yavlyayutsya sostavnoj chast'yu yadra. Oni mogut obra-
shchat'sya k strukturam dannyh i algoritmam yadra, ne pribegaya k vyzovu sistemnyh
funkcij, otsyuda vytekaet ih isklyuchitel'nost'. Odnako, oni ne obladayut takoj
222
+------------------------------------------------------------+
| algoritm init /* process init, v sisteme imenuemyj |
| "process 1" */ |
| vhodnaya informaciya: otsutstvuet |
| vyhodnaya informaciya: otsutstvuet |
| { |
| fd = open("/etc/inittab",O_RDONLY); |
| while (line_read(fd,buffer)) |
| { |
| /* chitat' kazhduyu stroku fajlu */ |
| if (invoked state != buffer state) |
| continue; /* ostat'sya v cikle while */ |
| /* najden identifikator sootvetstvuyushchego sostoyaniya |
| */ |
| if (fork() == 0) |
| { |
| execl("process ukazan v bufere"); |
| exit(); |
| } |
| /* process init ne dozhidaetsya zaversheniya potomka */ |
| /* vozvrat v cikl while */ |
| } |
| |
| while ((id = wait((int*) 0)) != -1) |
| { |
| /* proverka sushchestvovaniya potomka; |
| * esli potomok prekratil sushchestvovanie, rassmatri- |
| * vaetsya vozmozhnost' ego perezapuska */ |
| /* v protivnom sluchae, osnovnoj process prosto pro- |
| * dolzhaet rabotu */ |
| } |
| } |
+------------------------------------------------------------+
Risunok 7.31. Algoritm vypolneniya processa init
+------------------------------------------------------------+
| Format: identifikator, sostoyanie, dejstvie, specifikaciya |
| processa |
| Polya razdeleny mezhdu soboj dvoetochiyami |
| Kommentarii v konce stroki nachinayutsya s simvola '#' |
| |
| co::respawn:/etc/getty console console #Konsol' v mashzale|
| 46:2:respawn:/etc/getty -t 60 tty46 4800H #kommentarii |
+------------------------------------------------------------+
Risunok 7.32. Fragment fajla inittab
zhe gibkost'yu, kak upravlyayushchie processy, poskol'ku dlya togo, chtoby vnesti iz-
meneniya v ih programmy, pridetsya eshche raz perekompilirovat' yadro.
V dannoj glave byli rassmotreny sistemnye funkcii, prednaznachennye dlya
raboty s kontekstom processa i dlya upravleniya vypolneniem processa. Sistem-
naya funkciya fork sozdaet novyj process, kopiruya dlya nego soderzhimoe vseh ob-
lastej, podklyuchennyh k roditel'skomu processu. Osobennost' realizacii funk-
cii fork sostoit v tom, chto ona vypolnyaet inicializaciyu sohranennogo regist-
223
rovogo konteksta porozhdennogo processa, takim obrazom etot process nachinaet
vypolnyat'sya, ne dozhidayas' zaversheniya funkcii, i uzhe v tele funkcii nachinaet
osoznavat' svoyu prednaznachenie kak potomka. Vse processy zavershayut svoe vy-
polnenie vyzovom funkcii exit, kotoraya otsoedinyaet oblasti processa i posy-
laet ego roditelyu signal "gibel' potomka". Process-roditel' mozhet sovmestit'
moment prodolzheniya svoego vypolneniya s momentom zaversheniya processa-potomka,
ispol'zuya sistemnuyu funkciyu wait. Sistemnaya funkciya exec daet processu voz-
mozhnost' zapuskat' na vypolnenie drugie programmy, nakladyvaya soderzhimoe is-
polnyaemogo fajla na svoe adresnoe prostranstvo. YAdro otsoedinyaet oblasti,
ranee zanimaemye processom, i naznachaet processu novye oblasti v sootvetst-
vii s potrebnostyami ispolnyaemogo fajla. Sovmestnoe ispol'zovanie oblastej
komand i nalichie rezhima "sticky-bit" dayut vozmozhnost' bolee racional'no is-
pol'zovat' pamyat' i ekonomit' vremya, zatrachivaemoe na podgotovku k zapusku
programm. Prostym pol'zovatelyam predostavlyaetsya vozmozhnost' poluchat' privi-
legii drugih pol'zovatelej, dazhe superpol'zovatelya, blagodarya obrashcheniyu k
uslugam sistemnoj funkcii setuid i setuid-programm. S pomoshch'yu funkcii brk
process mozhet izmenyat' razmer svoej oblasti dannyh. Funkciya signal daet pro-
cessam vozmozhnost' upravlyat' svoej reakciej na postupayushchie signaly. Pri po-
luchenii signala proizvoditsya obrashchenie k special'noj funkcii obrabotki sig-
nala s vneseniem sootvetstvuyushchih izmenenij v stek zadachi i v sohranennyj re-
gistrovyj kontekst zadachi. Processy mogut sami posylat' signaly, ispol'zuya
sistemnuyu funkciyu kill, oni mogut takzhe kontrolirovat' poluchenie signalov,
prednaznachennyh gruppe processov, pribegaya k uslugam funkcii setpgrp.
Komandnyj processor shell i process nachal'noj zagruzki init ispol'zuyut
standartnye obrashcheniya k sistemnym funkciyam, proizvodya nabor operacij, v dru-
gih sistemah obychno vypolnyaemyh yadrom. Shell interpretiruet komandy pol'zo-
vatelya, perenaznachaet standartnye fajly vvoda-vyvoda dannyh i vydachi oshibok,
porozhdaet processy, organizuet kanaly mezhdu porozhdennymi processami, sinhro-
niziruet svoe vypolnenie s etimi processami i formiruet kody, vozvrashchaemye
komandami. Process init tozhe porozhdaet razlichnye processy, v chastnosti, up-
ravlyayushchie rabotoj pol'zovatelya za terminalom. Kogda takoj process zavershaet-
sya, init mozhet porodit' dlya vypolneniya toj zhe samoj funkcii eshche odin pro-
cess, esli eto vytekaet iz informacii fajla "/etc/inittab".
1. Zapustite s terminala programmu, privedennuyu na Risunke 7.33. Pereadre-
sujte standartnyj vyvod dannyh v fajl i sravnite rezul'taty mezhdu so-
boj.
+------------------------------------+
| main() |
| { |
| printf("hello\n"); |
| if (fork() == 0) |
| printf("world\n"); |
| } |
+------------------------------------+
Risunok 7.33. Primer modulya, soderzhashchego vyzov funkcii fork i obra-
shchenie k standartnomu vyvodu
2. Razberites' v mehanizme raboty programmy, privedennoj na Risunke 7.34,
i sravnite ee rezul'taty s rezul'tatami programmy na Risunke 7.4.
3. Eshche raz obratimsya k programme, privedennoj na Risunke 7.5 i pokazyvayu-
shchej, kak dva processa obmenivayutsya soobshcheniyami, ispol'zuya sparennye ka-
naly. CHto proizojdet, esli oni popytayutsya vesti obmen soobshcheniyami, is-
pol'zuya odin kanal ?
4. Vozmozhna li poterya informacii v sluchae, kogda process poluchaet neskol'-
224
ko signalov prezhde chem emu predostavlyaetsya vozmozhnost' otreagirovat' na
nih nadlezhashchim obrazom ? (Rassmotrite sluchaj, kogda process podschityva-
et kolichestvo poluchennyh signalov o preryvanii.) Est' li neobhodimost'
v reshenii etoj problemy ?
5. Opishite mehanizm raboty sistemnoj funkcii kill.
6. Process v programme na Risunke 7.35 prinimaet signaly tipa "gibel' po-
tomka" i ustanavlivaet funkciyu obrabotki signalov v ishodnoe sostoyanie.
CHto proishodit pri vypolnenii programmy ?
7. Kogda process poluchaet signaly opredelennogo tipa i ne obrabatyvaet ih,
yadro dampiruet obraz processa v tom vide, kotoryj byl u nego v moment
polucheniya signala. YAdro sozdaet v tekushchem kataloge processa fajl s ime-
nem "core" i kopiruet v nego prostranstvo processa, oblasti komand,
dannyh i steka. Vposledstvii pol'zovatel' mozhet tshchatel'no izuchit' damp
obraza processa s pomoshch'yu standartnyh sredstv otladki. Opishite algo-
ritm, kotoromu na Vash vzglyad dolzhno sledovat' yadro v processe sozdaniya
fajla "core". CHto nuzhno predprinyat' v tom sluchae, esli v tekushchem kata-
loge fajl s takim imenem uzhe sushchestvuet ? Kak dolzhno vesti sebya yadro,
kogda v odnom i tom zhe kataloge dampiruyut svoi obrazy srazu neskol'ko
processov?
8. Eshche raz obratimsya k programme (Risunok 7.12), opisyvayushchej, kak odin
process zabrasyvaet drugoj process signalami, kotorye prinimayutsya ih
adresatom. Podumajte, chto proizoshlo by v tom sluchae, esli by algoritm
obrabotki signalov byl pererabotan v lyubom iz sleduyushchih napravlenij:
+------------------------------------------------------------+
| #include |
| int fdrd,fdwt; |
| char c; |
| |
| main(argc,argv) |
| int argc; |
| char *argv[]; |
| { |
| if (argc != 3) |
| exit(1); |
| fork(); |
| |
| if ((fdrd = open(argv[1],O_RDONLY)) == -1) |
| exit(1); |
| if (((fdwt = creat(argv[2],0666)) == -1) && |
| ((fdwt = open(argv[2],O_WRONLY)) == -1)) |
| exit(1); |
| rdwrt(); |
| } |
| rdwrt() |
| { |
| for (;;) |
| { |
| if (read(fdrd,&c,1) != 1) |
| return; |
| write(fdwt,&c,1); |
| } |
| } |
+------------------------------------------------------------+
Risunok 7.34. Primer programmy, v kotoroj process-roditel' i
process-potomok ne razdelyayut dostup k fajlu
* yadro ne zamenyaet funkciyu obrabotki signalov do teh por, poka pol'zo-
vatel' yavno ne potrebuet etogo;
225
* yadro zastavlyaet process ignorirovat' signaly do teh por, poka pol'zo-
vatel' ne obratitsya k funkcii signal vnov'.
9. Pererabotajte algoritm obrabotki signalov tak, chtoby yadro avtomaticheski
perenastraivalo process na ignorirovanie vseh posleduyushchih postuplenij
signalov po vozvrashchenii iz funkcii, obrabatyvayushchej ih. Kakim obrazom
yadro mozhet uznat' o zavershenii funkcii obrabotki signalov, vypolnyayushchej-
sya v rezhime zadachi ? Takogo roda perenastrojka priblizila by nas k
traktovke signalov v sisteme BSD.
*10. Esli process poluchaet signal, nahodyas' v sostoyanii priostanova vo vremya
vypolneniya sistemnoj funkcii s dopuskayushchim preryvaniya prioritetom, on
vyhodit iz funkcii po algoritmu longjump. YAdro proizvodit neobhodimye
ustanovki dlya zapuska funkcii obrabotki signala; kogda process vyjdet
iz funkcii obrabotki signala, v versii V eto budet vyglyadet' tak, slov-
no on vernulsya iz sistemnoj funkcii s priznakom oshibki (kak by prervav
svoe vypolnenie). V sisteme BSD sistemnaya funkciya v etom sluchae avtoma-
ticheski perezapuskaetsya. Kakim obrazom mozhno realizovat' etot moment v
nashej sisteme?
+------------------------------------------------------------+
| #include |
| main() |
| { |
| extern catcher(); |
| |
| signal(SIGCLD,catcher); |
| if (fork() == 0) |
| exit(); |
| /* pauza do momenta polucheniya signala */ |
| pause(); |
| } |
| |
| catcher() |
| { |
| printf("process-roditel' poluchil signal\n"); |
| signal(SIGCLD,catcher); |
| } |
+------------------------------------------------------------+
Risunok 7.35. Programma, v kotoroj process prinimaet signaly
tipa "gibel' potomka"
11. V tradicionnoj realizacii komandy mkdir dlya sozdaniya novoj vershiny v
dereve katalogov ispol'zuetsya sistemnaya funkciya mknod, posle chego dvazh-
dy vyzyvaetsya sistemnaya funkciya link, privyazyvayushchaya tochki vhoda v kata-
log s imenami "." i ".." k novoj vershine i k ee roditel'skomu katalogu.
Bez etih treh operacij katalog ne budet imet' nadlezhashchij format. CHto
proizojdet, esli vo vremya ispolneniya komandy mkdir process poluchit sig-
nal ? CHto esli pri etom budet poluchen signal SIGKILL, kotoryj process
ne raspoznaet ? |tu zhe problemu rassmotrite primenitel'no k realizacii
sistemnoj funkcii mkdir.
12. Process proveryaet nalichie signalov v momenty perehoda v sostoyanie pri-
ostanova i vyhoda iz nego (esli v sostoyanii priostanova process naho-
dilsya s prioritetom, dopuskayushchim preryvaniya), a takzhe v moment perehoda
v rezhim zadachi iz rezhima yadra po zavershenii ispolneniya sistemnoj funk-
cii ili posle obrabotki preryvaniya. Pochemu process ne proveryaet nalichie
signalov v moment obrashcheniya k sistemnoj funkcii ?
*13. Predpolozhim, chto posle ispolneniya sistemnoj funkcii process gotovitsya k
vozvrashcheniyu v rezhim zadachi i ne obnaruzhivaet ni odnogo neobrabotannogo
signala. Srazu posle etogo yadro obrabatyvaet preryvanie i posylaet pro-
226
cessu signal. (Naprimer, pol'zovatelem byla nazhata klavisha "break".)
CHto delaet process posle togo, kak yadro zavershaet obrabotku preryvaniya?
*14. Esli processu odnovremenno posylaetsya neskol'ko signalov, yadro obraba-
tyvaet ih v tom poryadke, v kakom oni perechisleny v opisanii. Sushchestvuyut
tri sposoba reagirovaniya na poluchenie signala - priem signalov, zaver-
shenie vypolneniya so sbrosom na vneshnij nositel' (dampirovaniem) obraza
processa v pamyati i zavershenie vypolneniya bez dampirovaniya. Mozhno li
ukazat' nailuchshij poryadok obrabotki odnovremenno postupayushchih signalov ?
Naprimer, esli process poluchaet signal o vyhode (vyzyvayushchij dampirova-
nie obraza processa v pamyati) i signal o preryvanii (vyhod bez dampiro-
vaniya), to kakoj iz etih signalov imelo by smysl obrabotat' pervym ?
15. Zapomnite novuyu sistemnuyu funkciyu newpgrp(pid,ngrp);
kotoraya vklyuchaet process s identifikatorom pid v gruppu processov s no-
merom ngrp (ustanavlivaet dlya processa novuyu gruppu). Podumajte, dlya
kakih celej ona mozhet ispol'zovat'sya i kakie opasnosti tait v sebe ee
vyzov.
16. Prokommentirujte sleduyushchee utverzhdenie: po algoritmu wait process mozhet
priostanovit'sya do nastupleniya kakogo-libo sobytiya i eto ne otrazilos'
by na rabote vsej sistemy.
17. Rassmotrim novuyu sistemnuyu funkciyu
nowait(pid);
gde pid - identifikator processa, yavlyayushchegosya potomkom togo processa,
kotoryj vyzyvaet funkciyu. Vyzyvaya funkciyu, process tem samym soobshchaet
yadru o tom, chto on ne sobiraetsya dozhidat'sya zaversheniya vypolneniya svoe-
go potomka, poetomu yadro mozhet po okonchanii sushchestvovaniya potomka srazu
zhe ochistit' zanimaemoe im mesto v tablice processov. Kakim obrazom eto
realizuetsya na praktike ? Ocenite dostoinstva novoj funkcii i sravnite
ee ispol'zovanie s ispol'zovaniem signalov tipa "gibel' potomka".
18. Zagruzchik modulej na Si avtomaticheski podklyuchaet k osnovnomu modulyu na-
chal'nuyu proceduru (startup), kotoraya vyzyvaet funkciyu main, prinadlezha-
shchuyu programme pol'zovatelya. Esli v pol'zovatel'skoj programme otsutst-
vuet vyzov funkcii exit, procedura startup sama vyzyvaet etu funkciyu
pri vyhode iz funkcii main. CHto proizoshlo by v tom sluchae, esli by i v
procedure startup otsutstvoval vyzov funkcii exit (iz-za oshibki zagruz-
chika) ?
19. Kakuyu informaciyu poluchit process, vypolnyayushchij funkciyu wait, esli ego
potomok zapustit funkciyu exit bez parametra ? Imeetsya v vidu, chto pro-
cess-potomok vyzovet funkciyu v formate exit() vmesto exit(n). Esli
programmist postoyanno ispol'zuet vyzov funkcii exit bez parametra, to
naskol'ko predskazuemo znachenie, ozhidaemoe funkciej wait ? Dokazhite
svoj otvet.
20. Ob®yasnite, chto proizojdet, esli process, ispolnyayushchij programmu na Ri-
sunke 7.36 zapustit s pomoshch'yu funkcii exec samogo sebya. Kak v takom
sluchae yadro smozhet izbezhat' vozniknoveniya tupikovyh situacij, svyazannyh
s blokirovkoj indeksov ?
+----------------------------------+
| main(argc,argv) |
| int argc; |
| char *argv[]; |
| { |
| execl(argv[0],argv[0],0); |
| } |
+----------------------------------+
Risunok 7.36
21. Po usloviyu pervym argumentom funkcii exec yavlyaetsya imya (poslednyaya kom-
ponenta imeni puti poiska) ispolnyaemogo processom fajla. CHto proizojdet
v rezul'tate vypolneniya programmy, privedennoj na Risunke 7.37 ? Kakov
budet effekt, esli v kachestve fajla "a.out" vystupit zagruzochnyj mo-
227
dul', poluchennyj v rezul'tate translyacii programmy, privedennoj na Ri-
sunke 7.36 ?
22. Predpolozhim, chto v yazyke Si podderzhivaetsya novyj tip dannyh "read-only"
(tol'ko dlya chteniya), prichem process, pytayushchijsya zapisat' informaciyu v
pole s etim tipom, poluchaet otkaz sistemy zashchity. Opishite realizaciyu
etogo momenta. (Namek: sravnite eto ponyatie s ponyatiem "razdelyaemaya ob-
last' komand".) V kakie iz algoritmov yadra potrebuetsya vnesti izmeneniya
? Kakie eshche ob®ekty mogut byt' realizovany analogichnym s oblast'yu obra-
zom ?
23. Kakie izmeneniya imeyut mesto v algoritmah open, chmod, unlink i unmount
pri rabote s fajlami, dlya kotoryh ustanovlen rezhim "sticky-bit" ? Kakie
dejstviya, naprimer, sleduet predprinyat' v otnoshenii takogo fajla yadru,
kogda s fajlom razryvaetsya svyaz' ?
24. Superpol'zovatel' yavlyaetsya edinstvennym pol'zovatelem, imeyushchim pravo na
zapis' v fajl parolej "/etc/passwd", blagodarya chemu soderzhimoe fajla
predohranyaetsya ot umyshlennoj ili sluchajnoj porchi. Programma passwd daet
pol'zovatelyam vozmozhnost' izmenyat' svoj sobstvennyj parol', zashchishchaya ot
izmenenij chuzhie zapisi. Kakim obrazom ona rabotaet ?
+-----------------------------------------------------+
| main() |
| { |
| if (fork() == 0) |
| { |
| execl("a.out",0); |
| printf("neudachnoe zavershenie funkcii exec\n");|
| } |
| } |
+-----------------------------------------------------+
Risunok 7.37
*25. Poyasnite, kakaya ugroza bezopasnosti hraneniya dannyh voznikaet, esli
setuid-programma ne zashchishchena ot zapisi.
26. Vypolnite sleduyushchuyu posledovatel'nost' komand, v kotoroj "a.
out" - imya ispolnyaemogo fajla:
+-----------------------------------------------------+
| main() |
| { |
| char *endpt; |
| char *sbrk(); |
| int brk(); |
| |
| endpt = sbrk(0); |
| printf("endpt = %ud posle sbrk\n", (int) endpt); |
| |
| while (endpt--) |
| { |
| if (brk(endpt) == -1) |
| { |
| printf("brk s parametrom %ud zavershilas' |
| neudachno\n",endpt); |
| exit(); |
| } |
| } |
| } |
+-----------------------------------------------------+
Risunok 7.38
228
chmod 4777 a.out
chown root a.out
Komanda chmod "vklyuchaet" bit setuid (4 v 4777); pol'zovatel' "root"
tradicionno yavlyaetsya superpol'zovatelem. Mozhet li v rezul'tate vypolne-
niya etoj posledovatel'nosti proizojti narushenie zashchity informacii ?
27. CHto proizojdet v processe vypolneniya programmy, predstavlennoj na Ri-
sunke 7.38 ? Poyasnite svoj otvet.
28. Bibliotechnaya podprogramma malloc uvelichivaet oblast' dannyh processa s
pomoshch'yu funkcii brk, a podprogramma free osvobozhdaet pamyat', vydelennuyu
podprogrammoj malloc. Sintaksis vyzova podprogramm:
ptr = malloc(size);
free(ptr);
gde size - celoe chislo bez znaka, oboznachayushchee kolichestvo vydelyaemyh
bajt pamyati, a ptr - simvol'naya ssylka na vnov' vydelennoe prostranst-
vo. Prezhde chem poyavit'sya v kachestve parametra v vyzove podprogrammy
free, ukazatel' ptr dolzhen byt' vozvrashchen podprogrammoj malloc. Vypol-
nite eti podprogrammy.
29. CHto proizojdet v processe vypolneniya programmy, predstavlennoj na Ri-
sunke 7.39 ? Sravnite rezul'taty vypolneniya etoj programmy s rezul'ta-
tami, predusmotrennymi v sistemnom opisanii.
+-----------------------------------------------------+
| main() |
| { |
| int i; |
| char *cp; |
| extern char *sbrk(); |
| |
| cp = sbrk(10); |
| for (i = 0; i < 10; i++) |
| *cp++ = 'a' + i; |
| sbrk(-10); |
| cp = sbrk(10); |
| for (i = 0; i < 10; i++) |
| printf("char %d = '%c'\n",i,*cp++); |
| } |
+-----------------------------------------------------+
Risunok 7.39. Primer programmy, ispol'zuyushchej podprogrammu sbrk
30. Kakim obrazom komandnyj processor shell uznaet o tom, chto fajl ispolnya-
emyj, kogda dlya vypolneniya komandy sozdaet novyj process ? Esli fajl
ispolnyaemyj, to kak uznat', sozdan li on v rezul'tate translyacii ishod-
noj programmy ili zhe predstavlyaet soboj nabor komand yazyka shell ? V
kakom poryadke sleduet vypolnyat' proverku ukazannyh uslovij ?
31. V komandnom yazyke shell simvoly ">>" ispol'zuyutsya dlya napravleniya vyvo-
da dannyh v fajl s ukazannoj specifikaciej, naprimer, komanda: run >>
outfile otkryvaet fajl s imenem "outfile" (a v sluchae otsutstviya fajla
s takim imenem sozdaet ego) i zapisyvaet v nego dannye. Napishite prog-
rammu, v kotoroj ispol'zuetsya eta komanda.
32. Processor komandnogo yazyka shell proveryaet kod, vozvrashchaemyj funkciej
exit, vosprinimaya nulevoe znachenie kak "istinu", a lyuboe drugoe znache-
nie kak "lozh'" (obratite vnimanie na nesoglasovannost' s yazykom Si).
Predpolozhim, chto fajl, ispolnyayushchij programmu na Risunke 7.40, imeet imya
"truth". Poyasnite, chto proizojdet, kogda shell budet ispolnyat' sleduyu-
shchij nabor komand:
while truth
229
+------------------+
| main() |
| { |
| exit(0); |
| } |
+------------------+
Risunok 7.40
do
truth &
done
33. Vopros po Risunku 7.29: V svyazi s chem voznikaet neobhodimost' v sozda-
nii processov dlya konvejernoj obrabotki dvuhkomponentnoj komandy v uka-
zannom poryadke ?
34. Napishite bolee obshchuyu programmu raboty osnovnogo cikla processora shell
v chasti obrabotki kanalov. Imeetsya v vidu, chto programma dolzhna umet'
obrabatyvat' sluchajnoe chislo kanalov, ukazannyh v komandnoj stroke.
35. Peremennaya sredy PATH opisyvaet poryadok, v kotorom shell'u sleduet
prosmatrivat' katalogi v poiskah ispolnyaemyh fajlov. V bibliotechnyh
funkciyah execlp i execvp perechislennye v PATH katalogi prisoedinyayutsya k
imenam fajlov, krome teh, kotorye nachinayutsya s simvola "/". Vypolnite
eti funkcii.
*36. Dlya togo, chtoby shell v poiskah ispolnyaemyh fajlov ne obrashchalsya k teku-
shchemu katalogu, superpol'zovatel' dolzhen zadat' peremennuyu sredy PATH.
Kakaya ugroza bezopasnosti hraneniya dannyh mozhet vozniknut', esli shell
popytaetsya ispolnit' fajly iz tekushchego kataloga ?
37. Kakim obrazom shell obrabatyvaet komandu cd (sozdat' katalog) ? Kakie
dejstviya predprinimaet shell v processe obrabotki sleduyushchej komandnoj
stroki: cd pathname & ?
38. Kogda pol'zovatel' nazhimaet na klaviature terminala klavishi "delete"
ili "break", vsem processam, vhodyashchim v gruppu registracionnogo
shell'a, terminal'nyj drajver posylaet signal o preryvanii. Pol'zova-
tel' mozhet imet' namerenie ostanovit' vse processy, porozhdennye
shell'om, bez vyhoda iz sistemy. Kakie usovershenstvovaniya v svyazi s
etim sleduet proizvesti v tele osnovnogo cikla programmy shell (Risunok
7.28) ?
39. S pomoshch'yu komandy nohup command_line
pol'zovatel' mozhet otmenit' dejstvie signalov o "zavisanii" i o zaver-
shenii (quit) v otnoshenii processov, realizuyushchih komandnuyu stroku
(command_line). Kak eta komanda budet obrabatyvat'sya v osnovnom cikle
programmy shell ?
40. Rassmotrim nabor komand yazyka shell:
nroff -mm bigfile1 > big1out &
nroff -mm bigfile2 > big2out
i vnov' obratimsya k osnovnomu ciklu programmy shell (Risunok 7.28). CHto
proizojdet, esli vypolnenie pervoj komandy nroff zavershitsya ran'she vto-
roj ? Kakie izmeneniya sleduet vnesti v osnovnoj cikl programmy shell na
etot sluchaj ?
41. CHasto vo vremya vypolneniya iz shell'a neprotestirovannyh programm poyav-
lyaetsya soobshchenie ob oshibke sleduyushchego vida: "Bus error - core dumped"
(Oshibka v magistrali - soderzhimoe pamyati sbrosheno na vneshnij nositel').
Ochevidno, chto v programme vypolnyayutsya kakie-to nedopustimye dejstviya;
otkuda shell uznaet o tom, chto emu nuzhno vyvesti soobshchenie ob oshibke ?
42. Processom 1 v sisteme mozhet vystupat' tol'ko process init. Tem ne me-
nee, zapustiv process init, administrator sistemy mozhet tem samym izme-
nit' sostoyanie sistemy. Naprimer, pri zagruzke sistema mozhet vojti v
odnopol'zovatel'skij rezhim, oznachayushchij, chto v sisteme aktiven tol'ko
konsol'nyj terminal. Dlya togo, chtoby perevesti process init v sostoyanie
230
2 (mnogopol'zovatel'skij rezhim), administrator sistemy vvodit s konsoli
komandu
init 2 .
Konsol'nyj shell porozhdaet svoe otvetvlenie i zapuskaet init. CHto imelo
by mesto v sisteme v tom sluchae, esli by aktiven byl tol'ko odin pro-
cess init ?
43. Format zapisej v fajle "/etc/inittab" dopuskaet zadanie dejstviya, svya-
zannogo s kazhdym porozhdaemym processom. Naprimer, s getty-processom
svyazano dejstvie "respawn" (vozrozhdenie), oznachayushchee, chto process init
dolzhen vozrozhdat' getty-process, esli poslednij prekrashchaet sushchestvova-
nie. Na praktike, kogda pol'zovatel' vyhodit iz sistemy process init
porozhdaet novyj getty-process, chtoby drugoj pol'zovatel' mog poluchit'
dostup k vremenno bezdejstvuyushchej terminal'noj linii. Kakim obrazom eto
delaet process init ?
44. Nekotorye iz algoritmov yadra pribegayut k prosmotru tablicy processov.
Vremya poiska dannyh mozhno sokratit', esli ispol'zovat' ukazateli na:
roditelya processa, lyubogo iz potomkov, drugoj process, imeyushchij togo zhe
roditelya. Process obnaruzhivaet vseh svoih potomkov, sleduya snachala za
ukazatelem na lyubogo iz potomkov, a zatem ispol'zuya ukazateli na drugie
processy, imeyushchie togo zhe roditelya (cikly nedopustimy). Kakie iz algo-
ritmov vyigrayut ot etogo ? Kakie iz algoritmov nuzhno ostavit' bez izme-
231
Last-modified: Thu, 12 Feb 1998 07:19:53 GMT