GLAVA 7. UPRAVLENIE PROCESSAMI V predydushchej glave byl rassmotren kontekst processa i opisany algoritmy dlya raboty s nim; v dannoj glave rech' pojdet ob ispol'zovanii i realizacii sistemnyh funkcij, upravlyayushchih kontekstom processa. Sistemnaya funkciya fork sozdaet novyj process, funkciya exit zavershaet vypolnenie processa, a wait daet vozmozhnost' roditel'skomu processu sinhronizirovat' svoe prodolzhenie s zaversheniem porozhdennogo processa. Ob asinhronnyh sobytiyah processy informi- ruyutsya pri pomoshchi signalov. Poskol'ku yadro sinhroniziruet vypolnenie funkcij exit i wait pri pomoshchi signalov, opisanie mehanizma signalov predvaryaet so- boj rassmotrenie funkcij exit i wait. Sistemnaya funkciya exec daet processu vozmozhnost' zapuskat' "novuyu" programmu, nakladyvaya ee adresnoe prostranstvo na ispolnyaemyj obraz fajla. Sistemnaya funkciya brk pozvolyaet dinamicheski vy- delyat' dopolnitel'nuyu pamyat'; temi zhe samymi sredstvami yadro dinamicheski na- rashchivaet stek zadachi, vydelyaya v sluchae neobhodimosti dopolnitel'noe prost- ranstvo. V zaklyuchitel'noj chasti glavy daetsya kratkoe opisanie osnovnyh grupp operacij komandnogo processora shell i nachal'nogo processa init. Na Risunke 7.1 pokazana vzaimosvyaz' mezhdu sistemnymi funkciyami, rassmat- rivaemymi v dannoj glave, s odnoj storony, i algoritmami, opisannymi v pre- dydushchej glave, s drugoj. Pochti vo vseh funkciyah ispol'zuyutsya algoritmy sleep i wakeup, otsutstvuyushchie na risunke. Funkciya exec, krome togo, vzaimodejstvu- et s algoritmami raboty s fajlovoj sistemoj, rech' o kotoryh shla v glavah 4 i 5. +-----------------------------+---------------------+------------+ | Sistemnye funkcii, imeyushchie | Sistemnye funkcii, | Funkcii | | yushchie delo s upravleniem pa- | svyazannye s sinhro- | smeshannogo | | myat'yu | nizaciej | tipa | +-------+-------+-------+-----+--+----+------+----+-+-----+------+ | fork | exec | brk | exit |wait|signal|kill|setrgrr|setuid| +-------+-------+-------+--------+----+------+----+-------+------+ |dupreg |detach-|growreg| detach-| | |attach-| reg | | reg | | | reg |alloc- | | | | | | reg | | | | | |attach-| | | | | | reg | | | | | |growreg| | | | | |loadreg| | | | | |mapreg | | | | +-------+-------+-------+--------+-------------------------------+ Risunok 7.1. Sistemnye funkcii upravleniya processom i ih svyaz' s drugimi algoritmami 7.1 SOZDANIE PROCESSA 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 | | z