| | | | for (i = 0; i < 18; i++) | | { | | switch (fork()) | | { | | case -1: /* oshibka --- prevysheno maksimal'noe chis-| | lo processov */ | | exit(); | | | | default: /* roditel'skij process */ | | break; | | | | case 0: /* porozhdennyj process */ | | /* format vyvoda stroki v peremennoj output */ | | sprintf(output,"%%d\n%s%d\n",form,i,form,i); | | for (;;) | | write(1,output,sizeof(output)); | | } | | } | | } | +----------------------------------------------------------------+ Risunok 10.14. Peredacha dannyh cherez standartnyj vyvod v dlinu, to est' slishkom velika dlya togo, chtoby pomestit'sya v simvol'nom bloke (dlinoj 64 bajta) v versii V sistemy. Sledovatel'no, terminal'nomu drajveru trebuetsya bolee odnogo simvol'nogo bloka dlya kazhdogo vyzova funkcii write, inache vyvodnoj potok mozhet stat' iskazhennym. Naprimer, sleduyushchie stroki byli chast'yu vyvodnogo potoka, poluchennogo v rezul'tate vypolneniya programmy na mashine AT&T 3B20: this is a sample output string from child 1 this is a sample outthis is a sample output string from child 0 CHtenie dannyh s terminala v kanonicheskom rezhime bolee slozhnaya operaciya. V vyzove sistemnoj funkcii read ukazyvaetsya kolichestvo bajt, kotorye process hochet schitat', no strokovyj interfejs vypolnyaet chtenie po poluchenii simvola perevoda karetki, dazhe esli kolichestvo simvolov ne ukazano. |to udobno s prakticheskoj tochki zreniya, tak kak process ne v sostoyanii predugadat', skol'ko simvolov pol'zovatel' vvedet s klaviatury, i, s drugoj storony, ne imeet smysla zhdat', kogda pol'zovatel' vvedet bol'shoe chislo simvolov. Napri- mer, pol'zovateli vvodyat komandnye stroki dlya komandnogo processora shell i ozhidayut otveta shell'a na komandu po poluchenii simvola vozvrata karetki. Pri etom net nikakoj raznicy, yavlyayutsya li vvedennye stroki prostymi komandami, takimi kak "date" ili "who", ili zhe eto bolee slozhnye posledovatel'nosti ko- mand, podobnye sleduyushchej: pic file* | tbl | eqn | troff -mm -Taps | apsend Terminal'nyj drajver i strokovyj interfejs nichego ne znayut o sintaksise komandnogo processora shell, i eto pravil'no, poskol'ku drugie programmy, kotorye schityvayut informaciyu s terminalov (naprimer, redaktory), imeyut raz- 312 lichnyj sintaksis komand. Poetomu strokovyj interfejs vypolnyaet chtenie po po- luchenii simvola vozvrata karetki. Na Risunke 10.15 pokazan algoritm chteniya s terminala. Predpolozhim, chto terminal rabotaet v kanonicheskom rezhime; v razdele 10.3.3 budet rassmotrena rabota v rezhime bez obrabotki. Esli v nastoyashchij moment v lyubom iz simvol'nyh spiskov dlya hraneniya vvodnoj informacii otsutstvuyut dannye, process, vypol- +------------------------------------------------------------+ | algoritm terminal_read | | { | | esli (v kanonicheskom simvol'nom spiske otsutstvuyut dan- | | nye) | | { | | vypolnit' (poka v spiske dlya nestrukturirovannyh | | vvodnyh dannyh otsutstvuet informaciya) | | { | | esli (terminal otkryt s parametrom "no delay" | | (bez zaderzhki)) | | vozvratit' upravlenie; | | esli (terminal v rezhime bez obrabotki s ispol'zo-| | vaniem tajmera i tajmer ne aktiven) | | predprinyat' dejstviya k aktivizacii tajmera | | (tablica otvetnyh signalov); | | priostanovit'sya (do postupleniya dannyh s termina-| | la); | | } | | | | /* v spiske dlya nestrukturirovannyh vvodnyh dannyh | | est' informaciya */ | | esli (terminal v rezhime bez obrabotki) | | skopirovat' vse dannye iz spiska dlya nestrukturi-| | rovannyh vvodnyh dannyh v kanonicheskij spisok; | | v protivnom sluchae /* terminal v kanonicheskom re- | | zhime */ | | { | | vypolnit' (poka v spiske dlya nestrukturirovannyh | | vvodnyh dannyh est' simvoly) | | { | | kopirovat' po odnomu simvolu iz spiska dlya | | nestrukturirovannyh vvodnyh dannyh v kano- | | nicheskij spisok: | | vypolnit' obrabotku simvolov stiraniya i uda-| | leniya; | | esli (simvol - "vozvrat karetki" ili "konec | | fajla") | | prervat'sya; /* vyhod iz cikla */ | | } | | } | | } | | | | vypolnit' (poka v kanonicheskom spiske eshche est' simvoly | | i ne ischerpano kolichestvo simvolov, ukazannoe v vyzove | | funkcii read) | | kopirovat' simvoly iz simvol'nyh blokov kanonicheskogo| | spiska v adresnoe prostranstvo zadachi; | | } | +------------------------------------------------------------+ Risunok 10.15. Algoritm chteniya s terminala 313 nyayushchij chtenie, priostanavlivaetsya do postupleniya pervoj stroki dannyh. Kogda dannye postupayut, programma obrabotki preryvaniya ot terminala zapuskaet "programmu obrabotki preryvaniya" strokovogo interfejsa, kotoraya pomeshchaet dannye v spisok dlya hraneniya nestrukturirovannyh vvodnyh dannyh dlya peredachi processam, osushchestvlyayushchim chtenie, i v spisok dlya hraneniya vyvodnyh dannyh, peredavaemyh v kachestve ehosoprovozhdeniya na terminal. Esli vvedennaya stroka soderzhit simvol vozvrata karetki, programma obrabotki preryvaniya vozobnovlya- et vypolnenie vseh priostanovlennyh processov chteniya. Kogda process, osushches- tvlyayushchij chtenie, vypolnyaetsya, drajver vybiraet simvoly iz spiska dlya hrane- niya nestrukturirovannyh vvodnyh dannyh, obrabatyvaet simvoly stiraniya i uda- leniya i pomeshchaet simvoly v kanonicheskij simvol'nyj spisok. Zatem on kopiruet stroku simvolov v adresnoe prostranstvo zadachi do simvola vozvrata karetki ili do ischerpaniya chisla simvolov, ukazannogo v vyzove sistemnoj funkcii read, chto vstretitsya ran'she. Odnako, process mozhet obnaruzhit', chto dannyh, radi kotoryh on vozobnovil svoe vypolnenie, bol'she ne sushchestvuet: drugie processy schitali dannye s terminala i udalili ih iz spiska dlya nestrukturi- rovannyh vvodnyh dannyh do togo, kak pervyj process byl zapushchen vnov'. Takaya situaciya pohozha na tu, kotoraya imeet mesto, kogda iz kanala schityvayut dannye neskol'ko processov. Obrabotka simvolov v napravlenii vvoda i v napravlenii vyvoda asimmet- richna, chto vidno iz nalichiya dvuh simvol'nyh spiskov dlya vvoda i odnogo - dlya vyvoda. Strokovyj interfejs vyvodit dannye iz prostranstva zadachi, obrabaty- vaet ih i pomeshchaet ih v spisok dlya hraneniya vyvodnyh dannyh. Dlya simmetrii sledovalo by imet' tol'ko odin spisok dlya vvodnyh dannyh. Odnako, v takom sluchae potrebovalos' by ispol'zovanie programmy obrabotki preryvanij dlya interpretacii simvolov +--------------------------------------------------------------+ | char input[256]; | | | | main() | | { | | register int i; | | | | for (i = 0; i < 18; i++) | | { | | switch (fork()) | | { | | case -1: /* oshibka */ | | printf("operaciya fork ne vypolnena iz-za oshibki\n");| | exit(); | | | | default: /* roditel'skij process */ | | break; | | | | case 0: /* porozhdennyj process */ | | for (;;) | | { | | read(0,input,256); /* chtenie stroki */ | | printf("%d chtenie %s\n",i,input); | | } | | } | | } | | } | +--------------------------------------------------------------+ Risunok 10.16. Konkurenciya za dannye, vvodimye s terminala 314 stiraniya i udaleniya, chto sdelalo by proceduru bolee slozhnoj i dlitel'noj i zapretilo by vozniknovenie drugih preryvanij na vse kriticheskoe vremya. Is- pol'zovanie dvuh simvol'nyh spiskov dlya vvoda podrazumevaet, chto programma obrabotki preryvanij mozhet prosto sbrosit' simvoly v spisok dlya nestrukturi- rovannyh vvodnyh dannyh i vozobnovit' vypolnenie processa, osushchestvlyayushchego chtenie, kotoryj sobstvenno i voz'met na sebya rabotu po interpretacii vvodnyh dannyh. Pri etom programma obrabotki preryvanij nemedlenno pomeshchaet vveden- nye simvoly v spisok dlya hraneniya vyvodnyh dannyh, tak chto pol'zovatel' is- pytyvaet lish' minimal'nuyu zaderzhku pri prosmotre vvedennyh simvolov na ter- minale. Na Risunke 10.16 privedena programma, v kotoroj roditel'skij process po- rozhdaet neskol'ko processov, osushchestvlyayushchih chtenie iz fajla standartnogo vvoda, konkuriruya za poluchenie dannyh, vvodimyh s terminala. Vvod s termina- la obychno osushchestvlyaetsya slishkom medlenno dlya togo, chtoby udovletvorit' vse processy, vedushchie chtenie, poetomu processy bol'shuyu chast' vremeni nahodyatsya v priostanovlennom sostoyanii v sootvetstvii s algoritmom terminal_read, ozhidaya vvoda dannyh. Kogda pol'zovatel' vvodit stroku dannyh, programma obrabotki preryvanij ot terminala vozobnovlyaet vypolnenie vseh processov, vedushchih chte- nie; poskol'ku oni byli priostanovleny s odnim i tem zhe urovnem prioriteta, oni vybirayutsya dlya zapuska s odinakovym urovnem prioriteta. Pol'zovatel' ne v sostoyanii predugadat', kakoj iz processov vypolnyaetsya i schityvaet stroku dannyh; uspeshno sozdannyj process pechataet znachenie peremennoj i v moment ego sozdaniya. Vse drugie processy v konce koncov budut zapushcheny, no vpolne vozmozhno, chto oni ne obnaruzhat vvedennoj informacii v spiskah dlya hraneniya vvodnyh dannyh i ih vypolnenie snova budet priostanovleno. Vsya procedura povtoryaetsya dlya kazhdoj vvedennoj stroki; nel'zya dat' garantiyu, chto ni odin iz processov ne zahvatit vse vvedennye dannye. Odnovremennomu chteniyu s terminala neskol'kimi processami prisushcha neod- noznachnost', no yadro spravlyaetsya s situaciej nailuchshim obrazom. S drugoj storony, yadro obyazano pozvolyat' processam odnovremenno schityvat' dannye s terminala, inache porozhdennye komandnym processorom shell processy, chitayushchie iz standartnogo vvoda, nikogda ne budut rabotat', poskol'ku shell tozhe obra- shchaetsya k standartnomu vvodu. Koroche govorya, processy dolzhny sinhronizirovat' svoi obrashcheniya k terminalu na pol'zovatel'skom urovne. Kogda pol'zovatel' vvodit simvol "konec fajla" (Ctrl-d v ASCII), stroko- vyj interfejs peredaet funkcii read vvedennuyu stroku do simvola konca fajla, no ne vklyuchaya ego. On ne peredaet dannye (kod vozvrata 0) funkcii read, esli v simvol'nom spiske vstretilsya tol'ko simvol "konec fajla"; vyzyvayushchij pro- cess sam raspoznaet, chto obnaruzhen konec fajla i bol'she ne sleduet schityvat' dannye s terminala. Esli eshche raz obratit'sya k primeram programm po shell'u, privedennym v glave 7, mozhno otmetit', chto cikl raboty shell'a zavershaetsya, kogda pol'zovatel' nazhimaet : funkciya read vozvrashchaet 0 i proizvo- ditsya vyhod iz shell'a. V etom razdele rassmotrena rabota terminalov vvoda-vyvoda, kotorye pere- dayut dannye na mashinu po odnomu simvolu za odnu operaciyu, v tochnosti kak pol'zovatel' ih vvodit s klaviatury. Intellektual'nye terminaly podgotavli- vayut svoj vvodnoj potok na vneshnem ustrojstve, osvobozhdaya central'nyj pro- cessor dlya drugoj raboty. Struktura drajverov dlya takih terminalov pohodit na strukturu drajverov dlya terminalov vvoda-vyvoda, nesmotrya na to, chto fun- kcii strokovogo interfejsa razlichayutsya v zavisimosti ot vozmozhnostej vneshnih ustrojstv. 10.3.3 Terminal'nyj drajver v rezhime bez obrabotki simvolov Pol'zovateli ustanavlivayut parametry terminala, takie kak simvoly stira- niya i udaleniya, i izvlekayut znacheniya tekushchih ustanovok s pomoshch'yu sistemnoj 315 funkcii ioctl. Shodnym obrazom oni ustanavlivayut neobhodimost' eho-soprovozh- deniya vvoda dannyh s terminala, zadayut skorost' peredachi informacii v bodah, zapolnyayut ocheredi simvolov vvoda i vyvoda ili vruchnuyu zapuskayut i ostanavli- vayut vyvodnoj potok simvolov. V informacionnoj strukture terminal'nogo draj- vera hranyatsya razlichnye upravlyayushchie ustanovki (sm. [SVID 85], str.281), i strokovyj interfejs poluchaet parametry funkcii ioctl i ustanavlivaet ili schityvaet znacheniya sootvetstvuyushchih polej struktury dannyh. Kogda process us- tanavlivaet znacheniya parametrov terminala, on delaet eto dlya vseh processov, ispol'zuyushchih terminal. Ustanovki terminala ne sbrasyvayutsya avtomaticheski pri vyhode iz processa, sdelavshego izmeneniya v ustanovkah. Processy mogut takzhe perevesti terminal v rezhim bez obrabotki simvolov, v kotorom strokovyj interfejs peredaet simvoly v tochnom sootvetstvii s tem, kak pol'zovatel' vvel ih: obrabotka vvodnogo potoka polnost'yu otsutstvuet. Odnako, yadro dolzhno znat', kogda vypolnit' vyzvannuyu pol'zovatelem sistemnuyu funkciyu read, poskol'ku simvol vozvrata karetki traktuetsya kak obychnyj vve- dennyj simvol. Ono vypolnyaet funkciyu read posle togo, kak s terminala budet vvedeno minimal'noe chislo simvolov ili po prohozhdenii fiksirovannogo prome- zhutka vremeni ot momenta polucheniya s terminala lyubogo nabora simvolov. V poslednem sluchae yadro hronometriruet vvod simvolov s terminala, pomeshchaya za- pisi v tablicu otvetnyh signalov (glava 8). Oba kriteriya (minimal'noe chislo simvolov i fiksirovannyj promezhutok vremeni) zadayutsya v vyzove funkcii ioctl. Kogda sootvetstvuyushchie kriterii udovletvoreny, programma obrabotki preryvanij strokovogo interfejsa vozobnovlyaet vypolnenie vseh priostanovlen- nyh processov. Drajver peresylaet vse simvoly iz spiska dlya hraneniya nest- rukturirovannyh vvodnyh dannyh v kanonicheskij spisok i vypolnyaet zapros pro- cessa na chtenie, sleduya tomu zhe samomu algoritmu, chto i v sluchae raboty v kanonicheskom rezhime. Rezhim bez obrabotki simvolov osobenno vazhen v ekran- no-orientirovannyh prilozheniyah, takih kak ekrannyj redaktor vi, mnogie iz komand kotorogo ne zakanchivayutsya simvolom vozvrata karetki. Naprimer, koman- da dw udalyaet slovo v tekushchej pozicii kursora. Na Risunke 10.17 privedena programma, ispol'zuyushchaya funkciyu ioctl dlya sohraneniya tekushchih ustanovok terminala dlya fajla s deskriptorom 0, chto soot- vetstvuet znacheniyu deskriptora fajla standartnogo vvoda. Funkciya ioctl s ko- mandoj TCGETA prikazyvaet drajveru izvlech' ustanovki i sohranit' ih v strukture s imenem savetty v ad- resnom prostranstve zadachi. |ta komanda chasto ispol'zuetsya dlya togo, chtoby opredelit', yavlyaetsya li fajl terminalom ili net, poskol'ku ona nichego ne iz- menyaet v sisteme: esli ona zavershaetsya neudachno, processy predpolagayut, chto fajl ne yavlyaetsya terminalom. Zdes' zhe, process vtorichno vyzyvaet funkciyu ioctl dlya togo, chtoby perevesti terminal v rezhim bez obrabotki: on otklyuchaet eho-soprovozhdenie vvoda simvolov i gotovitsya k vypolneniyu operacij chteniya s +----------------------------------------------------------------+ | #include | | #include | | struct termio savetty; | | main() | | { | | extern sigcatch(); | | struct termio newtty; | | int nrd; | | char buf[32]; | | signal(SIGINT,sigcatch); | | if (ioctl(0,TCGETA,&savetty) == -1) | | { | | printf("ioctl zavershilas' neudachno: net terminala\n"); | | exit(); | | } | | newtty = savetty; | 316 | newtty.c_lflag &= ~ICANON;/* vyhod iz kanonicheskogo rezhima */| | newtty.c_lflag &= ~ECHO; /* otklyuchenie eho-soprovozhdeniya*/ | | newtty.c_cc[VMIN] = 5; /* minimum 5 simvolov */ | | newtty.c_cc[VTIME] = 100; /* interval 10 sekund */ | | if (ioctl(0,TCSETAF,&newtty) == -1) | | { | | printf("ne mogu perevesti ter-l v rezhim bez obrabotki\n");| | exit(); | | } | | for(;;) | | { | | nrd = read(0,buf,sizeof(buf)); | | buf[nrd] = 0; | | printf("chtenie %d simvolov '%s'\n",nrd,buf); | | } | | } | | sigcatch() | | { | | ioctl(0,TCSETAF,&savetty); | | exit(); | | } | +----------------------------------------------------------------+ Risunok 10.17. Rezhim bez obrabotki - chtenie 5-simvol'nyh blokov +----------------------------------------------------------------+ | #include | | | | main() | | { | | register int i,n; | | int fd; | | char buf[256]; | | | | /* otkrytie terminala tol'ko dlya chteniya s opciej "no delay" */ | | if((fd = open("/dev/tty",O_RDONLY|O_NDELAY)) == -1) | | exit(); | | | | n = 1; | | for(;;) /* vsegda */ | | { | | for(i = 0; i < n; i++) | | ; | | | | if(read(fd,buf,sizeof(buf)) > 0) | | { | | printf("chtenie s nomera %d\n",n); | | n--; | | } | | else | | /* nichego ne prochitano; vozvrat vsledstvie "no delay" */ | | n++; | | } | | } | +----------------------------------------------------------------+ Risunok 10.18. Opros terminala 317 terminala po poluchenii s terminala 5 simvolov, kak minimum, ili po prohozhde- nii 10 sekund s momenta vvoda pervoj porcii simvolov. Kogda process poluchaet signal o preryvanii, on sbrasyvaet pervonachal'nye parametry terminala i za- vershaetsya. 10.3.4 Opros terminala Inogda udobno proizvodit' opros ustrojstva, to est' schityvat' s nego dannye, esli oni est', ili prodolzhat' vypolnyat' obychnuyu rabotu - v protivnom sluchae. Programma na Risunke 10.18 illyustriruet etot sluchaj: posle otkrytiya terminala s parametrom "no delay" (bez zaderzhki) processy, vedushchie chtenie s nego, ne priostanovyat svoe vypolnenie v sluchae otsutstviya dannyh, a vernut upravlenie nemedlenno (sm. algoritm terminal_read, Risunok 10.15). |tot me- tod rabotaet takzhe, esli process sledit za mnozhestvom ustrojstv: on mozhet otkryt' kazhdoe ustrojstvo s parametrom "no delay" i oprosit' vseh iz nih, ozhidaya postupleniya informacii s kazhdogo. Odnako, etot metod rastrachivaet vy- chislitel'nye moshchnosti sistemy. V sisteme BSD est' sistemnaya funkciya select, pozvolyayushchaya proizvodit' op- ros ustrojstva. Sintaksis vyzova etoj funkcii: select(nfds,rfds,wfds,efds,timeout) gde nfds - kolichestvo vybiraemyh deskriptorov fajlov, a rfds, wfds i efds ukazyvayut na dvoichnye maski, kotorymi "vybirayut" deskriptory otkrytyh faj- lov. To est', bit 1 << fd (sdvig na 1 razryad vlevo znacheniya deskriptora faj- la) sootvetstvuet ustanovke na tot sluchaj, esli pol'zovatelyu nuzhno vybrat' etot deskriptor fajla. Parametr timeout (tajm-aut) ukazyvaet, na kakoe vremya sleduet priostanovit' vypolnenie funkcii select, ozhidaya postupleniya dannyh, naprimer; esli dannye postupayut dlya lyubyh deskriptorov i tajm-aut ne zakon- chilsya, select vozvrashchaet upravlenie, ukazyvaya v dvoichnyh maskah, kakie desk- riptory byli vybrany. Naprimer, esli pol'zovatel' pozhelal priostanovit'sya do momenta polucheniya dannyh po deskriptoram 0, 1 ili 2, parametr rfds ukazhet na dvoichnuyu masku 7; kogda select vozvratit upravlenie, dvoichnaya maska budet zamenena maskoj, ukazyvayushchej, po kakim iz deskriptorov imeyutsya gotovye dan- nye. Dvoichnaya maska wfds vypolnyaet pohozhuyu funkciyu v otnoshenii zapisi desk- riptorov, a dvoichnaya maska efds ukazyvaet na sushchestvovanie isklyuchitel'nyh uslovij, svyazannyh s konkretnymi deskriptorami, chto byvaet polezno pri rabo- te v seti. 10.3.5 Naznachenie operatorskogo terminala Operatorskij terminal - eto terminal, s kotorogo pol'zovatel' registri- ruetsya v sisteme, on upravlyaet processami, zapushchennymi pol'zovatelem s ter- minala. Kogda process otkryvaet terminal, drajver terminala otkryvaet stro- kovyj interfejs. Esli process vozglavlyaet gruppu processov kak rezul'tat vy- polneniya sistemnoj funkcii setpgrp i esli process ne svyazan s odnim iz ope- ratorskih terminalov, strokovyj interfejs delaet otkryvaemyj terminal opera- torskim. On sohranyaet starshij i mladshij nomera ustrojstva dlya fajla termina- la v adresnom prostranstve, vydelennom processu, a nomer gruppy processov, svyazannoj s otkryvaemym processom, v strukture dannyh terminal'nogo drajve- ra. Otkryvaemyj process stanovitsya upravlyayushchim processom, obychno vhodnym (nachal'nym) komandnym processorom, chto my uvidim dalee. Operatorskij terminal igraet vazhnuyu rol' v obrabotke signalov. Kogda pol'zovatel' nazhimaet klavishi "delete" (udaleniya), "break" (preryvaniya), stiraniya ili vyhoda, programma obrabotki preryvanij zagruzhaet strokovyj in- terfejs, kotoryj posylaet sootvetstvuyushchij signal vsem processam v gruppe. 318 Podobno etomu, kogda pol'zovatel' "zavisaet", programma obrabotki preryvanij ot terminala poluchaet informaciyu o "zavisanii" ot apparatury, i strokovyj interfejs posylaet sootvetstvuyushchij signal vsem processam v gruppe. Takim ob- razom, vse processy, zapushchennye s konkretnogo terminala, poluchayut signal o "zavisanii"; reakciej po umolchaniyu dlya bol'shinstva processov budet vyhod iz programmy po poluchenii signala; eto pohozhe na to, kak pri zavershenii raboty pol'zovatelya s terminalom iz sistemy udalyayutsya pobochnye processy. Posle po- sylki signala o "zavisanii" programma obrabotki preryvanij ot terminala raz- ®edinyaet terminal s gruppoj processov, chtoby processy iz etoj gruppy ne mog- li bol'she poluchat' signaly, voznikayushchie na terminale. 10.3.6 Drajver kosvennogo terminala Zachastuyu processam neobhodimo prochitat' il zapisat' dannye neposredst- venno na operatorskij terminal, hotya standartnyj vvod i vyvod mogut byt' pe- renaznacheny v drugie fajly. Naprimer, shell mozhet posylat' srochnye soobshcheniya neposredstvenno na terminal, nesmotrya na to, chto ego standartnyj fajl vyvoda i standartnyj fajl oshibok, vozmozhno, perenaznacheny v drugoe mesto. V versiyah sistemy UNIX podderzhivaetsya "kosvennyj" dostup k terminalu cherez fajl ust- rojstva "/dev/tty", v kotorom dlya kazhdogo processa opredelen upravlyayushchij (operatorskij) terminal. Pol'zovateli, proshedshie registraciyu na otdel'nyh terminalah, mogut obrashchat'sya k fajlu "/dev/tty", no oni poluchat dostup k raznym terminalam. Sushchestvuet dva osnovnyh sposoba poiska yadrom operatorskogo terminala po imeni fajla "/dev/tty". Vo-pervyh, yadro mozhet special'no ukazat' nomer ust- rojstva dlya fajla kosvennogo terminala s otdel'noj tochkoj vhoda v tablicu klyuchej ustrojstv posimvol'nogo vvoda-vyvoda. Pri zapuske kosvennogo termina- la drajver etogo terminala poluchaet starshij i mladshij nomera operatorskogo terminala iz adresnogo prostranstva, vydelennogo processu, i zapuskaet draj- ver real'nogo terminala, ispol'zuya dannye tablicy klyuchej ustrojstv posim- vol'nogo vvoda-vyvoda. Vtoroj sposob, obychno ispol'zuemyj dlya poiska opera- torskogo terminala po imeni "/dev/tty", svyazan s proverkoj sootvetstviya starshego nomera ustrojstva nomeru kosvennogo terminala pered vyzovom proce- dury open, opredelyaemoj tipom dannogo drajvera. V sluchae sovpadeniya nomerov osvobozhdaetsya indeks fajla "/dev/tty", vydelyaetsya indeks operatorskomu ter- minalu, tochka vhoda v tablicu fajlov pereustanavlivaetsya tak, chtoby ukazy- vat' na indeks operatorskogo terminala, i vyzyvaetsya procedura open, prinad- lezhashchaya terminal'nomu drajveru. Deskriptor fajla, vozvrashchennyj posle otkry- tiya fajla "/dev/tty", ukazyvaet neposredstvenno na operatorskij terminal i ego drajver. 10.3.7 Vhod v sistemu Kak pokazano v glave 7, process nachal'noj zagruzki, imeyushchij nomer 1, vy- polnyaet beskonechnyj cikl chteniya iz fajla "/etc/inittab" instrukcij o tom, chto nuzhno delat', esli zagruzhaemaya sistema opredelena kak "odnopol'zovatel'- skaya" ili "mnogopol'zovatel'skaya". V mnogopol'zovatel'skom rezhime samoj per- voj obyazannost'yu processa nachal'noj zagruzki yavlyaetsya predostavlenie pol'zo- vatelyam vozmozhnosti registrirovat'sya v sisteme s terminalov (Risunok 10.19). On porozhdaet processy, imenuemye getty-processami (ot "get tty" - poluchit' terminal), i sledit za tem, kakoj iz processov otkryvaet kakoj terminal; kazhdyj getty-process ustanavlivaet svoyu gruppu processov, ispol'zuya vyzov sistemnoj funkcii setpgrp, otkryvaet otdel'nuyu terminal'nuyu liniyu i obychno priostanavlivaetsya vo vremya vypolneniya funkcii open do teh por, poka mashina ne poluchit apparatnuyu svyaz' s terminalom. Kogda funkciya open vozvrashchaet up- ravlenie, getty-process ispolnyaet programmu login (registracii v sisteme), kotoraya trebuet ot pol'zovatelej, chtoby oni identificirovali sebya ukazaniem 319 registracionnogo imeni i parolya. Esli pol'zovatel' zaregistrirovalsya uspesh- no, programma login nakonec zapuskaet komandnyj processor shell i pol'zova- tel' pristupaet k rabote. |tot vyzov shell'a imenuetsya "login shell" (regis- tracionnyj shell, registracionnyj interpretator komand). Process, svyazannyj s shell'om, imeet tot zhe identifikator, chto i nachal'nyj getty-process, poe- tomu login shell yavlyaetsya processom, vozglavlyayushchim gruppu processov. Esli pol'zovatel' ne smog uspeshno zaregistrirovat'sya, programma registracii za- vershaetsya cherez opredelennyj promezhutok vremeni, zakryvaya otkrytuyu termi- nal'nuyu liniyu, a process nachal'noj zagruzki porozhdaet dlya etoj linii sleduyu- shchij getty-process. Process nachal'noj zagruzki delaet pauzu do polucheniya sig- nala ob okonchanii porozhdennogo ranee processa. Posle vozobnovleniya raboty on vyyasnyaet, byl li prekrativshij sushchestvovanie process registracionnym shell'om i esli eto tak, porozhdaet eshche odin getty-process, otkryvayushchij terminal, vmesto prekrativshego sushchestvovanie. +------------------------------------------------------------+ | algoritm login /* procedura registracii */ | | { | | ispolnyaetsya getty-process: | | ustanovit' gruppu processov (vyzov funkcii setpgrp); | | otkryt' terminal'nuyu liniyu; /* priostanov do zaversheniya| | otkrytiya */ | | esli (otkrytie zavershilos' uspeshno) | | { | | ispolnit' programmu registracii: | | zaprosit' imya pol'zovatelya; | | otklyuchit' eho-soprovozhdenie, zaprosit' parol'; | | esli (registraciya proshla uspeshno) | | /* najden sootvetstvuyushchij parol' v /etc/passwd */ | | { | | perevesti terminal v kanonicheskij rezhim (ioctl);| | ispolnit' shell; | | } | | v protivnom sluchae | | schitat' kolichestvo popytok registracii, pytat'sya| | zaregistrirovat'sya snova do dostizheniya oprede- | | lennoj tochki; | | } | | } | +------------------------------------------------------------+ Risunok 10.19. Algoritm registracii 10.4 POTOKI Shema realizacii drajverov ustrojstv, hotya i otvechaet zalozhennym trebo- vaniyam, stradaet nekotorymi nedostatkami, kotorye s godami stali zametnee. Raznye drajvery imeyut tendenciyu dublirovat' svoi funkcii, v chastnosti draj- very, kotorye realizuyut setevye protokoly i kotorye obychno vklyuchayut v sebya sekciyu upravleniya ustrojstvom i sekciyu protokola. Nesmotrya na to, chto sekciya protokola dolzhna byt' obshchej dlya vseh setevyh ustrojstv, na praktike eto ne tak, poskol'ku yadro ne imeet adekvatnyh mehanizmov dlya obshchego ispol'zovaniya. Naprimer, simvol'nye spiski mogli by byt' poleznymi blagodarya svoim vozmozh- nostyam v buferizacii, no oni trebuyut bol'shih zatrat resursov na posimvol'nuyu obrabotku. Popytki obojti etot mehanizm, chtoby povysit' proizvoditel'nost' sistemy, priveli k narusheniyu modul'nosti podsistemy upravleniya vvodom-vyvo- dom. Otsutstvie obshchnosti na urovne drajverov rasprostranyaetsya vplot' do 320 urovnya komand pol'zovatelya, na kotorom neskol'ko komand mogut vypolnyat' ob- shchie logicheskie funkcii, no razlichnymi sredstvami. Eshche odin nedostatok post- roeniya drajverov zaklyuchaetsya v tom, chto setevye protokoly trebuyut ispol'zo- vaniya sredstva, podobnogo strokovomu interfejsu, v kotorom kazhdaya disciplina realizuet odnu iz chastej protokola i sostavnye chasti soedinyayutsya gibkim ob- razom. Odnako, soedinit' tradicionnye strokovye interfejsy dovol'no trudno. Richi nedavno razrabotal shemu, poluchivshuyu nazvanie "potoki" (streams), dlya povysheniya modul'nosti i gibkosti podsistemy upravleniya vvodom-vyvodom. Nizhesleduyushchee opisanie osnovyvaetsya na ego rabote [Ritchie 84b], hotya reali- zaciya etoj shemy v versii V slegka otlichaetsya. Potok predstavlyaet soboj pol- nodupleksnuyu svyaz' mezhdu processom i drajverom ustrojstva. On sostoit iz so- vokupnosti linejno svyazannyh mezhdu soboj par ocheredej, kazhdaya iz kotoryh (para) vklyuchaet odnu ochered' dlya vvoda i druguyu - dlya vyvoda. Kogda process zapisyvaet dannye v potok, yadro posylaet dannye v ocheredi dlya vyvoda; kogda drajver ustrojstva poluchaet vhodnye dannye, on peresylaet ih v ocheredi dlya vvoda k processu, proizvodyashchemu chtenie. Ocheredi obmenivayutsya soobshcheniyami s sosednimi ocheredyami, ispol'zuya chetko opredelennyj interfejs. Kazhdaya para ocheredej svyazana s odnim iz modulej yadra, takim kak drajver, strokovyj in- terfejs ili protokol, i moduli yadra rabotayut s dannymi, proshedshimi cherez so- otvetstvuyushchie ocheredi. Kazhdaya ochered' predstavlyaet soboj strukturu dannyh, sostoyashchuyu iz sleduyu- shchih elementov: * procedury otkrytiya, vyzyvaemoj vo vremya vypolneniya sistemnoj funkcii open * procedury zakrytiya, vyzyvaemoj vo vremya vypolneniya sistemnoj funkcii close * procedury "vyvoda", vyzyvaemoj dlya peredachi soobshcheniya v ochered' * procedury "obsluzhivaniya", vyzyvaemoj, kogda ochered' zaplanirovana k is- polneniyu * ukazatelya na sleduyushchuyu ochered' v potoke * ukazatelya na spisok soobshchenij, ozhidayushchih obsluzhivaniya * ukazatelya na vnutrennyuyu strukturu dannyh, s pomoshch'yu kotoroj podderzhiva- etsya rabochee sostoyanie ocheredi * flagov, a takzhe verhnej i nizhnej otmetok, ispol'zuemyh dlya upravleniya potokami dannyh, dispetcherizacii i podderzhaniya rabochego sostoyaniya ochere- di. YAdro vydelyaet pary ocheredej, sosedstvuyushchie v pamyati; sledovatel'no, oche- red' legko mozhet otyskat' svoego partnera po pare. +----------+ | Indeks | +-----------------------+ fajla | | |ustrojstva| v +----------+ +------------+-----------+ Zagolovok | Ochered' | Ochered' | potoka | dlya vyvoda | dlya vvoda | +------+-----+-----------+ | ^ v | +------------+-----+-----+ Drajver | Ochered' | Ochered' |------- para ocheredej | dlya vyvoda | dlya vvoda | +------------+-----------+ Risunok 10.20. Potok posle otkrytiya Ustrojstvo s potokovym drajverom yavlyaetsya ustrojstvom posimvol'nogo vvo- 321 da-vyvoda; ono imeet v tablice klyuchej ustrojstv sootvetstvuyushchego tipa speci- al'noe pole, kotoroe ukazyvaet na strukturu inicializacii potoka, soderzhashchuyu adresa procedur, a takzhe verhnyuyu i nizhnyuyu otmetki, upomyanutye vyshe. Kogda yadro vypolnyaet sistemnuyu funkciyu open i obnaruzhivaet, chto fajl ustrojstva imeet tip "special'nyj simvol'nyj", ono proveryaet nalichie novogo polya v tab- lice klyuchej ustrojstv posimvol'nogo vvoda-vyvoda. Esli v tablice otsutstvuet sootvetstvuyushchaya tochka vhoda, to drajver ne yavlyaetsya potokovym, i yadro vypol- nyaet proceduru, obychnuyu dlya ustrojstv posimvol'nogo vvoda-vyvoda. Odnako, pri pervom zhe otkrytii potokovogo drajvera yadro vydelyaet dve pary ocheredej - odnu dlya zagolovka potoka i druguyu dlya drajvera. U vseh otkrytyh potokov mo- dul' zagolovka imeet identichnuyu strukturu: on soderzhit obshchuyu proceduru "vy- voda" i obshchuyu proceduru "obsluzhivaniya" i imeet interfejs s modulyami yadra bo- lee vysokogo urovnya, vypolnyayushchimi funkcii read, write i ioctl. YAdro inicia- liziruet strukturu ocheredej drajvera, naznachaya znacheniya ukazatelyam kazhdoj ocheredi i kopiruya adresa procedur drajvera iz struktury inicializacii draj- vera, i zapuskaet proceduru otkrytiya. Procedura otkrytiya drajvera vypolnyaet obychnuyu inicializaciyu, no pri etom sohranyaet informaciyu, neobhodimuyu dlya povtornogo obrashcheniya k associirovannoj s etoj proceduroj ocheredi. Nakonec, yadro otvodit special'nyj ukazatel' v kopii indeksa v pamyati dlya ssylki na zagolovok potoka (Risunok 10.20). Kogda eshche odin process otkryvaet ustrojst- vo, yadro obnaruzhivaet naznachennyj ranee potok s pomoshch'yu etogo ukazatelya i zapuskaet proceduru otkrytiya dlya vseh modulej potoka. Moduli podderzhivayut svyaz' so svoimi sosedyami po potoku putem peredachi soobshchenij. Soobshchenie sostoit iz spiska zagolovkov blokov, soderzhashchih infor- maciyu soobshcheniya; kazhdyj zagolovok bloka soderzhit ssylku na mesto raspolozhe- niya nachala i konca informacii bloka. Sushchestvuet dva tipa soobshchenij - uprav- lyayushchee i informacionnoe, kotorye opredelyayutsya ukazatelyami tipa v zagolovke soobshcheniya. Upravlyayushchie soobshcheniya mogut byt' rezul'tatom vypolneniya sistemnoj funkcii ioctl ili rezul'tatom osobyh uslovij, takih kak zavisanie terminala, a informacionnye soobshcheniya mogut voznikat' v rezul'tate vypolneniya sistemnoj funkcii write ili v rezul'tate postupleniya dannyh ot ustrojstva. Soobshchenie 1 Soobshchenie 2 Soobshchenie 3 +---------+ +---------+ +---------+ | Blok +--------->| +-------->| | +----+----+ +---------+ +----+----+ v v +---------+ +---------+ | | | | +----+----+ +---------+ v +---------+ | | +---------+ Risunok 10.21. Soobshcheniya v potokah Kogda process proizvodit zapis' v potok, yadro kopiruet dannye iz adres- nogo prostranstva zadachi v bloki soobshcheniya, kotorye vydelyayutsya modulem zago- lovka potoka. Modul' zagolovka potoka zapuskaet proceduru "vyvoda" dlya modu- lya sleduyushchej ocheredi, kotoraya obrabatyvaet soobshchenie, nezamedlitel'no pere- daet ego v sleduyushchuyu ochered' ili stavit v etu zhe ochered' dlya posleduyushchej ob- rabotki. V poslednem sluchae modul' svyazyvaet zagolovki blokov soobshcheniya v spisok s ukazatelyami, formiruya dvunapravlennyj spisok (Risunok 10.21). Zatem on ustanavlivaet v strukture dannyh ocheredi flag, pokazyvaya tem samym, chto i