Ocenite etot tekst:





    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



    7.2.1 Obrabotka 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

    7.2.2 Gruppy processov

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.

    7.10 VYVODY

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".

    7.11 UPRAZHNENIYA

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
Ocenite etot tekst: