Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




GESTIUNEA I/O FIZICE

Informatica


GESTIUNEA I/O FIZICE

Subsistemul I/O permite unui proces sa comunice cu dispozitivele periferice cum ar fi discuri, terminale, imprimante si retele, iar modulele nucleu care controleaza dispozitivele sunt cunoscute sub denumirea de drivere de dispozitiv. Exista de obicei o corespondenta unu la unu intre driverele de dispozitiv si tipurile de dispozitive. Sistemele pot contine un driver de disc care sa controleze toate discurile, un driver de terminal care sa controleze toate terminalele si un driver de banda care sa controleze toate unitatile de banda. Sistemele configurate cu dispozitive de la mai multi producatori - de exemplu doua unitati de banda - le pot trata ca doua tipuri de dispozitive diferite si pot avea doua drivere separate, deoarece astfel de dispozitive pot cere secvente de comenzi diferite pentru a putea opera corespunzator. Un driver poate controla mai multe dispozitive fizice de acelasi tip. De exemplu, un driver de terminal poate controla toate terminalele conectate in sistem. Driverul face distinctie intre dispozitivele pe care le controleaza: iesirea ce se intentioneaza sa fie trimisa la un terminal nu trebuie sa ajunga la altul.



Sistemul suporta "dispozitive soft" care nu au asociate dispozitive fizice. De exemplu, el tratează memoria fizica ca un dispozitiv ce permite accesul unui proces la memoria fizica in afara spatiului sau de adrese, cu toate ca memoria nu este un dispozitiv periferic. Comanda ps, de exemplu, citeste structurile de date ale nucleului din memoria fizica pentru a raporta statistici referitoare la procese. Similar, driverele pot scrie înregistrari folositoare pentru depanare si pot permite utilizatorilor sa le citeasca.

Acest capitol examineaza interfetele intre procese si subsistemul I/O si intre masina si drivere. El investigheaza structura generala si functiile driverelor, apoi trateaza driverele de disc si driverele de terminal ca un exemplu detaliat al unei interfete generale. Se incheie cu o descriere a unei noi metode pentru implementarea driverelor de dispozitive numite stream-uri.

6.1 Interfetele de driver

Sistemul UNIX contine doua feluri de dispozitive, dispozitive de tip bloc 222b12c si dispozitive de tip caracter. Dispozitivele de tip bloc 222b12c , cum ar fi discurile si benzile, sunt privite ca dispozitive de memorare cu acces aleator. Dispozitivele de tip caracter includ toate celelalte dispozitive, cum ar fi terminalele si mediile de retea. Dispozitivele de tip bloc 222b12c pot avea o interfata de dispozitiv de tip caracter.

Interfata utilizator - dispozitive trece prin sistemul de fisiere. Fiecare dispozitiv are un nume vazut ca nume de fisier si este accesat ca un fisier. Fisierul special de tip dispozitiv are un inod si ocupa un nod in ierarhia de directoare a sistemului de fisiere. Fisierul dispozitiv se distinge de celelalte fisiere prin tipul fisierului memorat in inodul sau, si poate fi bloc 222b12c , sau caracter, corespunzator dispozitivului pe care il reprezinta. Daca un dispozitiv are atât interfata bloc 222b12c cât si caracter, acesta este reprezentat de doua fisiere dispozitiv : fisierul special de tip bloc 222b12c si fisierul special de tip caracter. Apelurile sistem pentru fisierele obisnuite, cum ar fi open, close, read si write au aceeasi semnificatie pentru dispozitive. Apelul sistem ioctl furnizeaza o interfata ce permite proceselor sa controleze dispozitivele de tip caracter, dar nu este aplicabila pentru fisierele obisnuite. Oricum, nu este nevoie ca fiecare driver de dispozitiv sa suporte toate apelurile sistem. De exemplu, driverul pentru depanare mentionat mai inainte permite utilizatorilor sa citeasca inregistrarile scrise de alte drivere, dar nu permite utilizatorilor sa le scrie.

Configurarea sistemului

Configurea sistemului este procedura prin care administratorii specifica parametrii care sunt dependenti de instalare. Unii parametrii specifica marimea tabelelor nucleului, cum ar fi tabela de procese, tabela de inoduri si tabela de fisiere si numarul de buffere ce vor fi alocate pentru un sistemul de buffere. Alti parametrii specifica configurarea dispozitivelor, informând nucleul care dispozitive sunt incluse in sistem si adresele lor. De exemplu,se poate specifica daca o placa de terminal este conectata intr-un slot particular pe placa de baza. Există trei etape in care poate fi specificat modul de configurare a unui dispozitiv. Intâi, administratorii pot coda hardware datele de configurare in fisiere care sunt compilate si linkeditate când se construieste codul nucleu. Datele de configurare sunt specificate intr-un format simplu si programul de configurare le converteste intr-un fisier porivit pentru compilare. Apoi, administratorii pot furniza informatii de configurare dupa ce sistemul este deja in executie; nucleul actualizează tabelele interne de configurare dinamic. In final, autoidentificarea dispozitivelor permite nucleului sa recunoasca care dispozitiv a fost instalat. Nucleul citeste comutatoarele hardware pentru a se autoconfigura. Detaliile configurarii sistemului depasesc scopul acestui curs, dar in toate cazurile procedura de configurare genereaza sau umple tabelele de configurare care formeaza o parte a codului nucleului.

Interfata dintre nucleu si driver este descrisa prin tabela de comutare a dispozitivelor de tip bloc 222b12c ( bloc 222b12c k device switch table) si prin tabela de comutare a dispozitivelor de tip caracter ( character device switch table ). Fiecare tip de dispozitiv are intrari in tabela ce directioneaza nucleul spre interfata de driver corespunzatoare apelurilor sistem. Apelurile sistem open si close ale unui fisier dispozitiv cauta prin cele doua tabele, in functie de tipul fisierului.

Figura 6.1. Puncte de intrare in driver

Apelurile sistem mount si umount invoca de asemenea procedurile open si close ale dispozitivului pentru dispozitive de tip bloc 222b12c . Apelurile sistem read, write si ioctl ale fisierelor speciale de tip caracter trec prin procedurile respective in tabela de comutare a dispozitivelor de tip caracter. Apelurile sistem read ­si write ale dispozitivelor de tip bloc 222b12c si ale fisierelor de pe sisteme de fisiere montate invoca algoritmii buffer-ului cache care invoca procedura strategy a dispozitivului. Unele drivere invoca procedura strategy intern din procedurile lor read si write. Urmatoarea sectiune exploreaza fiecare interfata de driver si mai amanuntit.

Interfata dintre dispozitiv si hardware este alcatuita din registri de control dependenti de masina sau instructiuni I/O pentru manipularea dispozitivului si vectorilor de întrerupere: când o întrerupere de dispozitiv apare, sistemul identifica dispozitivul care a generato si apeleaza rutina de tratare corespunzatoare. Evident, dispozitivele software nu au o interfata hardware, dar alte rutine de tratare a întreruperilor pot apela direct o rutina de tratare a unei întreruperi software.

Administratorii instaleaza fisierele speciale cu comanda mknod furnizând tipul fisierului (bloc 222b12c sau caracter ) si numerele minor si major.

Comanda mknod invoca apelul sistem mknod pentru a crea un fisier dispozitiv. De exemplu in linia de comanda :

mknod /dev/tty13 c 2 13

"/dev/tty13" este numele de fisier al dispozitivului, c specifica ca este un fisier special de tip caracter ( b specifica un fisier special de tip bloc 222b12c ), 2 este numarul major si 13 este numarul minor. Numarul major indica un tip de dispozitiv ce corespunde unei intrari in tabela de comutare a dispozitivelor de tip caracter sau in tabela de comutare a dispozitivelor de tip bloc 222b12c si numarul minor indica o unitate a dispozitivului. Daca un proces deschide un fisier special de tip bloc 222b12c " /dev/dsk1" si numarul sau major este zero, nucleul apeleaza rutina gdopen din intrarea zero in tabela de comutare a dispozitivelor de tip bloc 222b12c ( Figura 6.2.); daca un proces citeste fisierul special de tip caracter "/dev/mem" si numarul sau major este 3, nucleul apeleaza rutina "mmread" din intrarea 3 in tabela de comutare a dispozitivelor de tip caracter. Rutina nulldev este o rutina "goala" care este folosita când nu este nevoie de o functie anume de driver. Mai multe dispozitive periferice pot fi asociate cu un numar major de dispozitiv; numarul minor face distinctie intre dispozitive. Fisierele speciale nu trebuie sa fie create de fiecare data când sistemul este incarcat: este nevoie ca ele sa fie schimbate numai daca se schimba configuratia, de exemplu când adaugam dispozitive in sistem.


Figura 6.2. Exemplu de tabele de comutare a dispozitivelor de tip

caracter si de tip bloc 222b12c

Apelurile sistem si interfata de driver

Aceasta sectiune descrie interfata intre nucleu si driverele dispozitivelor. Pentru apelurile sistem care folosesc descriptori de fisier, nucleul urmareste pointerii de la descriptorul de fisier al utilizatorului la tabela de fisiere a nucleului si la inod, unde examineaza tipul fisierului si acceseaza tabela de comutare a dispozitivelor de tip caracter sau tabela de comutare a dispozitivelor de tip bloc 222b12c . El extrage numarul minor si numarul major din inod, foloseste numarul major ca un index in tabela corespunzatoare si apeleaza functia driverului in concordanta cu apelul sistem facut, transmitând numarul minor ca parametru. O diferenta importanta intre apelurile sistem pentru fisiere dispozitiv si fisiere obisnuite este că inodul pentru un fisier special nu este bloc 222b12c at in timp ce nucleul executa driverul. Driverele asteapta frecvent conectarile hardware sau sosirea datelor. Daca inodul ar fi bloc 222b12c at, alte procese care ar încerca sa-l acceseze ( prin apelul sistem stat , de exemplu ) ar putea sa se puna in asteptare un timp nedefinit.

Driverul de dispozitiv interpreteaza parametrii apelului sistem in concordanta cu tipul dispozitivului. Driverul pastreaza structurile de date ce descriu starea fiecarei unitati pe care o controleaza; functiile driverului si rutinele de tratare a intreruperilor se executa in acord cu starea driverului.

Open

Nucleul urmeaza pentru deschiderea unui dispozitiv aceeasi procedura pe care o foloseste pentru deschiderea unui fisier obisnuit ( Sectiunea 5.1), alocând un inod in memoria interna, incrementând contorul sau de referinta si asignând o intrare in tabela de fisiere si un descriptor de fisier pentru utilizator. Nucleul returneaza, eventual, descriptorul de fisier procesului apelant, asa incât deschiderea unui dispozitiv arata ca deschiderea unui fisier obisnuit. Oricum, el invoca procedura open specifica dispozitivului inainte de intoarcerea in modul utilizator (Figura 6.3). Pentru un dispozitiv de tip bloc 222b12c , el invoca procedura open din tabela de comutare a dispozitivelor de tip bloc 222b12c si pentru un dispozitiv de tip caracter invoca procedura open din tabela de comutare a dispozitivelor de tip caracter. Daca un dispozitiv este si de tip bloc 222b12c si de tip caracter, nucleul va invoca procedura open corespunzatoare depinzând de fisierul particular pe care utilizatorul l-a deschis. Cele doua proceduri open pot fi chiar identice, aceasta depinzând de driver.

Procedura open specifica dispozitivului stabileste o conexiune intre procesul apelant si dispozitivul deschis, si initializeaza structurile proprii de date ale driverului. Pentru un terminal, de exemplu, procedura open poate pune procesul in asteptare pâna când masina detecteaza un semnal purtator (hardware) care sa indice ca un utilizator încearca sa se logheze in sistem.

Apoi initializează structurile de date ale driverului in concordanta cu setarile corespunzatoare ale terminalului (cum ar fi rata de transfer a terminalului ). Pentru dispozitivele software, cum ar fi memoria, procedura open poate sa nu aiba initializari de facut.

Daca un proces trebuie sa se puna in asteptare pentru unele motive externe, când deschidem un dispozitiv, este posibil ca evenimentul care ar trebui sa trezeasca procesul sa nu apara niciodata. De exemplu, daca nici un utilizator nu se logheaza la un terminal, procesull getty ramâne in asteptare pâna când un utilizator incearca acest lucru, posibil un timp indelungat. Nucleul trebuie sa fie capabil sa trezeasca procesul si sa intrerupa apelul open la receptionarea unui semnal. El trebuie sa reseteze inodul, intrarea in tabela de fisiere si descriptorul de fisier care a fost alocat inainte de intrarea in driver, deoarece deschiderea dispozitivului esueaza. Din acest motiv, nucleul salveaza contextul procesului folosind algoritmul setjmp ( Sectiunea 7.4.4) inainte de intrarea in rutina open specifica driverului; daca procesul este trezit din cauza unui semnal, nucleul restaureaza contextul procesului la starea de dinainte de a intra in driver folosind algoritmul longjmp (Sectiunea 7.4.4) si elibereaza toate structurile de date pe care le-a alocat pentru apelul open. Similar, driverul poate intercepta semnalul si sterge structurile de date private, daca este necesar. Nucleul reajusteaza structurile de date ale sistemului de fisiere când driverul intâlneste conditii de eroare, cum ar fi când un utilizator incearca sa acceseze un dispozitiv care nu a fost configurat. Apelul open esueaza in aceste cazuri.

Procesele pot specifica diferite optiuni pentru apelul open . Cea mai obisnuita optiune este "fara întârziere" , însemnând ca procesul nu se va pune in asteptare in timpul procedurii open daca dispozitivul nu este pregatit. Apelul sistem open se termina imediat si procesul utilizator nu are de unde sa stie dacă conectarea hardware a fost facuta sau nu. Deschiderea unui dispozitiv cu optiunea "fara întârziere" afecteaza semantica apelului sistem read.

Daca un dispozitiv este deschis de mai multe ori, nucleul manipuleaza descriptorii de fisier, inodul si intrarile in tabela de fisiere cum s-a descris in capitolul 5, invocând procedura open specifica dispozitivului pentru fiecare apel sistem open. Driverul dispozitivului poate deci numara de câte ori a fost deschis un dispozitiv si apelul open esueaza daca numarul nu este potrivit. De exemplu, are sens sa se permită mai multor procese sa deschida un terminal pentru scriere asa incât utilizatorii sa poata schimba mesaje. Dar nu are sens sa se permita mai multor procese sa deschida o imprimanta pentru scriere simultan, deoarece s-ar putea scrie datele unui proces peste datele altor procese. Diferentele sunt mai curând practice decât de implementare: permiterea scrierii simultane la terminare inlesneste comunicarea intre utilizatori; prevenirea scrierii simultane la imprimanta creste sansa obtineri unor rezultate lizibile la iesirea imprimantei.

algoritmul open ( pentru drivere de dispozitive )

intrari: numele fisierului

mod de deschidere

iesiri : descriptorul de fisier

else

if ( deschiderea esueaza )

decrementeaza contorul din tabela de fisiere si din inod;

Figura 6.3. Algoritmul pentru deschiderea unui dispozitiv

Close

Un proces se deconecteaza de la un dispozitiv deschis prin inchiderea lui. Oricum, nucleul invoca procedura close specifica numai driverului pentru ultimul apel close adresat dispozitivului, numai daca nici un alt proces nu are dispozitivul deschis, deoarece procedura close inchide conexiunea hardware; evident aceasta trebuie sa astepte pâna când nici un alt proces nu mai acceseaza dispozitivul. Deoarece nucleul invoca procedura open in timpul fiecarui apel sistem open si invoca procedura close numai o singura data, driverul dispozitivului nu stie niciodata sigur de câte procese mai folosesc inca dispozitivul.

Driverele pot ajunge usor intr-o stare incorecta daca nu sunt modificate cu atentie. Daca ele sunt puse in asteptare in procedura close si un alt proces deschide dispozitivul înaintea terminarii procedurii close, dispozitivul poate fi considerat nefolositor daca combinatia de apeluri open si close furnizeaza o stare incorecta.

Algoritmul pentru închiderea unui dispozitiv este similar cu algoritmul pentru închiderea unui fisier obisnuit (figura 6.4).Totusi, înainte de eliberarea inodului, nucleul executa unele operatiuni specifice.

1. Nucleul cauta in tabela de fisiere pentru a fi sigur ca nici un alt proces nu are inca dispozitivul deschis. Nu este suficient sa ne bazam pe contorul din tabela de fisiere pentru a indica ultima inchidere a dispozitivului, deoarece mai multe procese pot accesa dispozitivul cu o intrari diferite in tabela de fisiere. De asemenea nu este suficient sa ne bazam pe contorul din tabela de inoduri, deoarece mai multe fisiere pot specifica acelasi dispozitiv. De exemplu, rezultatul urmatoarei comenzi: ls -l arata doua fisiere speciale de tip caracter (primul "c" de pe linie) care refera un singur dispozitiv, deoarece numerele lor majore si minore (9 si 1) sunt egale. Numarul de legaturi (1) pentru fiecare fisier arata ca exista doua inoduri.

crw--w--w- 1 root vis 9, 1 Aug 6 1984 /dev/tty01

crw--w--w- 1 root unix 9, 1 May 3 15:02 /dev/tty01

Daca procesele deschid cele două fisiere independent, ele acceseaza inoduri diferite dar acelasi dispozitiv.

2. Pentru un dispozitiv de tip caracter, nucleul invoca procedura close si revine in modul utilizator. Pentru un dispozitiv de tip bloc 222b12c , nucleul cauta in tabela de montare pentru a se asigura ca dispozitivul nu contine un sistem de fisiere montat. Daca exista un sistem de fisiere montat pe dispozitivul de tip bloc 222b12c , nucleul nu poate invoca procedura close , deoarece nu este ultimul apel close al dispozitivului. Chiar daca dispozitivul nu contine un sistem de fisiere montat, buffer-ul cache poate contine inca bloc 222b12c uri de date care au fost ramase de la sistemul de fisiere montat anterior si nu au fost scrise pe dispozitiv, deoarece ele au fost marcate" intârziere la scriere". Nucleul cauta deci in buffer-ul cache astfel de bloc 222b12c uri si le scrie pe dispozitiv inainte de invocarea procedurii close. Dupa inchiderea dispozitivului, nucleul trece din nou prin buffer-ul cache si invalideaza toate bufer-ele ce contin bloc 222b12c uri ale dispozitivului inchis, permitând buffere-lor cu date folositoare sa mai ramâna in cache.

3. Nucleul elibereaza inodul fisierului dispozitiv.

Concluzionând, procedura close deconecteaza dispozitivul si reinitializeaza structurile de date ale driverului si hardware-ul dispozitivului, asa incât nucleul sa poata redeschide dispozitivul mai târziu.

Figura 6.4. Algoritmul pentru inchiderea unui dispozitiv

Read si Write

Algoritmii nucleului pentru citirea si scrierea in,respectiv din dispozitiv sunt similari cu aceia pentru un fisier obisnuit. Daca procesul citeste sau scrie un dispozitiv de tip caracter, nucleul invoca procedurile read sau write . Desi acestea sunt cazuri importante in care nucleul transmite date direct intre spatiul de adrese utilizator si dispozitiv, driverele de dispozitiv pot pastra bufferele de date intern. De exemplu, driverele de terminal folosesc liste de caractere pentru aceasta sa buffereze datele (Sectiunea 6.3.1.). In astfel de cazuri, driverul dispozitivului aloca un buffer, copiaza datele din spatiul utilizator in timpul unui apel write, si scoate datele din bufer la dispozitiv. Procedura write limiteaza cantitatea de date scoasa la iesire ( controlul fluxului) : daca procesele genereaza date mai rapid decât dispozitivul le poate scoate la iesire, procedura write pune procesele in asteptare pâna când dispozitivul poate acepta mai multe date. Pentru o citire driverul de dispozitiv primeste date de la dispozitiv intr-un buffer si copiaza datele din buffer la adresa utilizator specificata in apelul sistem.

Metoda precisa prin care un driver comunica cu un dispozitiv depinde de hardware. Unele masini furnizeaza operatii de I/O mapate in memorie, ceea ce inseamna ca anumite adrese din spatiul de adrese nucleu nu sunt locatii in memoria fizica dar sunt registre speciale ce controleaza anumite dispozitive. Prin scrierea parametrilor de control in registrii specificati in concordanta cu specificatiile hardware, driverul controleaza dispozitivul. De exemplu controller-ele I/O pentru calculatoarele VAX - 11 contin registre speciale pentru înregistrarea starii dispozitivului (registrii de stare si control) si pentru transmisia datelor (registrii de buffer-are a datelor), care sunt configurati la adrese specifice in memoria fizica. In particular, controller-ul terminalului VAX DZ 11 controleaza 8 linii asincrone pentru comunicarea cu terminalul. Presupunem ca registrul de stare si control al unui controller DZ 11 este la adresa 160120 , registrul de buffer-are a datelor de transmis este la adresa 160126, si registrul de buffer-are a datelor primite este la adresa 160122 (Figura 6.5).Pentru a scrie un caracter la terminalul "/dev/tty09", driverul de terminal scrie 1 (1=9 mod 8) in pozitia specificata din registrul de control si stare si apoi scrie caracterul in registrul de buffer-are a datelor de transmis. Operatia de scriere a registrului de buffer-are a datelor de transmis înseamna transmiterea datelor. Controller-ul DZ 11 seteaza bitul "done" in registrul de control si stare când este gata sa accepte mai multe date. Driverul poate seta optional un bit "activare întrerupere "in registrul de control si stare, care face ca controller-ul DZ 11 sa întrerupa sistemul când este gata sa accepte mai multe date. Citirea datelor de la DZ 11 este similara.


Figura 6.5. I/O mapate in memorie cu controllerul VAX DZ11

Alte masini au I/O programate, însemnând ca masina contine instructiuni de control pentru dispozitiv. Driverele controleaza dispozitivele prin executarea instructiunilor corespunzatoare. De exemplu, calculatorul IBM 370 are o instructiune start I/O pentru a initializa operatii I/O cu un dispozitiv. Metoda pe care un driver o foloseste sa comunice cu perifericele este transparenta pentru utilizator.

Deoarece interfata intre driverele de dispozitiv si suportul hardware este dependenta de masina , nu exista nici o standardizare a interfetei la acest nivel. Pentru I/O mapate in memorie si I/O programate, un driver poate sa activeze secventele de control ale unui dispozitiv setând accesul direct la memorie (DMA) intre dispozitiv si memorie. Sistemul permite transferul DMA al datelor intre dispozitiv si memorie in paralel cu operatiunile UCP, si dispozitivul întrerupe sistemul când un astfel de transfer s-a terminat. Driverul seteaza maparea memoriei virtuale asa încât locatiile corespunzatoare din memorie sunt folosite pentru DMA.

Dispozitivele de mare viteza pot uneori transfera date direct intre dispozitiv si spatiul de adrese utilizator, fara interventia unui buffer al nucleului. Rezulta o viteza mai mare de transfer deoarece am renuntat la operatiunea de copiere in nucleu, si cantitatea de date transmisa intr-o operatie de transfer nu este limitata de marimea buffere-lor nucleului.

Interfata de strategy

Nucleul foloseste interfata de strategy pentru a transmite date intre buffer-ul cache si un dispozitiv, desi cum s-a mentionat anterior, procedurile read si write ale dispozitivului de tip caracter folosesc uneori procedura lor de strategy pentru a transfera datele direct intre dispozitiv si spatiul de adrese utilizator. Procedura de strategy poate inlantui sarcinile I/O ale unui dispozitiv intr-o lista de lucru sau poate sa faca mult mai complicata procesarea, planificând aceste sarcini de I/O. Driverele pot seta transmisia datelor pentru o adresa fizica sau mai multe. Nucleul transfera procedurii strategy adresa antetului buffer-ului. Antetul contine o lista a adreselor (paginilor) si marimea datelor de transmis la si de la dispozitiv. Pentru buffer-ul cache, nucleul transmite datele de la o adresa de date; când se face swapping, nucleul transmite datele de la mai multe adrese ( pagini). Daca datele sunt copiate la sau din spatiul de adrese utilizator, driverul trebuie sa bloc 222b12c heze procesul ( sau cel putin, paginile semnificative) in memorie pâna când transferul I/O este complet.

De exemplu, dupa montarea unui sistem de fisiere, nucleul identifica fiecare fisier in sistemul de fisiere prin numarul de dispozitiv si prin numarul de inod. Numarul de dispozitiv este o combinatie a numarului major si numarului minor al dispozitivului. Când nucleul acceseaza un bloc 222b12c dintr-un fisier, el copiaza numarul dispozitivului si numarul bloc 222b12c ului in antetul buffer-ului, cum s-a descris in capitolul 3. Când algoritmii buffer-ului cache ( bread sau bwrite, de exemplu ) acceseaza discul, ei invoca procedura de strategy indicata prin numarul major al dispozitivului. Procedura de strategy foloseste numarul minor si numarul bloc 222b12c ului in antetul buffer-ului pentru a identifica datele pe dispozitiv si foloseste adresa buffer-ului sa identifica unde trebuie transferate datele. Similar, daca un proces acceseaza direct un dispozitiv de tip bloc 222b12c ( adica îl deschide si scrie sau citeste din el ), el foloseste algoritmii buffer-ului cache si interfata lucreaza exact cum s-a descris.

Ioctl

Apelul sistem ioctl este o generalizare a apelurilor sistem specifice terminalului stty si gtty disponibile in versiunile anterioare ale sistemului UNIX. Furnizeaza un punct de intrare pentru interceptarea tuturor comenzilor specifice unui dispozitiv, permitând unui proces sa seteze optiunile hardware asociate cu un dispozitiv si optiunile software asociate cu driverul. Programele care folosesc ioctl trebuie sa stie ce tip are fisierul pe care îl trateaza. Aceasta este o exceptie de la regula generala ca sistemul nu face diferentieri intre diferitele tipuri de fisiere. Sectiunea 6.3.3. furnizeaza mai multe detalii referitoare la folosirea apelului ioctl pentru terminale.

Sintaxa apelului sistem este:

ioctl ( fd, comandă, arg );

unde fd este descriptorul de fisier returnat de apelul sistem open, comanda este o cerere de executare a unei actiuni de catre driver si arg este un parametru ( posibil un pointer catre o structura ) pentru comanda. Comenzile sunt specifice driverului; din acest motiv fiecare driver interpreteaza comenzile in concordanta cu specificatiile interne, si formatul structurii de date arg depinde de comanda. Driverele pot citi structura de date arg din spatiul utilizator in concordanta cu formatele predefinite, sau pot scrie setarile dispozitivului in spatiul de adrese utilizator la adresa arg. De exemplu, interfata ioctl permite utilizatorilor sa seteze ratele de transfer ale terminalului; permite utilizatorilor sa deruleze benzile la un driver de banda; in final, permite operatii specifice retelelor cum ar fi specificarea numerelor circuitelor virtuale si ale adreselor de retea.

Alte apeluri sistem referitoare la sistemul de fisiere

Apelurile sistem cum ar fi stat si chmod au acelasi rol pe care îl au pentru fisierele obisnuite, manipuleaza inodul fara sa acceseze driverul. Chiar si apelul sistem lseek este accesibil fisierelor speciale. De exemplu, daca un proces apeleaza lseek pentru un octet particular al unei benzi, nucleul actualizeaza deplasamentul din tabela de fisiere, dar nu face operatii specifice driverului. Când procesul citeste sau scrie mai târziu, nucleul muta deplasamentul din tabela de fisiere in uArea, asa cum face si pentru fisierele obisnuite, si dispozitivul cauta fizic la adresa corect indicata in uArea . Un exemplu in sectiunea 6.3. ilustreaza acest caz.


Figura 6.6. Întreruperile de dispozitiv

6.4 Rutinele de tratare a întreruperilor

Aparitia unei întreruperi face ca nucleul sa execute o rutina de tratare a întreruperii, bazata pe corelatia intre dispozitivul întrerupt si un deplasament in tabela vectorilor de întrerupere. Nucleul invoca rutina de tratare a întreruperii specifica dispozitivului, transmitându-i numarul de dispozitiv sau alti parametri pentru a identifica unitatea care a produs întreruperea. De exemplu, figura 6.6 arata doua intrari in tabela vectorilor de întrerupere pentru tratarea întreruperilor de terminal ttyintr , fiecare tratând întreruperile pentru 8 terminale. Daca dispozitivul tty09 întrerupe sistemul, acesta apeleaza rutina de tratare a întreruperii asociata cu pozitia hardware a dispozitivului întrerupt. Deoarece multe dispozitive fizice pot fi asociate cu o intrare in tabela vectorilor de întrerupere, driverul trebuie sa fie capabil sa afle care dispozitiv a produs întreruperea. In figura doua intrari in tabela vectorilor de întrerupere pentru ttyintr sunt etichetate cu 0 si 1, implicând ca sistemul face distinctie intre cele doua intrari când se apeleaza rutina de tratare a întreruperii, prin folosirea acestui numar (eticheta ) ca un parametru al apelului. Rutina de tratare a întreruperii poate folosi acest numar si alte informatii transmise prin mecanismul de întreruperi ca sa se asigure ca dispozitivul tty09 a întrerupt sistemul si nu tty12, de exemplu. Acest exemplu este o simplificare a ceea ce se întâmpla intr-un sistem real, unde figura ar cuprinde mai multe nivele ale controllere-lor si rutinele lor de tratare a întreruperilor.

Pe scurt, numarul dispozitivului folosit in rutina de tratare a întreruperii identifica o unitate hardware si numarul minor al fisierului dispozitiv identifica un dispozitiv. Driverul de dispozitiv coreleaza numarul minor al dispozitivului cu numarul unitatii hardware.

6.5 Driverele de disc

Unitatile de disc pe sistemele UNIX au fost configurate in sectiuni ce contin sisteme de fisiere individuale. Daca un disc contine 4 sisteme de fisiere , un administrator poate lasa unul nemontat, poate monta altul cu optiunea "doar pentru citire "si poate monta ultimele doua cu optiunea "citire-scriere" . Chiar daca toate sistemele de fisiere coexista pe o unitate fizica, utilizatorii nu pot accesa fisierele din sistemul de fisiere nemontat folosind metodele de acces descrise in capitolele 4 si 5 si nici nu pot scrie fisiere in sistemul de fisiere marcat doar pentru citire. In plus, întrucât fiecare sectiune ( si din acest motiv sistemul de fisiere ) ocupa piste si cilindrii alaturati pe disc, este mai usor sa se copieze întregul sistem de fisiere decât daca ar fi dispersat pe întregul volum al discului.

Driverul de disc translateaza adresa sistemului de fisiere, constând intr-un numar de dispozitiv logic si numarul bloc 222b12c ului, intr-un sector particular de pe disc. Driverul obtine adresa intr-unul din cele doua moduri: fiecare procedura de strategy foloseste un buffer din sistemul de buffere si antetul buffer-ului contine numarul dispozitivului si al bloc 222b12c ului, sau procedurile read si write folosesc numarul dispozitivului logic (numarul minor ) ca un parametru; convertesc deplasamentul salvat in uArea la adresa de bloc 222b12c potrivita. Driverul de disc foloseste numarul dispozitivului pentru a identifica driverul fizic si sectiunea particulara ce va fi folosita, mentinând tabelele interne pentru a gasi sectorul care marcheaza începutul unei sectiuni de disc. In final, adauga numarul bloc 222b12c ului din sistemul de fisiere la numarul sectorului de start pentru a identifica sectorul folosit pentru transmisia I/O.

Figura 6.7. Sectiunile de disc pentru discul RP07

Marimea si lungimea sectiunilor de disc au fost fixate in concordanta cu tipul discului. De exemplu, discul DEC RP07 este partitionat in sectiunile aratate in figura 6.7. Presupunem ca fisierele "/dev/dsk0", "/dev/dsk1", "/dev/dsk2" si "/dev/dsk3" corespund sectiunilor de la 0 la 3 ale unui disc RP07 si au numerele minore de la 0 la 3. Presupunem ca marimea unui bloc 222b12c logic al sistemului de fisiere este aceeasi cu a unui bloc 222b12c disc. Daca nucleul încearca sa acceseze bloc 222b12c ul 940 din sistemul de fisiere continut in "/dev/dsk3", driverul de disc acceseaza bloc 222b12c ul 336940 (sectiunea 3 începe la bloc 222b12c ul 336000; 336000+940=336940 ) de pe disc.

Marimea sectiunilor discului variaza si administratorii configureaza sectiunile sistemului de fisiere la marimea corespunzatoare. Sectiunile se pot suprapune pe disc. De exemplu, sectiunile 0 si 1 in RP07 sunt disjuncte, dar împreuna ele pot acoperi bloc 222b12c urile de la 0 la 1008000, întregul disc. Suprapunerea sectiunilor nu conteaza, sistemele de fisiere continute in sectiuni fiind configurate asa încât sa nu se suprapuna. Este avantajos sa avem o sectiune care sa includa întregul disc, pentru ca întregul volum sa poata fi copiat rapid.

Folosirea unor sectiuni fixe restrictioneaza flexibilitatea configurarii discului. Cunostintele codificate hardware despre sectiunile de disc nu pot fi pastrate in driverul de disc dar pot fi pastrate pe disc intr-o tabela configurabila. Oricum, este dificil de gasit o pozitie generica pe toate discurile pentru tabela de cuprins a volumului si care sa pastreze compatibilitatea cu versiunile anterioare ale sistemului. In implementarea curenta a System V se asteapta ca bloc 222b12c ul de boot al primului sistem de fisiere de pe un disc sa ocupe primul sector al volumului. Cu toate acestea, driverul de disc poate contine informatii codificate hardware acolo unde tabela de cuprins a volumului este memorata pentru acest disc particular, permitând sectiuni de disc de dimensiuni variabile.

Din cauza traficului înalt la nivelul discului tipic sistemelor UNIX, driverul de disc trebuie sa maximizeze cantitatea de date transferate pentru a obtine cele mai bune performante ale sistemului. Cel mai moderne controllere de disc realizeaza planificarea sarcinilor discului, pozitionand bratul discului si transferând datele intre disc si CPU; altfel driverul de disc trebuie sa îndeplineasca aceste sarcini.

Programele utilitare pot folosi fiecare o interfata bloc 222b12c sau caracter pentru a accesa datele de pe disc direct, ocolind metodele de acces de la fisierele obisnuite investigate in capitolele 4 si 5. Doua programe importante care lucreaza direct cu discul sunt mkfs si fsck. Mkfs formateaza o sectiune de disc pentru un sistem de fisiere UNIX, creând un superbloc 222b12c , lista de inoduri, lista bloc 222b12c urilor disc libere si un director radacina al noului sistem de fisiere. Fsck verifica consistenta unui sistem de fisiere existent si corecteaza erorile.

Consideram programul din figura 6.8 si fisierele "/dev/dsk15" si "/dev/rdsk15", si presupunem ca comanda ls tipareste urmatoarele informatii:

ls -l /dev/dsk15 /dev/rdsk15

br - - - - - - - - 2 root root 0,21 Feb 12 15:40 /dev/dsk15

crw- rw - - - - 2 root root 7,21 Mar 7 09:29 /dev/rdsk15

Programul arata ca "/dev/dsk15"este un dispozitiv de tip bloc 222b12c apartinând radacinii si numai radacina poate sa-l citeasca direct. Numarul sau major este 0 si numarul minor este 21. Fisierul "/dev/rdsk15" este de tip caracter apartinând radacinii, dar permite citirea si scrierea pentru proprietar si grup . Numarul major este 7 si numarul minor este 21.

#include <fcntl.h>

main()

lseek (fd1, 8192L, 0);

lseek (fd2, 8192L, 0);

if ((read(fd1,buf1,sizeof(buf1))==-1) || (read (fd2,buf2,sizeof(buf2))==-1

for (i=0; i < sizeof(buf1); i++)

if (buf1[i] != buf2[i]

printf ( "ambele siruri (buf1 si buf2) contin aceleasi informatii\n");

}

 

Figura 6.8. Citirea datelor de pe disc folosind interfata caracter si

interfata bloc 222b12c

Un proces deschizând fisierele câstiga accesul la dispozitiv prin tabela de comutare a dispozitivelor de tip caracter si, respectiv, prin tabela de comutare a dispozitivelor de tip bloc 222b12c si numarul minor 21 informeaza driverul care sectiune de disc este accesata - de exemplu, driverul fizic 2, sectiunea 1. Deoarece numerele minore sunt identice pentru cele doua fisiere, amândoua refera aceeasi sectiune de disc, presupunând ca este un singur dispozitiv. Deci un proces care executa programul deschide acelasi driver de doua ori ( prin interfete diferite ), se pozitioneaza la deplasamentul 8192 in dispozitiv si citeste datele de la acea pozitie. Rezultatele apelurilor read trebuie sa fie identice , presupunând ca nici o alta operatie a sistemului nu este in curs de desfasurare.

Programele care citesc si scriu direct pe disc sunt periculoase deoarece ele pot citi si scrie date nesigure, primejduind securitatea sistemului. Administratorii pot proteja interfetele prin setarea permisiunilor corespunzatoare. De exemplu, fisierele "/dev/dsk15" si "/dev/rdsk15" trebuie sa aiba acelasi proprietar ca cel al radacinii si permisiunile lor trebuie sa permita acestuia sa citeasca fisierele dar nu trebuie sa permita nici unui alt utilizator sa citeasca sau sa scrie.

Programele care citesc si scriu direct pe disc pot de asemenea sa distruga consistenta datelor sistemului de fisiere. Algoritmii sistemului de fisiere explicati in capitolele 3,4 si 5 coordoneaza operatiunile de I/ O cu discul pentru a pastra o imagine consistenta a structurilor de date ale acestuia, incluzând listele bloc 222b12c urilor disc libere si pointeri de la inoduri la bloc 222b12c urile de date directe sau indirecte. Procesele care acceseaza discul direct ocolesc acesti algoritmi. Chiar daca sunt configurate cu atentie, exista inca problema consistentei daca ruleaza in timp ce activitatea altor sisteme de fisiere continua. Pentru aceste motive, fsck nu trebuie sa se execute pe un sistem de fisiere activ.

Diferenta intre cele doua interfete de disc consta in modul de lucru cu buffer-ul cache. Când acceseaza interfata dispozitivului de tip bloc 222b12c , nucleul urmareste acelasi algoritm ca si pentru fisierele obisnuite, exceptând faptul ca dupa convertirea deplasamentului logic intr-un deplasament de bloc 222b12c logic, el îl trateaza ca un numar de bloc 222b12c fizic in sistemul de fisiere. Apoi acceseaza datele prin buffer-ul cache si interfata de strategy a driverului. Totusi, când acceseaza discul prin interfata de tip caracter, nucleul nu converteste deplasamentul in fisier , dar îl transmite imediat la driver prin uArea. Rutina read sau write a driverului converteste deplasamentul la o adresa de bloc 222b12c si copiaza datele direct in spatiul de adrese utilizator, ocolind buffer-le nucleului.

Deci, daca un proces scrie un dispozitiv de tip bloc 222b12c si un al doilea proces citeste apoi un dispozitiv de tip caracter de la aceeasi adresa, al doilea proces nu poate citi datele pe care primul proces le-a scris, deoarece datele pot fi inca in buffer-ul cache si nu pe disc.

Folosirea unei interfete de tip caracter poate de asemenea introduce o comportare ciudata. Daca un proces citeste sau scrie un dispozitiv brut in unitati mai mici decât lungimea bloc 222b12c ului, de exemplu, rezultatele sunt dependente de driver. Când un octet este scris pe o banda, fiecare octet poate aparea in diferite bloc 222b12c uri ale benzii.

Avantajul folosirii interfetei brute este viteza, presupunând ca nu exista avantaje la pastrarea datelor pentru accesul anterior. Procesele care acceseaza dispozitive de tip bloc 222b12c , transfera bloc 222b12c uri de date a caror marime este constrânsa de marimea bloc 222b12c ului logic al sistemului de fisiere. De exemplu, daca un sistem de fisiere are o marime a bloc 222b12c ului logic de 1ko, cel mult 1 ko se transfera la o singura operatiune I/O. Totusi, procesele care acceseaza discul ca pe un dispozitiv de tip caracter pot transfera mai multe bloc 222b12c uri disc in timpul unei operatiuni cu discul. Functional, procesul vede acelasi rezultat, dar interfata de tip caracter poate fi mult mai rapida. In figura 6.8. când un proces citeste 4096 de octeti folosind interfata bloc 222b12c pentru un sistem de fisiere cu bloc 222b12c uri de 1ko, nucleul executa un ciclu intern de 4 ori si acceseaza discul in timpul fiecarei iteratii înainte de revenirea din apelul sistem, dar când citeste interfata de tip caracter, driverul poate satisface citirea printr-o singura operatiune cu discul. In plus, folosirea interfetei bloc 222b12c determina o extracopie intre spatiul de adrese utilizator si buffere-le nucleului, operatiune care este evitata de interfata de tip caracter.

6.6 Driverele de terminale

Driverele de terminal au aceeasi functie ca celelalte drivere: sa controleze transmisia datelor la si de la terminale. Totusi, terminalele sunt speciale deoarece ele sunt interfata utilizatorului cu sistemul. Pentru acomodarea cu folosirea interactiva a sistemului UNIX, driverele de terminal contin o interfata interna pentru modulele de disciplina a liniei care interpreteaza intrarile si iesirile. In modul canonic, disciplina de linie converteste secventele de date de tip caracter de la tastatura la o forma canonica, înainte de trimiterea datelor la procesul care trebuie sa le receptioneze. Disciplina de linie converteste, de asemenea, secventa de caractere scrisa la iesire de un proces la un format pe care utilizatorul îl asteapta. In modul caracter, disciplina de linie transmite datele intre procese si terminal fara astfel de conversii.

De exemplu, programatorii sunt rapizi dar predispusi greselilor. Terminalele furnizeaza o cheie de "stergere" asa încât utilizatorul poate sterge logic parti din secventa tiparita si poate introduce corectiile. Terminalul trimite masinii întreaga secventa, incluzând caracterele sterse. In modul canonic, disciplina de linie pastreaza datele in linii ( secvente de caractere ce se încheie cu CR) si procesele sterg caracterele intern înainte de trimiterea secventei revizuite la procesul cititor.

Functiile unei discipline de linie sunt:

- sa imparta sirurile de intrare in linii,

- sa proceseze un caracter "kill" ce invalideaza toate caracterele tiparite in continuare pe linia curenta,

- sa scrie caracterele receptionate la terminal,

- sa extinda iesirea, cum ar fi caracterele "tab" la o secventa de spatii

-sa genereze semnale proceselor pentru întreruperile de terminal, întreruperile de linii sau ca raspuns la apasarea de catre utilizator a tastei "delete ",

- sa permita un mod caracter care nu interpreteaza caracterele speciale, cum ar fi "erase", "kill" sau "CR ",

Suportul modului caracter implica utilizarea unui terminal asincron, deoarece procesele pot citi caractere când ele sunt tiparite, in loc sa astepte pâna ce un utilizator apasa "CR".

Figura 6.9 arata fluxul logic de date prin driverul de terminal, disciplina de linie si fluxul de control corespunzator prin driverul de terminal. Utilizatorii pot specifica care disciplina de linie trebuie sa fie utilizata printr-un apel ioctl , dar este dificil sa se implementeze o schema astfel încât un dispozitiv sa foloseasca mai multe discipline de linie simultan, unde fiecare modul de disciplina de linie apeleaza succesiv urmatorul modul pentru a procesa datele.

Figura 6.9. Secventa de apel si flux de date prin disciplina de linie

Liste de caractere

Disciplina de linie manipuleaza datele pe liste de caractere. O lista de caractere este o lista inlantuita de lungime variabila de bloc 222b12c uri de caractere si contine un contor care memoreaza numarul de caractere din lista. Un bloc 222b12c de caractere contine un pointer spre urmatorul bloc 222b12c de caractere din lista inlantuita, un mic sir de caractere care contine datele si un set de adrese care indica pozitia datelor valide in bloc 222b12c ul de caractere (Figura 6.10). Adresa de start indica prima locatie a datelor valide din sir si adresa de sfârsit indica prima locatie de date care nu sunt valide.

Figura 6.10. Un bloc 222b12c de caractere

Nucleul pastreaza o lista inlantuita a bloc 222b12c urilor de caractere libere si are sase operatii pentru bloc 222b12c uri si liste de caractere.

1. Are operatia de asignare a unui bloc 222b12c de caractere din lista bloc 222b12c urilor libere

de la un driver .

2. De asemenea are o operatie de adaugare a unui bloc 222b12c de caractere la lista

bloc 222b12c urilor libere.

3. Nucleul poate recupera primul caracter dintr-o lista de caractere: el scoate primul caracter din primul bloc 222b12c de caractere din lista si ajusteaza numarul caracterelor din lista si indicii in bloc 222b12c asa încât urmatoarele operatii nu vor accesa acelasi caracter. Daca o operatie de accesare consuma ultimul caracter al bloc 222b12c ului, nucleul plaseaza bloc 222b12c ul gol in lista bloc 222b12c urilor libere si ajusteaza pointerii. Daca o lista nu contine caractere când se executa o operatie de recuperare , nucleul returneaza caracterul null.

4. Nucleul poate plasa un caracter la sfârsitul unei liste prin gasirea ultimului bloc 222b12c din lista, punând caracterul in el si ajustând valoarea deplasamentului. Daca bloc 222b12c ul este plin, nucleul aloca un nou bloc 222b12c , îl leaga la sfârsitul listei si plaseaza caracterul in noul bloc 222b12c .

5. Nucleul poate scoate un grup de caractere de la începutul unei liste, intr-o operatie aceasta fiind echivalent cu scoaterea tuturor caracterelor din bloc 222b12c intr-o singura operatiune.

6. Nucleul poate plasa un bloc 222b12c de caractere la sfârsitul unei liste.

Listele de caractere furnizeaza un mecanism de buffer-are simplu, folositor pentru volume mici de date de transmis tipice dispozitivelor lente cum sunt terminalele. Ele permit manipularea datelor caracter la un moment dat sau in grupuri de bloc 222b12c uri de caractere. De exemplu, figura 6.11 arata modul de scoatere a caracterelor din lista (Figura 6.11 a-c ) pâna când nu mai sunt caractere in bloc 222b12c ( Figura 6.11 d ); apoi, el ajusteaza pointerul clistei sa pointeze la urmatorul cbloc 222b12c , care devine primul din lista inlantuita. Similar, figura 6.12 descrie cum nucleul pune caractere in lista de caractere: presupunând ca un bloc 222b12c are o capacitate de 8 caractere, nucleul leaga un nou bloc 222b12c la sfârsitul listei inlantuite ( Figura 6.12 d ).

Figura 6.11. Scoaterea caracterelor dintr-o lista


Figura 6.12. Plasarea unui caracter intr-o lista

Driverul de terminal in modul canonic

Structurile de date pentru driverele de terminal au 3 liste de caractere asociate cu ele: prima lista pentru a memora datele de iesire la terminal , o a doua lista pentru a memora datele de intrare de tip caracter furnizate prin rutina de tratare a întreruperii de terminal asa cum le-a tastat utilizatorul si o a treia lista pentru a memora datele de intrare prelucrate, dupa ce disciplina de linie converteste caracterele speciale intr-o lista de caractere, cum ar fi caracterele " erase " si " kill ".

algoritmul terminal_write

copiaza bloc 222b12c ul de date din spatiul utilizator în lista de iesire:

disciplina de linie converteste caracterele "tab",etc;

}

începe operatia de scriere la hardware a datelor din lista de iesire;

}

Figura 6.13. Algoritmul pentru scrierea datelor la un terminal

Când un proces scrie la un terminal ( Figura 6.13 ), driverul de terminal invoca disciplina de linie. Aceasta executa un ciclu, citind caracterele rezultate din spatiul de adrese utilizator si le plaseaza in lista de iesire, pâna când se epuizeaza datele. Disciplina de linie proceseaza aceste caractere, expandând caracterele "tab" la o serie de spatii, de exemplu. Daca numarul de caractere din lista de iesire devine mai mare decât limita superioara, disciplina de linie apeleaza procedurile driverului pentru a transmite datele din lista de iesire la terminal si pune procesul care a scris datele in asteptare. Când cantitatea de date din lista de iesire scade sub limita inferioara, rutina de tratare a întreruperii trezeste toate procesele adormite pe evenimentul "terminalul poate accepta mai multe date". Disciplina de linie termina ciclul sau, având copiate toate datele de iesire din spatiul utilizator in lista de iesire si apeleaza procedurile driverului pentru a transmite datele la terminal.

Daca mai multe procese scriu la un terminal, ele urmaresc procedura data independent. Datele scrise de procese pot fi intercalate intre ele la terminal. Aceasta se poate întâmpla deoarece un proces poate scrie la terminal folosind mai multe apeluri sistem write . Nucleul poate comuta contextul in timp ce procesul este in modul utilizator intre doua apeluri sistem write succesive si un nou proces planificat poate scrie la terminal in timp ce procesul initial este in asteptare. Datele de iesire pot fi, de asemenea, amestecate la un terminal deoarece un proces care scrie se poate pune in asteptare in mijlocul unui apel sistem write in timp ce datele de iesire anterioare sunt scoase din sistem. Nucleul poate planifica alte procese care scriu la terminal înainte ca procesul initial sa fie replanificat. Din cauza aceasta, nucleul nu garanteaza ca continutul buffer-ului de date ce urmeaza sa fie scos la iesire printr-un apel sistem write apare contiguu la terminal .

Consideram programul din figura 6.14. Procesul parinte creeaza 18 fii; fiecare proces fiu formateaza un sir ( prin functia de biblioteca sprintf ) in variabila output, care include un mesaj si valoarea lui "i " in momentul apelului fork si apoi intra in bucla, scriind sirul la fisierul standard de iesire in timpul fiecarei iteratii. Daca iesirea standard este terminalul, driverul de terminal regleaza fluxul de date la terminal. sirul de iesire este mai mare decât 64 de caractere , prea mare sa încapa intr-un bloc 222b12c (64 de octeti lungime ) in implementarea System V. Din acest motiv, driverul de terminal are nevoie de mai mult de un bloc 222b12c pentru fiecare apel sistem write si iesirea poate deveni amestecata.

char formst = "acesta este un sir de caractere de iesire pentru procesul fiu"

main()

}

}

Figura 6.14. Supraîncarcarea iesirii standard cu date

De exemplu, liniile urmatoare au fost parti ale iesirii produse când s-a rulat programul pe un calculator AT&T 3B20:

acesta este un sir obisnuit de caractere pentru procesul fiu 1

acesta este o iesire obisnuita care consta dintr-un sir obisnuit de caractere

pentru procesul fiu 0

Citirea datelor de la un terminal in modul canonic este o operatie mult mai complexa. Apelul sistem read specifica numarul de octeti pe care procesul doreste sa-l citeasca, dar disciplina de linie satisface citirea la receptionarea unui CR, chiar daca numarul caracterelor nu este satisfacut. Aceasta este o modalitate practica, pentru ca este imposibil ca un proces sa prevada cât de multe caractere va introduce utilizatorul de la tastatura si nu are sens sa astepte ca utilizatorul sa tasteze un numar mare de caractere. De exemplu, utilizatorul introduce linii de comanda shell si se asteapta ca shell-ul sa raspunda la comanda pe receptionarea unui caracter CR. Nu este nici o diferenta daca comanda este simpla, cum ar fi "date" sau "who" sau daca este o secventa de comanda mai complicata cum ar fi:

pic file *|tbl|eqn|troff - mm - Taps|apsend

Driverul de terminal si disciplina de linie nu stiu nimic despre sintaxa shell-ului, si asa este corect, deoarece alte programe care citesc de la terminale ( cum ar fi editoarele ) au sintaxe diferite pentru comenzi. Din acest motiv, disciplina de linie satisface apelul read la receptionarea unui CR.

algoritmul terminal_read

if ( tty este în modul caracter )

copiaza toate datele din lista de caractere în lista de caracter

canonica;

else /* tty este în modul canonic */

}

}

while ( sunt caractere în lista canonica si contorul de citire nu este

satisfacut)

copiaza din bloc 222b12c urile de caractere din lista canonica în spatiul de

adrese utilizator;

}

Figura 6.15. Algoritmul pentru citirea unui terminal

Figura 6.15 arata algoritmul pentru citirea unui terminal. Presupunem ca terminalul este in modul canonic. Sectiunea 6.3.3. va trata cazul modului caracter. Daca nu sunt date in nici o lista de intrare, procesele care citesc se pun in asteptare pâna la sosirea unei linii de date. Când datele au fost introduse, rutina de tratare a întreruperii de terminal invoca disciplina de linie "rutina de tratare a întreruperii ", care plaseaza datele in lista de caractere pentru intrarea proceselor care citesc si in lista de iesire pentru ecou la terminal. Daca sirul de intrare contine un CR, rutina de tratare a întreruperii trezeste toate procesele cititor adormite. Când un proces cititor ruleaza, driverul scoate caracterele din lista de caractere, face procesarea caracterelor "erase" si "kill" si plaseaza caracterele in lista canonica. Apoi copiaza caracterele in spatiul de adrese utilizator pâna la caracterul CR sau pâna se satisface numarul de caractere care trebuiesc in apelul sistem read.

Totusi, un proces poate constata ca datele pentru care a fost trezit nu mai exista. Alte procese pot citi terminalul si scoate datele din lista de caracter înainte ca primul proces sa fie replanificat. Acest lucru este similar cu ceea ce se întâmpla când mai multe procese citesc datele dintr-un pipe.

Procesarea caracterului in directiile de intrare si de iesire este asimetrica, evidentiata prin cele doua liste de intrare si numai o lista de iesire. Disciplina de linie scoate la iesire datele din spatiul utilizator, le proceseaza si le plaseaza in lista de iesire. Ca sa fie simetric, ar trebui sa fie numai o clista de intrare. Oricum, aceasta ar cere rutinei de tratare a întreruperii sa proceseze caracterele "erase" si "kill", facând-o mai complexa, consumând timp si bloc 222b12c ând alte întreruperi intr-un moment critic.

Cu toate acestea, rutina de tratare a întreruperii pune caracterele de intrare imediat in lista de iesire.

Figura 6.16 prezinta un program unde un proces creeaza mai multe procese, care citesc fisierele lor standard de intrare, fiecare încercând sa citeasca date de la terminal. Intrarea terminalului este de obicei prea lenta pentru a satisface toate procesele care vor sa citeasca, asa ca procesele vor petrece majoritatea timpului lor asteptând in algoritmul terminal - read introducerea datelor. Când un utilizator introduce o linie de date, rutina de tratare a întreruperii de terminal trezeste toate procesele care vor sa citeasca date; pentru ca ele au adormit pe acelasi nivel de prioritate, sunt eligibile sa ruleze la aceeasi prioritate. Utilizatorul nu poate prevedea care proces ruleaza si citeste linia de date; procesul care ruleaza va tipari valoarea lui "i " la momentul la care a început sa ruleze. Toate celelalte procese vor fi, eventual, replanificate sa ruleze , dar este posibil ca ele sa nu mai gaseasca date in lista de intrare si sa se puna din nou in asteptare. Întreaga procedura este repetata pentru fiecare linie de intrare.

char input [256];

main()

}

}

}

Figura 6.16. Concurenta pentru datele de intrare ale terminalului

Este inerenta ambiguitatea ce rezulta din citirea de la un terminal de catre mai multe procese, dar nucleul rezolva situatia. Pe de alta parte, nucleul trebuie sa permita mai multor procese sa citeasca un terminal, altfel procesele create de shell care citesc intrarea standard nu vor lucra niciodata .Pe scurt, procesele trebuie sa-si sincronizeze accesul la terminal la nivel utilizator .

Când utilizatorul introduce caracterul EOF(end-of-file cu codul ASCII CTRL_D), disciplina de linie satisface citirile de la terminal, dar nu include caracterul EOF in sirul citit. Ea nu returneaza date ( returneaza valoarea 0 ) pentru apelul sistem read ce contine numai sfârsitul de fisier in liste de caractere; procesul apelant este responsabil sa recunoasca daca el a citit EOF. Referindu-ne la exemplele pentru shell din capitolul 8, bucla shell-ului se termina când un utilizator introduce CTRL_D: apelul read returneaza 0, si shell-ulse termina.

Teminalele inteligente isi pregatesc singure intrarile in periferice, eliberând UCP-ul pentru alte sarcini.

Driverul de terminal in modul caracter

Utilizatorii seteaza parametrii terminalului, cum ar fi caracterele "erase" si "kill" si recupereaza valorile setarilor curente cu apelul sistem ioctl. Similar, ei controleaza daca terminalul afiseaza intrarea (ecoul) , seteaza rata de transfer a terminalului, golesc listele de caractere de intrare si de iesire, sau pornesc si opresc manual afisarea caracterelor de iesire. Structura de date a driverului de terminal salveaza diferite setari de control si disciplina de linie primeste parametrii apelului ioctl si seteaza sau preia câmpurile relevante din structura de date a terminalului. Când un proces seteaza parametrii terminalului, el face aceasta pentru toate procesele care utilizeaza terminalul. Setarile terminalului nu sunt sterse automat când procesul care le-a fixat se termina.

Procesele pot, de asemenea, sa seteze terminalul in modul caracter, unde disciplina de linie transmite caracterele exact cum le tasteaza utilizatorul: nu se face nici o procesare asupra lor. Totusi nucleul trebuie sa stie când sa satisfaca apelurile read ale utilizatorului din moment ce tasta CR este tratata ca un caracter de intrare obisnuit. El satisface apelurile sistem read dupa ce un numar minim de caractere a fost introdus de la terminal sau dupa ce asteapta o perioada de timp fixata de la receptionarea unui caracter oarecare de la terminal . In ultimul caz, nucleul cronometreaza introducerea de caractere de la terminal plasându-le in tabela callout (capitolul 9).

Ambele criterii ( numar minim de caractere si perioada de timp fixata ) sunt setate printr-un apel ioctl . Când este întâlnit un criteriu particular, rutina de tratare a întreruperii a disciplinei de linie trezeste toate procesele adormite. Driverul muta toate caracterele din lista de caractere intr-o lista de caractere canonica si satisface cererea de citire a procesului, urmând acelasi algoritm ca in cazul canonic. Modul caracter este important mai ales pentru aplicatiile orientate ecran, cum ar fi editorul vi , care are multe comenzi ce nu se termina cu caracterul CR . De exemplu, comanda dw sterge cuvântul de la pozitia curenta a cursorului.

Figura 6.17 prezinta un program care face un apel ioctl pentru salvarea setarilor terminalului pentru descriptorul de fisier 0, fisierul standard de intrare. Comanda ioctl TCGETA instruieste driverul sa obtina setarile si le salveaza in structura "savetty", in spatiul de adrese utilizator. Aceasta comanda e folosita in mod curent pentru a determina daca un fisier este un terminal sau nu, deoarece acesta (fisierul) nu schimba nimic in sistem: daca comanda da gres, procesul presupune ca nu este terminal. Aici procesul face un alt apel ioctl pentru a seta terminalul in modul caracter.

#include <signal.h>

#include <termio.h>

struct termio savetty;

main()

newtty = savetty;

newtty.c_lflag &=~CANON; /*se dezactiveaza modul canonic */

newtty.c_lflag &=~ECHO; /*se dezactiveaza ecoul */

newtty.c_cc[VMIN] = 5; /*minim 5 caractere */

newtty.c_cc[VTIME] = 10; /*interval 10 secunde */

if (ioctl(0, TCSETAF, &newtty) ==-1

for (;;)

}

sigcatch()

Figura 6.17. Modul caracter

Procesul dezactiveaza ecoul si seteaza satisfacerea citirilor de la terminal la receptionarea a cel putin 5 caractere de la terminal sau la 10 secunde de la receptionarea primului caracter. Când procesul primeste un semnal de întrerupere, procesul reseteaza optiunile initiale ale terminalului si se termina.

Verificarea terminalelor

Este avantajos uneori sa se verifice un dispozitiv, pentru a-l citi daca exista date sau pentru a continua procesarea obisnuita in celelalte cazuri. Programul din figura 6.18 ilustreaza acest caz: prin deschiderea unui terminal cu optiunea "fara întârziere ", apelurile read urmatoare nu vor astepta daca nu exista date si programul se va termina imediat ( vezi algoritmul terminal -read, figura 6.15.). O astfel de metoda este buna daca un proces monitorizeaza mai multe dispozitive: el poate deschide fiecare dispozitiv cu optiunea "fara întârziere" si sa le verifice pe toate, asteptând o intrare de la oricare dintre ele. Totusi aceasta metoda scade puterea de procesare.

#include <fcntl.h>

main()

else /*nu sunt date de citit */

n++;

}

}

Figura 6.18.Verificarea unui terminal

Sistemul BSD are un apel sistem select care permite verificarea unui dispozitiv . Sintaxa pentru apel este:

select (nfds,rfds,wfds,efds,timeout)

unde nfds da numarul descriptorilor de fisiere selectati, rfds,wfds si efds pointeaza la mastile de bit care "selecteaza" descriptorii fisierelor deschise. Adica, bitul 1 << fd ( bitul1 deplasat la stânga cu valoarea descriptorului de fisier ) este setat daca un utilizator doreste sa selecteze acel descriptor de fisier. Timeout indica cât de mult ar trebui sa astepte apelul select, pâna la sosirea datelor, de exemplu; daca datele sosesc pentru oricare din descriptorii de fisiere si valoarea timeout nu a expirat, apelul select se încheie, indicând in mastile de bit care din descriptorii de fisier au fost selectati. De exemplu, daca un utilizator a dorit sa astepte pâna la receptionarea de intrari pe descriptorii de fisiere 0,1 sau 2 , rfds trebuia sa pointeze la masca de bit 7; când apelul select se încheie, masca de bit trebuie rescrisa cu o masca care sa indice care descriptor de fisier are date pregatite. Masca de bit wfds are o functie similara pentru descriptori de fisier pentru scriere si masca efds indica când exista conditii exceptionale pentru descriptorii de fisier particulari, folositoare in cazul retelelor.

Stabilirea unui terminal de control

Terminalul de control este terminalul pe care un utilizator se logheaza in sistem si controleaza procesele pe care utilizatorul le lanseaza de la terminal. Când un proces deschide un terminal, driverul de terminal deschide disciplina de linie. Daca procesul este liderul de grup de procese ca rezultat al unui apel sistem setpgrp si daca procesul nu are un terminal de control asociat, disciplina de linie transforma terminalul deschis in terminal de control. Acesta memoreaza numarul minor si numarul major ale fisierului dispozitiv in zona uArea si memoreaza numarul de grup de procese al procesului care a deschis terminalul in structura de date a driverului de terminal. Procesul care a deschis terminalul este procesul de control, de obicei shell-ul.

Terminalul de control joaca un rol important in tratarea semnalelor. Când un utilizator apasa tastele delete, break,robout sau quit, rutina de tratare a întreruperii invoca disciplina de linie care trimite semnalul corespunzator tuturor proceselor din grupul procesului de control. In mod similar, daca un utilizator întrerupe terminalul, rutina de tratare a întreruperii de terminal primeste o instiintare de întrerupere de la hardware iar disciplina de linie trimite semnalul hangup tuturor proceselor din grupul de procese. In acest fel, toate procesele initiate la un terminal particular primesc semnalul hangup; reactia implicita a celor mai multor procese este sa se termine la receptionarea semnalului. Acesta este modul in care procesele ratacite sunt terminate când un utilizator închide dintr-o data un terminal. Dupa trimiterea semnalului hangup, rutina de tratare a întreruperii desparte terminalul de grupul de procese astfel încât procesele din grupul de procese nu mai receptioneaza semnale de la terminal pentru mult timp.

Driverul de terminal indirect

Procesele au nevoie deseori sa citeasca sau sa scrie date direct la terminalul de control, desi intrarea si iesirea standard ar putea fi redirectate catre alte fisiere. De exemplu, un program shell poate trimite mesaje urgente direct la terminal desi fisierele standard de iesire si eroare ar putea fi redirectate altundeva. Sistemul UNIX furnizeaza acces indirect la terminal prin fisierul de dispozitiv "/dev/tty" care desemneaza terminalul de control pentru fiecare proces care are unul. Utilizatorii logati pe terminale separate pot accesa "/dev/tty", dar ei acceseaza terminale diferite.

Exista doua modalitati pentru nucleu de a gasi terminalul de control plecând de la numele fisierului "/dev/tty". In primul caz, nucleul poate defini un numar de dispozitiv special pentru fisierul de terminal indirect cu o intrare speciala in tabela de comutare a dispozitivelor de tip caracter . Când se invoca terminalul indirect, driverul acestuia obtine numarul minor si numarul major ale terminalului din uArea si invoca driverul terminalului real prin aceeasi tabelă. In al doilea caz nucleul testeaza daca numarul major este al terminalului indirect înaintea apelarii rutinei open. Daca este asa, elibereaza inodul pentru "/dev/tty", aloca inodul pentru terminalul de control, reseteaza intrarea in tabela de fisiere pentru a pointa la inodul terminalului de control si apeleaza rutina open . Descriptorul de fisier returnat la deschiderea "/dev/tty" refera direct terminalul de control si driverul lui.

Logarea in sistem

Asa cum se va arata, procesul 1, init , executa o bucla infinita citind fisierul "/etc/inittab" pentru instructiuni de intrare in sistem ( de exemplu, verificare un singur utilizator sau multi-utilizator ). In starea multi-utilizator, prima responsabilitate a procesului init este sa permita utilizatorilor logarea la terminal . El creeaza procesele numite gettty si pastreaza numarul procesului gettty care a deschis terminalul; fiecare proces gettty reseteaza numarul sau de grup folosind apelul sistem setpgrp, deschide o linie terminal si astepta pâna când simte o conectare hardware de terminal. Când se termina apelul open, procesul gettty executa programul login care cere utilizatorilor sa se identifice prin nume si parola. Daca utilizatorul se logheaza cu succes, programul login execută in final shell-ul. Procesul shell are acelasi identificator ca procesul initial gettty si shell-ul este deci un lider de procese. Daca un utilizator nu se logheaza cu succes, procesul login se termina dupa o limita de timp potrivita, închizând linia terminal iar init creeaza alt proces gettty pentru linie.

Init ingheata pâna la receptionarea semnalului "terminare fiu" . La trezire, el afla daca procesul in starea zombie a fost shell-ul si daca da, creeaza alt proces gettty pentru a deschide terminalul in locul procesului celui care a fost suprimat.

algoritmul login

else

numara încercarile de logare, încearca din nou pâna la un

punct;

}

}

Figura 6.19. Algoritmul pentru logare in sistem

6.7. Stream-uri

Schema de implementare a driverelor de dispozitiv, sufera din pricina unor schimbari ce apar de-a lungul anilor. Diferite drivere tind sa dubleze functionalitatea, mai ales driverele care implementeaza protocoale de retea, ceea ce implica o parte de control de dispozitiv si o parte de protocol. Desi partea de protocol ar trebui sa fie comuna tuturor dispozitivelor din retea, acesta nu este cazul real din practica, deoarece nucleul nu furnizeaza mecanisme adecvate pentru folosire in comun. De exemplu :listele de caractere sunt folositoare in cazul buffer-arii, dar ele sunt costisitoare datorita manipularii caracter cu caracter. Încercari de a ocoli acest mecanism pentru performante mai mari cauzeaza scaderea modularitatii subsistemului I/O.

Lipsa generalitatii la nivel de driver filtreaza nivelul comenzilor utilizator unde mai multe comenzi pot îndeplini functii logice comune dar peste medii diferite.

Stream-urile au fost implementate recent de Ritchie pentru a furniza o mai mare modularitate si flexibilitate subsistemului de I/O. Descrierea de aici se bazeaza pe lucrarea lui Ritchie, desi implementarea in System V difera putin. Un stream e o conexiune full-duplex intre un proces si driverul unui dispozitiv. El consta dintr-un set de perechi de cozi inlantuite liniar, un membru al perechii pentru intrare si celalalt pentru iesire. Când un proces scrie date intr-un stream , nucleul trimite datele spre cozile de iesire. Când un driver de dispozitiv receptioneaza datele introduse, el trimite datele spre cozile de intrare pentru un proces cititor. Cozile transmit mesajele cozilor adiacente in concordanta cu interfata definita. Fiecare pereche este asociata cu o instanta a unui modul nucleu, cum ar fi driver, disciplina de linie, sau protocol si modulele manipuleaza datele transmise prin cozile lor.

Fiecare coada este o structura de date ce contine urmatoarele elemente:

- o procedura de deschidere apelata in timpul apelului sistem open,

- o procedura de închidere apelata in timpul apelului sistem close,

- o procedura put apelata pentru introducerea unui mesaj in coada,

- o procedura "service " apelata când o coada este planificata sa se

execute,

- un pointer la urmatoarea coada din stream,

- un pointer la o lista de mesaje ce asteapta servirea,

- un pointer la o structura de date privata care pastreaza starea cozii,

- flag-uri si indicatori de tip limita superioara(inferioara) folositi pentru

controlul fluxului, planificare si pastrarea starii cozii.

Nucleul aloca perechi care sunt adiacente in memorie. Din acest motiv, o coada poate gasi usor celalalt membru al perechii ( figura 6.20).


Figura 6.20. Un stream dupa deschidere

Un dispozitiv cu driver de tip stream este dispozitiv de tip caracter. El are un câmp special in tabela de comutare a dispozitivelor de tip caracter care pointeaza spre structura de initializare a stream-ului care contine adresele rutinelor si indicatorii limita superioara si limita inferioara. Când nucleul executa apelul sistem open si descopera ca fisierul dispozitiv este de tip caracter, el examineaza noul câmp in tabela de comutare a dispozitivelor de tip caracter . Daca acolo nu exista nici o intrare driverul nu este de tip stream, iar nucleul urmareste procedura uzuala pentru dispozitivele de tip caracter. Totusi pentru prima deschidere a unui driver de tip stream, nucleul aloca doua perechi de cozi, una pentru capul de stream, si cealalta pentru driver.

Modulul cap de stream este identic pentru toate instatierile stream-ului deschis: el are proceduri generice put si service si interfata cu modulele nucleu de nivel înalt care implementeaza apelurile sistem read,write si ioctl. Nucleul initializeaza structura de coada a driverului, asignând pointerii si copiind adresele rutinelor de driver dintr-o structura de initializare si invoca procedura de deschidere a driverului. Procedura de deschidere a driverului face initializarile uzuale dar salveaza si informatii pentru identificarea cozii cu care este asociat. In final, nucleul asigneaza un pointer special in inod din memorie pentru a indica capul de stream (figura 6.20 ). Când un alt proces deschide dispozitivul, nucleul gaseste stream-ul alocat anterior prin pointerul din inod si invoca procedura de deschidere a tuturor modulelor din stream. Modulele comunica prin transmiterea de mesaje la modulele vecine. Un mesaj consta dintr-o lista inlantuita de antete de bloc 222b12c uri de mesaje; fiecare antet de bloc 222b12c pointeaza spre locatia de început si sfârsit a datelor din bloc 222b12c . Exista doua tipuri de mesaje (de control si de date ) identificate printr-un identificator de tip din antetul de mesaj. Mesajele de control pot rezulta din apelul sistem ioctl sau din conditii speciale, cum ar fi întreruperea unui terminal, si mesajele de date pot rezulta din apeluri sistem write sau sosiri din datelor de la un dispozitiv (figura 6.21).

Figura 6.21. Mesaje pentru stream-uri

Când un proces scrie intr-un stream, nucleul copiaza datele din spatiul utilizator in bloc 222b12c urile de mesaje alocate de capul de stream. Modulul capul de stream invoca procedura put a urmatorului modul care poate procesa mesajul, trimite imediat mesajul la urmatoarea coada sau îl retine pentru o procesare ulterioara. In ultimul caz modulul leaga antetele bloc 222b12c urilor de mesaje intr-o lista inlantuita, formând o lista dublu inlantuita ( Figura 6.21). Apoi seteaza un indicator in structura de date a cozii proprii pentru a indica daca are date de procesat si se autoplanifica pentru deservire. Modulul plaseaza coada intr-o lista inlantuita de cozi care solicita sa fie servite si invoca un mecanism de planificare; planificatorul apeleaza procedurile de deservire ale fiecarei cozi din lista. Nucleul ar putea planifica modulele prin întreruperi software ca in cazul invocarii functiilor in tabela "callout" ; rutina de tratare a întreruperii software apeleaza procedurile de deservire individual.

Figura 6.22. Punerea unui modul intr-un stream

Procesele pot pune modulele intr-un stream deschis prin apeluri ioctl. Nucleul insereaza modulul imediat sub capul de stream si seteaza pointerii cozii pentru a mentine structura de lista dublu inlantuita. Modulele finale ale stream-ului nu fac diferenta intre comunicarea cu capul de stream sau cu modul pus in lista. Interfata este procedura put a cozii urmatoare din stream; urmatoarea coada apartine modulului tocmai introdus. De exemplu, un proces poate sa introduca un modul de disciplina de linie intr-un stream de driver de terminal pentru stergerea si suprimarea procesarii de caractere (Figura 6.22); modulul de disciplina de linie nu are aceleasi interfete ca disciplinele descrise in sectiunea 6.3, dar functioneaza la fel. Fara modulul de disciplina de linie , driverul de terminal nu proceseaza caracterele introduse si astfel de caractere ajung nealterate la capul de stream. Un segment de cod care deschide un terminal si introduce o disciplina de linie poate arata astfel:

fd = open( "/dev/ttyxy",O_RDWR);

ioctl(fd,PUSH,TTYLD)

unde PUSH este numele comenzii si TTYLD este numarul care identifica modulul disciplinei de linii. Nu exista nici o restrictie asupra numarului de module ce pot fi introduse in stream. Un proces poate scoate (pop) module dintr-un stream intr-o ordine "lifo", folosind un alt apel ioctl:

ioctl (fd,POP,0)

Deoarece un modul de disciplina de linie implementeaza functii de procesare obisnuite ale terminalului, dispozitivul in discutie poate fi o conexiune de retea in locul unei conexiuni spre un dispozitiv terminal . Modulul disciplinei de linie lucreaza in acelasi mod, fara sa tina cont de modulele anterioare. Acest exemplu arata marea flexibilitate derivata din combinarea modulelor nucleului.

Un exemplu detaliat de stream

Pike descrie o implementare a terminalelor virtuale multiplexate utilizând stream-uri. Utilizatorul vede terminalele virtuale, fiecare ocupând o fereastra separata pe terminalul fizic. Desi lucrarea lui Pike descrie o schema pentru un terminal grafic inteligent, aceasta este valabila si pentru terminale obisnuite; fiecare fereastra ocupa întregul ecran si utilizatorul apasa o secventa de taste

pentru a comuta intre ferestrele virtuale.


Figura 6.23. Afisarea mai multor terminale virtuale pe un

terminal fizic

Figura 6.23 prezinta aranjarea proceselor si modulelor nucleului. Utilizatorul invoca un proces, mpx, pentru a controla terminalul fizic. Mpx citeste linia terminalului fizic si asteapta pentru aparitia evenimentelor de control, cum ar fi crearea de noi ferestre, comutarea controlului spre alta fereastra, stergerea unei ferestre si altele. Când receptioneaza un eveniment de creare a unei ferestre noi, mpx creeaza un proces pentru a controla noua fereastra si comunica cu ea printr-un pseudo-terminal(pty). Un pty este un dispozitiv software ce opereaza in pereche. Iesirea alocata unui membru al perechii este trimisa intrarii celuilalt membru; intrarea este trimisa modulului anterior din stream.

/* presupunem ca descriptorii de fisiere 0 si 1 se refera deja la terminalul fizic tty */

for (;;)

închide descriptorii de fisier care nu sunt necesari; /* fiu */

deschide celalalt membru al perechii pseudo - terminalului,

obtine stdin,stdout,stderr;

pune disciplina de linie a terminalului;

executa programul shell;

}

demultiplexeaza datele citite de la terminalul fizic, înlatura antetele si

scrie la terminalul pty corespunzator ;

continue;

case terminal logic:

decodifica antetul care indica pentru ce fereastra sunt datele ;

scrie datele si antetul la terminalul fizic;

continue;

}

}

Figura 6.24. Pseudocod pentru multiplexarea ferestrelor

Pentru a seta o fereastra ( Figura 6.24), mpx aloca o pereche pty si deschide un membru stabilind un stream spre el (deschiderea driverului garanteaza ca pty nu a fost alocat anterior). Mpx creeaza un proces si acesta deschide celalalt membru al perechii pty. Mpx pune un modul de mesaj in stream-ul pty pentru a converti mesajele de control in mesaje de date ( explicat in paragraful urmator ) si procesul fiu pune un modul de disciplina de linie in stream-ul pty înainte sa apeleze exec pentru crearea shell-ului. Acest shell ruleaza acum pe un terminal virtual; pentru utilizator, nu este nici o diferenta intre terminalul virtual si un terminal fizic.

Procesul mpx este un multiplexor, care trimite iesirile de la terminalele virtuale la terminalul fizic si demultiplexeaza intrarea de la terminalul fizic la terminalul virtual corespunzator. Mpx asteapta sosirea datelor pe orice linie, folosind apelul sistem select. Când datele sosesc de la terminalul fizic, mpx decide daca este un mesaj de control, care îl informeaza ca trebuie sa creeze o noua fereastra sau sa stearga una veche, sau daca este un mesaj de date care trebuie sa fie trimis proceselor care citesc un terminal virtual. In ultimul caz, datele au un antet care identifica terminalul virtual tinta; mpx înlatura antetul din mesaj si scrie datele la stream-ul pty corespunzator. Driverul al lui pty dirijeaza datele prin disciplina de linie a terminalului la procesele cititor. Procedura inversa se executa când un proces scrie terminalul virtual:mpx adauga un antet la date, informând terminalul fizic in care fereastra trebuie sa fie tiparite datele.

Daca un proces invoca un apel ioctl pe un terminal virtual, disciplina de linie a terminalului face setarile de terminal necesare pentru linia sa virtuala; setarile pot diferi pentru fiecare terminal virtual. Oricum, unele informatii trebuie sa fie trimise la terminalul fizic, depinzând de dispozitiv. Modulul de mesaj converteste mesajele de control care sunt generate de ioctl in mesaje de date potrivite pentru citirea si scrierea prin mpx si aceste mesaje sunt transmise la dispozitivul fizic.

Analiza stream-urilor

Ritchie mentioneaza ca el a încercat sa implementeze stream-uri numai cu proceduri put sau numai cu proceduri service. Totusi, procedura service este necesara pentru controlul fluxului, deoarece modulele trebuie uneori sa puna datele intr-o coada de asteptare daca modulele vecine nu pot primi, temporar, mai multe date. Procedura put este, de asemenea, necesara deoarece datele trebuie uneori sa fie livrate la un modul vecin. De exemplu, disciplina de linie a unui terminal trebuie sa reactioneze trimitând datele de intrare la terminal cât de repede este posibil. Ar putea fi posibil pentru un apel sistem write sa invoce procedura put a cozii urmatoare direct, fara sa fie nevoie de un mecanism de planificare.

Un proces se pune in asteptare daca cozile de iesire sunt supraaglomerate. Totusi, modulele nu pot sta in asteptare pe partea de intrare, deoarece ele sunt invocate printr-o rutina de tratare a întreruperii si un proces nevinovat ar putea fi pus in asteptare. Comunicarea intre module ar putea sa nu fie simetrica pe cele doua directii de intrare si de iesire.

Este preferabil, de asemenea, sa implementam fiecare modul ca un proces separat, dar folosirea unui numar mare de module ar putea cauza o supraîncarcare a tabelei de procese. Ele sunt implementate cu un mecanism de planificare special - întrerupere software - independent de procesul planificator normal. Modulele nu se pot pune in asteptare, deoarece ele ar putea pune in asteptare un proces arbitrar ( unul care a fost întrerupt ). Modulele trebuie sa salveze informatiile lor de stare intern, facând sa se complice codul lor mai mult decât daca le-ar fi fost permis sa se puna in asteptare .

Exista unele anomalii in implementarea stream-urilor. Gestiunea proceselor este dificila, deoarece nu este necesar ca modulele sa ruleze in contextul procesului care foloseste stream-ul. Este fals sa presupunem ca toate procesele folosesc in comun in mod uniform executia modulelor din stream, deoarece unele procese pot cere folosirea unor protocoale complicate de retea, iar altele pot folosi discipline de linie de terminal simple.

Utilizatorii pot pune un driver de terminal in modul caracter, asa încât apelurile read sa se termine dupa un timp scurt daca datele nu sunt disponibile ( de exemplu, if newtty.c­_ccșVMINț = 0; in figura 6.17 ). Este dificil sa implementam aceasta caracteristica cu stream-uri, daca codul nu este introdus la nivelul capului de stream.

Stream-urile sunt conexiuni liniare si nu permit cu usurinta multiplexarea in nucleu. De exemplu, fereastra prezenta in sectiunea anterioara face multiplexarea intr-un proces de nivel utilizator.


Document Info


Accesari: 1621
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2024 )