Curs So

168
Curs de SISTEME DE OPERARE 1995-1996

Transcript of Curs So

Page 1: Curs So

Curs de

SISTEME DE OPERARE

Autor :prep. ing. Győrödi Robert

1995-1996

Page 2: Curs So

Curs de SISTEME DE OPERARE

CUPRINS

1. Introducere............................................................................................................................

1.1 Prezentare generală..........................................................................................................1.2 Responsabilităţile unui S.O..............................................................................................1.3 Dezvoltarea istorică a S.O...............................................................................................

1.3.1 Istoria timpurie a S.O...............................................................................................1.3.2 Sisteme cu prelucrare în loturi şi multiprogramare....................................................1.3.3 Sisteme cu divizarea timpului...................................................................................1.3.4 Sisteme cu memorie virtuală.....................................................................................1.3.5 S.O. pentru minicalculatoare.....................................................................................1.3.6 S.O. pentru microprocesoare şi calculatoare personale..............................................1.3.7 Reţele de calculatoare şi sisteme distribuite..............................................................1.3.8 Perspective...............................................................................................................

2. Structura Sistemelor de Operare...........................................................................................

2.1 Organizarea memoriei.....................................................................................................2.2 Structuri de execuţie........................................................................................................2.3 Interacţiunea componentelor............................................................................................2.4 Adaptabilitatea la configuraţii hardware..........................................................................

3. Sistemul de Operare MS-DOS. Probleme generale................................................................

3.1 Structura S.O. MS-DOS. Încărcarea sistemului...............................................................3.2 Utilizarea şi organizarea spaţiului pe discuri....................................................................3.3 Hard discuri.....................................................................................................................

3.3.1 Floppy discuri...........................................................................................................3.3.2 Formatarea................................................................................................................3.3.3 Partiţii.......................................................................................................................3.3.4 MBR-ul, sectoare boot şi tabele de partiţii................................................................3.3.5 Partiţii extinse şi logice.............................................................................................

3.4 Organizarea spaţiului pe discuri.......................................................................................3.4.1 Caracteristicile fizice ale discului..............................................................................3.4.2 Organizarea logică a discurilor.................................................................................3.4.3 Partiţionarea discurilor fixe.......................................................................................

3.5 Sistemul de întreruperi în MS-DOS.................................................................................3.5.1 Întreruperi hardware.................................................................................................3.5.2 Întreruperi BIOS.......................................................................................................3.5.3 Întreruperi DOS........................................................................................................

3.6 Formatul fişierelor executabile. Prefixul segmentului de program...................................3.6.1 Structura fişierelor .COM.........................................................................................3.6.2 Structura fişierelor .EXE..........................................................................................

4. Interfaţa MS-DOS cu utilizatorul..........................................................................................

4.1 Generalităţi......................................................................................................................4.2 Servicii oferite de MS-DOS. Serviciile sistem.................................................................

4.2.1 Funcţii pentru gestionarea fişierelor..........................................................................4.2.2 Funcţii pentru gestionarea cataloagelor.....................................................................

- 1 -

Page 3: Curs So

Curs de SISTEME DE OPERARE

4.2.3 Funcţii pentru I/E cu dispozitive standard orientate pe caractere...............................4.2.4 Funcţii pentru gestionarea perifericelor.....................................................................4.2.5 Funcţii pentru gestionarea memoriei şi a proceselor.................................................4.2.6 Alte funcţii sistem.....................................................................................................

4.3 Funcţii de bibliotecă C pentru apelul sistemului MS-DOS...............................................4.3.1 Funcţii pentru gestionarea fişierelor..........................................................................4.3.2 Funcţii pentru gestionarea cataloagelor.....................................................................4.3.3 Funcţii pentru gestionarea perifericelor.....................................................................4.3.4 Funcţii pentru gestionarea memoriei.........................................................................4.3.5 Funcţii pentru gestionarea proceselor........................................................................4.3.6 Alte funcţii sistem.....................................................................................................

5. Gestionarea memoriei...........................................................................................................

5.1 Memoria convenţională...................................................................................................5.2 Blocurile din Memoria Superioară (UMB)......................................................................5.3 Structuri de date folosite de MS-DOS în gestionarea memoriei.......................................5.4 Procesarea liniei A20. Memoria înaltă.............................................................................

6. Sistemul de Operare UNIX. Probleme generale.....................................................................

6.1 Introducere......................................................................................................................6.1.1 Cauzele răspândirii sistemului de operare UNIX......................................................6.1.2 Considerente de realizare a S.O. UNIX.....................................................................6.1.3 Caracteristici generale al sistemelor UNIX...............................................................

6.2 Principii de utilizare ale sistemului UNIX.......................................................................6.3 Principalele comenzi UNIX.............................................................................................6.4 Elemente ale limbajului de comandă UNIX (Shell).........................................................6.5 Proceduri shell (Shell scripts)..........................................................................................

6.5.1 Crearea şi executarea unui fişier de comenzi.............................................................6.5.2 Variabile şi parametri care pot fi prevăzuţi în pseudo-programe shell.......................6.5.3 Intrarea şi ieşirea standard........................................................................................6.5.4 Structuri de control în proceduri shell.......................................................................6.5.5 Comentarii................................................................................................................6.5.6 Substituţia comenzilor..............................................................................................6.5.7 Ordinea evenimentelor..............................................................................................6.5.8 Opţiunile shell-ului...................................................................................................6.5.9 Redirectarea întreruperilor........................................................................................6.5.10 Ambianţa sau mediul de lucru.................................................................................6.5.11 Lansarea shell-ului din login...................................................................................6.5.12 Un exemplu de shell script......................................................................................

6.6 Vedere generală asupra sistemului...................................................................................6.6.1 Arhitectura sistemului UNIX....................................................................................6.6.2 Mediul de procesare..................................................................................................6.6.3 Servicii ale sistemelor de operare..............................................................................6.6.4 Restricţii hardware....................................................................................................6.6.5 Întreruperi şi excepţii................................................................................................6.6.6 Nivele de execuţie ale procesorului...........................................................................6.6.7 Gestionarea memoriei...............................................................................................

7. Arhitectura Sistemului de Operare UNIX..............................................................................

7.1 Introducere......................................................................................................................7.2 Subsistemul de fişiere......................................................................................................7.3 Subsistemul de procese....................................................................................................

- 2 -

Page 4: Curs So

Curs de SISTEME DE OPERARE

7.3.1 Contextul unui proces...............................................................................................7.3.2 Stările şi tranziţiile unui proces.................................................................................

7.4 Controlul proceselor........................................................................................................7.4.1 Crearea proceselor....................................................................................................7.4.2 Semnale....................................................................................................................7.4.3 Terminarea proceselor..............................................................................................7.4.4 Aşteptarea terminării proceselor...............................................................................7.4.5 Executarea altor programe........................................................................................

- 3 -

Page 5: Curs So

Curs de SISTEME DE OPERARE

1. Introducere.

1.1 Prezentare generală.

Prin sistem de calcul vom înţelege un ansamblu de echipamente fizice (hardware) şi programe şi date (software).

Programele se consideră împărţite în două clase foarte largi : programe de aplicaţie - sunt cele care rezolvă probleme pentru un utilizator sau o

clasă de utilizatori. programe de sistem - sunt destinate administrării sistemelor de calcul, utilizând

resursele acelui sistem.

Programele de sistem se divid în : programe utilitare sistem de operare

În categoria programelor utilitare intră : translatoare de limbaj, compilatoare interpretoare de comenzi utilitare de întreţinere interpretoare

Sistemul de operare este responsabil pentru inclusiv unele forme de comunicare cu utilizatorii.

Reprezentarea schematică a unui sistem de calcul :

Calcululsalariilor

Proiectareacircuitelor digitale

CompilatorEditor de

texteInterpretorde comenzi

SISTEM DEOPERARE

Limbaj maşină

Echipamente fizice

Programe deaplicaţie

Programesistem

Hardware}

}

Fig. 1.1-1

O posibilă definiţie a S.O. : Vom spune că un S.O. este un set de programe care are două obiective :

asigură gestionarea resurselor unui sistem de calcul, implementând algoritmi care să realizeze performanţe cât mai bune;

- 4 -

Page 6: Curs So

Curs de SISTEME DE OPERARE

realizează o interfaţă între utilizatori şi sistemul de calcul, extinzând dar şi simplificând setul de operaţii disponibile.

Se consideră că rolul primar al unui S.O. este administrarea resurselor sistemului de calcul, care pot fi resurse logice sau resurse fizice.

Considerăm resurse fizice : echipamentele unui sistem de calcul (procesorul, memoria internă, memoria externă, echipamentele de introducere/extragere şi echipamente interne).

Principalele resurse logice ar fi : fişierele, procesele (activităţi legate de execuţia unor programe), unităţile de lucru, job-uri sau sesiuni de lucru.

Din punctul de vedere al unui administrator al sistemului de calcul, S.O. trebuie să asigure un raport cost/performanţă cât mai bun în utilizarea resurselor, aceasta ducând adesea la utilizarea în comun a unor resurse. Din punctul de vedere al utilizatorului unui sistem de calcul este important ca accesul la sistem să fie făcut într-un mod cât mai simplu, fără a fi necesară cunoaşterea de particularităţi constructive ale echipamentelor, sau de detalii de implementare ale programelor. Utilizatorul doreşte să obţină cât mai rapid serviciile solicitate. Scopurile administratorului şi utilizatorului sunt în multe cazuri divergente.

Există cel puţin trei clase de persoane care fac uz de sistemul de calcul : utilizatori obişnuiţi - aceştia folosesc programele scrise de alţii, ei nu ştiu să

programeze, dar trebuie să aibe cunoştinţe despre modul de utilizare al sistemului de calcul.

programatori de aplicaţie - ei ştiu să programeze, lucrează în limbaje de nivel înalt şi din aceste limbaje fac apel indirect la o serie de servicii oferite de S.O.

programatori de sistem - care programează în limbaje de nivel înalt sau în limbaj de asamblare şi fac uz mai direct de serviciile S.O., folosind un mecanism de declanşare al serviciilor, diferit de cel aflat la dispoziţia programatorilor de aplicaţii.

1.2 Responsabilităţile unui S.O.

a) Interfaţa cu utilizatorul.Există cel puţin două componente distincte ale interfeţei :

interfaţa prin comenzi interfaţa prin apeluri sistem

Interfaţa prin comenzi - este realizat prin introducerea de la un dispozitiv de intrare a unor comenzi care sunt prelucrate de interpretorul de comenzi al sistemului.

Apelurile sistem - se folosesc în programe şi se declanşează în timpul execuţiei acestor programe. Ca formă ele se apropie de apelurile de funcţie dar au un alt mecanism de execuţie.

Interfaţa la nivel de comenzi este cea care determină în bună măsură dacă S.O. este atractiv pentru utilizator sau nu. În noile S.O., se insistă pe crearea de interfeţe “user-friendly”.

b) Gestionarea fişierelor.Suportul cel mai folosit al fişierelor este discul magnetic, dar există şi alte medii de

stocare (de ex. discuri compacte).În componenta de S.O. care realizează gestionarea de fişiere sunt prevăzute servicii

pentru crearea, distrugerea, citirea, scrierea, organizarea şi controlul accesului la informaţiile din fişiere.

- 5 -

Page 7: Curs So

Curs de SISTEME DE OPERARE

c) Gestionarea perifericelor.Datorită varietăţii echipamentelor periferice care se pot conecta într-un sistem de

calcul se impune ca S.O. să preia detaliile legate de lucrul cu aceste periferice. În modulul de gestionare a perifericelor sunt incluse toate aspectele specifice pentru fiecare periferic, astfel încât spre utilizatorii acestui modul funcţionarea tuturor perifericelor să apară standardizată. De regulă modulul de gestionare a perifericelor funcţionează pe baza unor interacţiuni cu mecanismul de întreruperi.

d) Gestionarea memoriei.Din memoria internă o parte este întotdeauna rezervată S.O., iar restul memoriei este

disponibilă pentru unul sau mai mulţi utilizatori. Dacă S.O. permite existenţa mai multor programe utilizator în memoria internă se pune problema controlului accesului acestor programe la diverse zone de memorie. În sistemele cu memorie virtuală gestionarea memoriei include şi o parte a memoriei externe, care serveşte ca suport pentru memoria virtuală.

e) Gestionarea proceselor.Numim proces un program în execuţie sub controlul unui S.O. Majoritatea S.O.

prevăd posibilitatea existenţei simultane a mai multor procese, de unde rezultă necesitatea de a controla interacţiunea acestora. Este vorba în primul rând de accesul proceselor la unitatea centrală dar şi de mecanisme de sincronizare între procese.

f) Tratarea erorilor.S.O. trebuie să fie pregătit pentru a reacţiona la o mare diversitate de erori cu cauze

atât în hardware cât şi în software. Erorile trebuie detectate şi în măsura posibilului trebuie asigurată revenirea din erori şi continuarea lucrului.

g) Gestionarea sistemului.Instalarea unui S.O. pe un nou echipament, culegerea de date statistice despre

comportarea sistemului pentru ajustarea funcţionării sale în viitor şi în special ţinerea evidenţei resurselor consumate de fiecare utilizator al sistemului.

În prezent se tinde spre standardizarea S.O. în special spre standardizarea interfeţelor.

1.3 Dezvoltarea istorică a S.O.

1.3.1 Istoria timpurie a S.O.

La primele calculatoare programarea se făcea în cod maşină, cu instrucţiuni, dacă nu şi date, introduse prin chei de la panoul de comandă al calculatorului. În aceste condiţii utilizarea unui calculator cerea cunoştinţe profesionale foarte bune din partea programatorului, care avea control complet asupra calculatorului. O primă îmbunătăţire apare prin conectarea la calculator a unor dispozitive periferice care să faciliteze introducerea programelor şi datelor şi extragerea rezultatelor. În domeniul limbajelor apare conceptul de limbaj de asamblare şi care devine un prim limbaj de sistem, precum şi asamblorul care constituie embrionul unui S.O.

Programe utilitare : editor de legături şi încărcătorul de programe.Utilizarea calculatoarelor în aceste condiţii implica efectuarea unui număr mare de

operaţii manuale, situaţie răsturnată după introducerea benzilor şi discurilor magnetice. După 1950 este perioada în care numărul de calculatoare începe să crească (UNIVAC şi IBM).

- 6 -

Page 8: Curs So

Curs de SISTEME DE OPERARE

Utilizatorii acestor sisteme îşi creează organizaţii proprii şi au întâlniri la care discută în primul rând reducerea operaţiilor manuale şi simplificarea operaţiilor de introducere/extragere. În urma acestor discuţii apare la firma General Motors primul S.O. numit I.O.S. (Input Output System). Exista o porţiune rezidentă în memorie care conţinea rutinele pentru operaţiile de I/O şi ele se apelau din subrutine. Se făcea salt la sfârşitul fiecărui program pentru ca o rutină încărcător din I.O.S. să încarce în memorie următorul program. Apoi au apărut S.O.S. - IBM 709, mai perfecţionat, includea şi un asamblor şi apoi sistemul FMS, tot la IBM.

1.3.2 Sisteme cu prelucrare în loturi şi multiprogramare.

Apariţia acestor sisteme a fost determinată de apariţia discurilor magnetice şi a benzilor magnetice în sistemele de calcul. Apar sistemele T.O.S. şi D.O.S. Apare dorinţa de utilizare a puterii de calcul sporite a hardware-ului. Utilizatorii nu mai aveau acces direct la calculator, ci programele lor împreună cu datele necesare pentru execuţie se colectau de către un personal specializat şi ele erau însoţite şi de cartele de comandă, prin care se specifică serviciile dorite de la sistem. Pentru aceasta se folosea J.C.L. - Job Control Language - convenţia pentru serviciile dorite de la sistem.

Pachetele de cartele formau loturi care erau lansate în execuţie când atingeau o anumită dimensiune. Lucrul în loturi permite sporirea gradului de utilizare a U.C. O creştere suplimentară a gradului de utilizare a U.C., dar şi a celorlalte echipamente dintr-un sistem de calcul se obţin prin introducerea multiprogramării (prezenţa simultană în memoria operativă a unui sistem de calcul a mai multor programe utilizator). Atunci când un program solicită o operaţie periferică U.C. este dată unui alt program din memorie.

Progr.A

Progr.B

Progr.C

UC înactivitate

operaţieperiferică

UCneutilizat

timp

timp

timp

Timpaşteptare

Grad deutilizare

Fig. 1.3-1

Din punctul de vedere al utilizatorului sistemele cu prelucrare în loturi produc o separare a utilizatorului de sistemul de calcul şi lungesc timpul dintre predarea (introducerea) unei lucrări în sistem şi obţinerea rezultatelor.

- 7 -

Page 9: Curs So

Curs de SISTEME DE OPERARE

1.3.3 Sisteme cu divizarea timpului.

Datorită introducerii în sistemele de calcul a unor echipamente numite terminale, a fost posibilă dezvoltarea unor sisteme cu divizarea timpului. Terminalul permite introducerea informaţiilor în sistem (de ex. prin tastatură), precum şi extragerea rezultatelor (prin mecanisme de imprimare pe hârtie, echipament cu tub catodic).

Folosind acest sistem este posibil ca mai mulţi utilizatori să aibă acces simultan direct la resursele calculatorului.

Memoriaexternă

Calculator(UC + memorie)

Imprimantă

. . . . .

Terminale

Fig. 1.3-2

Timpul UC este acum distribuit între terminale active în cantităţi egale numite cuante. Toate programele active la un moment dat pot progresa. Ordinul de mărime al unei cuante era de 100 ms. Nu toate programele active la un moment dat au loc în memoria operativă. De aceea, în astfel de sisteme se utilizează şi un mecanism (algoritm) special pentru gestionarea memoriei numit swapping. Aceasta înseamnă că atunci când UC este luată de la un program activ în acel moment şi cedată la alt program, dacă programul care primeşte controlul nu este prezent în memorie, el va fi transferat în memorie în locul unui program care a pierdut dreptul de utilizare a UC. Acesta este transferat în memoria externă în starea în care e la momentul respectiv (programele îşi schimbă locul).

De regulă însă algoritmul de swapping este combinat cu multiprogramarea rezultând o creştere a gradului de utilizare a memoriei şi a UC.

Exemple : OS/360 - sistem de operare cu multiprogramare, scris în 1965 pentru IBM 360. CTSS - sistem de operare cu divizarea timpului (Compatible Time Sharing System)

pentru IBM 7094 (generaţia a II-a) scris la MIT. TSS - Time Sharing System scris de IBM. TSO - variantă a lui OS/360 care permite şi o opţiune de divizare a timpului. MULTICS

proiect realizat la MIT S.O. bazat pe calculatorul GE635 (General Electric) alte concepte exploatate :

memorie virtuală segmentată ierarhie de fişiere redirectarea operaţiilor de I/E acces protejat la resurse interfaţă extinsă cu utilizatorul

ideea de bază : puterea de calcul să se transforme în utilitate publică

- 8 -

Page 10: Curs So

Curs de SISTEME DE OPERARE

1.3.4 Sisteme cu memorie virtuală.

Exemple : Atlas - 1961 - conceptul de memorie cu un singur nivel IBM 370 :

OS/MVS - Multiple Virtual Space OS/VM - Virtual Machine - face posibilă rularea simultană a mai multor S.O.

1.3.5 S.O. pentru minicalculatoare.

Minicalculatoarele erau sisteme de calcul cu performanţe mai modeste dar cu un preţ redus, acest preţ lărgind categoria potenţialilor cumpărători. Firma care a produs cele mai multe sisteme de acest fel este DEC iar calculatorul produs se numeşte PDP (PDP 7, PDP 8).

După 1970 apare PDP-11 care a avut o foarte mare răspândire. Asemenea calculatoare au fost construite şi la noi : CORAL, Independent. Pentru PDP-11 primul S.O. oferit a fost RT11 (Real Time 11). RT11 este un sistem cu divizarea timpului. Pe modele mai perfecţionate ale lui PDP-11 sau utilizat S.O. RSX-11 (avea un sistem de gestionare a fişierelor mai performant precum şi un set extins de comenzi şi programe utilitare).

Tot firma DEC a dezvoltat ulterior o altă familie de calculatoare VAX-11. Pentru aceste sisteme s-a folosit S.O. VMS (Virtual Memory System).

Alt S.O. dezvoltat pentru minicalculatoare este UNIX, care a fost scris de Thompson 1968-1969, de la Bell Labs (AT&T). Acest sistem a fost inspirat din sistemul de operare MULTICS. Ca şi particularităţi conţine mecanisme pentru comunicare între procese, sistem de fişiere ierarhic şi limbaj de comandă deosebit de flexibil. Sistemul a fost rescris pentru PDP-11 de Thompson şi Ritchie, pentru aceasta folosindu-se limbajul C. În acest fel UNIX a devenit primul S.O. scris în bună măsură în limbaj de nivel înalt, deoarece până atunci toate S.O. erau scrise în limbaj de asamblare. Aceasta face ca sistemul să fie uşor portabil şi s-a realizat implementarea lui şi pe alte tipuri de calculatoare.

Azi UNIX este disponibil pe toate tipurile de calculatoare. Pentru standardizarea sistemului există un institut numit POSIX.

1.3.6 S.O. pentru microprocesoare şi calculatoare personale.

În 1971 Intel a produs primul microprocesor pe 4 biţi : 4004. Pentru 8080 a fost scris S.O. CP/M (Digital Research), care era simplu, monoutilizator şi avea un set redus de comenzi.

Apariţia microprocesoarelor pe 16 biţi duce la apariţia calculatoarelor personale : 8086 (8088), Motorola 6800.

Pentru familia 8086 apare MS-DOS, scris de Microsoft. Acest sistem împrumută elemente de la UNIX dar este monoutilizator şi monoprocesor.

La apariţia P 80286, IBM a introdus familia PS/2, pentru care a elaborat S.O. OS/2. Baza de aplicaţii a lui OS/2 este mai redusă decât aceea pentru MS-DOS şi astfel este folosit mai puţin.

Microprocesoarele începând cu 80386 sunt deja suficient de puternice pentru folosirea S.O. UNIX.

- 9 -

Page 11: Curs So

Curs de SISTEME DE OPERARE

Pe lângă calculatoarele personale se răspândesc staţiile de lucru (workstation), care au putere de lucru mare, bazate pe procesoare RISC.

1.3.7 Reţele de calculatoare şi sisteme distribuite.

Reţelele de calculatoare înseamnă integrarea sistemelor de calcul cu sisteme de comunicaţie. Ideea comunicaţiei între calculatoare a fost realizată pentru prima dată în sistemul ARPANET, finanţată de o agenţie numită DARPA (Defence Advanced Research Project Agency). Fiecare dintre calculatoarele conectate avea sistemul propriu de operare, iar operaţiile dintre calculatoare erau privite ca operaţii periferice.

Realizarea reţelelor a impus modificări în software şi hardware. Odată cu răspândirea sistemelor s-a pus problema sistemelor de operare de reţea. Acest deziderat s-a putut realiza atunci când s-au răspândit calculatoarele interconectate local (LAN - Local Area Networks), astfel apărând MAN (Metropolitan Area Networks) şi WAN (Wide Area Networks).

Există şi încercări de realizare a unor S.O. care tratează toate resursele dintr-o reţea ca făcând parte dintr-un sistem unic, deci nu mai lasă vizibilă utilizarea topologiei de reţea. Acestea se numesc S.O. distribuite.

1.3.8 Perspective.

Câteva dintre tendinţele actuale ar fi : dezvoltarea reţelelor de calculatoare, realizarea unor sisteme cu paralelism masiv, interconectarea strânsă a sute sau mii P.

Includerea în S.O. a elementelor de gestionare pentru paralelism masiv este considerată o sarcină dificilă. Va fi deasemenea dificil să se dezvolte limbaje de programare şi compilatoare pentru astfel de sisteme.

O altă tendinţă este realizarea unor interfeţe cu utilizatorul cât mai evoluate, în special integrarea şi interpretarea a cât mai multor medii de comunicare (text, grafic, voce, imagine ...) adică o tendinţă spre sisteme multimedia.

Deasemenea o tendinţă este orientarea spre sisteme deschise, sisteme ale căror specificaţii sunt făcute publice şi sunt standardizate. Astfel se pot realiza implementări diferite dar care să respecte specificările standardizate. Aceasta va permite portabilitatea aplicaţiilor şi chiar a S.O.

- 10 -

Page 12: Curs So

Curs de SISTEME DE OPERARE

2. Structura Sistemelor de Operare.

Sistemele de Operare sunt sisteme de complexitate mare, care pentru a fi înţelese şi stăpânite trebuie divizate în subsisteme. O cale de divizare funcţională a S.O. ar fi considerarea diverselor responsabilităţi ale sistemului ca module separate. Există şi alţi factori cu importanţă în stabilirea structurii unui S.O., cum ar fi : caracteristicile hardware ale sistemului, limbajul de implementare folosit, domeniile de aplicaţie etc. Din cauza complexităţii un S.O. va apare diferit când este examinat din puncte de vedere diferite.

Posibile puncte de vedere ar fi : organizarea codului sursă al sistemului organizarea memoriei structura de execuţie interacţiunea dintre componente adaptabilitatea la configuraţii hardware

2.1 Organizarea memoriei.

Întotdeauna o parte a unui S.O. trebuie să se găsească în memorie în timpul funcţionării sistemului. Acesta este partea rezidentă a S.O. şi constă din cod care tratează servicii critice :

planificarea proceselor tratarea erorilor tratarea iniţială a apelurilor sistem

Componentele utilizate cu frecvenţă redusă cum ar fi părţi din sistemul de gestionare a sistemului sau interpretorul de comenzi, nu rămân în permanenţă în memorie ci se încarcă la cerere de pe un suport extern. Acestea se numesc componente tranzitorii ale S.O..

Pentru partea rezidentă a S.O. se rezervă o zonă fixă a memoriei. De obicei începutul şi sfârşitul memoriei fizice.

Pentru componentele tranzitorii ale sistemului poate fi rezervată o zonă denumită sau acestea pot fi tratate la fel ca şi programele utilizatorului, fiind încărcate în orice porţiune de memorie disponibilă.

În zona inferioară a memoriei găsim detalii despre întreruperi. Zona superioară a memoriei este uneori utilizată pentru comunicare cu perifericele iar în alte arhitecturi se foloseşte pentru S.O. din motive de simplificarea scrierii programelor.

Organizarea memoriei în S.O. este prezentată prin hărţi de memorie, unde de regulă apar 3 aspecte distincte :

conţinutul spaţiului virtual de adrese al unui program utilizator conţinutul spaţiului virtual de adrese al unui program sistem conţinutul memoriei fizice

- 11 -

Page 13: Curs So

Curs de SISTEME DE OPERARE

În CP/M nu se face distincţie între cele 3 aspecte, deci harta va reprezenta conţinutul memoriei fizice (Fig. 2.1-1).

64K

256

0

BIOS

BDOS

CCP

zonă comunicaţie

Programe deaplicaţie + date

Nefolosit

BIOS - conţine rutinele pentru tratarea la nivel fizic a operaţiilor periferice

BDOS - conţine elemente necesare pentru construcţia unui sistem de fişiereBIOS + BDOS 10K

CCP - interpretor de comenzi al sistemului (2K), el este încărcat la cerere. Dacă este necesar, un program de aplicaţie poate acoperi zona de memorie a CCP.

Obs. : Toate programele de aplicaţie sunt generate considerând că ele se încarcă în memorie de la adresa 1000H (4K).

Fig. 2.1-1

În MS-DOS deosebim o hartă a memoriei fizice şi una a spaţiului virtual de adrese a programelor (Fig. 2.1-2 şi Fig. 2.1-3).

1M

1536

0

BIOS (ROM)

Mem video

Interpretor c-zi

zonă comunicaţie

Programe deaplicaţie + date

Nefolosit

zona de comunicaţii constă din tabela vectorilor deîntreruperi (1K) şi zona de transfer cu discul 512 octeţi.zona rezident SO se includ rutinele pentru gestiuneasistemului, rutinele pentru realizarea sistemului de fişiere şio parte din interpretorul de comenzi.memoria video cuprinde zona care se pune încorespondenţă directă cu zona consolei utilizator.

640K

~100KRezident SO

Fig. 2.1-2

Din punctul de vedere al unui program spaţiul virtual de adrese se compune din 1 4 segmente de 64 Kocteţi. În figura Fig. 2.1-3 se prezintă cazul tipic : modelul de memorie small.

stiva aplicaţiei

datele aplicaţiei

segmentul de date (DS)

cod propriuzis

zona de comunicaţie (PSP)

segmentul de cod (CS)

64 K 64 K

0 0

Fig. 2.1-3

- 12 -

Page 14: Curs So

Curs de SISTEME DE OPERARE

În UNIX harta fizică a memoriei va depinde de arhitectura calculatorului pe care este implementat sistemul.

Există o separare totală între spaţiul de adrese al unui program utilizator şi spaţiul de adrese al unui program sistem (Fig. 2.1-4). Orice comunicare între programele utilizator şi sistem se face prin apeluri sistem (deci nu prin memorire comună).

STIVA

Cod program

Program utilizator

Partea rezidentă a S.O.

Sistemul de Operare

AdreseMARI

Adresemici

Date iniţiale

AdreseMARI

Adresemici

Neutilizat

Fig. 2.1-4

Obs.: Comparativ, partea rezidentă a celor trei S.O. prezentate necesită următoarele cantităţi de memorie :

CP/M 10Kb MS-DOS 100Kb UNIX 1Mo

2.2 Structuri de execuţie.

Codul unui S.O. constă din mai multe unităţi executabile, execuţia fiecărei unităţi fiind declanşată de evenimente specifice.

În organizarea tradiţională S.O. pot fi privite ca o colecţie de rutine, activate fiecare prin apeluri sistem din programe utilizator, sau ca urmare a unor întreruperi.

dispecerapeluri sistem

intr #1

intr #2

punctede

intrareîn

sistem

Rutine de tratarea apelurilor sistem

Rutine de tratarespecifice

Fig. 2.2-1

Rutinele care servesc ca puncte de întrerupere în S.O. trebuie să fie în partea rezidentă a sistemului de operare.

- 13 -

Page 15: Curs So

Curs de SISTEME DE OPERARE

Obs.: Majoritatea S.O. prevăd un singur punct de intrare în sistem, acesta fiind un dispecer care va rezolva apelurile.

În timpul execuţiei acestor rutine sau altora pot apare solicitări de încărcare a unor părţi nerezidente. Aduse în memorie ele vor avea acelaşi nivel de privilegiu cu rutinele rezidente (există şi excepţii). Un apel sistem apare în programe cu aceeaşi sintaxă ca şi apelul obişnuit de rutine. Traducerea lor în cod executabil este însă diferită, prevăzându-se operaţiile necesare pentru schimbarea regimului de execuţie (se trece din regim neprivilegiat, specific programelor utilizator, în regim privilegiat, specific S.O., adică nu mai sunt aplicate toate elementele de protecţie aplicate programului utilizator).

Multe din rutinele S.O. revin la programul apelant numai după satisfacerea completă a serviciilor solicitate.

Există apeluri sistem (şi deci rutine din S.O.) care declanşează activităţi ce se vor desfăşura simultan cu desfăşurarea activităţilor U.C. fără a avea nevoie de U.C. (de exemplu operaţiile de I/O). În aceste cazuri, programul care a făcut apelul, e de regulă suspendat până la terminarea serviciului, iar U.C. poate fi folosit de alte programe (vezi multiprogramarea). La terminarea unui serviciu de durată, solicitat de un program, se declanşează o întrerupere ce va face ca U.C. să suspende execuţia programului în curs şi să treacă la execuţia rutinei de tratare a întreruperii. Ca urmare a execuţiei acestei rutine se vor modifica diferite structuri de date şi este posibil ca programul care a fost blocat pentru efectuarea serviciului să devină gata de execuţie. La terminarea rutinei de tratare a întreruperii, o componentă a S.O., numită planificator decide dacă se reia execuţia programului care a fost suspendat în momentul apariţiei întreruperii sau se alege un alt program.

În S.O. simple toate serviciile sunt duse până la capăt fără a se reveni la programul de aplicaţie sau altele.

În S.O. mai complexe, apar activităţi ale S.O. care trebuie să continuie pe o perioadă mai lungă în paralel cu execuţia proceselor utilizator (tipărirea unor fişiere la imprimantă, controlul unor linii de telecomunicaţie, o serie de activităţi periodice cum ar fi la UNIX salvarea tampoanelor din memorie pe disc). Ele sunt organizate ca procese distincte, numite taskuri sistem şi sunt tratate asemănător cu procesele utilizator, având însă prioritate de planificare mai mari.

Organizarea unei părţi din S.O. ca procese este o cale de reducere a erorilor în realizarea S.O. (pentru că trebuie controlat un volum mai mic de cod). Există o parte a codului de S.O. care rămâne în afara proceselor sistem şi cuprinde servicii esenţiale, între ele fiind inclusă şi planificarea proceselor, comunicarea între procese, rutine pentru gestionarea memoriei etc.

- 14 -

Page 16: Curs So

Curs de SISTEME DE OPERARE

2.3 Interacţiunea componentelor.

Într-o structură fără restricţii, orice rutină a unui S.O. ar putea apela orice altă rutină sau ar putea face acces la orice structuri de date ale sistemului. Un astfel de S.O. ar fi foarte puţin fiabil pentru că ar fi extrem de dificil să se controleze efectele unei schimbări într-o rutină sau într-o structură de date. Restricţii asupra interacţiunilor componentelor pot fi impuse atât în procesul de proiectare a S.O. cât şi în timpul execuţiei rutinelor sistem. La proiectare restricţiile se pot realiza prin intermediul compilatorului, dacă se foloseşte un limbaj adecvat pentru implementare. La execuţie este necesar un sprijin din partea hardware-ului, ceea ce în cele mai multe arhitecturi nu este întâlnit.

Primul S.O. proiectat structurat a fost sistemul T.H.E. (Technische Hocheschool Eindhard), realizat de un grup condus de Dýkstra. A fost experimental, a apărut înainte de 1968 şi a fost scris pentru minicalculatoarele Philips. Era organizat pe mai multe nivele (Fig. 2.3-1) :

5. Utilizatori

4. Programe de aplicaţie

3. Periferice

2. Consola utilizator

1. Memoria virtuală

0. Planificarea proceselor,tratarea întreruperilor

Fig. 2.3-1

Fiecare nivel gestionează o categorie de resurse, vitualizează resursele respective. Se realizează astfel o secvenţă de maşini abstracte (sau virtuale), fiecare bazată pe maşina de la nivelul inferior şi fiecare oferind noi funcţii pentru nivelul inferior :

La nivelul 0 există o colecţie de rutine, ce realizează virtualizarea procesorului. deasupra acestui nivel este asigurat faptul că fiecare proces are propriul său procesor virtual.

La nivelul 1 există un proces sistem care realizează virtualizarea memoriei. În nivelele următoare fiecare proces are propriul spaţiu de memorie virtuală. Resursele gestionate la nivelul 1 sunt memoria internă şi un tambur magnetic, care serveşte ca suport extern al memoriei virtuale (precursorul discului magnetic).

Nivelul 2 conţine un proces care gestionează consola calculatorului. Prin virtualizarea acesteia fiecare proces din nivelele superioare are propria consolă utilizator, la care poate emite mesaje.

La nivelul 3 se găseşte câte un proces pentru fiecare periferic, altul decât consola sau tamburul prezent în configuraţia sistemului de calcul.

Nivelul 4 conţine un număr oarecare de procese care funcţionează ca interpretoare de comenzi şi deci pot controla execuţia programelor utilizatorilor.

- 15 -

Page 17: Curs So

Curs de SISTEME DE OPERARE

Structurarea pe nivele a S.O. permite ca porţiunile critice ale sistemului să fie izolate în nivelele inferioare care se construiesc şi se testează cu foarte multă rigurozitate. Numărul de nivele din structura unui sistem nu este fix, depinde de deciziile luate de proiectanţi, funcţie de domeniul de aplicaţie, de experienţa proiectanţilor etc.

O extindere a modelului este prezentată în figura Fig. 2.3-2.

Shell (interpretor de c-zi)

Cataloage

Procese utilizator

I/E la nivel logic

Periferice

Sistem de fişiere

Comunicaţii interprocese

Mecanisme de protecţie

Memorie virtuală

Memorie secundarã localã

Procese elementare

Întreruperi

Mecanisme pentru proceduri

Setul de instrucţiuni

Circuite electronice

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

Hardware

Capabilităţi

Calculatorsingular

Reţea (nuneapărat)

Fig. 2.3-2

2.4 Adaptabilitatea la configuraţii hardware.

S.O. depinde în mare măsură de hardware-ul calculatorului, aceasta fiind una din principalele deosebiri ale S.O. faţă de alte componente software. Este de dorit ca un S.O. să fie proiectat avându-se în vedere şi portabilitatea. în cazul cel mai simplu este necesar ca un S.O. să poată fi uşor adaptat la sisteme de calcul cu configuraţii diferite dar din aceeaşi familie. Adică să se poată uşor specifica un număr diferit de periferice, cantitate diferită de memorie etc. În cazul extrem pentru adaptarea la o nouă configuraţie ar trebui făcute modificări în codul sursă al S.O. Modalitatea uzuală întâlnită însă este ca la iniţializarea S.O. să fie consultată o serie de fişiere de configurare din care se culeg informaţii specifice unui sistem de calcul dat. La MS-DOS acest fişier este config.sys, în UNIX există mai multe fişiere de configurare pe mai multe zone funcţionale ale sistemului. Mai trebuie prevăzută şi modalitatea de a adăuga simplu la sistem porţiuni de program numite drivere care controlează funcţionarea unor periferice noi adăugate în configuraţia hardware.

- 16 -

Page 18: Curs So

Curs de SISTEME DE OPERARE

3. Sistemul de Operare MS-DOS. Probleme generale.

Sistemul există din 1981. Este primul S.O. pentru microprocesoare pe 16 biţi. În momentul de faţă se consideră că este cel mai răspândit S.O. din lume, având vândute câteva zeci de milioane de exemplare. Sistemul de operare constituie baza pentru câteva zeci de mii de aplicaţii, ceea ce îl situează pe primele locuri în lume.

MS-DOS versiunea 1.0 a apărut în august 1981. Această versiune avea multe caracteristici în comun cu S.O. CP/M (care a fost folosit ca şi model). Avea sistem de fişiere cu un singur nivel, ceea ce s-a corectat în martie 1983, la versiunea 2.0, care conţine pentru prima dată driver pentru discul winchester de 10Mb şi sistem de fişiere ierarhic. În versiunea 2.0 se împrumută de la UNIX modul de realizare a apelurilor sistem pentru lucrul cu fişiere.

În august 1984 apare versiunea 3.0 care este legată de introducerea calculatoarelor AT cu Intel 80286 şi cu discuri fixe de 20Mb (arhitectura standard I.B.M.) şi discuri flexibile de 1,2Mb. Versiunea 3.0 permite definirea de discuri virtuale în RAM şi introduce posibilitatea de protecţie a fişierelor (un fişier poate fi considerat read only).

În noiembrie 1984 apare versiunea 3.1 care permite lucrul în reţea şi posibilitatea ca în aceeaşi reţea să se lucreze cu sisteme de fişiere diferite.

În 1986 s-a introdus versiunea 3.2 cu driver pentru discuri flexibile de 31/2 inch şi câteva comenzi suplimentare între care xcopy. De asemenea introduce un driver special care permite copierea pe aceeaşi unitate de disc.

În 1987 este lansată versiunea 3.30 care adaugă câteva funcţii cerute de utilizatori, pe noua familie de calculatoare numită PS/2. Se permit 4 porturi de comunicare, se permit dischete de 1.44Mb şi se permit pe discuri fixe mai multe (4) partiţii de maximum 32Mb fiecare.

În 1988 este introdusă versiunea 4.0 care permite lucrul cu discuri fixe cu capacităţi de până la 2Gb. Permite utilizarea de către programe a memoriei expandate şi introduce o interfaţă grafică cu utilizatorul, realizată conform specificaţiilor T.B.M. numite C.U.A. (Common User Access). Versiunea 4.1 lansată spre sfârşitul lui 1988 corectează unele anomalii găsite la 4.0.

În primăvara lui 1991 apare versiunea 5.0 care extinde interfaţa grafică în sensul unei apropieri de Windows.

Din 1993 este disponibilă versiunea MS-DOS 6.0 iar din 1994 versiunea 6.2, care dispun de următoarele facilităţi :

includerea unui utilitar pentru compresia datelor pe disc ce poate determina chiar dublarea capacităţii suporţilor magnetici (DoubleSpace);

incorporarea unui program antivirus (MSAV şi VSAFE); înlocuirea comenzilor Backup-Restore cu un produs mai bun şi posibilitatea eliminării

fragmentărilor de pe disc (DEFRAG); incorporarea unei modalităţi îmbunătăţite de gestionare a memoriei superioare

(MemMaker); determinarea în mod automat a programelor ce se pot executa în memoria superioară

(DOS 6.0 ocupă 200K din totalul de 384K); comanda MOVE care permite mutarea unui director cu întreg conţinutul; comanda CHOICE, ce permite citiri de la tastatură în timpul execuţiei, inclusă în

limbajul de comenzi al fişierelor batch.

- 17 -

Page 19: Curs So

Curs de SISTEME DE OPERARE

3.1 Structura S.O. MS-DOS. Încărcarea sistemului.

3.2 Utilizarea şi organizarea spaţiului pe discuri.

Când se instalează , sau se face upgrade la un sistem, o mare parte a lucrului implică manipularea şi utilizarea discurilor. Pentru ca pe un disc să se poată stoca fişiere, acesta trebuie pregătit în conformitate cu sistemul utilizat.

Principalii paşi în pregătirea discurilor sunt: Formatarea discului. Acest proces implică mai multe operaţii de pregătire, ca de

exemplu căutarea de sectoare defecte. În prezent cele mai multe hard discuri nu necesită această operaţie, deoarece ele vin deja gata formatate de la producător. Acest proces mai este cunoscut şi sub numele de Formatare Low Level.

Partiţionarea hard discului, aceasta în cazul în care se doreşte utilizarea lui pentru mai multe activităţi care să nu interfere unele cu altele. Un motiv pentru partiţionare este folosirea unui singur disc pentru mai multe sisteme de operare. Un alt motiv este de a ţine separat fişierele utilizatorilor de cele de sistem, aceasta simplificând back-up-urile şi deasemenea ajută la protejarea fişierelor sistem.

Crearea unui sistem de fişiere (de un tip potrivit) pe fiecare disc sau partiţie. De obicei discurile, respectiv partiţiile nu se pot utiliza până când nu se creează pe ele un sistem de fişiere. Acest proces mai este cunoscut şi sub numele de Formatare High Level.

Pentru anumite sisteme, pentru ca sistemele de fişiere create să se poată utiliza, ele trebuiesc montate sau automat sau manual. (UNIX). De obicei sistemele de fişiere montate manual trebuiesc demontate tot manual.

- 18 -

Page 20: Curs So

Curs de SISTEME DE OPERARE

3.3 Hard discuri

În figura următoare se prezintă schematic părţile importante ale unui hard disc.

Sector

Pistă / Track

Sens de rotaţie

Cap decitire / scriere

Privit de sus :

Platan (Platter)

Feţe

Cilindru

Fig. 3.3-1

Un hard disc constă dintr-unul sau mai multe platane circulare, care au una sau ambele feţe acoperite cu o substanţă magnetică, folosită pentru înregistrarea informaţiilorr. (Platanele sunt de obicei construite dintr-o substanţă mai dură, de ex. aluminiu, ceea ce le dă şi numele de discuri dure sau de masă - hard disc). Pentru fiecare suprafaţă există un cap de citire/scriere care examinează sau alterează informaţia înregistrată. Platanele se rotesc pe o axă comună, cu o viteză tipică de 3600 rotaţii pe minut, deşi discurile de înaltă performanţă au o viteză de rotaţie mărită. Capetele se deplasează de-a lungul razei platanelor. Această mişcare combinată cu rotaţia platanelor permite accesarea oricărei părţi a suprafeţei.

Procesorul şi discul comunică printr-un controller de disc. Acesta separând restul computerului de sarcina de a controla efectiv discul.

- 19 -

Page 21: Curs So

Curs de SISTEME DE OPERARE

Suprafeţele, de obicei sunt divizate în inele concentrice, numite piste (tracks), iar acestea sunt divizate în sectoare (sectors). Această împărţire este folosită pentru specificarea unei anumite locaţii de pe disc şi pentru alocarea spaţiului pentru fişiere. Astfel pentru a găsi un anumit loc pe disc se poate specifica : suprafaţa x, pista y, sectorul z. De obicei numărul de sectoare este acelaşi pentru toate pistele, dar unele hard discuri au mai multe sectoare pe pistele exterioare şi mai puţine pe pistele interioare. Tipic, un sector va conţine 512 octeţi de date. Discul nu poate manipula o cantitate mai mică de date decât aceea a unui sector.

Fiecare suprafată este divizată în piste şi sectoare în acelaşi fel. Aceasta înseamnă că dacă capul pentru o suprafaţă este pe o pistă, capetele pentru celelalte suprafeţe sunt deasemenea pe pistele corespondente. Toate pistele corespondente luate împreună poartă denumirea de cilindru. Mutarea capetelor de pe un cilindru pe altul durează un anumit timp, astfel plasând împreună datele care sunt accesate des, astfel ca să fie situate pe acelaşi cilindru, nu este necesară operaţia de mutare a capetelor pentru a citi toate aceste date. Aceasta înbunătăţeşte performanţele. Din păcate nu întotdeauna este posibil să plasăm astfel fişierele. Fişierele care sunt stocate în mai multe părţi de pe disc se numesc fragmentate.

Numărul feţelor (sau capetelor), cilindrilor şi sectoarelor variază destul de mult. Specificarea numărului fiecăruia este numită geometria hard discului. Această geometrie de obicei este memorată într-o memorie specială numită CMOS RAM.

Din păcate BIOS-urile mai vechi au o limitare în implementare, fiind imposibilă specificarea unui număr de piste mai mare de 1024, în memoria CMOS, aceasta este însă prea puţin pentru hard discurile mari. Pentru a depăşi această limitare, controllerele de disc comunică o geometrie falsă şi translatează adresele date de calculator astfel încât să concorde cu realitatea. De exemplu un hard disc ar putea avea 8 capete, 2048 piste şi 35 sectoare pe pistă. În acest caz, o posibilă translatare ar fi : 16 capete, 1024 piste şi 35 sectoare pe pistă. Această translatare ar putea afecta performanţele (vezi discuţia despre fragmentare).

Translatarea este o problemă doar pentru discurile IDE. Discurile SCSI utilizează o numerotare secvenţială a sectoarelor.

3.3.1 Floppy discuri

Un disk floppy constă dintr-o membrană flexibilă acoperită pe una sau ambele feţe cu o substanţă magnetică similară cu cea a hard discurilor. Un disc floppy corespunde unui platan dintr-un hard disc, dar este îndepărtabil din unitate, pe când hard discurile constituie o unitate indivizibilă.

Ca şi un hard disc, un floppy este divizat în piste şi sectoare (iar cele două piste corespondente de pe feţele unui floppy formează un cilindru), dar sunt mult mai puţine decât pe un hard disc.

O unitate de floppy discuri de obicei poate fi folosită cu mai multe tipuri de discuri, de exemplu o unitate de 31/2 inch poate fi utilizată atât cu dischete de 720KB cât şi de 1,44MB.

3.3.2 Formatarea

Formatarea este procesul scrierii de marcaje pe mediul magnetic care sunt utilizate la marcarea pistelor şi sectoarelor. Înainte ca un disc să fie formatat, suprafaţa sa magnetică este un haos complet de semnale magnetice. Când este formatată, se introduce o anumită ordine în acest haos, în principal prin ”tragerea” de linii acolo unde vor fi pistele precum şi acolo unde acestea sunt despărţite în sectoare. Detaliile de implementare nu sunt relevante pentru acest curs. Ceea ce este însă important, este că un disc nu poate fi folosit până când el nu este formatat.

- 20 -

Page 22: Curs So

Curs de SISTEME DE OPERARE

Pentru discurile IDE şi SCSI în prezent formatarea se face de către producător, astfel încât aceasta nu mai trebuie făcută. Mai mult s-ar putea ca unele discuri să necesite o formatare specială, astfel o reformatare ar duce la scăderea performanţelor hard discului.

Dicurile care totuşi au nevoie de formatare necesită programe speciale care de obicei există în BIOS, sau ca şi programe executabile sub un anumit sistem de operare.

3.3.3 Partiţii

Un hard disc poate fi împărţit în mai multe partiţii. Fiecare partiţie se comportă ca şi cum ar fi un hard disc separat. Ideea este accea că există doar un singur hard disc şi se doreşte instalarea a două sisteme de operare, se poate împărţi hard discul în două părţi. Fiecare sistem de operare folosind partiţia sa cum doreşte şi ne atingându-se de alte partiţii. Fără partiţii ar trebui ca pentru fiecare sistem de operare să existe un hard disc separat.

Discurile floppy nu sunt partiţionate. Nu există nici un impediment tehnic pentru aceasta, dar deoarece ele sunt de capacitate relativ mică, partiţiomarea lor nu ar ajuta aproape la nimic.

3.3.4 MBR-ul, sectoare boot şi tabele de partiţii

Informaţia cu privire la modul în care un hard disc a fost partiţionat este memorată în primul sector al acestuia (adică în primul sector al primei piste de pe prima faţă). Primul sector este Master Boot Record-ul discului, acesta este sectorul pe care BIOS-ul îl citeşte şi îl lansează când sistemul este pornit pentru prima dată. MBR-ul conţine un mic program care citeşte tabela de partiţii, caută partiţia activă (cea care este marcată ca şi bootable) şi citeşte în memorie primul sector al acelei partiţii, adică sectorul de boot al partiţiei (MBR-ul este tot un sector de boot, dar are un statut special). Acest sector de boot conţine un alt program care citeşte în memorie prima parte a sistemului de operare care există pe acea partiţie şi îi dă controlul.

Partiţionarea este doar o convenţie urmată de cele mai multe sisteme de operare. Unele sisteme de operare suportă partiţii, dar ele ocupă o singură partiţie şi folosesc o partiţionare internă în cadrul acelei partiţii. Aceste tipuri de sisteme de operare pot coexista cu alte sisteme de operare, dar un sistem de operare care nu suportă partiţii nu poate coexista pe acelaşi hard disc cu alte sisteme de operare.

3.3.5 Partiţii extinse şi logice

Schema originală de partiţionare pentru hard discurile de PC-uri admite doar patru partiţii. Pentru a depăşi această limitare au fost introduse partiţiile extinse. Aceasta este un truc pentru a permite partiţionarea unei partiţii primare în subpartiţii. O astfel de partiţie primară, împărţită în subpartiţii se numeşte partiţie extinsă, iar subpartiţiile sunt partiţii logice. Acestea din urmă se comportă ca şi partiţiile primare, dar sunt create într-un mod diferit.

Structura de partiţionare a unui hard disc ar putea arăta ca în următoarea figură. Discul este divizat în trei partiţii primare, a doua partiţie fiind divizată în două partiţii logice. O parte a discului nu este partiţionată deloc, deci nu este folosită. Discul ca şi întreg şi fiecare partiţie primară are câte un sector de boot.

- 21 -

Page 23: Curs So

Curs de SISTEME DE OPERARE

Primary partition

Logical Extended partition partition

Logical partition

Primary partition

Observaţie: Aici ar trebui să se completeze de la 3.2.3. (din curs) tabela de partiţii şi explicarea acesteia. După aceea ar trebui continuat cu 3.2.2. cu câteva observaţii de la 3.2.1.

3.4 Organizarea spaţiului pe discuri.

3.4.1 Caracteristicile fizice ale discului.

În configuraţia calculatoarelor personale compatibile IBM se întâlnesc două tipuri de floppy discuri (discuri flexibile) şi hard disc (discuri fixe). Din punct de vedere fizic discurile sunt împărţite pe fiecare faţă în piste, iar fiecare pistă în sectoare. Capacitatea standard pentru discurile flexibile a fost o perioadă de 360 Kocteţi ceea ce înseamnă 40 piste 9 sectoare pe fiecare faţă, dimensiunea unui sector fiind 512 octeţi. S-a folosit şi 720 Koceteţi, ceea ce a făcut să se dubleze numărul de piste, după care dimensiunea standard pentru un disc de 5 1/4 a fost 1,2 Mocteţi (80 de piste 15 sectoare).

Pentru discurile de 31/2 s-au folosit două capacităţi standard: 720 Kocteţi (80 de piste 9 sectoare). 1,44 Mocteţi (80 piste 18 sectoare).

Pentru discurile fixe capacităţile au fost de 10 Mocteţi (20, 40, 80, 220, 300, 600, 1 Goctet, …).

Se folosesc două numerotări ale sectoarelor, o numerotare zisă BIOS şi cealaltă DOS. Numerotarea BIOS consideră adresele unui sector prin trei componente : cap, pistă şi sector. Adresele DOS consideră sectoarele numerotate în continuare fără a putea considera adresa fizică a sectorului. Numerotarea capetelor porneşte de la 0, numerotarea pistelor de la 0, iar numerotarea sectoarelor de la 1.

În notaţia DOS se porneşte de la primul sector de pe pista 0 a feţei 0, după epuizarea ei se continuă cu pista 0 a feţei 1. Numerotarea se face în ordinea cilindrilor.

- 22 -

MBRBoot sector

Date areaof partition

Boot sectorUnused boot sector

Date area

Unused boot sector

Date area

Unused boot sectorBoot sector

Date area

Page 24: Curs So

Curs de SISTEME DE OPERARE

3.4.2 Organizarea logică a discurilor.

În sistemul MS-DOS se foloseşte o convenţie materializată prin comanda format care împarte suprafaţa fizică a unui disc în patru zone :

sectorul de încărcare tabela de alocare a fişierelor (FAT) catalogul rădăcină spaţiul pentru date

Sectorîncãrcare

FAT Catalogrãdãcinã

Zona dedate

În cazul discurilor fixe există un element suplimentar şi anume tabela de partiţii.Sectorul de încărcare pe lângă programul încărcător mai conţine informaţii despre

structura sistemului de operare.FAT are la început informaţii generale despre structura discului şi apoi evidenţa

alocării sectoarelor pentru diferite fişiere şi a spaţiului liber. Pentru siguranţă se păstrează două copii pentru FAT, fiecare având o dimensiune în funcţie de capacitatea discului şi este dată de comanda FORMAT. Discurile flexibile au 4 16 sectoare pentru fiecare FAT.

Catalogul rădăcină : are o dimensiune fixă, în funcţie de capacitatea discului (la discurile fixe este între 714 sectoare) şi este compus din intrări care descriu câte un fişier. În catalogul rădăcină se pot descrie doar un număr limitat de fişiere. O intrare de catalog conţine numele fişierului şi numărul intrării din tabela de alocare a fişierelor (FAT), care corespunde primei zone de date alocate acestui fişier.

Zona de date conţine informaţii propriu-zise înregistrate în fişere, unele dintre aceste fişiere pot să fie cataloage.

A. Sectorul de încărcare.Primii trei octeţi ai sectorului de încărcare în MS-DOS conţin un salt necondiţionat la

adresa 2Eh, de la această adresă începe de fapt programul încărcător. Începând cu al patrulea octet al sectorului este înregistrat aici blocul de parametri BIOS.

La sfârşitul sectorului de încărcare, ultimii doi octeţi, există o informaţie specifică numită semnătură DOS, 55 AAh.

Deplasament Lungime Descriere 03 0B 0D 0E 10 11 13 15 16 18 1A 1C

8 2 1 2 1 2 2 1 2 2 2 2

Identificatorul sistemului (DOS 4.0)Număr octeţi / sectorNumăr sectoare / grupă (cluster)Număr sectoare rezervate la începutul disculuiNumăr copii FATNumăr intrări în catalogul rădăcinăNumăr total de sectoare / discIdentificator de formatNumăr sectoare / FATNumăr sectoare / pistăNumăr feţeSectoare speciale

- 23 -

Page 25: Curs So

Curs de SISTEME DE OPERARE

B. Tabela de alocare a fişierelor.Există două structuri pentru FAT :

tabele FAT în care intrarea are 12 biţi tabele în care intrarea are 16 biţi.

Conţinutul unei intrări în FAT este de fapt un număr de grupă. Alocarea spaţiului pentru fişiere făcându-se la nivel de grupă de sectoare.

Dimensiunea unei grupe este 18 sectoare (se alege în funcţie de capacitatea discului). Dacă dimensiunea intrării este 12 biţi valoarea maximă 0FFFh (4095) 4096 de

valori putem descrie discuri cu capacitatea 4096 / 2 Kocteţi 20 Mocteţi.Dacă dimensiunea intrării este de 16 biţi 0FFFFh 65535 valori.Prin numerele de grupă care se înregistrează prin intrările FAT se formează liste

simplu înlănţuite ale grupelor alocate fiecărui fişier. Începutul fiecărei liste este păstrată în intrarea de catalog a fişierului.

Există valori rezervate ale intrărilor în FAT :0 - corespunde unei grupe libere.F peste tot - sfârşit de listă.(F)FF7 - marchează zone defecte pe disc.

0 1 2 3 4 5 6 7 200 000 206 000 205 000 208 206 800 208 21A 000 000 000 20D FFF 000 000 210 000 000 000 FFF 000 000 000 000 218 000 000 FFF 0 0 0 0 0

Când se şterge un fişier toate intrările FAT corespunzătoare spaţiului marcat de acel fişier vor fi marcate ca disponibile. Nu e afectat fişierul în zona sa de date. Spaţiul alocat unui fişier creşte odată cu creşterea dimensiunii fişierului. La crearea unui fişier nu se alocă spaţiu peste necesarul din acel moment pentru fişier.

C. Catalogul rădăcină.Fiecare intrare de catalog are lungimea de 32 octeţi, deci un sector de pe disc conţine

16 intrări de catalog (7 sectoare pentru un catalog 112 fişiere). În subcataloage, dimensiunea nu este limitată. Numărul de intrări din catalogul rădăcină este limitat la 256 (16 sectoare). O intrare are 8 câmpuri. Formatul unei intrări de catalog este :

Deplasament Dimensiunea Format Descriere 00h 8 ASCII Numele fişierului 08h 3 ASCII Extensia fişierului 0Bh 1 Binar Atributele fişierului 0Ch 10 –––– Rezervat 16h 2 Binar Timp 18h 2 Binar Data 1Ah 2 Binar Prima intrare FAT 1Ch 4 Binar Dimensiunea fişierului (în octeţi)

Numele fişierului, dacă este mai scurt de opt caractere, se completează la dreapta cu blancuri. Între caractere nu sunt recomandate blancuri. Deasemenea nu se recomandă utilizarea caracterelor ’*’ şi ’?’ ce au o semnificaţie specială pentru interpretorul de comenzi. Deasemenea caracterul ’.’.

- 24 -

Page 26: Curs So

Curs de SISTEME DE OPERARE

MS-DOS nu face deosebirea între litere mari şi litere mici. În primul octet al câmpului de nume dintr-o intrare de catalog pot apărea trei combinaţii binare, care au semnificaţie specială.

00h - că această intrare de catalog nu a fost folosită;E5h - fişierul respectiv a fost şters.2Eh - se consideră ca şi cod special: punctul ’.’ pentru intrările speciale, şi ’..’, care există în fiecare subcatalog, ’.’ descrie catalogul însuşi şi al doilea catalogul părinte.

Prima intrare a catalogului rădăcină este deasemenea rezevată pentru a înregistra eticheta de volum (care poate fi un şir de maxim 11 caractere).

Extensia se poate completa la dreapta cu blancuri. Combinaţia care se foloseşte ca extensie dă o anumită informaţie despre conţinutul fişierului.

Octetul de atribute foloseşte fiecare bit din octet pentru a preciza unele caracteristici ale fişierelor :

Cod hexa Semnificaţie 01 RO (pentru citire) 02 Atributul de fişier ascuns (Nu îl listează comanda DIR) 04 Fişier sistem 08 Descrie eticheta de volum 10 Intrarea subcatalog (este subdirector) 20 Arhivă 40 Rezervat 80 Rezervat

Câmpul pentru timp :

Depl 17h Depl 16h

h h m m x x

5cb 6cb 5cb

Câmpul pentru dată : Depl 19h Depl 18h

y y m m d d

7cb 4cb 5cbÎn câmpul pentru an 0 119 lună zi

pentru lună 0 12 pentru zi 0 31

Câmpurile de dată şi timp se pot folosi împreună cu un întreg lung fără semn (4 octeţi) la operaţii de comparare. Pentru fişierele care au fost create fără a avea spaţiu alocat şi intrarea care descrie eticheta de volum, pentru acest câmp avem 0.

Câmpul pentru dimensiunea fişerului. Valoarea lui corespunde în mod real cu dimensiunea fişierului. La fişierele create prin editoare de texte se poate întâmpla ca valoarea înregistrată aici să depăşească valoarea reală, deoarece acestea salvează câte un buffer odată. Sfârşitul real al fişierului în acest caz va fi identificat prin codul ^Z (1Ah).

- 25 -

Page 27: Curs So

Curs de SISTEME DE OPERARE

D. Zona de date.Unitatea de alocare este grupa, de obicei alocarea se face la prima grupă disponibilă,

cu toate că se pot aplica algoritmi de selecţie a grupelor astfel încât spaţiul unui fişier să fie într-o zonă cât mai restrânsă a discului. Dacă un fişier ajunge să fie fragmentat, adică ajunge să aibă grupe din zone diferite ale discului, se reduc performanţele de transfer, deoarece creşte numărul de deplasări ale capetelor de citire-scriere.

3.4.3 Partiţionarea discurilor fixe.

Este un nivel superior de gestionare al spaţiului în sensul că înainte ca un disc să poată fi utilizat spaţiul său este împărţit într-un număr de secţiuni logice numite partiţii, fiecare comportându-se ca o unitate specifică distinctă. Convenţia adoptată la MS-DOS este aceea că numărul maxim de partiţii este patru.

Este permis ca în partiţii diferite să se găsească sisteme de operare diferite cu propriile sale organizări ale spaţiului din partiţia rezervată. Această divizare în partiţii a fost impusă şi de imposibilitatea unor resurse MS-DOS de a gestiona spaţii mai mari de 32 Mocteţi.

Fiecare partiţie constă dintr-o zonă contiguă de cilindri şi are o dimensiune dată de utilizator. Numărul şi dimensiunea partiţiilor se pot modifica, dar doar prin distrugerea vechiului conţinut al partiţiei.

Primul sector al discului fix va conţine informaţii despre partiţionare, iar prima partiţie va începe cu primul sector de pe faţa a doua a discului. Deasemenea în primul sector se mai găseşte un program de iniţializare, care verifică tabela de partiţii, deduce care este partiţia activă şi determină încărcarea partiţiei active.

Tabela de partiţii ocupă ultima parte a sectorului, patru intrări de câte 16 octeţi. Această tabelă începe la octetul cu deplasamentul 1BEh, pentru că ultimii doi octeţi ai sectorului trebuie să conţină semnătura sistemului.

O intrare a tabelei de partiţii :

Deplasament Lungime Descriere 0 1 Partiţie activă / inactivă 1 1 Adresă cap început de partiţie 2 1 Adresă sector început de partiţie 3 1 Adresă cilindru început de partiţie 4 1 Identificator sistem 5 1 Adresă cap sfârşit de partiţie 6 1 Adresă sector sfârşit de partiţie 7 1 Adresă cilindru sfârşit de partiţie 8 2 Număr sectoare care preced partiţia (LOW WORD) A 2 Număr sectoare care preced partiţia (HIGH WORD) C 2 Număr sectoare ocupate de partiţie (LOW WORD) E 2 Număr sectoare ocupate de partiţie (HIGH WORD)

- 26 -

Page 28: Curs So

Curs de SISTEME DE OPERARE

3.5 Sistemul de întreruperi în MS-DOS.

În arhitectura calculatoarelor personale compatibile IBM semnalele de întrerupere pot fi generate de trei categorii de surse :

întreruperi hardware interne - sunt generate chiar în procesor, într-una din următoarele situaţii :

1. instrucţiunea precedentă provoacă o depăşire a capacităţii registrelor procesorului (frecvent datorită unei împărţiri cu 0).

2. în registrul de stare program este poziţionat fanionul de deviere (TRAP), ceea ce face ca după fiecare instrucţiune să se genereze o întrerupere.

3. instrucţiunea precedentă a fost INTO (interrupt overflow) şi este poziţionat fanionul de depăşire OF (overflow flag).

întreruperi hardware externe - sunt generate de surse exterioare procesorului şi ajung direct sau prin intermediul controllerului programabil de întreruperi la pinii corespunzători ai procesorului.

întreruperi software - sunt generate prin instrucţiuni speciale prevăzute în programe (INT), argumentul acestei instrucţiuni fiind nivelul pe care se generează întreruperea. Acestea se folosesc în mod normal pentru a apela diverse servicii oferite de S.O.

În arhitectura 80x86 sunt prevăzute 256 de nivele de întrerupere. Nivelul de întrerupere are rolul de a permite selectarea unei anumite rutine de tratare. În procesor nu se definesc priorităţi între aceste nivele. Adresele rutinelor de tratare (exprimate pe câte 4 octeţi) se găsesc într-o tabelă de vectori de întreruperi, situată în primul kilooctet de RAM (0 3FF). Nivelul de întrerupere este folosit ca indice în această tabelă. Atunci când se ia în considerare un semnal de întrerupere, procesorul execută următoarele operaţii :

1. Salvează în stivă registrul fanioanelor (registrul stare program).2. Dezactivează temporar întreruperile hardware prin ştergerea

fanioanelor corespunzătoare din registrul de stare program (TF şi IF).3. Salvează în stivă adresa instrucţiunii următoare din programul în curs

(CS:IP).4. Citeşte din tabela de vectori de întrerupere adresa corespunzătoare

nivelului pe care a sosit întreruperea şi efectuează salt la această adresă.

Rutinele de tratare a întreruperilor se termină cu o instrucţiune de revenire specială IRET, care provoacă următoarele operaţii :

1. Extrage din stivă IP şi CS.2. Extrage din stivă registrul fanioanelor.

Astfel se provoacă implicit reluarea programului suspendat când a apărut întreruperea.

fanioane

CS

IP

SP

stiva

Fig. 3.5-1

- 27 -

Page 29: Curs So

Curs de SISTEME DE OPERARE

Iniţializarea conţinutului tabelei vectorilor de întrerupere se face la încărcarea sistemului de operare, parţial de rutinele din BIOS şi parţial de rutinele de iniţializare din IO.SYS şi MSDOS.SYS.

3.5.1 Întreruperi hardware.

Se numesc astfel nivelele de întrerupere din prima grupă de 16 : 00h 0Fh.Utilizarea lor este următoarea :

nivelul 00h - împărţire la 0 şi oferă posibilitatea tratării printr-o rutină a acestei situaţii. La încărcarea S.O., vectorul pentru acest nivel este iniţializat din BIOS să indice spre o instrucţiune IRET. Sistemul MS-DOS nu oferă implicit o tratare a împărţirii cu 0.

nivelul 01h - este nivelul de execuţie pas cu pas. Aici sunt dirijate întreruperile care se generează după fiecare instrucţiune de program, când este poziţionat TF. Acest vector este deasemenea iniţializat de BIOS spre o instrucţiune IRET.

nivelul 02h - pe acest nivel se tratează întreruperile nemascabile (de exemplu apariţia unei erori de paritate în memorie). Acest vector este iniţializat la fel ca cele de mai sus.

nivelul 03h - este nivelul pentru întreruperile de test, prin care se fixează puncte de control (breakpoints) în program. Iniţializat la fel ca mai sus.

nivelul 04h - pe acest nivel se semnalează întreruperea de depăşire, cea produsă de instrucţiunea INTO; se foloseşte tot în scopuri de depanare. Iniţializat la fel ca mai sus.

nivelul 05h - tipărirea conţinutului ecranului (print screen). Aici există un vector spre o rutină adevărată. Rezultatul execuţiei rutinei de întrerupere este memorat într-un octet de stare care se găseşte la adresa de paragraf 0050:0. Dacă este : 0 atunci tipărirea s-a efectuat corect, 1 atunc este în curs de tipărire, FF atunci a apărut o eroare la tipărire.

nivelul 06h - nu este folosit de MS-DOS. nivelul 07h - nu este folosit de MS-DOS. nivelul 08h - întreruperea de ceas - este o întrerupere hardware externă. Semnalele de

întrerupere pe acest nivel sosesc de la un circuit de tip 8259 de pe canalul 0. Întreruperile de ceas la PC-uri sunt generate de circa 18,2 ori pe secundă, iar tratarea acestor întreruperi constă în incrementarea unui contor. Contorul este situat în memorie la adresa 0046:C. În rutina de tratarese face apel şi la rutina de tratare a nivelului 1Ch, pe care programatorii pot include programe cu acţiune dependentă de timp.

nivelul 09h - întrerupere de la tastatură (se produce la apăsarea şi la eliberarea unei taste). În esenţă rutina care tratează aceste întreruperi asigură preluarea de la tastatură a codului de scanare a tastei apăsate. Rutina asigură transformarea codului de scanare şi în cod ASCII şi împreună cele două coduri se memorează în tamponul pentru tastatură, utilizat de BIOS. Acest tampon se găseşte la adresa 40:1E în aşa zisa zonă de date ROM-BIOS. Tot această rutină mai asigură şi recunoaşterea unor configuraţii speciale de taste, cum ar fi : CTRL-ALT-DEL, CTRL-Break.

nivelul 0Ah - este tot pentru întreruperile de ceas, dar de pe canalul 2 al lui 8259. nivelul 0Bh - nu este folosit de MS-DOS. nivelul 0Ch - nu este folosit de MS-DOS. nivelul 0Dh - este nivelul pe care sosesc întreruperile externe de la unităţile de discuri.

Acestea sunt dirijate pe canalul 5 al lui 8259. nivelul 0Eh - nu este folosit de MS-DOS.

- 28 -

Page 30: Curs So

Curs de SISTEME DE OPERARE

nivelul 0Fh - nu este folosit de MS-DOS.

3.5.2 Întreruperi BIOS.

Aceste întreruperi sunt generate prin software, cu ajutorul instrucţiunii INT xx, unde xx este nivelul întreruperii.

Caracteristic tuturor întreruperilor generate prin software este faptul că sunt generate sincron cu programul în execuţie. Majoritatea au rolul de a apela servicii de sistem aşa încât întrerupera trebuie să fie însoţită de informaţii încărcate în registre care să precizeze serviciul dorit şi eventual infomaţii necesare acelui serviciu.

Utilizarea întreruperilor BIOS este următoarea : nivelul 10h - serveşte la apelarea serviciilor de ecran, cum ar fi fixarea modului de

lucru, a formei cursorului, afişarea unui caracter, a unui şir, defilarea ecranului etc. nivelul 11h - furnizează informaţii despre configuraţia hardware a sistemului. nivelul 12h - serveşte pentru obţinerea dimensiunii memoriei nivelul 13h - serveşte pentru apelarea serviciilor de lucru la nivel fizic cu discuri :

iniţializare, citirea stării, poziţionări, citiri, scrieri etc. nivelul 14h - este prevăzut pentru apelarea serviciilor de lucru cu interfaţa serială :

iniţializare, emisia sau recepţia unui caracter, fixarea regimului de transmisie etc. nivelul 15h - acest nivel se foloseşte pentru comanda altor periferice şi pentru

raportarea evenimentelor de intrare/ieşire. nivelul 16h - permite realizarea de operaţii asupra tamponului tastaturii. nivelul 17h - permite controlul interfeţei paralele, la care de regulă este conectată o

imprimantă. nivelul 18h - întrerupere rezervată, folosită pentru declanşarea interpretorului de

BASIC din ROM. nivelul 19h - întreruperea pentru încărcarea la cald. nivelul 1Ah - întreruperea pentru citirea şi poziţionarea timpului. nivelul 1Bh - întreruperea la care se ataşează rutina de tratare a combinaţiei CTRL-C. nivelul 1Ch - întreruperea care se leagă de nivelul 08h şi dă posibilitatea activării unui

program la momente determinate în timp. nivelul 1Dh - nu conţine o adresă de rutină, ci conţine o adresă la care se găsesc

parametri pentru iniţializarea ecranului. nivelul 1Eh - conţine adresa unui bloc de parametri pentru lucrul cu discurile. nivelul 1Fh - conţine adresa tabelei folosită pentru generatorul de caractere pentru

codurile ASCII extinse.

3.5.3 Întreruperi DOS.

Întreruperile DOS sunt cele cu nivelele 20h 3Fh. Şi acestea au evoluat faţă de primele versiuni ale sistemului DOS, prin concentrarea majorităţii serviciilor oferite pe nivelul 21h. Pe acest nivel sunt prevăzute şi servicii apelabile prin intermediul întreruperilor BIOS.

Utilizarea întreruperilor DOS este următoarea (vor fi enumerate doar cele mai folosite):

nivelul 20h - este întreruperea pentru terminarea programului curent. Generarea unui astfel de întreruperi face ca execuţia programului să se termine şi controlul să revină programului care a lansat acel program.

nivelul 21h - pe acest nivel sunt concentrate funcţiile MS-DOS.

- 29 -

Page 31: Curs So

Curs de SISTEME DE OPERARE

nivelul 22h - vectorul de pe acest nivel este adresa rutinei care se apelează la terminarea programului în curs, după un INT 20h sau INT 27h sau după apelarea unor funcţii sistem (ca de exemplu : 00h, 4Ch şi 31h).

nivelul 23h - conţine adresa la care se transferă controlul pentru combinaţia de taste CTRL-Break.

nivelul 24h - este întreruperea de tratare a erorilor critice de intrare-ieşire. nivelul 25h - foloseşte pentru citirea de pe disc, localizarea sectoarelor făcându-se prin

adrese DOS. nivelul 26h - foloseşte pentru scrierea pe disc, localizarea sectoarelor făcându-se prin

adrese DOS. nivelul 27h - întreruperea TSR (Terminate and Stay Resident), se termină execuţia

programului dar nu se eliberează memoria corespunzătoare lui. nivelul 2Fh - întreruperea pentru gestionarea proceselor. Acest serviciu este disponibil

numai de la versiunea 3.0 şi permite ca anumite programe ataşate pe acest nivel să se desfăşoare în paralel cu programele de aplicaţie (de exemplu comanda print).

3.6 Formatul fişierelor executabile. Prefixul segmentului de program.

În sistemul de operare MS-DOS există două formate de fişiere executabile care sunt tratate în mod diferit. Identificarea tipului de format executabil se face prin extensia numelui de fişier (.COM şi .EXE).

3.6.1 Structura fişierelor .COM.

Aceste fişiere au dimensiunea limitată la 64KB. Astfel într-un singur segment se găseşte atât codul cât şi datele programului. În fişier se găseşte imaginea pură a unui program (toate adresele din program se vor pune în legătură cu adresele fizice numai relativ la conţinutul registrului CS). Atunci când un fişier .COM este adus în memorie, sunt identificate două zone în porţiunea de memorie rezevată programului. O primă zonă de 256 octeţi numită PSP care conţine informaţii generale, valabile pentru orice program şi o a doua zonă care cuprinde codul şi datele, aduse direct din fişier. PSP-ul este construit de S.O. pentru fiecare program executabil adus în memorie.

Încărcarea unui program are loc în două etape :1. Găsirea unei zone de memorie şi construirea PSP.2. Încărcarea programului imediat în continuarea PSP.

PSP

Program.COM

CS:0

CS:100

program deaplicaţie

S.O.

Fig. 3.6-1

- 30 -

Page 32: Curs So

Curs de SISTEME DE OPERARE

Structura PSP este prezentată în următorul tabel :

Nr.câmp

Depl. Lung. Semnificaţie

1. 00h 2 INT 20h2. 02h 2 Dimensiunea memoriei (în paragrafe)3. 04h 1 nefolosit4. 05h 5 CALL FAR5. 0Ah 4 Vector INT 22h6. 0Eh 4 Vector INT 23h7. 12h 4 Vector INT 24h8. 16h 2 CS pentru programul apelant (de ex. COMMAND.COM)9. 18h 20 rezervat

10. 2Ch 2 Pointer spre ambianţă11. 2Eh 4 Adresa stivei pentru funcţii DOS12. 32h 30 rezervat13. 50h 3 INT 21h urmat de RETF14. 53h 9 rezervat15. 5Ch 16 FCB116. 6Ch 16 FCB217. 7Ch 4 rezervat18. 80h 128 DTA

Tabelul 3.6-1

În câmpul 1 este prevăzută instrucţiunea INT 20h care constituie unul din modurile de terminare a execuţiei unui program. În program va apare un salt necondiţionat la locaţia respectivă. O justificare a acestei soluţii ar fi că dacă într-un program care face referiri externe rămâne o referinţă nerezolvată aceasta ar apărea ca apel la adesa 0.

Câmpul 2 arată câtă memorie este disponibilă pentru program, precizând adresa de paragraf a sfârşitului memoriei accesibile programului.

Câmpul 4 se foloseşte la apelarea serviciilor DOS din prima versiune (00h 24h).În câmpurile 5, 6, 7 se salvează la începutul execuţiei programului vectorii pentru

nivelele de întreruperi indicate (22h, 23h, 24h). Vectorii vor fi instalaţi la sfârşitul execuţiei. Este posibil ca pe durata programului acesta să folosească alţi vectori pentru nivelele respective, fără a perturba funcţionarea altor programe.

Câmpul 10 este adresa de segment care indică spre zona în care apar sub formă de şiruri de caractere variabilele sistem şi valorile lor.

Câmpul 13 conţine instrucţiuni pentru apelarea funcţiilor sistem mai recente.Câmpurile 15 şi 16 servesc la prelucrarea fişierelor în stilul CP/M.Câmpul 18, în timpul execuţiei programului acest câmp serveşte ca tampon pentru

operaţiile cu discuri, dacă programul apelează funcţii care necesită un astfel de tampon şi nu este prevăzută o zonă corespunzătoare în cadrul programului. Înainte de începerea propriuzisă a programului, aici se găsesc parametrii din linia de comandă sub forma unui şir de caractere. Se precizează că între parametri nu se găsesc numele programului şi eventualele informaţii de redirectare ale intrării sau ieşirii.

- 31 -

Page 33: Curs So

Curs de SISTEME DE OPERARE

3.6.2 Structura fişierelor .EXE.

Programele care se păstrează în fişiere .EXE pot avea orice dimensiune, dar nu putem lansa în execuţie un program mai lung decât zona disponibilă de memorie RAM.

Un fişier cu extensia .EXE constă din două părţi, prima conţine antetul şi tabela de relocare iar a doua conţine programul propriu-zis şi datele aferente acestuia. Antetul începe cu primul octet al fişierului. În antet se găsesc informaţii folosite în procesul de încărcare al programului în memorie.

Nr. câmp

Depl. Dim. Conţinut

1. 00h 2 4Dh, 5Ah - semnătură fişier .EXE2. 02h 2 ExtraBytes - număr octeţi din ultimul sector alocat fişierului3. 04h 2 Pages - număr de sectoare alocate fişierului4. 06h 2 RelocItems - număr intrări în tabela de relocare5. 08h 2 HeaderSize - dimensiunea antetului în paragrafe

6. 0Ah 2 MinAlloc - numărul minim de paragrafe solicitate de program dincolo de sfârşitul programului

7. 0Ch 2 MaxAlloc - numărul maxim de paragrafe pe care îl solicită programul

8. 0Eh 2 InitSS - valoarea iniţială pentru SS9. 10h 2 InitSP - valoarea iniţială pentru SP

10. 12h 2CheckSum - suma de control = suma negativă a tuturor

cuvintelor din codul programului fără a lua în considerare antetul, ci doar partea executabilă

11. 14h 2 InitIP - valoarea iniţială pentru IP12. 16h 2 InitCS - valoarea iniţială pentru CS

13. 18h 2 RelocTable - deplasamentul tabelei de relocare faţă de începutul fişierului (01Ch)

14. 1Ah 2 Overlay - numărul de suprapuneri

Tabelul 3.6-2

Câmpurile MinAlloc şi MaxAlloc se completează la editarea de legături. Dacă nu se precizează, valoarea lui MaxAlloc va fi completată cu 0FFFFh ceea ce înseamnă că programul solicită toată memoria disponibilă. Dacă ambele sunt zero atunci programul se va încărca la capătul superior al memoriei disponibile.

Pentru a încărca un program .EXE, MS-DOS-ul mai întâi citeşte antetul fişierului pentru a determina semnătura precum şi pentru a calcula dimensiunea imaginii programului. După aceasta încearcă să aloce memoria necesară. Mai întâi adună dimensiunea imaginii programului cu dimensiunea PSP-ului şi cu cantitatea de memorie specificată în câmpul MinAlloc. Dacă această sumă depăşeşte dimensiunea celui mai mare bloc de memorie disponibil, se opreşte încărcarea programului şi se întoarce un cod de eroare. Altfel se adună dimensiunea imaginii programului cu dimensiunea PSP-ului şi cu cantitatea de memorie specificată în câmpul MaxAlloc. Dacă această a doua sumă este mai mică decât dimensiunea celui mai mare bloc de memorie disponibil, MS-DOS alocă respectiva cantitate de memorie. Altfel se alocă cel mai mare bloc de memorie disponibil.

După alocarea memoriei, se determină adresa de segment, numită adresa segment de start, la care se va încărca imaginea programului. Dacă ambele câmpuri MinAlloc şi MaxAlloc sunt diferite de 0, imaginea va fi încărcată imediat în continuarea zonei rezervate PSP-ului.

- 32 -

Page 34: Curs So

Curs de SISTEME DE OPERARE

Următorul pas este citirea înregistrărilor din tabela de relocare şi ajustarea tuturor adreselor de segment specificate de pointerii de relocare. Pentru fiecare pointer din tabela de relocare se caută adresa segmentului relocatabil corespunzător din imaginea program şi se adună la aceasta adresa segment de start. Odată ajustate, adresele de segment indică spre segmentele de memorie unde sunt încărcate codul şi datele programului.

I_OFF I_SEG

START_SEG - adresa de început al programului(PSP+10h)

RELO_SEG = START_SEG + I_SEG

(RELO_SEG : I_OFF) += START_SEG

Tabela de relocare conţine intrări de câte 2cuvinte de 16 biţi :

Fig. 3.6-2

După acestea se construieşte PSP-ul în partea inferioară a memoriei alocate. MS-DOS-ul foloseşte valorile din antetul fişierului pentru a seta regiştrii SP şi SS şi se ajustează registrul SS prin adunarea la aceasta a adresei segment de start. Deasemenea se setează regiştrii ES şi DS să indice adresa de segment a PSP-ului.

În final se citesc valorile iniţiale pentru CS şi IP, tot din antetul fişierului, ajustându-se valoarea registrului CS la fel ca şi SS-ul, adunându-se la aceasta adresa segment de start şi se transferă controlul programului aflat la adresa ajustată.

- 33 -

Page 35: Curs So

Curs de SISTEME DE OPERARE

4. Interfaţa MS-DOS cu utilizatorul.

4.1 Generalităţi.

Serviciile oferite de S.O. se apelează prin intermediul întreruperilor. Pentru DOS nivelul de întrerupere folosit pentru apelul serviciilor sistem este 21h (INT 21h).

Ca regulă generală : registrul AH conţine numărul serviciului. ceilalţi regiştri conţin informaţii suplimentare necesare apelului respectiv. în urma execuţiei, rezultatele se vor găsi în diferite registre. cele mai multe servicii, în urma apelului, dacă a apărut o eroare, poziţionează

CARRY, iar în AX se întoarce un cod de eroare.

Exemplificare : pentru funcţia 36h, care furnizează spaţiul liber disponibil pe disc avem:

AH <- 36h - codul serviciuluiDL <- id. disc - numărul discului (0 - disc implicit, 1 - A, 2 - B etc.)

La întoarcerea din apel :AX - conţine numărul de sectoare/cluster sau FFFFh pentru eroare.BX - numărul de clustere disponibile.CX - numarul de octeţi/sector.DX - numărul total de clustere.

Ca şi secvenţă de cod în limbaj de asamblare :

mov AH,36hmov DL,1 ; discul Aint 21hcmp AX,0FFFFhje err_rtn ; salt la rutina de tratare a eroriimov sec_du,AX ; nr. sectoare/clustermov avl_du,BX ; nr. clustere disponibilemov byt_sec,CX ; nr. octeţi/sector

Pentru ca funcţiile DOS să poată fi apelate din limbajul C, există câteva funcţii de bibliotecă : bdos, bdosptr, int86, int86x, intdos, intdosx, intr, geninterrupt. Prototipul acestor funcţii se găseşte în dos.h.

Funcţiile intdos, intdosx apelează servicii DOS prin intermediul lui INT 21h. Mai generale sunt funcţiile int86, int86x (oferă accesul la regiştrii DS şi ES).

Structurile de date care intervin în aceste apeluri (aceste structuri sunt puse în corespondenţă cu regiştrii microprocesorului) :

struct WORDREGS { /* regiştrii pe cuvânt */unsigned int ax, bx, cx, dx, si, di, cflag, flags;

};struct BYTEREGS { /* regiştrii pe octet */

unsigned char al, ah, bl, bh, cl, ch, dl, dh;};

- 34 -

Page 36: Curs So

Curs de SISTEME DE OPERARE

struct SREGS { /* structură separată pentru regiştrii de segment */unsigned int es, cs, ss, ds;

};

union REGS { /* combină WORDREGS şi BYTEREGS */struct WORDREGS x;struct BYTEREGS h;

};

struct REGPACK { /* similar cu WORDREGS */unsigned r_ax, r_bx, r_cx, r_dx;unsigned r_bp, r_si, r_di, r_ds, r_es, r_flags;

};

Prototipurile funcţiilor sunt următoarele (toate sunt definite ca int) :

int bdos(int dosfun, unsigned dosdx, unsigned dosal);primeşte ca argumente :

numărul serviciului în dosfun conţinutul registrului DX în dosdx conţinutul registrului AL în dosal

valoarea returnată este conţinutul registrului AX după apelul DOS.

int bdosptr(int dosfun, void *arg, unsigned dosal);există unele servicii care solicită o zonă de memorie (în care să se memoreze mai multe informaţii decât încap în regiştri, de aceea se transmite un pointer).

int int86(int intno, union REGS *in, union REGS *out);primeşte numărul întreruperii şi doi pointeri. Cade în sarcina programatorului să completeze regiştrii (pentru apeluri DOS : intno = 21h, in.h.ah = numărul serviciului).

int int86x(int intno, union REGS *in, union REGS *out, struct SREGS *sregs);

Funcţiile int86 şi int86x copiază conţinutul variabilei in în regiştrii procesorului, iar după apel copiază în out conţinutul rezultat al regiştrilor.

Funcţiile intdos şi intdosx nu mai conţin numărul de întrerupere.

int intdos(union REGS *in, union REGS *out);int intdosx(union REGS *in, union REGS *out, struct SREGS *sregs);

În caz de eroare toate returnează ca valoare conţinutul registrului AX. Informaţii suplimentare se găsesc în variabila “globală” doserrno. Mai există şi variabila errno care este poziţionată în urma unor funcţii mai evoluate (nu cele care lucrează direct cu întreruperi).

- 35 -

Page 37: Curs So

Curs de SISTEME DE OPERARE

EXEMPLU : Se consideră următorul program, care determină spaţiul disponibil pe disc:

#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <dos.h>

long free_space(int drive) /* primeste ca argument drive-ul */{

union REGS inregs, outregs;

inregs.h.ah = 0x36;inregs.h.dl = drive;int86(0x21, &inregs, &outregs);

/* se face testul daca a aparut eroare */if (outregs.x.ax == 0xFFFF)

return (-1); /* cod de eroare *//* trebuie fortata conversia de tip : unsigned -> long */return (long)outregs.x.ax*(long)outregs.x.bx*(long)outregs.x.cx;

}

void main(int argc, char *argv[]){

int drive;long space;

if (argc != 2) {printf("Utilizare : FREE_SP <drive>\n");exit(1);

}drive = (int)(toupper(*argv[1]) - 'A' + 1);if ((space = free_space(drive)) == -1)

printf("Unitate invalida !\n");else

printf("Spatiul liber pe discul %c: este %ld octeti.\n",*argv[1], space);

exit(0);}

Programul se mai putea face apelând o funcţie de bibliotecă getdfree.În funcţia free_space avem : int86(0x21, &inregs, &outregs), ar fi fost suficientă o

singură variabilă, astfel : int86(0x21, &inregs, &inregs), asta presupunând că după apel nu ne interesează conţinutul acesteia de dinaintea apelului (folosim aceeaşi zonă de memorie).

- 36 -

Page 38: Curs So

Curs de SISTEME DE OPERARE

4.2 Servicii oferite de MS-DOS. Serviciile sistem.

4.2.1 Funcţii pentru gestionarea fişierelor.

În primele versiuni operaţiile asupra fişierelor se efectuau folosind FCB-uri (File Control Block), aceasta fiind preluată de la sistemul CP/M.

În versiunile mai noi funcţiile cele mai folosite au devenit cele care lucrează cu indici de fişier (File Handle) - fiecare fişier este identificat printr-un număr, astfel programatorul lucrează doar cu un număr întreg, restul operaţiilor fiind preluate de S.O.

Fişierele standard au următorii indici : stdin = 0 stdout= 1 stderr = 2 prn = 3 aux = 4

În următoarele se vor enumera cele mai folosite funcţii : 3Ch : funcţia de creare a unui fişier. Crează un fişier cu numele precizat de

utilizator şi îi asignează un indice (în funcţie de câţi indici erau deja asignaţi). 5Bh : funcţia care crează un fişier numai dacă numele specificat este unic

(dacă fişierul există atunci returnează un cod de eroare). 5Ah : funcţia care crează un fişier temporar cu nume unic. Numele acestui

fişier se formează din cifre hexa oţinute din data şi ora curentă. Acest fişier de obicei va trebui şters la terminarea programului.

41h : funcţia de stergere a unui fişier. 3Dh : funcţia de deschidere a unui fişier specificat într-un mod de asemenea

specificat (citire, scriere, citire-scriere etc.). 3Eh : funcţia de închidere a unui fişier specificat prin indice. Indicele

respectiv este eliberat, astfel încât va putea fi folosit pentru lucrul cu un alt fişier.

3Fh : funcţia de citire dintr-un fişier. Se furnizează indicele şi numărul de octeţi care se vor citi. Octeţii citiţi se depun la o adresă, deasemenea specificată de programator. Se întoarce numărul de octeţi citiţi.

40h : funcţia de scriere într-un fişier. Se furnizează indicele şi numărul de octeţi care se vor scrie. Deasemenea se specifică adresa de unde se vor prelua octeţii de scris. Se întoarce numărul de octeţi scrişi.

42h : funcţia de poziţionare a pointerului de citire-scriere în fişier. Se furnizează indicele, poziţia relativă la care urmează să fie poziţionat pointerul şi locul de referinţă, faţă de care s-a comunicat poziţia relativă, care poate fi : începutul, poziţia curentă sau sfârşitul fişierului. Pentru ca această funcţie să se poată executa corect fişierul trebuie să fie deschis.

45h : funcţia care face duplicarea unui indice de fişier. Această funcţie crează un nou indice care se referă la acelaşi canal de intrare/ieşire ca şi cel original. Noul indice moşteneşte drepturile de acces precizate pentru primul indice.

46h : funcţia de redirectare. Această funcţie face ca doi indici de fişier să se refere la acelaşi fişier fizic, se presupune că ambii indici existau deja şi corespundeau unor canale de intrare/ieşire diferite.

- 37 -

Page 39: Curs So

Curs de SISTEME DE OPERARE

Diferenţa dintre 45h şi 46h : funcţia 45h este utilă pentru golirea bufferelor (un fel de flush) cu indicele duplicat se poate forţa închiderea fişierului, astfel golindu-se bufferele DOS. Secvenţa este mai rapidă decât dacă am face acelaşi lucru cu un singur indice close şi apoi open. Versiunile mai noi ale DOS au o funcţie specială de golire a bufferelor. Funcţia 46h se foloseşe la redirectarea intrărilor şi ieşirilor.

EXEMPLU : Pentru a exemplifica folosirea funcţiilor pentru gestionarea fişierelor considerăm

următorul exemplu :

/* Programul este conceput pentru modelul de memorie SMALL ! */

#include <stdlib.h>#include <stdio.h>#include <dos.h>

#define SIZE 512 /* numar octeti pe care ii citim sau scriem */

int copiaza(char *srs, char *dst){

union REGS regs;unsigned idsrs, iddst;char buffer[SIZE];unsigned nbytes; /* variabila care memoreaza cati octeti au */

/* intervenit in operatia de citire */regs.h.ah = 0x5B;regs.x.cx = 0x0000; /* definim fara atribute */regs.x.dx = (unsigned)dst;

/* in DX se memoreaza adresa numelui *//* fisierului destinatie *//* Daca se doreste alt model decat SMALL *//* se va completa si DS */

int86(0x21, &regs, &regs);if (regs.x.cflag != 0)

return (-1); /* intoarce un cod de eroare */iddst = regs.x.ax; /* memoram indicele fisierului destinatie */

regs.h.ah = 0x3D;regs.h.al = 0x00; /* acces in citire */regs.x.dx = (unsigned)srs;int86(0x21, &regs, &regs);if (regs.x.cflag != 0)

return (-1); /* intoarce un cod de eroare */idsrs = regs.x.ax; /* memoram indicele fisierului sursa */

/* urmeaza un ciclu care citeste dintr-un fisier si scrie in celalalt fisier */do {

/* citirea */regs.h.ah = 0x3F;regs.x.bx = idsrs;regs.x.cx = (unsigned)SIZE; /* dimensiunea cat se citeste */regs.x.dx = (unsigned)buffer;

- 38 -

Page 40: Curs So

Curs de SISTEME DE OPERARE

/* adresa bufferului unde se face citirea */int86(0x21, &regs, &regs);nbytes = regs.x.ax;/* functia read din C face acelasi lucru */

/* scrierea */regs.h.ah = 0x40;regs.x.bx = iddst;regs.x.cx = nbytes;regs.x.dx = (unsigned)buffer;int86(0x21, &regs, &regs);

} while (nbytes == SIZE);/* cand s-au citit mai putini octeti decat cati s-au precizat *//* in apel, ciclul se opreste */

/* inchidere fisiere */regs.h.ah = 0x3E;regs.x.bx = idsrs;int86(0x21, &regs, &regs);regs.h.ah = 0x3E;regs.x.bx = iddst;int86(0x21, &regs, &regs);/* ca valoare de intoarcere dam valoarea indicatorului CARRY *//* care ne spune cum s-a inchis fisierul destinatie */return ((int)regs.x.cflag);

}

/* programul este valabil pentru cazuri pentru care nu avem nume *//* ambigue de fisiere, adica sa nu contina * sau ? */int main(int argc, char *argv[]){

if (argc != 3) {printf("Utilizare : COPIAZA <fis_srs> <fis_dst>\n");exit(1);

}if (copiaza(argv[1], argv[2]) == 0)

printf("Program terminat normal.\n");else

printf("Eroare la copiere.\n");exit(0);

}

- 39 -

Page 41: Curs So

Curs de SISTEME DE OPERARE

4.2.2 Funcţii pentru gestionarea cataloagelor.

În următoarele se vor enumera funcţiile folosite pentru gestionarea cataloagelor : 39h : funcţia de creare a unui catalog. Parametrii (cum ar fi numele

catalogului) se comunică în registre. 3Ah : funcţia de ştergere a unui catalog. Se admite ştergerea catalogului

numai dacă acesta este gol. 3Bh : funcţia de schimbarea catalogului curent. 43h : funcţia pentru citirea/poziţionarea atributelor unui fişier. 47h : funcţia de obţinere a numelui catalogului curent. 4Eh : funcţia pentru găsirea primului fişier care corespunde unui tipar dat.

Determină în catalogul curent numele primului fişier care se poate pune în corespondenţă cu tiparul dat. Informaţii despre fişierul găsit (dată, atribute, lungimea fişierului etc.) se furnizează în zona de transfer cu discul (DTA).

4Fh : funcţia pentru găsirea următorului fişier care corespunde unui tipar dat. Se utilizează după un apel la 4Eh. Găseşte următorul fişier sau spune că nu există sau nu mai există fişier corespunzător tiparului dat.

56h : funcţia pentru schimbarea numelui unui fişier. Prin această funcţie se poate face şi mutarea unui fişier într-un alt catalog, dar doar pe acelaşi disc.

57h : funcţia pentru citirea/poziţionarea datei şi orei unui fişier.

EXEMPLU : Programul afişează numele catalogului curent de pe o unitate logică specificată.

Dacă nu se specifică, la apelul programului, unitatea logică, se consideră unitatea implicită. Se lucrează cu modelul de memorie SMALL.

#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <dos.h>

void main(int argc, char *argv[]){

union REGS r;char nume[64];unsigned drive = 0;if (argc > 1)

drive = (unsigned)(toupper(*argv[1])-'A'+1);r.h.ah = 0x47;r.x.si = (unsigned)nume;r.h.dl = drive;int86(0x21, &r, &r);if (r.x.cflag) {

printf("Nume de periferic invalid.\n");exit(1);

}printf("Catalog curent : %c%c\\%s\n",

drive ? ('A'+drive-1) : ' ', drive ? ':' : '\b', nume);exit(0);

}

- 40 -

Page 42: Curs So

Curs de SISTEME DE OPERARE

Următorul program schimbă catalogul curent. În program se va ilustra şi lucrul cu pointeri FAR.

#include <stdio.h>#include <dos.h>

static char buffer[80];

int main(void){

char far* nume_cat;union REGS r;struct SREGS sr;printf("Introduceti numele noului catalog : ");gets(buffer);nume_cat = buffer;r.h.ah = 0x3B;r.x.dx = FP_OFF(nume_cat); /* se preia deplasamentul bufferului */sr.ds = FP_SEG(nume_cat); /* se preia adresa de segment */int86x(0x21, &r, &r, &sr);return (0);

}

4.2.3 Funcţii pentru I/E cu dispozitive standard orientate pe caractere.

Dispozitivele standard orientate pe caractere sunt : consola (tastatura şi monitorul), imprimanta, porturile seriale, porturile paralele. Dacă într-un program se folosesc aceste funcţii, actunci este permisă redirecţionarea intrării şi/sau ieşirii standard a acelui program.

Se recomandă utilizarea subserviciilor oferite de funcţia 44h. În rutinele pentru tratarea erorilor critice, în driverele de periferice trebuiesc folosite funcţiile vechi (cele cu numere mici).

În următoarele se enumeră funcţiile din această categorie : 01h : citire cu ecou de la tastatură. Codul caracterului citit se va găsi în AL. 02h : afişarea unui caracter. Codul caracterului de afişat trebuie încărcat în

DL. 03h : citire caracter de la intrarea auxiliară COM1. Codul caracterului citit

se va găsi în AL. 04h : trimiterea unui caracter la ieşirea auxiliară COM1. Codul caracterului

de trimis trebuie încărcat în DL. 05h : tipărirea unui caracter (LPT1). Codul caracterului de tipărit trebuie

încărcat în DL. 06h : intrare/ieşire directă, fără ecou de la tastatură, respectiv pe ecran. Se

preia un caracter de la STDIN dacă există un caracter pregătit şi dacă în DL se găseşte FFh, sau se trimite un caracter la STDOUT, dacă în DL se găseşte altceva decât FFh (adică codul unui caracter).

07h : simplă citire fără ecou de la tastatură. Se aşteaptă până când există un caracter disponibil.

Obs. : Funcţiile 06h şi 07h nu tratează caracterele speciale.

- 41 -

Page 43: Curs So

Curs de SISTEME DE OPERARE

08h : citire fără ecou de la tastatură, se deosebeşte de 06h şi 07h prin faptul că se recunosc tastele speciale CTRL-Break etc., acestea generând o întrerupere pe nivelul 23h.

09h : afişarea unui şir de caractere. DS:DX trebuie să indice spre adresa şirului de caractere terminat cu caracterul ‘$’.

0Ah : intrare prin zonă tampon de la tastatură. Citeşte un şir de caractere de la STDIN până la apariţia caracterului CR (Carriage Return), şirul fiind memorat într-o zonă tampon cu următorul format :

LT LE caractere

LT - lungime totală a zonei rezervateLE - lungime efectivă (împreună cu

CR)

0 1 2 ...

Fig. 4.2-1

0Bh : verificarea stării intrării. Se determină dacă există sau nu un caracter disponibil la intrare (AL = 00h <=> nu există, AL = FFh <=> există ).

0Ch : ştergerea zonei tampon de intrare şi citire de la tastatură. Se curăţă zona tampon de intrare după care se apelează una din funcţiile de citire caractere (01h, 06h, 07h, 08h, 0Ah) al cărui cod este introdus în registrul AL.

4.2.4 Funcţii pentru gestionarea perifericelor.

Considerăm în această grupă funcţiile care permit obţinerea de informaţii sau controlul echipamentelor periferice standard, precum şi funcţia specială 44h, care permite lucrul cu orice periferic, dacă driverele perifericului există şi respectă anumite restricţii :

19h : obţinerea unităţii implicite (curente). Rezultatul se întoarce în AL (0 - A, 1 - B etc. - aceasta este o excepţie, deoarece numerotarea discurilor în acest caz porneşte de la 0 şi nu de la 1).

0Eh : selectarea unităţii implicite (curente). Ca şi parametru în DL se specifică numărul discului. La revenire funcţia furnizaează în AL numărul de unităţi logice existente.

2Fh : obţinerea adresei zonei de transfer cu discul (DTA). Funcţia furnizează în ES:BX adresa DTA.

1Ah : poziţionarea adresei DTA. În DS:DX se comunică adresa noului DTA. Zona de transfer cu discul este folosită la toate accesele la fişiere prin FCB-uri şi este implicată în funcţiile de regăsirea fişierelor.

1Bh : obţinerea informaţiilor despre tabela de alocare a fişierelor FAT, a unităţii curente. Informaţiile obţinute sunt : AL - număr sectoare/cluster, CX - număr octeţi/sector, DX - număr unităţi de alocare.

1Ch : obţinerea informaţiilor despre FAT, a unei unităţi specificate. Se comportă ca şi precedentul dar cere ca parametru de intrare în DL numărul unităţii (0 - implicit, 1 - A, 2 - B etc.).

36h : obţinerea spaţiului liber pe disc. 44h : controlul general de intrare/ieşire (IOCTL). Realizează schimbul de

informaţii dintre aplicaţii şi echipamente ne-standard. Este prevăzută cu mai multe subfuncţii prin care se realizează următoarele :

- 42 -

Page 44: Curs So

Curs de SISTEME DE OPERARE

a) Obţinerea informaţiilor despre un echipament.b) Poziţionarea informaţiilor de comandă pentru un echipament.c) Citire în mod caracter.d) Scriere în mod caracter.e) Citire în mod bloc.f) Scriere în mod bloc.g) ... alte funcţii.

EXEMPLU : Program care afişează numele şi lungimea tuturor fişierelor normale din catalogul

curent. Deasemenea se mai afişează lungimea totală a acestor fişiere. O formă simplificată a comenzii DIR.

/* In zona DTA se respecta urmatoarea conventie :

00h - 14h - rezervati15h - atributele fisierului16h - 17h - ora ultimei modificari18h - 19h - data ultimei modificari1Ah - 1Dh - lungimea fisierului1Eh - 2Bh - numele si extensia fisierului

*/

#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <dos.h>

int gata;char ndta[256];char *dta;

int find_first(char *tipar);int find_next(void);void set_dta(char dta[]);void get_dta(void);

char *tipar = “*.*”;

void main(void){

long total = 0L;long *dim;set_dta(ndta);get_dta();printf(“Adresa DTA este %p\n”, dta);dim = (long*)(ndta + 0x1A);gata = find_first(tipar);while (!gata) {

total += (*dim);gata = find_next();

}

- 43 -

Page 45: Curs So

Curs de SISTEME DE OPERARE

printf(“Lungimea totala fisiere = %ld\n”, total);}

int find_first(char *tipar){

union REGS r;r.h.ah = 0x4E;r.x.dx = (unsigned)tipar; /* Obs. se lucreaza cu modelul SMALL ! */r.x.cx = 0;int86(0x21, &r, &r);printf(“%-20s %ld\n”, (ndta + 0x1E), *(long*)(ndta + 0x1A));return (r.x.ax == 18);

}

int find_next(void){

union REGS r;r.h.ah = 0x4F;int86(0x21, &r, &r);printf(“%-20s %ld\n”, (ndta + 0x1E), *(long*)(ndta + 0x1A));return (r.x.ax == 18);

}

void set_dta(char dta[]){

union REGS r;r.h.ah = 0x1A;r.x.dx = (unsigned)dta;int86(0x21, &r, &r);

}

void get_dta(void){

union REGS r;r.h.ah = 0x2F;int86(0x21, &r, &r);dta = (char*)r.x.bx;

}

4.2.5 Funcţii pentru gestionarea memoriei şi a proceselor.

Funcţiile pentru gestionarea memoriei şi a proceselor se prezintă împreună deoarece o utilizare importantă a funcţiilor de gestionare a memoriei este aceea de a elibera suficientă memorie pentru a putea rula un proces fiu :

48h : alocarea memoriei. Încearcă să aloce dinamic, procesului curent, un număr de paragrafe de memorie specificat în registrul BX, dacă în BX se va introduce 0xFFFF se va aloca toată memoria disponibilă. În caz că alocarea reuşeşte, adresa de segment pentru memoria alocată este returnată în AX, în caz de eroare se va poziţiona indicatorul CARRY.

- 44 -

Page 46: Curs So

Curs de SISTEME DE OPERARE

49h : eliberarea memoriei alocate. Face disponibil un bloc de memorie care a fost alocat anterior cu funcţia 48h. Adresa blocului va fi dată prin ES.

4Ah : modificarea alocării memoriei. Încearcă să modifice dimensiunea unui bloc de memorie alocat anterior cu 48h. Noua dimensiune dorită se încarcă în BX iar adresa de segment a zonei în ES. La lansarea normală în execuţie a unui program, acestuia i se alocă toată memoria disponibilă, deci pentru a putea lansa în execuţie un proces fiu, trebuie mai întâi redusă dimensiunea blocului de memorie a cărui adresă de început este PSP-ul.

58h : citirea/poziţionarea strategiei de alocare a memoriei. Se poate face alocare de tipul First Fit (ceea ce înseamnă prima potrivire), Best Fit (se examinează toată lista şi se alocă blocul cel mai mic care satisface cerinţele), Last Fit (se parcurge lista şi se alocă ultima potrivire). Prin conţinutul registrului AL se alege citirea (00h) sau poziţionarea (01h), iar în BX se va găsi/transmite strategia (00h, 01h, 02h).

4Bh : încărcarea şi executarea unui program. Permite ca programul apelant să încarce în memorie un alt program (AL = 03h) şi eventual să-l lanseze în execuţie (AL = 00h). Numele fişierului executabil care conţine programul ce va fi încărcat se precizează printr-un şir ASCIIZ a cărui adresă se încarcă în DS:DX. Tot ca parametru de intrare în registrele ES:BX se introduce un pointer la un bloc de parametri care se vor transmite noului program. Acest bloc de parametri are o structură diferită după cum se cere lansarea în execuţie sau numai încărcare.

Pentru lansarea în execuţie :

Depl. Lung. Semnificaţie

00h 2 Adresa de segment a ambianţei (pentru 0 se copiază ambianţa părintelui).

02h 4Adresa de segment şi deplasamentul pentru o linie de comandă de maximum 128 octeţi, transmisă programului.

06h 4 Adresa primului FCB.0Ah 4 Adresa celui de-al doilea FCB.

Tabelul 4.2-1

Pentru încărcare :

Depl. Lung. Semnificaţie00h 2 Adresa de segment la care se încarcă programul.02h 2 Factor de relocare al programului.

Tabelul 4.2-2

Obs.: Cea mai simplă metodă de a încărca şi executa un alt program constă în lansarea în execuţie a unei noi copii a procesorului de comenzi command.com căreia i se transmite o linie de comandă având prevăzut comutatorul /c. Funcţia 4Bh cu AL = 03h este folosită pentru încărcarea de segmente ale unui program cu segmente suprapuse şi deasemenea pentru încărcarea unor drivere.

4Ch : terminarea execuţiei unui proces. Un program apelează această funcţie pentru a anunţa către sistem terminarea execuţiei şi predarea

- 45 -

Page 47: Curs So

Curs de SISTEME DE OPERARE

controlului către procesul părinte. În mod uzual procesului părinte i se poate transmite şi un cod de întoarcere de un octet. Înainte de terminare se închid fişierele şi se reâncarcă vectorii de întrerupere pentru nivelele 22h, 23h şi 24h. Deasemenea se realizează şi eliberarea memoriei.

4Dh : obţinerea codului de retur al unui proces fiu. Această funcţie întoarce codul transmis de un proces fiu care s-a terminat fie prin funcţia 4Ch fie prin 31h. Valoarea codului de retur este în AX. În AL este codul returnat de proces, iar în AH este un alt cod, care precizează condiţiile de terminare (AH = 0 - terminare normală, 1 - proces terminat cu CTRL-Break sau CTRL-C, 2 - eroare critică de periferic, 3 - s-a făcut terminarea prin 31h - TSR).

62h : obţinerea adresei PSP. Adresa de segment se întoarce în BX. 31h : realizează revenirea în procesul părinte în aşa fel încât programul care

a apelat funcţia să-şi reţină o anumită zonă de memorie. Dimensiunea memoriei rezidente trebuie introdusă în registrul DX (în paragrafe). Se poate transmite şi un cod de retur prin AL. Fişierele deschise de program nu se închid implicit. Spre deosebire de întreruperea 27h, prin această funcţie se pot reţine zone de memorie de peste 64K.

EXEMPLU : Utilizarea funcţiilor de gestiune a proceselor şi memoriei se ilustrează printr-un

exemplu care constă din două programe. Primul PARENT.C şi al doilea CHILD.C./*Programul PARENT.C va solicita introducerea de la tastatură a numelui unui fişier executabil (forma executabilă a lui CHILD.C) pe care îl lansează în execuţie prin funcţia 4Bh. Programul citeşte şi afişează codul de retur furnizat la terminare de programul lansat în execuţie.*/#include <stdio.h>#include <dos.h>

static char tampon[128], param[14];char *errmsg[] = {

"eroare necunoscuta","numar de functie invalid","fisierul nu a fost gasit","cale invalida","eroare necunoscuta","acces refuzat","eroare necunoscuta","eroare necunoscuta","memorie insuficienta","eroare necunoscuta","ambianta invalida","format invalid"

};

void main(void){

char far*numefis, far*bloc;union REGS r;struct SREGS sr;printf("Dati numele programului fiu : ");

- 46 -

Page 48: Curs So

Curs de SISTEME DE OPERARE

gets(tampon);numefis = tampon;bloc = param;r.h.ah = 0x4B; /* Lansare in executie a unui proces */r.h.al = 0x00; /* Incarcare si lansare in executie */r.x.dx = FP_OFF(numefis);sr.ds = FP_SEG(numefis);r.x.bx = FP_OFF(bloc);sr.es = FP_SEG(bloc);int86x(0x21, &r, &r, &sr);if (!r.x.cflag) {

printf("Terminare normala !\n");r.h.ah = 0x4D;int86(0x21, &r, &r);printf("Codul de intoarcere este : %X\n", r.h.al);

}else printf("Terminare anormala, %s !\n",

(r.x.ax <= 11) ? errmsg[r.x.ax] : errmsg[0]);}

/*Programul CHILD.C va anunţa intrarea sa în execuţie printr-un mesaj, după care alocă mai multă memorie, dacă poate, prin 48h şi se termină prin apelul funcţiei exit (4Ch).*/#include <stdio.h>#include <dos.h>

void main(void){

union REGS r;printf("Hello, I'm the child !\nI need more memory !\n");r.h.ah = 0x48;r.x.bx = 200;int86(0x21, &r, &r);if (r.x.cflag)

printf("Not enough memory, AX = %x, BX = %x\n", r.x.ax, r.x.bx);else

printf("The allocated memory starts at : %x\n", r.x.ax);r.h.ah = 0x4c;r.h.al = 0x5A;printf("Tnto thy hands I deliver my soul.\n");int86(0x21, &r, &r);

}

4.2.6 Alte funcţii sistem.

În următoarele se va menţiona o listă a funcţiilor sistem care nu au intrat în categoriile menţionate până acum :

- 47 -

Page 49: Curs So

Curs de SISTEME DE OPERARE

2Ah : obţinerea datei curente a sistemului. Produce ca rezultat în registre data curentă : an, lună, zi. AL = ziua în săptămână (0 - duminica, 1 - luni, ...), CX = anul curent, DH = luna curentă (1 12), DL = ziua curentă (1 31).

2Bh : poziţionarea datei curente. 2Ch : obţinerea timpului sistem curent. CH = ora curentă (0 23), CL =

minutul curent (0 59), DH = secunda (0 59), DL = sutimea de secundă (0 99).

2Dh : poziţionarea timpului curent. În AH se returnează 00h dacă în registre s-au introdus informaţii valide şi FFh dacă informaţiile sunt invalide.

35h : obţinerea valorii curente ale unui vector de întrerupere. Pentru apelul funcţiei se încarcă în AL numărul nivelului de întrerupere dorit iar rezultatul se obţine în ES:BX. Se recomandă ca asupra vectorilor de întrerupere să se opereze întotdeauna prin funcţii sistem şi nu prin scriere directă în memorie.

25h : poziţionarea valorii unui vector de întrerupere. AL = numărul nivelului de întrerupere dorit, DS:DX = pointer la rutina care va trata întreruperea pe nivelul specificat. Se recomandă ca înainte de utilizarea acestei funcţii să se salveze vechea valoare a vectorului de întrerupere astfel ca la sfârşitul programului curent să se poată reface vectorii de întrerupere aşa cum au fost înaintea lansării acestui program.

5Ch : blocarea şi deblocarea accesului la un fişier. Interzice sau autorizează accesul la o regiune specificată a unui fişier. Se utilizează în special în reţelele de calculatoare. În registrul AL se precizează dacă se doreşte blocarea (00h) sau deblocarea (01h). În registrul BX se introduce identificatorul logic al fişierului. În CX:DX se introduce deplasamentul regiunii afectate, poziţia în fişier unde începe zona blocată sau deblocată, iar în SI:DI lungimea zonei afectate. Această funcţie are efect numai după ce programul SHARE a fost instalat. Se recomandă ca o regiune de fişier să fie ţinută blocată cât mai puţin timp. Un proces fiu nu moşteneşte drepturile de acces ale procesului părinte. Funcţia permite şi cererea blocării la nivel de fişier, în acest caz CX şi DX conţin valoarea 00h, iar SI şi DI conţin FFh.

4.3 Funcţii de bibliotecă C pentru apelul sistemului MS-DOS.

Majoritatea implementărilor pentru sistemul DOS prevăd funcţii de bibliotecă. Se recomandă folosirea acestor funcţii ori de câte ori este nevoie pentru portabilitatea programului. Aceste funcţii ne depind de proprietăţile hardware ale claculatoarelor iar unele dintre acestea nu sunt specifice doar sistemului de operare MS-DOS. Pot apare diferenţe între denumirile acestor funcţii de la o implementare la alta. De multe ori o funcţie există în două variante. Vom întâlni o funcţie _read şi o altă funcţie read. Prima funcţie este specifică MS-DOS (_read) şi în implementarea ei se apelează o funcţie MS-DOS, cealaltă este introdusă pentru compatibilitate cu sistemul UNIX.

4.3.1 Funcţii pentru gestionarea fişierelor.

1. Crearea unui fişier (3Ch)

int _creat(const char *path, int attribute);

- 48 -

Page 50: Curs So

Curs de SISTEME DE OPERARE

Returnează indicatorul fişierului (file handle) pentru succes, -1 pentru eroare. Ca şi atribute pot fi folosite orice combinaţii între următoarele : FA_RDONLY, FA_HIDDEN, FA_SYSTEM, FA_LABEL, FA_DIREC, FA_ARCH. Prototipul fucţiei se găseşte în fişierul antet io.h, iar constantele simbolice pentru atribute se găsesc în dos.h. Prin variabila errno se specifică natura erorii (ENOENT - calea nu este dată bine, ENFILE - prea multe fişiere deschise în program, EACCES - acces interzis la fişier).

2. Deschiderea unui fişier (3Dh)

int _open(const char *filename, int mode);

Specificarea modului de deschidere se poate face cu ajutorul unor constante simbolice, care pentru compatibilitate cu UNIX se găsesc în fcntl.h. Returnează indicatorul fişierului în caz de succes, iar în caz de eroare returnează -1. Se pot specifica trei elemente prin mode şi anume : care este forma de acces (O_RDONLY, O_WRONLY, ORDWR), care este forma de partajare a accesului (O_DENYALL, O_DENYWRITE, O_DENYREAD, O_DENYNONE) sau dacă fişierul este moştenit de procesele fiu (O_NOINHERIT).

3. Închiderea unui fişier (41h)

int unlink(const char *filename);

Returnează 0 pentru succes, respectiv -1 pentru eroare.

4. Închiderea unui fişier (3Eh)

int close(int handle);

Pentru închiderea unui fişier se specifică numai descriptorul fişierului. În caz de incident se returnează -1 iar prin variabila errno se descrie natura erorii (EBADF - descriptor eronat).

5. Citirea dintr-un fişier cu indice specificat (3Fh)

int _read(int filehandle, void *buffer, unsigned readcount);

Se pot citi până la 64K printr-o singură operaţie. La revenire funcţia returnează numărul de octeţi citiţi. Dacă a apărut o eroare se returnează -1.

6. Scrierea într-un fişier cu indice specificat (40h)

int _write(int filehandle, void *buffer, unsigned writecount);

Se returnează numărul de octeţi scrişi care trebuie să corespundă cu valoarea lui writecount. Aceleaşi erori ca şi la citire.

Pentru fiecare dintre aceste 5 funcţii există şi funcţia fără liniuţă, compatibile UNIX, diferenţa apare ca şi comportare la open, care corespunzând UNIX-ului permite o comportare diferită la citire, după cum fişierul este deschis în mod text sau în mod binar. Mai există şi funcţii de bibliotecă echivalente cu apeluri sistem DOS care nu conţin liniuţa :

int creatnew(const char *path, int attribute); (5Bh)

- 49 -

Page 51: Curs So

Curs de SISTEME DE OPERARE

int creattemp(char *path, int attribute); (5Ah)int dup(int handle); (45h)int dup2(int handle1, int handle2); (46h)long lseek(int handle, long offset, int origin); (42h)

Constantele simbolice acceptate ca şi origine sunt : SEEK_SET, SEEK_CUR şi SEEK_END, acestea fiind definite în fişierul stdio.h.

4.3.2 Funcţii pentru gestionarea cataloagelor.

Aceste funcţii au prototipurile în fişierul antet dir.h.

1. Crearea unui catalog (39h)

int mkdir(const char *path);

Returnează 0 pentru succes şi -1 pentru eroare. Ca şi pentru crearea unui fişier, se presupune că toate numele de cale există, altfel în errno se returnează codul de eroare corespunzător.

2. Ştergerea unui catalog (3Ah)

int rmdir(const char *path);

3. Schimbarea catalogului curent (3Bh)

int chdir(const char *path);

Prin această funcţie nu putem trece de pe o unitate de disc pe alta.

4. Obţinerea numelui complet al catalogului curent

char* getcwd(char *path, int maxchars);

Primul parametru path desemnează tamponul unde se va primi numele complet al catalogului, maxchars indică lungimea acestui tampon. Funcţia poate fi apelată şi cu valoarea NULL pentru path, caz în care getcwd alocă din memoria dinamică maxchars octeţi şi valoarea returnată este adresa acestei zone de memorie.

5. Obţinerea numelui catalogului curent de pe o unitate de disc specificată (47h)

int getcurdir(int drive, char *directory);

Unitatea de disc este specificată ca un întreg după convenţia : 0 - discul implicit, 1 discul A, 2 discul B etc. Rezultatul se obţine în şirul de caractere directory, acesta fiind un tampon.

6. Obţinerea sau poziţionarea atributelor unui fişier (43h)

- 50 -

Page 52: Curs So

Curs de SISTEME DE OPERARE

int _chmod(const char *pathname, int func, ...);

Este funcţie specifică DOS. Compilatorul de C acceptă prototipuri de această formă (...). pathname este numele fişierului care urmează să fie afectat, func este funcţia dorită (0 - citire atribute, 1 - poziţionare atribute). Dacă func = 1 atunci vom avea şi al treilea parametru, construit din constante atribut de fişier.

int chmod(char *path, int pmode);

Aceasta este compatibilă UNIX.

7. Găsirea primului fişier care corespunde unui tipar dat (4Eh)

int findfirst(const char *pathname, struct ffblk *fileinfo, int attribute);

Returnează 0 când este succes. În câmpul ff_name se gaseşte numele fişierului care satisface acest tipar. La eroare returnează -1, cu semnificaţia ENOFILE (nu s-a găsit nici un fişier corespunzător tiparului dat).

8. Găsirea unui fişier care corespunde unui tipar dat (4Fh)

int findnext(struct ffblk *fileinfo);

EXEMPLU : Dacă folosim funcţii de bibliotecă putem obţine o formă de dir astfel :

#include <stdio.h>#include <dir.h>

void main(void){

long total = 0L;int gata;struct ffblk fb;char *tipar = "*.*";gata = findfirst(tipar, &fb, 0);while (!gata){

total += fb.ff_size;printf("%-20s %ld\n", fb.ff_name, fb.ff_fsize);gata = findnext(&fb);

}printf("Lungimea totala a fisierelor : %ld\n", total);

}

4.3.3 Funcţii pentru gestionarea perifericelor.

1. Obţinerea unităţii implicite, curente (19h)

- 51 -

Page 53: Curs So

Curs de SISTEME DE OPERARE

int getdisk(void);

Prototipul funcţiei se găseşte în dir.h. Funcţia returnează 0 pentru A, 1 pentru B etc.

2. Selectarea unităţii implicite (0Eh)

int setdisk(int drive);

Prototipul funcţiei se găseşte în dir.h. Unitatea se specifică astfel : 0 - A, 1 - B etc.

3. Obţinerea adresei DTA (2Fh)

char* getdta(void);

Prototipul funcţiei se găseşte în dos.h.

4. Poziţionarea adresei DTA (1Ah)

void setdta(char far* dta);

Prototipul funcţiei se găseşte în dos.h.

5. Obţinerea informaţiilor despre FAT pentru unitatea curentă (1Bh)

void getfatd(struct fatinfo *dtable);

struct fatinfo {char fi_sclus; /* număr de sectoare pe cluster */char fi_fatid; /* octetul de identificare FAT */int fi_nclus; /* număr de clustere al unităţii */int fi_bysec; /* dimensiunea în octeţi a sectorului */

};

Prototipul funcţiei se găseşte în dos.h.

EXEMPLU : Programul afişează informaţii despre FAT.

#include <stdio.h>#include <dir.h>#include <dos.h>

int main(void){

struct fatinfo info;getfatd(&info);printf("Informatii FAT pentru discul implicit (%c:)\n", 'A' + getdisk());printf("Sectoare pe cluster : %5d\n", info.fi_sclus);printf("Identificator FAT : %5X\n", info.fi_fatid);printf("Numar de clustere : %5u\n", info.fi_nclus);printf("Octeti pe sector : %5d\n", info.fi_bysec);return 0;

- 52 -

Page 54: Curs So

Curs de SISTEME DE OPERARE

}

6. Obţinerea informaţiilor despre FAT pentru o unitate specificată (1Ch)

void getfat(unsigned char drive, struct fatinfo *dtable);

Prototipul funcţiei se găseşte în dos.h. Unitatea logică se dă ca şi număr : 0 - unitatea implicită, 1 - A, 2 - B etc.

7. Obţinerea spaţiului liber pe disc (36h)

void getdfree(unsigned char drive, struct dfre *dtable);

struct dfree {unsigned df_avail; /* număr de clustere disponibile */unsigned df_total; /* număr total de clustere */unsigned df_bsec; /* număr de octeţi / sector */unsigned df_sclus; /* număr de sectoare / cluster */

};

Prototipul funcţiei se găseşte în dos.h. Unitatea logică se dă ca şi număr : 0 - unitatea implicită, 1 - A, 2 - B etc. În caz de eroare funcţia poziţionează df_sclus pe 0FFFFh.

EXEMPLU : Programul afişează spaţiul liber pe discul curent.

#include <stdlib.h>#include <stdio.h>#include <dos.h>#include <dir.h>

int main(void){

struct dfree free;long avail;int drive;drive = getdisk();getdfree(drive+1, &free);if (free.df_sclus == 0xFFFF){

printf("Eroare getdfree()\n");exit(1);

}avail = (long)free.df_avail * (long)free.df_sclus * (long)free.df_bsec;printf("Discul %c: contine %ld octeti disponibili.\n", 'A'+drive, avail);

}

8. Controlul general al intrării/ieşirii (44h)

int ioctl(int handle, int func [,void *argdx, int argcx]);

- 53 -

Page 55: Curs So

Curs de SISTEME DE OPERARE

Prototipul funcţiei se găseşte în io.h. Funcţiile sunt specifice pentru o anumită versiune DOS. Portabilitatea este redusă. Această funcţie se foloseşte pentru obţinerea de informaţii despre periferice, starea I/O. La eroare se returnează -1, altfel valoarea returnată este corespunzătoare fiecărei subfuncţii. errno va conţine informaţii despre eroarea respectivă (EINVAL - argument invalid, EBADF - număr de fişier eronat, EINVDAT - date invalide).

EXEMPLU : Programul comută modul de lucru al ecranului din stilul RAM (caracterele de

control afişate fără interpretare) în COOKED (se interpretează caracterele de control, aceasta fiind modul normal de lucru). În modul RAM creşte foarte mult viteza de afişare pe ecran.

#include <stdlib.h>#include <string.h>#include <stdio.h>#include <io.h>

#define RAW_BIT 0x20

int main(int argc, char **argv){

int rawmode, handle = 1 /* stdout */, func, argdx;

if (argc < 2) {printf("Utilizare : RAMCOOK COOKED | RAW\n");exit(1);

}if (!stricmp(argv[1], "RAW"))

rawmode = 1;else

if (!stricmp(argv[1], "COOKED"))rawmode = 0;

else {printf("Mod necunoscut : %s\n", argv[1]);exit(2);

}/* citire informatie */func = 0;ioctl(handle, func, &argdx);if (rawmode)

argdx |= RAW_BIT;else

argdx &= ~RAW_BIT;func = 1;ioctl(handle, func, &argdx);return 0;

}

4.3.4 Funcţii pentru gestionarea memoriei.

- 54 -

Page 56: Curs So

Curs de SISTEME DE OPERARE

1. Funcţia de alocare a unei cantităţi de memorie (48h)

int allocmem(unsigned size, unsigned *segp);

Prototipul funcţiei se găseşte în dos.h. Primeşte dimensiunea în paragrafe a blocului de memorie solicitat (16 octeţi = 1 paragraf). segp este o locaţie de memorie unde se va memora adresa de segment a blocului alocat. Returnează -1 pentru alocare corectă - s-a putut aloca blocul de memorie solicitat. Altfel va returna dimensiunea celui ma mare bloc disponibil.

Deosebirea dintre allocmem şi malloc este că prima cere sistemului de operare o porţiune de memorie, pe când a doua cere alocarea memoriei din heap - spaţiul rezervat programului.

2. Funcţia de eliberarea memoriei alocate (49h)

int freemem(unsigned segadd);

Prototipul funcţiei se găseşte în dos.h. Codul de retur poate fi 0 pentru succes şi -1 pentru eroare. În caz de eroare se poziţionează errno pe ENOMEM, precizând că s-a transmis o adresă de segment eronată.

3. Funcţia de modificare a alocării memoriei (4Ah)

int setblock(unsigned segadd, unsigned newsize);

Prototipul funcţiei se găseşte în dos.h. Încearcă modificarea dimensiunii unui bloc deja alocat. Permite doar mărirea blocului, nu şi micşorarea lui. Întoarce -1 pentru succes, altfel dimensiunea memoriei disponibile.

EXEMPLU : Programul demonstrează folosirea funcţiilor amintite. În program se mai foloseşte

funcţia movedata care copiază o zonă de memorie într-o altă zonă de memorie.

#include <stdlib.h>#include <stdio.h>#include <dos.h>#include <mem.h>

#define DOS_PRTSTR 9

char str[80] = "Test allocmem()...\n\r$";

int main(void){

union REGS r;struct SREGS sr;char far *stradd;unsigned segadd, maxsize;

stradd = (char far*)(&str[0]);if (allocmem(1, &segadd) != -1){

- 55 -

Page 57: Curs So

Curs de SISTEME DE OPERARE

printf("Eroare de alocare !\n");exit(1);

}if ((maxsize = setblock(segadd, 5)) != -1){

printf("Eroare setblock()...\n");printf("Dimensiunea maxima posibila = %d paragrafe.\n", maxsize);exit(2);

}movedata(FP_SEG(stradd), FP_OFF(stradd), segadd, 0, 80);sr.ds = segadd;r.x.dx = 0;r.h.ah = DOS_PRTSTR;intdosx(&r, &r, &sr);freemem(segadd);return 0;

}

4.3.5 Funcţii pentru gestionarea proceselor.

1. Obţinerea adresei PSP (62h)

unsigned getpsp(void);

Prototipul funcţiei se găseşte în dos.h. Este util pentru citirea şirurilor de ambianţă (de exemplu PATH-ul). Valoarea returnată reprezintă adresa de segment al PSP. Trebuie să cunoaştem deplasamentul pentru a afla datele din PSP.

EXEMPLU : Program care afişează spaţiul ocupat de el însuşi.

#include <stdio.h>#include <dos.h>

int main(void){

unsigned mypsp, lastseg;long mem_allocated;mypsp = getpsp();printf("PSP incepe la %04X:0000\n", mypsp);lastseg = *((unsigned far*)(MK_FP(mypsp, 2)));printf("Sfarsitul memoriei alocate este la %04X:0000\n", lastseg);mem_allocated = 16 * (long) (lastseg - mypsp);printf("%ld octeti alocati programului.\n", mem_allocated);return 0;

}

2. Funcţia care determină rămânerea rezidentă a unui program (31h)

- 56 -

Page 58: Curs So

Curs de SISTEME DE OPERARE

void keep(unsigned char status, unsigned memsize);

Prototipul funcţiei se găseşte în dos.h. Primeşte ca parametru un cod de stare care se transmite programului părinte. memsize reprezintă cantitatea de memorie pe care o păstrează procesul care rămâne rezident. Este reprezentată în paragrafe. Este folosită pentru gestionarea vectorilor de întrerupere.

3. Terminarea execuţiei unui proces (4Ch)

void _exit(int status);

Prototipul funcţiei se găseşte în stdlib.h sau process.h. Nu închide fişierele aferente programului, face numai revenirea la procesul părinte şi nu goleşte tampoanele.

Funcţia compatibilă UNIX este :

void exit(int status);

Prototipul funcţiei se găseşte în stdlib.h sau process.h. Închide toate fişierele aferente programului. La ambele funcţii status este codul de întoarcere pentru procesul părinte.

4. Execuţia unei comenzi DOS în interiorul unui program

int system(const char *cmd);

Prototipul funcţiei se găseşte în stdlib.h sau process.h. cmd reprezintă comanda DOS care va fi executată. Se citeşte variabila COMSPEC pentru a localiza COMMAND.COM-ul şi se transmite argumentul cmd. Pentru execuţia acestei comenzi, dacă este nevoie, se inspectează şi variabila PATH. COMMAND.COM se lansează cu o singură comandă după execuţia căreia se revine.

Dacă cmd este şirul vid se face doar verificarea faptului că există COMMAND.COM. Dacă şirul este vid şi nu se găseşte COMMAND.COM atunci se returnează 0, altfel se returnează o valoare diferită de 0. Dacă şirul nu este vid se returnează 0 pentru execuţie normală şi -1 pentru eşec.

EXEMPLU : Programul următor lansează în execuţie o comandă.

#include <stdlib.h>#include <string.h>#include <stdio.h>

int main(void){

char command[128];while (1){

printf("Tastati o comanda (\"quit\" pentru iesire) : ");gets(command);strlwr(command); /* conversie la litere mici */if (strcmp(command, "quit") == 0)

exit(0);

- 57 -

Page 59: Curs So

Curs de SISTEME DE OPERARE

if (system(command) == -1)perror("Eroare system()");

}}

5. Încărcarea şi execuţia unui proce fiu

Prototipul funcţiilor din această categorie se găsesc în process.h.

int spawnl(int mode, char *path, char *arg0, ..., NULL);int spawnle(int mode, char *path, char *arg0, ..., NULL, char *envp[]);int spawnlp(int mode, char *path, char *arg0, ..., NULL);int spawnlpe(int mode, char *path, char *arg0, ..., NULL, char *envp[]);

int spawnv(int mode, char *path, char *argv[]);int spawnve(int mode, char *path, char *argv[], char *envp[]);int spawnvp(int mode, char *path, char *argv[]);int spawnvpe(int mode, char *path, char *argv[], char *envp[]);

mode reprezintă modul de execuţie al lui spawn, modul cum trebuie tratat procesul părinte. Valorile pe care le poate primi acest parametru sunt : P_WAIT - procesul părinte rămâne în aşteptare până la terminarea

procesului fiu. P_OVERLAY - programul procesului fiu se suprapune peste programul

procesului părinte în memorie. P_NOWAIT - procesul părinte îşi continuă execuţia în paralel cu procesul

fiu (această formă nu este implementată în S.O. MS-DOS).path reprezintă numele de cale al fişierului de executat.arg0, arg1, ... reprezintă argumentele din linia de comandă pentru procesul fiu (arg0

trebuie să fie identic cu path).argv[] reprezintă argumentele din linia de comandă pentru procesul fiu.envp[] reprezintă tabloul cu parametri de mediu.

Semnificaţia literelor din numele funcţiilor spawn este următoarea : l - se transmit argumentele ca o listă. v - se transmit argumentele ca un tablou, ca vector de pointeri. p - indică faptul că pentru localizarea fişierului executabil se va consulta şi

variabila de mediu PATH. e - precizează faptul că se transmit variabile de mediu. În absenţa lui e

procesul fiu moşteneşte variabilele de mediu ale părintelui.

Obs: 1. Este obligatoriu ca funcţiile spawn să transmită cel puţin un argument

procesului fiu, adică cel puţin numele fişierului care conţine codul procesului.2. Lungimea combinată a tuturor şirurilor folosite ca argumente în linia

de comandă, dacă este vorba de listă |arg0| + |arg1| + ... + |argn| sau dacă este tablou |arg[0]| + |arg[1]| + ... + |arg[n]| nu poate depăşi 128 octeţi.

3. Fişierele care au fost deschise în procesul părinte rămân deschise şi pentru procesul fiu.

4. Valoarea de revenire din procesul fiu are semnificaţie numai dacă mode este P_WAIT, dacă este P_OVERLAY atunci starea de revenire din procesul fiu va lua locul stării de revenire a procesului părinte.

- 58 -

Page 60: Curs So

Curs de SISTEME DE OPERARE

În caz că nu se poate lansa în execuţie procesul fiu, atunci se returnează -1, iar pentru variabila globală errno pot exista următoarele situaţii :

E2BIG, aceasta însemnând că lungimea totală a argumentelor depăşeşte 128 octeţi, sau că memoria necesară pentru variabilele de mediu ar depăşi 32K.

EINVAL, aceasta înseamnă că pentru mode s-a folosit o valoare invalidă (de exemplu P_NOWAIT).

ENOENT, arată că nu se poate găsi fişierul cu cod executabil. Fie că nu există acel fişier, fie că numele de cale este invalid.

ENOEXEC, arată că fişierul zis de cod nu este de fapt executabil. ENOMEM, arată că nu există memorie suficientă pentru încărcarea şi execuţia

procesului fiu (programul este prea mare).

Aceste funcţii sunt utile dacă vrem să lansăm în execuţie, din cadrul unui program, un alt program, care a fost compilat şi linkeditat separat. Între cele două programe (părinte şi fiu) se pot folosi în comun zone de memorie, rezultând o funcţionare asemănătoare cu a programelor rezidente (TSR).

EXEMPLU: Se ilustrează utilizarea acestor funcţii prin două programe : PARENT.C şi

CHILD.C. Programul PARENT.C lansează în execuţie programul CHILD.C întrebând utilizatorul care din variantele de spawn doreşte să le folosească. Înainte de lansarea în execuţie a fiului se pregăteşte în PARENT.C o structură de date care se va transmite procesului fiu prin codificarea adresei acestei structuri ca şir de caractere ce va figura ca unul dintre argumentele din linia de comandă. În procesul fiu se vor tipări argumentele din linia de comandă şi ambianţa transmisă. Se converteşte apoi adresa transmisă ca şir de caractere şi se face acces la structură. Se modifică în continuare diverse câmpuri ale structurii şi se termină programul fiu. La revenirea în programul părinte se tipăresc din nou valorile din structura de date comună pentru a verifica dacă s-au produs modificările executate în procesul fiu. Cele două programe vor fi în fişiere separate care se compilează şi se linkeditează separat.

/* Fisierul PARENT.C */#include <process.h>#include <string.h>#include <stdio.h>#include <alloc.h>

typedef struct TEST_DATA {char name[20];int n;double x;

} TEST_DATA;

/* Construim o ambianta */char *envp[] = { /* declaram acest tablou de pointeri spre */

/* siruri de caractere in care initializam *//* o singura variabila de mediu */

"PARENT=SPAWN FUNCTIONS",NULL

};

- 59 -

Page 61: Curs So

Curs de SISTEME DE OPERARE

void main(void){

char *nargv[4]; /* tabloul in care se construiesc argumentele */char buff[20]; /* tabloul de lucru pentru dialog cu utilizatorii */char fname[40]; /* si altul pentru conversii */

TEST_DATA *pdata;

if ((pdata = (TEST_DATA*)malloc(sizeof(TEST_DATA))) == NULL)abort();

pdata->n = 100; /* se pregateste structura de date comuna */pdata->x = 1000.99;strcpy(pdata->name, "PARENT");nargv[0] = "child.exe";nargv[1] = fname;sprintf(buff, "%Fp", (void far*)pdata);printf("PARENT : Lansare proces fiu : name = %s, n = %d, x = %f.\n",

pdata->name, pdata->n, pdata->x);nargv[2] = buff;nargv[3] = NULL;printf("Ce functie se apeleaza ?\n");gets(fname);strlwr(fname);if (strcmp(fname, "spawnl") == 0)

spawnl(P_WAIT, "child.exe", "child.exe", fname, buff, NULL);if (strcmp(fname, "spawnle") == 0)

spawnle(P_WAIT, "child.exe", "child.exe", fname, buff, NULL, envp);if (strcmp(fname, "spawnlp") == 0)

spawnlp(P_WAIT, "child.exe", "child.exe", fname, buff, NULL);if (strcmp(fname, "spawnlpe") == 0)

spawnlpe(P_WAIT, "child.exe", "child.exe", fname, buff, NULL, envp);if (strcmp(fname, "spawnv") == 0)

spawnv(P_WAIT, "child.exe", nargv);if (strcmp(fname, "spawnve") == 0)

spawnve(P_WAIT, "child.exe", nargv, envp);if (strcmp(fname, "spawnvp") == 0)

spawnvp(P_WAIT, "child.exe", nargv);if (strcmp(fname, "spawnvpe") == 0)

spawnvpe(P_WAIT, "child.exe", nargv, envp);if (strcmp(pdata->name, "CHILD") == 0)

printf("Revenire din procesul fiu : name = %s, n = %d, x = %f.\n",pdata->name, pdata->n, pdata->x);

elseprintf("A aparut o eroare !\n");

}

/* Fisierul CHILD.C */#include <stdlib.h>#include <string.h>#include <stdio.h>

- 60 -

Page 62: Curs So

Curs de SISTEME DE OPERARE

#include <dos.h>

typedef struct TEST_DATA {char name[20];int n;double x;

} TEST_DATA;

static char far *myname = "CHILD";

void main(int argc, char **argv, char **envp){

char **p_table; /* tablou de pointeri spre siruri de caractere */TEST_DATA far *pdata; /* tabela de parametri */void far *p_s1;void far *p_s2;

printf("CHILD : am primit %d argumente.\n", argc);if (argc < 3) {

printf("Nu sunt destule argumente !\n");exit(1);

}printf("CHILD a fost apelat prin %s.\n", argv[1]);printf("CHILD : ambianta contine :\n");/* se tiparesc sirurile de ambianta */for(p_table = envp; *p_table != NULL; p_table++)

printf("%s\n", *p_table);/* urmeaza conversia inversa, a sirului de caractere */sscanf(argv[2], "%Fp", (void far*)&pdata);printf("In CHILD : name = %Fs, n = %d, x = %f.\n",

pdata->name, pdata->n, pdata->x);p_s1 = (void far*)myname;p_s2 = (void far*)pdata->name;/* folosind p_s1, p_s2 putem copia ceva in structura respectiva */movedata(FP_SEG(p_s1),FP_OFF(p_s1),FP_SEG(p_s2),FP_OFF(p_s2),6);pdata->n = 101;pdata->x = 999.99;/* se termina procesul fiu si se transmite 0 ca si valoare de iesire */exit(0);

}

7. Încărcarea şi lansarea în execuţie a unui proces fiu fără revenire

int execl(char *path, char *arg0, .., NULL);int execle(char *path, char *arg0, .., NULL, char **env);int execlp(char *path, char *arg0, ..);int execlpe(char *path, char *arg0, .., NULL, char **env);

int execv(char *path, char *argv[]);int execve(char *path, char *argv[], char **env);int execvp(char *path, char *argv[]);int execvpe(char *path, char *argv[], char **env);

- 61 -

Page 63: Curs So

Curs de SISTEME DE OPERARE

Prototipurile acestor funcţii se găsesc în fişierul antet process.h. Într-un anumit sens acestea sunt asemănătoare cu familia de funcţii spawn la care mode este pe P_OVERLAY.

În MS-DOS utilizarea funcţiilor exec este recomandabilă în aplicaţii care presupun înlănţuirea unor programe. În caz de eşec de lansare în execuţie şi funcţiile exec returnează -1, iar în variabila globală errno se obţin detalii despre natura erorii. Pot apărea aceleaşi erori ca şi la spawn, mai puţin EINVAL, care era legat de argumentul mode. În plus mai pote apărea ENFILE, dacă sunt prea multe fişiere deschise, respectiv EACCESS, dacă un fişier specificat în PATH este blocat, sau nu este protejabil (la MS-DOS versiunile mai mari decât 3.3).

8. Terminarea anormală a execuţiei unui program

void abort(void);

Prototipul acestei funcţii se găseşte în fişierul antet stdlib.h sau process.h. Această funcţie determină afişarea unui mesaj de eroare : "Abnormal program termination", după care în funcţia respectivă este prevăzut un apel la funcţia exit() şi se dă codul de retur 3.

4.3.6 Alte funcţii sistem.

Prototipurile acestor funcţii sunt în fişierul antet dos.h.

1. Funcţii pentru obţinerea datei curente

void getdate(struct date *datep);

struct date {int da_year; /* anul dat în formă binară (deja convertită +1980) */char da_day; /* ziua 1 31 */char da_month; /* luna 1 12 */

};

2. Poziţionarea datei curente

void setdate(struct date *datep);

3. Obţinerea timpului curent al sistemului

void gettime(struct time *timep);

struct time {unsigned char ti_min;unsigned char ti_hour;unsigned char ti_hund;unsigned char ti_sec;

};

4. Poziţionarea timpului curent al sistemului

- 62 -

Page 64: Curs So

Curs de SISTEME DE OPERARE

void settime(struct time *timep);

5. Obţinerea valorii curente a unui vector de întrerupere

void interrupt (*getvect(int interruptno))();

Funcţia de bibliotecă este getvect. interruptno este numărul de întrerupere. Valoarea returnată de funcţie este o adresă, valoarea curentă a vectorului de întrerupere pe nivelul de întrerupere (dat de interruptno), acea adresă este adresa rutinei de tratare.

Funcţia se foloseşte în mod uzual pentru a putea salva valoarea vectorului de întrerupere înainte de poziţionarea sa.

6. Poziţionarea unui vector de întrerupere

void setvect(int intno, void interrupt (*handler)());

handler este adresa noii funcţii de tratare a întreruperii de nivel intno.

EXEMPLU : În continuare se prezintă un program în care se folosesc funcţiile getvect, setvect şi

de asemenea funcţia keep (folosită pentru a realiza programe rezidente). Programul instalează o rutină de tratare a întreruperii pe nivelul 1Ch, aceasta va incrementa un contor modulo 10 şi va afişa la fiecare întrerupere de timp valoarea contorului respectiv.

#include <dos.h>

#define INTR 0x1C#define SAFETY 64#define ATTR 0x7900

/* _heaplen - este variabila globala care specifica *//* dimensiunea zonei de alocare dinamica */extern unsigned _heaplen = 1024;

/* _stklen - este variabila globala care specifica *//* dimensiunea zonei de stiva */extern unsigned _stklen = 512;

void interrupt (*oldhandler)(...);

void interrupt handler(...){

/* tablou pentru a pastra un rand al ecranului */unsigned int (far *screen)[80];static int count;

/* screen trebuie sa indice in memoria video */(void far*)screen = MK_FP(0xB800, 0);

count++;count %= 10;screen[0][79] = count + '0' + ATTR;

- 63 -

Page 65: Curs So

Curs de SISTEME DE OPERARE

oldhandler();}

int main(void){

oldhandler = getvect(INTR);setvect(INTR, handler);/* se calculeaza dimensiunea pentru programul rezident *//* _psp - este variabila globala in care se gaseste *//* adresa prefixului segmentului de program PSP *//* _SS - corespunde registrului de segment SS *//* _SP - corespunde registrului pointer de stiva SP */keep(0, (_SS + (_SP + SAFETY) / 16 - _psp));return 0;

}

- 64 -

Page 66: Curs So

Curs de SISTEME DE OPERARE

5. Gestionarea memoriei

MS-DOS gestionează memoria pentru a asigura că toate programele au acces la memoria necesară pentru o execuţie normală. Sistemul alocă memorie pentru un program în timpul încărcării, iar acesta poate aloca la rândul lui cantităţi de memorie pe măsură ce are nevoie de ele sau poate elibera orice cantitate de memorie pe care nu o mai foloseşte.

5.1 Memoria convenţională.

Programele alocă memorie convenţională (adresele 0000:0000 ÷ A000:0000) prin folosirea funcţiei sistem de alocare a memoriei (Funcţia 48h). Această funcţie caută după un bloc de memorie cel puţin atât de mare cât blocul cerut şi întoarce adresa de segment al noului bloc. Deoarece la încărcarea unui program MS-DOS poate aloca toată memoria convenţională disponibilă, funcţia de alocare a memoriei poate întoarce o valoare de eroare 0008h (ERROR_NOT_ENOUGH_MEMORY). În acest caz registrul BX va conţine dimensiunea celui mai mare bloc disponibil, în paragrafe.

Dacă un program nu mai are nevoie de memoria pe care a alocat-o, el poate elibera memoria folosind funcţia de eliberare a memoriei alocate (Funcţia 49h). După ce a fost eliberată, memoria devine disponibilă, astfel încât ea poate fi alocată din nou, de acelaşi program sau altul. Un program îşi poate lărgi sau micşora cantitatea de memorie dintr-un bloc la un număr specificat de paragrafe, folosind funcţia modifică dimensiunea unui bloc de memorie (Funcţia 4Ah).

Un program care lansează în execuţie un alt program (numit program fiu) de obicei foloseşte funcţia de modificare a dimensiunii unui bloc de memorie, pentru a-şi reduce propria dimensiune, făcând astfel disponibilă mai multă memorie pentru programul fiu. În astfel de cazuri, programul părinte transmite funcţiei adresa de segment al PSP-ului său, împreună cu noua dimensiune. Programul părinte NU trebuie să elibereze memoria care conţine propriul său cod, date şi stivă, altfel alocări succesive ar putea distruge conţinutul acelei memorii. Pentru a înlătura această situaţie, unele programe îşi copiază codul şi datele pe disc şi eliberează toată memoria, cu excepţia memoriei corespunzătoare unei rutine mici, care va reloca memoria şi va reâncărca de pe disc codul şi datele, când va fi nevoie din nou de acestea.

Strategia curentă de alocare, stabilită prin funcţia de setare a strategiei de alocare (Funcţia 5801h), determină modul cum funcţia de alocare a memoriei va căuta pentru un bloc de memorie. Căutarea poate începe sau de la începutul sau de la sfârşitul memoriei convenţionale şi sfârşeşte la găsirea primului bloc care satisface cerinţele sau, dacă nu există nici un bloc disponoibil, se întoarce blocul cel mai apropiat. Tot strategia de alocare determină dacă funcţia va căuta în memoria convenţională sau în zona superioară a memoriei (UMB). Un program poate determina strategia curentă de alocare prin folosirea funcţiei de citire a strategiei de alocare (Funcţia 5800h).

Obs.: Dacă un program schimbă strategia de alocare, el ar trebui să salveze strategia originală şi să o restaureze înainte de terminare.

5.2 Blocurile din Memoria Superioară (UMB).

- 65 -

Page 67: Curs So

Curs de SISTEME DE OPERARE

Un bloc din memoria superioară (UMB) este o zonă RAM din memoria superioară care este disponibilă programelor. Zona de memorie superioară (adresele A000:0000 ÷ FFFF:0000) este rezervată în principal pentru memorii ROM şi dispozitive mapate în memorie, dar MS-DOS poate mapa RAM la orice adresă din această zonă, care nu este utilizată de ROM sau alte dispozitive.

Un program poate aloca un bloc de memorie superioară utilizând funcţia de alocare a memoriei. Înainte de a aloca memorie, trebuie ca programul să seteze o strategie de alocare potrivită şi să facă legătura cu zona de memorie superioară. Ca şi la memoria convenţională, un program foloseşte pentru funcţia de stabilire a strategiei de alocare funcţia 5801h. O strategie de alocare ca de exemplu FIRST_FIT_HIGH (0080h) determină ca funcţia de alocare să caute memoria superioară şi să continue cu căutarea în memoria convenţională, dacă nu a găsit bloc disponibil.

Funcţia de alocare nu poate căuta în memoria superioară doar dacă aceasta este legată de restul memoriei sistem. Un program poate stabili legarea memoriei superioare prin folosirea funcţiei de stabilire a legăturii cu memoria superioară (5803h), sau poate determina dacă această legătură există folosind citirea stării legăturii cu memoria superioară (Funcţia 5802h).

Obs. Dacă un program schimbă legătura cu memoria superioară el ar trebui să salveze starea anterioară şi să o refacă înainte de terminare.

Un program poate utiliza funcţia de eliberare a memoriei şi pentru eliberarea blocurilor din memoria superioară. Deasemenea poate utiliza şi funcţia de redimensionare a blocurilor pentru a reduce sau mări dimensiunea blocului alocat.

Dacă un program a fost lansat folosind comanda LOADHIGH, sistemul încarcă acel program în memorie alocată din zona de memorie superioară. Deşi un program poate fi în memoria superioară, memoria pe care o alocă depinde de strategia de alocare.

Blocurile de memorie superioară nu sunt accesibile prin funcţii MS-DOS doar dacă comanda dos = umb este inclusă în fişierul CONFIG.SYS şi driverul HIMEM.SYS şi software-ul de gestionare a memoriei, de ex. EMM386.EXE sunt încărcate. Dacă dos = umb nu este specificat în CONFIG.SYS, dar software-ul de gestionarea memoriei este încărcat, programele pot accesa zona de memorie suprioară folosind apeluri directe la software-ul de gestionare a memoriei.

5.3 Structuri de date folosite de MS-DOS în gestionarea memoriei.

MS-DOS-ul ţine evidenţa blocurilor de memorie prin crearea unei liste înlănţuite de structuri ARENA, care definesc dimensiunea şi proprietarul blocurilor de memorie.

Structura ARENA are următoarea componenţă:

ARENA STRUCarenaSignature db ? ;4dh=valid, 5ah=ultimarenaOwner dw ? ;proprietarul acestui blocarenaSize dw ? ;dimensiunea blocului în paragrafearenaReserveddb 3 dup(?) ;rezervatarenaName db 8 dup(?) ;numele de fişier al proprietarului

ARENA ENDS

La încărcare MS-DOS-ul crează astfel de structuri pentru memoria disponibilă. El crează alte astfel de structuri pe măsură ce este nevoie de ele, când încarcă programe şi

- 66 -

Page 68: Curs So

Curs de SISTEME DE OPERARE

drivere sau când programele alocă memorie. Numărul, dimensiunea şi poziţia structurilor ARENA depind de dimensiunea blocurilor de memorie alocate.

Programele trebuie să aibă grijă să nu altereze structurile ARENA. MS-DOS-ul nu poate reface structurile pe care programele le-au suprascris sau le-au modificat. Dacă o structură ARENA a fost alterată, funcţiile ca alocare de memorie şi eliberare de memorie eşuează, dând ca şi cod de eroare valoarea 0007h (ERROR_ARENA_TRASHED).

Câmpurile structură ARENA :

arenaSignature - specifică dacă structura este validă. Acest câmp trebuie să conţină 4Dh sau 5Ah. Valoarea 5Ah indică faptul că structura este ultima din listă.

arenaOwner - specifică proprietarul blocului. Acest câmp conţine adresa de segment al PSP-ului programului proprietar. Conţine zero dacă blocul este liber.

arenaSize - specifică dimensiunea blocului, în paragrafe. Blocul începe imediat după structura ARENA.

arenaReserved - rezervatarenaName - conţine un şir terminat cu 0, specificând numele fişierului

programului care deţine blocul. Nume ca SC şi SD sunt utilizate de MS-DOS pentru a reprezenta cod sistem (programe) respectiv date sistem.

Tabelul 5.3-1

Comentarii :Fiecare structră ARENA este urmată imediat de un bloc continuu de memorie.

Următoarea structură ARENA din listă este în continuarea respectivului bloc. Aceasta înseamnă că adresa segment a următoarei structuri din listă este egală cu adresa de segment a blocului de memorie curent plus dimensiunea sa.

MS-DOS-ul completează câmpul arenaName pentru un bloc când încarcă un program în acest bloc. Structurile ARENA pentru memoria alocată de programe prin funcţia de alocare nu sunt completate în acelaşi fel.

5.4 Procesarea liniei A20. Memoria înaltă.

Pentru calculatoarele bazate pe procesoare 80286, 80386 şi mai recente, cea de-a 21 linie de adresă a procesorului (A20) controlează accesul la un spaţiu suplimentar de 64K, numit zonă de memorie înaltă (HMA). Producătorii de calculatoare de obicei includ un circuit pentru a dezactiva linia A20 când procesorul rulează în mod real. Acesta asigură ca mediul de operare să fie identic cu acela al unui 8086, în care adresele ca şi FFFF:0010 se suprapun peste începutul memoriei. Când linia A20 este activă, adresele care s-ar repeta (adresele în intervalul FFFF:0010 ÷ FFFF:FFFF) asigură accesul la HMA.

Dacă un calculator oferă suport RAM pentru HMA, atunci MS-DOS poate activa linia A20 şi să realoce codul sistem în HMA, astfel eliberând memoria convenţională pentru alte programe. MS-DOS-ul se relocatează în HMA doar dacă comanda dos=high este în CONFIG.SYS iar HIMEM.SYS este încărcat. Acest driver conţine codul care permite activarea şi dezactivarea liniei A20.

Pentru a suporta programele care se aşteaptă ca adresele să se repete, MS-DOS-ul dezactivează linia A20 întotdeauna când încarcă şi execută un program. În timp ce linia A20

- 67 -

Page 69: Curs So

Curs de SISTEME DE OPERARE

este dezactivată, partea MS-DOS din HMA nu este accesibilă direct, deşi programele pot totuşi să apeleze funcţii sistem MS-DOS. Pentru a realiza acest lucru, MS-DOS-ul redirectează toate apelurile sistem la un “stub” din memoria convenţională, care activează linia A20 şi face salt la funcţia MS-DOS solicitată. Odată activată, linia A20 rămîne activată chiar după ce se revine din apelul funcţiei sistem.

Programele nu trebuie să folosească HMA dacă MS-DOS-ul a fost realocat aici. Un program poate determina dacă MS-DOS-ul este sau nu în HMA folosind funcţia care întoarce versiunea MS-DOS-ului. Această funcţie setează bitul 4 din registrul DH dacă MS-DOS-ul este în HMA.

- 68 -

Page 70: Curs So

Curs de SISTEME DE OPERARE

6. Sistemul de Operare UNIX. Probleme generale.

6.1 Introducere.

Sistemul UNIX, de la începuturile sale şi până astăzi, a devenit destul de popular, rulând pe maşini cu puteri de procesare variate, de la microprocesoare şi până la mainframe-uri, oferind astfel o ambianţă comună de execuţie pe toate acestea. Sistemul este împărţit în două mari părţi. Prima parte constă din programe şi servicii care au făcut din sistemul UNIX un sistem aşa de popular, aceasta fiind partea cu care iau contactul, de obicei, utilizatorii, incluzând programe ca shell-ul, mail-ul, pachete pentru procesare de text, sisteme de control al codului sursă etc. Cea de-a doua parte constă din sistemul de operare care suportă aceste programe şi servicii.

Între anii 1965-1969 laboratoarele Bell ale firmei Western Electric (filială a lui AT&T) împreună cu General Electric şi MIT au participat la dezvoltarea sistemului de operare MULTICS. Pe măsură ce lucrările progresau a devenit evident că deşi era foarte probabil că MULTICS va putea satisface o mare varietate de servicii, el devenea peste măsură de voluminos şi de scump. Din acest motiv, laboratoarele Bell se retrag din acest proiect, dar unii membri ai echipei, conduşi de Ken Thompson continuă să lucreze la un proiect mai puţin ambiţios. Au apărut astfel elementele definitorii pentru un nou sistem de operare, UNIX, a cărui primă versiune experimentală a fost scrisă în 1969 în limbaj de asamblare.

În anul 1972 a fost realizat primul compilator pentru limbajul C, iar sistemul UNIX a fost rescris în acest limbaj. Acest sistem s-a impus în anii '80 ca principala soluţie de standardiyare în domeniul sistemelor de operare, reprezentând de asemenea o modalitate de realizare a sistemelor deschise.

În figura Fig. 6.1-1 se poate urmări evoluţia sistemului de operare UNIX.

6.1.1 Cauzele răspândirii sistemului de operare UNIX.

S.O. UNIX cunoaşte o largă răspândire datorită mai multor motive : este agreat de utilizatori, posedând o gamă bogată de instrumente software ce se pot

utiliza cu uşurinţă, putându-se combina pentru a se obţine noi posibilităţi. Deoarece dispune de sute de programe utilitare diferite facilităţile oferite de UNIX acoperă o gamă largă de aplicaţii : baze de date, reţele, grafică, inteligenţă artificială, simulare, probleme de gestiune, statistică, instruire asistată de calculator;

sistemul UNIX este conceput ca sistem multiuser şi multitasking. Apare deci posibilitatea exploatării eficiente a capacităţii de prelucrare, pusă la dispoziţie de calculatoarele actuale;

S.O. UNIX este portabil, fiind scris în limbajul C, sistemul funcţionând aproape identic pe mainframe-uri, mini sau microcalculatoare. Se poate realiza astfel dezvoltarea de pachete de programe funcţionale pe o gamă largă de maşini, preţul produsului fiind mai scăzut şi programatorilor fiindu-le transparent hardware-ul de care dispun.

UNIX este foarte mult folosit în universităţi.

- 69 -

Page 71: Curs So

Curs de SISTEME DE OPERARE

UNIX - 1969

Versiunea 3 -1973

Versiunea 6 -1975

Versiunea 7 -1978

1982System III

1984System V Rel. 3.0

1988System V Rel. 4.0

1993System V Rel. 5.0

1981XENIX

1985XENIX V

1978PWB UNIX1981

BSD 4.1

1983BSD 4.2

1985BSD 4.3

1986SunOS 4.0

1986S.O. Mach

1988NeXT

multiprocessor

1989AIX IBM

1992AIX 3.2

1992SOLARIS

1992UnixWare

USL+Novell

1990SCO ODT Rel. 1.1

1992SCO ODT Rel. 2.0

Fig. 6.1-1

6.1.2 Considerente de realizare a S.O. UNIX.

Implementarea S.O. UNIX are la bază următoarele considerente : necesitatea standardizării şi unificării mediilor de operare şi în general a interfeţei cu

utilizatorul;

- 70 -

Page 72: Curs So

Curs de SISTEME DE OPERARE

transportabilitatea fişierelor între diverse sisteme de calcul, menţinând identică structura volumelor şi fişierelor;

asigurarea unor niveluri superioare de portabilitate a produselor program; folosirea unei game largi de arhitecturi de calcul, prin interconectarea calculatoarelor

de tipuri şi puteri diferite, funcţionând sub acelaşi sistem de operare; transparenţa produselor software faţă de evoluţia hardware-ului.

6.1.3 Caracteristici generale al sistemelor UNIX.

Printre caracteristicile generale ale S.O. UNIX care au contribuit la succesul acestui sistem de operare, putem menţiona :

UNIX este un sistem de operare de tip time-sharing, multitasking şi multiutilizator; Este asigurată protecţia fişierelor şi a modului de execuţie prin existenţa unor parole şi

drepturi de acces; S.O. promovează modularitatea; Operaţiile de intrare/ieşire sunt integrate în sistemul de fişiere, realizându-se aşa

numitele intrări/ieşiri generalizate; Există un sistem de gestiune a proceselor reentrante şi asincrone multiple, care se pot

sincroniza prin intermediul unui sistem de întreruperi logice; Gestiunea memoriei se face printr-un mecanism ce permite schimbul de pagini între

memoria RAM şi cea externă, gestionându-se spaţiul afectat execuţiei proceselor şi controlându-se timpul de acces la procesele în aşteptare;

S-a realizat o interfaţă simplă prin intermediul componentei SHELL, care nu este integrată în nucleul (KERNEL) sistemului de operare, asigurându-se totodată o identitate a sintaxei tuturor comenzilor;

Prin scrierea S.O. în limbajul C, s-a obţinut o portabilitate atât a sistemului UNIX propriu-zis, cât şi a software-ului de aplicaţie dezvoltat sub acest sistem, realizându-se astfel şi premisele dezideratului de sistem deschis. Sub aceste S.O. se pot astfel dezvolta pachete de programe funcţionale pe o gamă largă de maşini.

6.2 Principii de utilizare ale sistemului UNIX.

Fiind un sistem de operare multitasking şi multiutilizator, UNIX necesită efectuarea unei serii de operaţii relativ complexe atât la lansare cât şi înainte de scoaterea calculatorului de sub tensiune.

Lansarea sistemului UNIX are de obicei loc în patru etape, ale căror efecte se pot suprapune în timp :

La punerea calculatorului sub tensiune controlul este preluat de un program înscris în memoria permanentă. Acest program examinează configuraţia sistemului de calcul şi efectuează o serie de teste de bună funcţionare, după care se examinează perifericele în căutarea unui candidat pentru lansarea sistemului, se verifică existenţa unui sistem de fişiere UNIX pe discul ales după care se citeşte şi se încarcă în memorie nucleul sistemului de operare, aflat într-un fişier obişnuit, direct executabil (/vmlinuz pentru S.O. Linux).

Nucleul S.O. primeşte controlul şi determină montarea sistemului de fişiere de pe discul de pornire. Rădăcina acestui sistem de fişiere devine rădăcina întregii ierarhii de cataloage accesibile unui utilizator. În acest moment există un singur proces, care ulterior va deveni procesul fictiv 0 (însărcinat de obicei cu gestiunea memoriei

- 71 -

Page 73: Curs So

Curs de SISTEME DE OPERARE

virtuale). Nucleul creează procesul init (prin încărcarea programului /etc/init), acesta este singurul proces care nu este creat prin mecanismul uzual de duplicare (fork()). Controlul este preluat de init, care continuă activităţile legate de lansarea sistemului. La sfârşitul acestei etape iniţializarea nucleului a luat sfârşit, sistemul funcţionând normal, unicul proces utilizator prezent fiind init, care rulează cu privilegiile superutilizatorului.

init lansează un interpretor de comenzi (/bin/sh de exemplu), căruia îi revine sarcina citirii şi executării fişierului de comenzi indirecte de configurare /etc/rc, care conţine comenzi care asigură:

1. verificarea (cu ajutorul comenzii fsck) a corectitudinii sistemului de fişiere rădăcină, şi eventual corectarea automată a eventualelor erori minore. Dacă fsck eşuează, atunci un interpretor de comenzi este lansat cu intenţia ca operatorul să refacă manual consistenţa sistemului de fişiere. În acest timp sistemul lucrează şi operatorul primeşte privilegiile superutilizatorului;

2. montarea (cu ajutorul comenzii mount) a celorlalte discuri din configuraţie;

3. iniţializarea altor echipamente periferice (interfeţe de reţea de exemplu);

4. lansarea în fundal a unui număr de procese (demoni). De exemplu, sistemele din familia BSD lansează demonul inetd, destinat lansării automate a proceselor înregistrate ca servicii la distanţă (ftp, rlogin etc.).

init creează (prin duplicare) câte un proces getty pentru fiecare terminal. Fiecare getty aşteaptă introducerea unui nume de utilizator la terminalul respectiv, afişând un prompt (de exemplu login:); această condiţie fiind satisfăcută, getty se transformă în login, pentru a accepta utilizatorul în sistem.

Uneori ultimele două etape se desfăşoară în paralel; procesele lansate de init în ultima etapă pot fi sau înscrise în codul binar al lui init, sau listate într-un fişier destinat acestui scop, în general /etc/inittab. Toate aceste activităţi fiind îndeplinite, init (procesul 1) trece în aşteptare. Din această stare el va ieşi temporar la semnalarea morţii unui interpretor de comenzi principal.

Procesul login asociat terminalului în cauză, afişează un al doilea prompt (de exemplu password:) şi aşteaptă introducerea unei parole. Parola citită este cifrată, apoi login caută perechea (nume_utilizator, parolă_cifrată) în fişierul /etc/passwd. Dacă este găsită perechea respectivă, atunci din acelaşi /etc/passwd se citesc :

numărul de utilizator (uid-ul) utilizatorului şi numărul grupului (gid-ul) din care face parte. login, care până acum rulase cu privilegiile superutilizatorului, îşi schimbă apartenenţa, de acum înainte rulând sub uid-ul şi gid-ul utilizatorului în curs de acceptare.

catalogul de referinţă al utilizatorului. login schimbă catalogul curent în catalogul de referinţă al utilizatorului. Dacă schimbarea nu reuşeşte, catalogul curent este stabilit în catalogul rădăcină.

numele interpretorului de comenzi (de exemplu /bin/sh sau /bin/bash).

login introduce în mediu o serie de valori (de exemplu HOME=catalogul de referinţă, SHELL=numele absolut al interpretorului) şi se autoânlocuieşte (prin exec()) cu interpretorul de comenzi al cărui nume a fost citit. La începerea execuţiei, interpretorul de comenzi primeşte un prim argument (argumentul zero) începând cu un minus (de exemplu -sh în loc de sh), pentru a afla astfel că este un interpretor de comenzi principal. Interpretorul de comenzi efectuează o serie de iniţializări, apoi afişează un prompt (de exemplu $).

- 72 -

Page 74: Curs So

Curs de SISTEME DE OPERARE

Introducerea unui caracter sfârşit de fişier (<CONTROL> D) sau a comenzii exit sau logout determină terminarea execuţiei interpretorului de comenzi. Acest lucru poate avea loc şi ca urmare a recepţionării de către interpretorul de comenzi a unui semnal imperativ de oprire, emis fie ca urmare a începerii operaţiilor de oprire a sistemului (comanda shutdown), fie din iniţiativa superutilizatorului (prin comanda kill -KILL). Moartea interpretorului de comenzi determină înregistrarea într-un fişier datele referitoare la sesiunea proaspăt încheiată, trimite un semnal de rupere a legăturii către toate procesele legate de terminalul respectiv, apoi lansează (prin duplicare) un nou getty pentru acel terminal, astfel o nouă sesiune de lucru poate începe.

La oprirea S.O. trebuie terminate toate procesele active, înregistrate pe disc toate informaţiile prezente în zonele tampon de scriere, demontate toate sistemele de fişiere şi terminate toate comunicaţiile în reţea. Aceste activităţi sunt executate automat de comanda shutdown, accesibilă numai superutilizatorului. Scoaterea calculatorului de sub tensiune fără a da înainte comanda shutdown (sau fără a aştepta mesajul prin care sistemul anunţă că poate fi scos de sub tensiune) produce întotdeauna o serie de erori în sistemul de fişiere. De multe ori aceste inconsistenţe sau pot fi corectate automat, sau pot fi rezolvate manual (cu eventuale pierderi de date), nu de puţine ori însă, sistemul de fişiere este grav compromis.

6.3 Principalele comenzi UNIX.

În general există patru categorii de comenzi : comenzi de informare comenzi de lucru cu fişiere comenzi de lucru cu procese comenzi speciale

1. Listarea conţinutului unui catalog :

ls [-optiuni] [catalog sau fisier]

Forma cea mai simplă : $ ls <CR>, $ fiind proptul pentru utilizatori, furnizează o listă a numelor fişierelor şi cataloagelor din catalogul curent, mai puţin acele cataloage şi fişiere ale căror nume începe cu caracterul '.', considerate invizibile (. şi .. în primul rând).

Opţiuni :

-l - obţinem informaţii mai detaliate despre fiecare intrare în catalog (long)

Ex: pentru catalogul rădăcină :

Atribute Nr. legături

Proprie-tar

Dimensi-une

Data actualiz.

Ora actualiz.

Nume

drwxr-xr-x 2 root 1024 Apr 13 20:12 bindrwxr-xr-x 2 root 1024 Feb 19 16:56 dev

... ... ... ... ... ... ...-rwxr--r-- 1 root 402876 Aug 27 18:09 vmlinuz

Tabelul 6.3-1

Obs.: Pentru cataloage numărul de legături este minimum 2 (au şi legătură spre părinte)

- 73 -

Page 75: Curs So

Curs de SISTEME DE OPERARE

-a - determină afişarea şi a fişierelor ascunse, este folosită de obicei în conjuncţie cu opţiunea l : $ ls -la sau $ ls -al

-i - face ca în faţa informaţiei de tip şi protecţie să mai apară o coloană cu numărul nodurilor index ale fiecărui fişier.

-s - pentru a afişa lungimea fişierelor în Ko.-R - listare recursivă.

2. Copiere de fişiere.

cp fissrs ... fisdst

Efectul acestei comenzi este copierea fişierului sursă (unul) în fişierul destinaţie ($ cp fis1 fis2) sau copierea mai multor fişiere sursă într-un catalog ($ cp fis1 fis2 fis3 dir)

În unele implementări se admite opţiunea -R pentru o copiere recursivă de cataloage.

3. Afişarea conţinutului unui fişier.

cat [-optiuni] fis ...

În mod normal această comandă afişează pe ecran conţinutul fişierelor.Obs.: Pentru concatenarea fişierelor se poate folosi utilizând redirectarea ieşirii

standard : $ cat fis1 fis2 fis3 > fisconcatenat. În acest caz fişierele fis1, fis2 şi fis3 rămân fişiere distincte.

4. Transferarea unui fişier dintr-un bloc în altul (echivalent rename din MS-DOS).

mv [-optiuni] fis1 ... dst

Obs.: La cp se alocă noi noduri index şi noi blocuri. La mv se schimbă doar intrarea de catalog.

5. Ştergerea unui fişier.

rm [-optiuni] fis

Între opţiuni există şi opţiunea de ştergere recursivă -R. Comanda $ rm * este o comandă periculoasă deoarece determină ştergerea tuturor fişierelor şi cataloagelor din catalogul curent !

Obs.: Nu avem nevoie de *.* deoarece numele se tratează ca un tot unitar, fără extensie. Cataloagele se şterg doar dacă ele sunt goale.

Ex: $ rm .* şterge toate fişierele care încep cu '.'.

6. Ştergerea cataloagelor.

rmdir catalog

Catalogul este şters doar dacă este gol.

Obs.: Există opţiuni care determină confirmarea acţiunii de către utilizator.

7. Schimbarea modului de protecţie al fişierului.

- 74 -

Page 76: Curs So

Curs de SISTEME DE OPERARE

chmod protectie fis

Protecţia se specifică fie ca număr fie ca un şir de caractere.Drepturile de protecţie se referă la trei categorii de utilizatori :

proprietar grupul proprietar alţii

Drepturile posibile sunt (câte 3 biţi pe fiecare categorie) : citire : r scriere : w execuţie : x

Ex:$ chmod 644 fis.txt- proprietarul fişierului va avea drepturile rw- drepturile sunt specificate prin cifre octale, corespunzătoare celor 3 biţi care codifică

drepturile pe categorii.

$ chmod o+r fisier- dăm altora (others) dreptul de citire (u - user, adică proprietar; g - group, adică

grupul proprietar)- specificarea prin şir de caractere se poate face folosind + (adaugă dreptul), - (şterge

dreptul) sau = (specificare directă de valoare).

8. Schimbarea proprietarului unui fişier.

chown proprietar fisier

Dreptul de a executa această comandă îl are proprietarul curent al fişierului (care va pierde astfel dreptul de proprietate) şi superutilizatorul.

9. Schimbarea catalogului curent.

cd catalog

10. Aflarea catalogului curent (Print Working Directory).

pwd

11. Crearea unui nou catalog.

mkdir catalog

12. Afişarea numelui utilizatorului curent.

whoami

- 75 -

Page 77: Curs So

Curs de SISTEME DE OPERARE

13. Listarea tuturor utilizatorilor care au momentan sesiuni deschise.

who

14. Obţinerea datei şi orei curente.

date

15. Afişarea spaţiului liber pe fiecare dintre discurile montate sau specifiacte.

df [fisier_special]

Ex: $ df /dev/fd0 - obţinem spaţiul liber pe discheta din prima unitate.

16. Montarea sistemului de fişiere.

mount [fisier_special catalog]

Ex: $ mount /dev/hda1 / - de obicei această comandă o face implicit sistemul.$ mount /dev/hda3 /mnt - dicul /dev/hda3 va fi accesibil pe catalogul /mnt.

Obs.: mount fără nici un argument afişează lista sistemelor de fişiere montate precum şi locul în care acestea au fost montate.

17. Demontarea sistemului de fişiere.

umount nume

nume poate fi numele fişierului special care conţine un subsistem de fişiere sau catalogul unde a fost montat acel subsistem de fişiere.

18. Afişarea mărită a unui text pe ecran.

banner text

19. Afişarea calendarului.

cal [an] [luna]

20. Manualul de utilizare on line.

man comanda

Ex: $ man df

21. Afişarea pagină cu pagină a unui text.

more

- 76 -

Page 78: Curs So

Curs de SISTEME DE OPERARE

22. Un alt paginator mai puternic.

less

23. Poşta electronică.

mail nume

Ex:$ mail xxxxSubject : HelloTextul mesajului.$Obs.: Mesajul se termină cu caracterul '.' singur pe o linie, la începutul liniei.

24. Intrarea în sesiune.

login nume

Obs.: Dacă utilizatorul nume are parolă se va cere şi parola (Password :).

25. Ieşirea din sesiune.

logout

26. Schimbarea parolei unui utilizator.

passwd

6.4 Elemente ale limbajului de comandă UNIX (Shell).

Ori de câte ori se dă o comandă din linia de comandă, aceasta este preluată de un program numit shell, care examinează linia şi decide care program trebuie rulat pentru a executa comanda şi ce argumente îi vor fi transmise.

Procesorul de comenzi standard este sh (Bourne Shell). Alte procesoare de comenzi : csh (C Shell), ksh (Khorn Shell), bash (Bourne Again Shell) etc.

Procesorul implicit pentru un utilizator este specificat în descrierea sistem a utilizatorului, adică în fişierul /etc/passwd având următoarea structură :

Utilizator

Parola codificată

Nr. Utilizator Nr.Grup

Nume Complet

Directorul HOME

Procesor comenzi

john yH1!2tW3 324 55 John Barry /home/stud/john /bin/sh

Tabelul 6.4-1

Obs.: Câmpurile sunt separate prin ":".

Întotdeauna când shell-ul este gata pentru a primi o comandă, el afişează un prompt care este de obicei de forma : "$ " sau "% ", dar poate fi orice expresie.

- 77 -

Page 79: Curs So

Curs de SISTEME DE OPERARE

În general toate comenzile au ca efect execuţia unor programe. Programele pot fi programe standard sau pot alte programe. Numele programului care va fi rulat este dat de primul cuvânt din linia de comandă.

Numele programului poate fi specificat cu tot cu cale (/bin/cat) sau doar simplu numele, în acest caz shell-ul va căuta programul într-o serie de directoare, serie numită PATH. Pe cele mai multe sisteme PATH-ul va consta din cel puţin trei directoare : directorul curent("."), şi cele două directoare sistem /bin şi /usr/bin.

Înainte de a rula un program, shell-ul procesează linia de comandă pentru a determina ce argumente să transmită programului. În cel mai simplu caz argumentele vor fi formate din secvenţa de caractere diferite de spaţiu din linia de comandă.

Ex: $ ls -l myfile hisfileÎn exemplul precedent argumentele vor fi cele trei şiruri : -l, myfile şi hisfile.Există o serie de caractere care au o semnificaţie specială pentru shell, ele numindu-se

metacaractere şi în principiu ar fi următoarele : < > | ^ & ; ? * [ ] ( ) $ ` " ' \Dacă dorim ca vreunul din aceste caractere să fie interpretat ca şi un caracter obişnuit

într-un anumit context, el va trebui precedat de caracterul \Ex:$ echo ? - vor fi listate numele fişierelor care au numele format dintr-un singur

caracter.$ echo \? - va fi afişat ?

Acesta este mecanismul de quoting (citare).

Dacă dorim să transmitem ca parametru un şir de caractere în care să apară şi spaţiul atunci putem să includem şirul de caractere între apostroafe sau ghilimele.

Caracterele "*", "?" şi "[...]" sunt caractere care se folosesc pentru construcţia unor tipare. Când unul din aceste caractere este întâlnit în linia de comandă, este înlocuit cu o listă de nume de fişiere care se potrivesc cu tiparul din care face parte, urmând următoarele reguli :

* este înlocuit de zero sau mai multe caractere.? este înlocuit cu un singur caracter.[sir] se potriveşte cu orice caracter care este prezent în sir. Se permit şi specificarea

unor intervale : [a-z].

Excepţie de la aceste reguli sunt caracterele "/" şi ".", care nu pot fi substituite prin aceste caractere.

Şi în UNIX este posibilă redirectarea dispozitivelor standard (intrarea standard, ieşirea standard şi ieşirea de eroare standard). Pentru redirectare se folosesc caracterele "<" şi ">".

Ex:$ ls -l >listing - provoacă crearea unui fişier având ca şi conţinut ieşirea produsă de

comanda ls -l.$ cat <myfile - determină comanda cat să citească din fişierul myfile şi să afişeze

liniile citite.

În plus faţă de aceste redirectări simple există şi alte tipuri de redirectare, dintre care cele mai folosite sunt :

>> fisier - adaugă ieşirea standard la sfârşitul fişierului specificat (dacă fişierul nu există acesta va creat).

- 78 -

Page 80: Curs So

Curs de SISTEME DE OPERARE

<<terminator - foloseşte următoarele linii ca şi intrare standard, până când se întâlneşte linia care se potriveşte cu tterminator-ul dat. Aceasta este folosită în fişiere de comenzi (shell scripts).

2>fisier - redirectează ieşirea de eroare standard în fişierul specificat. Aceasta este defapt un caz special al cazului general de redirectare a unui identificator de fişier (stderr == 2).

O altă formă de redirectare este folosirea canalelor (pipelines). Într-un canal două sau mai multe programe sunt executate împreună, ieşirea unuia fiind intrarea următorului. În multe implementări ale UNIX-ului, programele dintr-un canal sunt executate concurent (în paralel). Principalul avantaj pentru utilizator este că acesta permite o notaţie concisă a unei operaţii care pe alte sisteme ar necesita fişiere temporare.

Ex:$ ls -l > fistemp1$ grep *.c < fistemp1 > fistemp2$ wc -l < fistemp2

Secvenţa de mai sus ar putea fi rescrisă folosind facilitatea de canal astfel :$ ls -l | grep *.c | wc -l

Rezultatul ambelor grupuri de comenzi ar fi un număr precizând câte fişiere având extensia .c există în catalogul curent.

După cum rezultă din exemplul de mai sus simbolul pentru crearea unui canal este o bară verticală "|".

Motivul pentru care canalele sunt atât de folositoare este că există multe utilitare UNIX, cunoscute ca fiind filtre, care primesc un şir la intrare, îl prelucrează şi transmit şirul rezultat la ieşire (Astfel de utilitare sunt grep - caută apariţia unor expresii în diferite fişiere, şi wc - care în principiu contorizează caracterele dintr-un fişier).

Din cele prezentate până acum a reieşit faptul că sistemul UNIX este capabil de a executa concurent mai multe lucrări, el poate gestiona simultan mai mulţi utilizatori, poate rula mai multe comenzi grupate în canale pentru un utilizator. În plus un utilizator poate rula explicit mai multe comenzi independente în acelaşi timp. Aceasta este posibil datorită rulării comenzilor în background, pentru a specifica execuţia în fundal a unei comenzi, aceasta va fi urmată de caracterul "&". Dacă execuţia este în fundal, tastatura este imediat disponibilă pentru introducerea unei noi comenzi.

Ex:$ ls -l /usr/bin &[524]$

Numărul [Nr] este identificatorul de proces al comenzii date. Acest identificator poate fi folosit pentru manipularea acestor procese, de exemplu pentru terminarea forţată a proceselor.

Ex:$ kill -9 524

Pentru comenzile care se execută în fundal, trebuie procedat în aşa fel încât ieşirea , respectiv intrarea lor să nu fie ecranul respectiv tastatura, pentru aceasta se pot folosi redirectările.

Ex:

- 79 -

Page 81: Curs So

Curs de SISTEME DE OPERARE

$ ls -l /usr/bin > lista &[524]$

În plus pentru manipularea proceselor există câteva utilitare care permit triumiterea unui proces în background (bg), respectiv aducerea lor în foreground (fg). Pentru a vedea situaţia proceselor există comanda ps (Process Status).

Pentru a putea specifica mai mult de o comandă pe o singură linie acestea se pot despărţi prin caracterul ";"

Ex:$ ls -l > lista ; grep *.c < lista

Caracterul ";" forţează execuţia comenzilor într-o ordine secvenţială, adică pentru a se executa o comandă, trebuie ca toate comenzile precedente să se fi terminat.

Pentru a grupa mai multe comenzi se pot folosi parantezele "(" şi ")".De exemplu dacă s-ar fi dorit execuţia comenzilor precedente în background atunci :

$ ls -l > lista ; grep *.c < lista &

nu ar avea efectul dorit, deoarece doar cea de a doua comandă s-ar executa în background, prima s-ar executa tot în foreground. Dar dacă comenzile ar fi grupate astfel :

$ (ls -l > lista ; grep *.c < lista)&

atunci am avea rezultatul dorit.

6.5 Proceduri shell (Shell scripts).

Shell-ul nu este doar un interpretor simplu de comenzi ci are totodată şi un limbaj de programare în care pot fi scrise noi comenzi, prin folosirea comenzilor existente. Un fişier de comenzi (shell script) este un fişier care conţine o secvenţă de comenzi ale shell-ului.

6.5.1 Crearea şi executarea unui fişier de comenzi.

Un script este creat prin crearea unui fişier conţinând secvenţa dorită de comenzi. El poate fi executat în două moduri :

Specificându-l explicit ca şi fişier de intrare pentru shell :

$ sh myscriptsau

$ sh < myscript

Dând numele fişierului de comenzi exact ca orice altă comandă, în linia de comandă a shell-ului :

$ myscriptPentru ca cea de a doua metodă să funcţioneze trebuie ca utilizatorul să aibă dreptul de

execuţie asupra respectivului fişier. Aceasta se poate realiza prin comanda :

- 80 -

Page 82: Curs So

Curs de SISTEME DE OPERARE

$ chmod u+x myscript

Când shell-ul încearcă să execute o comandă el mai întâi verifică dacă utilizatorul are dreptul de a executa acea comandă, iar dacă da atunci verifică dacă comanda este un program executabil sau un script (folosind primii doi bytes din fişier, aceşti doi bytes constituind ceea ce se numeşte număr magic - magic number).

6.5.2 Variabile şi parametri care pot fi prevăzuţi în pseudo-programe shell.

Shell-ul permite folosirea variabilelor pentru a manipula valori numerice şi şiruri. O variabilă poate fi creată simplu atribuindu-i o valoare, iar dacă se foloseşte o variabilă înainte de a i se atribui o valoare, atunci va avea ca şi valoare şirul vid. Atribuirile pot apărea în felul următor :

$ NAME=chris$ BIRTHDAY='December 1st'

În exemplul de mai sus s-au definit două variabile NAME şi BIRTHDAY la care li s-au atribuit şirurile "chris" şi respectiv "December 1st". Pentru a folosi valoarea unei variabile într-o linie de comană, numele variabilei va fi precedată de caracterul "$". Având cele două atribuiri de mai sus următoarele două comenzi sunt echivalente :

$ echo $NAME was born on $BIRTHDAYchris was born on December 1st$ echo chris was born on December 1stchris was born on December 1st

Shell-ul are mai multe variabile speciale, care sunt setate automat şi au un rol special :

HOME - indică calea către directorul utilizatorului. Acesta este directorul care devine directorul curent când se dă comanda cd fără parametri.

PATH - conţine o serie de directoare separate prin caracterul ":", acestea sunt locurile unde shell-ul va căuta după fişierele pentru comenzile care se doresc a fi executate.

PS1 - conţine promptul shell-ului, de obicei setat iniţial la "$ "PS2 - este promptul de continuare, dacă comanda se extinde pe mai mult de o

singură linie, iniţial "> ".$ - este identificatorul de proces al shell-ului curent (nu se poate

schimba !).! - este identificatorul de proces al comenzii lansate cel mai recent în

background.? - este starea de ieşire a comenzii precedente.1-9 - sunt argumentele cu care a fost apelat script-ul. De exemplu :

$ myscript chris staff 'December 1st'

"$1" va fi înlocuit prin "chris", "$2" prin "staff" şi "$3" prin "December 1st".

0 - este numele prin care a fost apelat script-ul. În exemplul precedent "$0" ar fi înlocuit prin "myscript".

- 81 -

Page 83: Curs So

Curs de SISTEME DE OPERARE

* - este înlocuit printr-o listă a tuturor argumentelor scriptului. Din exemplul precedent "$*" ar fi înlocuit prin "chris staff December 1st".

# - reprezintă numărul de argumente din linia de comandă. În exemplul precedent este 3.

O altă modalitate de a seta o variabilă shell este utilizând comanda shell read care citeşte o linie de la intrarea standard şi o asignează unei variabile.

Ex:echo "What program do you want to compile ?"read NAMEcc $NAME

6.5.3 Intrarea şi ieşirea standard.

Intrarea şi ieşirea standard al unui script sunt ca şi la celelalte comenzi moştenite de la shell-ul care l-a lansat. Deci şi pentru scripturi funcţionează aceleaşi redirectări ca şi la comenzile obişnuite. În plus în scripturi se pot face redirectări ale comenzilor din script.

6.5.4 Structuri de control în proceduri shell.

Ca şi majoritatea limbajelor de programare, shell-ul include construcţii pentru cicluri şi execuţii condiţionate ale comenzilor. Construcţiile corespunzătoare ciclurilor sunt : for, while şi until. Construcţiile condiţionale sunt : if şi case.

Construcţia if foloseşte starea de ieşire (exit state) a unei comenzi. Fiecare comandă care se execută întoarce o valoare numerică când se termină. Convenţia este că o valoare de ieşire de 0 corespunde unei terminări normale, pe când o valoare diferită de 0 corespunde unei terminări anormale.

Formatul instrucţiunii if este :

if commandathen

secventa de comenzielif comandathen

secventa de comenzi...else

secventa de comenzifi

Dacă prima comandă se termină cu starea 0, atunci va fi executată prima secvenţă de comenzi, iar restul nu va fi executat. Altfel comenda din partea de elif va fi executată şi dacă starea de ieşire a acelei comenzi este 0 secvenţa de comenzi corespunzătoare va fi executată. Partea de else va fi executată doar dacă toate testele anterioare întorc valori diferite de 0. Parţile elif şi else sunt opţionale.

EXEMPLU :

- 82 -

Page 84: Curs So

Curs de SISTEME DE OPERARE

Următorul script va verifica apariţia valorii din variabila NAME într+un fişier numit namelist şi va afişa mesaje diferite depinzând de faptul dacă s-a găsit sau nu acea valoare.

if grep -s $NAME namelistthen

echo $NAME is OKelse

echo I have never heard of $NAMEfi

Următorul script exemplifică folosirea programului test, care poate fi folosit pentru a testa existenţa unui fişier, dacă acesta poate fi citit sau scris, pentru verificarea egalităţii a două şiruri sau dacă un număr este mai mare, egal sau mai mic decât un alt număr ş.a.m.d. Pentru opţiunile permise de programul test se poate consulta manualul online. Acest script va adăuga conţinutul fişierului messagefile la sfârşitul fişierului summarzfile şi goleşte fişierul messagefile.

if test -r messagefilethen

if test -w summaryfile -a -w messagefilethen

cat messagefile >> summaryfilecp /dev/null messagefile

elseecho Cannot write to sumary or message file

fielse

echo Cannot read messagefilefi

Construcţia case corespunde unei instrucţiuni de selecţie multiplă, asemănătoare cu switch din C sau case din Pascal. Formatul acesteia este :

case word inpattern11 | pattern12 | ... )

secventa de comenzi1

;;pattern21 | pattern22 | ... )

secventa de comenzi2

...esac

Valoarea specificată prin word este testată pe rând cu fiecare tipar şi la prima potrivire se va executa secvenţa de comenzi corespunzătoare. Ca şi observaţie fiecare secvenţă de comenzi este terminată prin două caractere punct şi virgulă (';'). Tiparele corespund tiparelor utilizate de shell pentru nume de fişiere. Se pot specifica tipare alternative pentru aceeaşi secvenţă de comenzi, acestea se vor separa prin caracterul bară verticală ('|').

EXEMPLU :

- 83 -

Page 85: Curs So

Curs de SISTEME DE OPERARE

Următorul exemplu demonstrează folosirea tiparului '*' ca şi tipar implicit dacă nici un alt tipar nu se potriveşte, precum şi două moduri diferite pentru a alege o opţiune indiferent de litere mari sau mici.

case $OPTION in-p|-P)

print $FILE;;

-[nN])nroff $FILE;;

*)echo Unknown option $OPTION;;

esac

Cicluri pot fi scrise utilizând un cilcu while (sau until) care execută repetat o comandă, testează starea de ieşire a acesteia şi dacă este 0 (diferit de 0 pentru until) execută o secvenţă de comenzi corespunzătoare. Când starea de ieşire devine diferită de 0 (0 pentru until) shell+ul trece la intrucţiunea de după cilcu. Formatul celor două este :

while comandado

secventa de comenzidone

until comandado

secventa de comenzidone

EXEMPLU :

REPLAY=yeswhile test $REPLAY = yes

doecho "Here we go again !"echo "Do you want to go round the loop another time ?"read REPLY

done

Ultima construcţie folosită pentru cicluri este for care are următorul format :

for nume_de_variabila in lista_de_cuvintedo

secventa de comenzidone

Secvenţa de comenzi este executată odată pentru fiecare cuvânt din lista_de_cuvinte. Variabila va lua valori succesive din lista de cuvinte. Lista de cuvinte poate fi generată folosind tipare ca şi acelea folosite pentru nume de fişiere. Deasemenea lista de variabile

- 84 -

Page 86: Curs So

Curs de SISTEME DE OPERARE

poate lipsi, caz în care ca şi listă de variabile va fi considerată lista de argumente cu care a fost lansat shell-ul (adică $*).

EXEMPLU :

for file in *do

echo $filemv $file $file.old

done

for argumentdo

cat $argumentdone

6.5.5 Comentarii.

În script-uri se pot include şi comentarii, prin folosirea comenzii ":", aceasta este o comandă care nu face nimic, astfel încât argumentele sale pot fi folosite ca şi comentarii. Dar argumentele acestei comenzi sunt prelucrate la fel ca şi argumentele altor comenzi, deci trebuie să satisfacă aceeaşi sintaxă ca şi cele pentru comenzile normale. O formă sigură pentru comentariu este ca acesta să fie pus între apostroafe.

EXEMPLU : Următorul exemplu pe lângă exemplificarea comentariilor, introduce şi o nouă

comandă exit care determină terminarea execuţiei scriptului.

: 'are there too few arguments ?'if test $# -lt 3

thenecho Not enough argumentsexit 1

: '... or too many ?'elif test $# -gt 5then

echo Too many argumentsexit 2

fi

6.5.6 Substituţia comenzilor.

Este posibilă construcţia unei părţi a unei comenzi prin executarea unei alte comenzi. Dacă o comandă care este încadrată între caractere '`' (accente grave), este incorporată într-o linie de comandă, atunci ieşirea sa standard, cu trecerile la linie nouă înlocuite prin spaţii, va fi introdusă în locul acesteia în linia de comandă. Comanda din interiorul accentelor grave poate fi orice comandă validă, chiar şi un canal (pipeline).

EXEMPLU :

- 85 -

Page 87: Curs So

Curs de SISTEME DE OPERARE

Următoarea comandă va afişa o listă de fişiere din directorul curent în ordine inversă.

$ echo `ls | sort -r`

6.5.7 Ordinea evenimentelor.

Pentru a înţelege script-uri complexe este necesar să ştim în ce ordine se fac substituţiile de către shell.

1. Se fac substituţiile de parametri şi variabileş toate apariţiile lui "$" urmat de un nume, cifră sau una dintre numele de variabile speciale ca şi "*" sunt substituite, în afara situaţiei în care caracterul "$" se găseşte înconjurat de apostroafe sau este precedat de "\".

2. Se fac substituţiile comenzilor, în afara faptului când accentul grav apare înconjurat de apostroafe sau precedat de "\". Deci ambele substituţii menţionate până acum au loc şi în interiorul unor şiruri înconjurate cu ghilimele, acestea sunt diferenţele dintre şiruri înconjurate de apostroafe (single quotation) şi şiruri înconjurate de ghilimele (double quotation).

3. Se fac substituţiile numelor de fişiere ("*", "?" şi "[...]"), în afara cayului când aceste caractere speciale sunt înconjurate cu apostroafe sau ghilimele sau precedate de "\".

6.5.8 Opţiunile shell-ului.

Când shell-ul este lansat explicit prin comanda sh este posibilă transmiterea unor opţiuni pentru controlarea execuţiei acesteia. Cele mai folositoare opţiuni sunt Ş

-e Determină terminarea execuţiei imediat ce o comandă din script dă greş.-v Determină tipărirea fiecărei linii pe măsură ce este citită.-x Tipăreşte comenzile pe măsură ce ele sunt executate.

Opţiunile pot fi setate şi din interiorul unui script folosind comanda set. De exemplu :

set -vx

va determina tipărirea fiecărei linii şi tipărirea comenzilor pe măsură ce ele sunt executate.

6.5.9 Redirectarea întreruperilor.

În unele script-uri poate fi utilă posibilitatea terminării "curate", în cazul în care se întâmplă ceva neprevăzut, ca de exemplu apăsarea de către utilizator a tastei de întrerupere sau de terminare. Comanda de redirecatre are forma :

trap actiune lista_de_evenimente

lista_de_evenimente este o listă de întregi, corespunzătoare semnalelor UNIX. actiune este comanda care să fie executată când apare un semnal din lista de semnale. Dacă action este un şir gol atunci evenimentele corespunzătoare sunt ignorate.

- 86 -

Page 88: Curs So

Curs de SISTEME DE OPERARE

Cele mai folositoare semnale sunt :0 Ieşire din shell.2 Intrerupere de la terminal.3 Semnal de terminare de la terminal.15 S-a recepţionat semnalul Kill.

EXEMPLU : Următorul exemplu demonstrează folosirea redirectării întreruperilor în cazul în

care la terminarea unui script este necesară ştergerea unui fişier temporar.

trap "echo Interruptedş exit" 2 3trap "rm -tmp-tmpfile" 0

6.5.10 Ambianţa sau mediul de lucru.

În UNIX toate procesele posedă un mediu de lucru (ENVIRONEMENT), care este o colecţie de nume care au asociate valori şir de caractere. Când shell-ul este pornit el îşi încarcă ambianţa iniţială, care constă din variabilele shell-ului şi valorile iniţiale ale acestora. Mai departe el transmite acest mediu, această ambianţă, către toate comenzile pe care le execută. De obicei noile variabile create într-un shell nu sunt incluse implicit în ambianţă. Dacă se doreşte includerea de noi variabile în ambianţă aceasta se face explicit prin comanda export.

$ export NAME BIRTHDAY

Comanda de mai sus adaugă variabilele NAME şi BIRTHDAY la ambianţa curentă a shell-ului şi care va fi moştenită de orice comandă pe care acesta o va executa în continuare. Schimbarea ambianţei unui shell sau a unui program nu va avea efect asupra ambianţei shell-ului sau programului care a lansat în execuţie acel shell sau program.

Există însă un mod de a altera ambianţa unui shell dintr-un sub-program şi anume prin folsirea comenzii eval. Această comandă pur şi simplu evaluează argumentele sale ca şi cum ele ar fi constituit o linie de comandă a shell-ului. Astfel dacă un program name scrie, de exemplu, "NAME=chris" la ieşirea standard, atunci comanda :

$ eval `name`

este echivalentă cu :

$ NAME=chris

având efectul setării variabilei de mediu NAME. Un alt mod este de a determina execuţia unui script chiar de către shell-ul curent şi nu de către un sub-shell. Acest lucru se poate face folosind comanda ".".

$ . setup

va avea efectul includerii în fluxul de intrare a fişierului setup.În anumite cazuri se poate ca să se dorească ca valorile anumitor variabile să nu poată

fi modificate. Acest lucru poate fi făcut prin comanda readonly :

- 87 -

Page 89: Curs So

Curs de SISTEME DE OPERARE

readonly NAME BIRTHDAY

această comandă va determina raportarea unei erori dacă se va încerca modificarea valorii acestor variabile.

6.5.11 Lansarea shell-ului din login.

Când se intră pentru prima oară în lucru în UNIX, sistemul porneşte un shell. Acest shell înainte de a citi de la terminal, va căuta în directorul de login după un fişier numit .profile şi dacă acesta există va citi şi executa comenzile din el. Acest lucru permite definirea unui ambient propriu. Un fişier .profile tipic va arăta astfel :

PATH=$HOME/bin:/etc:/bin:/usr/binUSER=jimMAIL=/usr/spool/mail/$USERexport PATH USER MAIL

: prevent other users from writing to the terminalmesg n: set default file creation maskumask 027

echo People currently logged on:who

echo "Hello chris: nice to see you again"

6.5.12 Un exemplu de shell script.

EXEMPLU : Script-ul cptree face o copie al unui întreg arbore de directoare, pe multe sisteme

acesta este disponibil ca şi un program standard, cu mult mai multe opţiuni, dar acest script este destinat doar exemplificării unui script mai mare.

: Copy a directory hierarchy: With optional argument '-v' echo filenamesif test "$1" = -v

thenECHO=echoVERBOSE=-vshift

: 'replaces $1 by $2, $2 by $3, etc'else

ECHO=:fi

if test $# -ne 2then

echo usage: cptree from toexit 1

- 88 -

Page 90: Curs So

Curs de SISTEME DE OPERARE

fi: if first argument is a directory copy: all files to second argumentif test -d $1

thenif test -f $2

then: second argument exists, but is not a directoryecho cptree: $2 is not a directoryexit 1

elif test ! -d $2: second argument does not exist - create it

then$ECHO mkdir $2: Will echo the command if -v was set,: otherwise just a commentmkdir $2

fifor FILE in `ls -a $1`

: To make sure we get files beginning with "."do

if test $FILE = . -o $FILE = ..then

: ignore this directory and: directorycontinue

fi: call cptree recursively, passing on VERBOSE optioncptree $VERBOSE $1/$FILE $2/$FILE

doneelif test -r $1then

: just copy a non-directory$ECHO cp $1 $2cp $1 $2

elseecho cptree: cannot read $1exit 1

fi

- 89 -

Page 91: Curs So

Curs de SISTEME DE OPERARE

6.6 Vedere generală asupra sistemului.

6.6.1 Arhitectura sistemului UNIX.

Sistemul de operare interacţionează direct cu hard-ul, oferind anumite servicii programelor, izolându-le în acelaşi timp de partea hard. Din acest motiv programele sunt uşor portabile pe diferitele sisteme UNIX.

HARDWARE

ALTE PROGRAME

DE APLICAŢIE

UTILITARE

KERNEL

Fig. 6.6-1

Sistemul oferă anumite facilităţi printre care se află ţi sistemul de fişiere.Sistemul de fişiere UNIX este caracterizat printr-o structură ierarhică, tratarea

consistentă a datelor din fişiere, posibilitatea de creare şi ştergere a fişierelor, posibilitatea creşterii dinamice a dimensiunii fişierelor, protejarea datelor din fişiere, tratarea dispozitivelor periferice ca şi fişiere.

bin etc dev usr home

/

… comenzi …fd0 fd1 tty0 hda

… utilizatori …

Fig. 6.6-2

- 90 -

Page 92: Curs So

Curs de SISTEME DE OPERARE

EXEMPLU :

char buffer[4096];

main(int argc, char *argv[]){

int fdnew, fdold;

if (argc != 3){

printf(“Eroare !\n”);exit(1);

}fdold = open(argv[1], O_RDONLY);if (fdold == -1){

printf(“Eroare !\n”);exit(1);

}fdnew = creat(argv[2], 0666);if (fdnew == -1){

printf(“Eroare !\n”);exit(1);

}copy(fdold, fdnew);exit(0);

}

copy(int fdold, int fdnew){

int count;while ((count = read(fdold, buffer, sizeof(buffer))) > 0)

write(fdnew, buffer, count);}

6.6.2 Mediul de procesare.

Un program este un fişier executabil iar un proces este o instanţă a unui program în execuţie. Se pot executa mai multe procese simultan, nefiind impusă o limită asupra numărului de procese existente în sistem.

Există mai multe apeluri sistem care permit proceselor crearea de noi procese, terminarea unor procese, sincronizarea execuţiei unor procese şi efectuarea unor acţiuni la apariţia unor evenimente.

EXEMPLU :

- 91 -

Page 93: Curs So

Curs de SISTEME DE OPERARE

Programul exemplifică folosirea apelului sistem fork - pentru crearea unui nou proces, precum şi a apelurilor sistem exec - pentru lansarea în execuţie a unui alt program, wait - pentru aşteptarea terminării unui proces fiu.

main(int argc, char *argv[]){

int pid, wpid, status;

pid = fork();if (pid == 0)

execl(“copy”, “copy”, argv[1], argv[2]);wpid = wait(&status);exit(0);

}

6.6.3 Servicii ale sistemelor de operare

Cele mai obşnuite servicii oferite de nucleul sistemului de operare sunt următoarele : controlul execuţiei proceselor, permiţând crearea, terminarea, suspendarea şi

comunicarea interproces. planificarea corectă a proceselor pentru execuţie. Procesele folosesc acelaşi procesor,

astfel dacă procesorul execută un proces, nucleul suspendă acest proces atunci când cuanta de timp a acestuia expiră şi planifică un alt proces la execuţie.

alocarea memoriei pentru execuţia proceselor. Nucleul permite proceselor să pună în comun porţiuni din spaţiul lor de adrese în anumite condiţii, dar protejează spaţiul de adrese privat împotriva acceselor nepermise, de asemenea dacă sistemul, la un moment dat, are la dispoziţie prea puţină memorie liberă, acesta eliberează memorie prin transferarea temporară a unui proces sau porţiuni ale acestuia în memoria secundară, care de obicei este un disc şi care se numeşte disc de swap. Există sisteme UNIX numite sisteme cu SWAPPING şi sisteme cu PAGING. Sistemele cu SWAPPING transferă un întreg proces din memoria principală în memoria secundară, iar sistemele cu PAGING transferă la un moment dat doar pagini de memorie din memoria principală în memoria secundară.

alocarea eficientă a memoriei secundare pentru depozitarea respectiv regăsirea eficientă a datelor utilizatorilor. Acest serviciu reprezintă chiar sistemul de fişiere.

acordarea accesului controlat proceselor la dispozitivele periferice, cum ar fi terminale, discuri, discuri de reţea sau alte periferice.

6.6.4 Restricţii hardware.

Execuţia unui proces utilizator în sistemele UNIX este divizată pe două nivele : nivelul utilizator - user nivelul de nucleu - kernel

Când un proces execută un apel sistem, modul de execuţie al procesului se schimbă din mod utilizator în mod nucleu (vom folosi pentru acest mod denumirea de mod kernel). Chiar dacă utilizatorul nu face apel explicit la serviciile sistemului de operareacestea totuşi au

- 92 -

Page 94: Curs So

Curs de SISTEME DE OPERARE

loc, deoarece pentru fiecare proces utilizator trebuiesc executete anumite operaţii ca şi tratarea întreruperilor, planificarea proceselor la execuţie, gestionarea memoriei şi altele. Multe arhitecturi de calculatoare suportă mai multe nivele decât cele două menţionate, dar cele două moduri sunt necesare şi suficiente pentru sistemele UNIX.

Diferenţele dintre aceste două moduri sunt : procesele în mod utilizator pot accesa instrucţiunile şi datele proprii, dar nu pot accesa

instrucţiunile şi datele nucleului sau ale altor procese. procesele în mod kernel pot accesa atât adresele utilizator cât şi adresele nucleului. unele instrucţiuni sunt instrucţiuni privilegiate şi execuţia lor în mod utilizator duce la

semnalarea unor erori.

6.6.5 Întreruperi şi excepţii.

Sistemele UNIX permit dispozitivelor să întrerupă procesorul în mod asincron. La apariţia unei întreruperi, nucleul îşi salvează contextul curent, determină cauza întreruprii şi tratează întreruperea. După tratarea întreruperii, nucleul reface contextul şi continuă procesul întrerupt.

Hardware-ul de obicei alocă priorităţi unor întreruperi, corespunzător ordinii în care ar trebui tratate acestea. Când nucleul tratează o întrerupere el inhibă toate întreruperile cu prioritate egală sau mai redusă decât întreruperea curentă, astfel încât în timpul tratării pot să fie tratate doar întreruperi cu un nivel mai mare de prioritate.

O condiţie de excepţie se referă la evenimentele cauzate de procese, ca şi adresarea ilegală a unei zone de memorie, execuţia unei instrucţiuni privilegiate, împărţirea la 0 şi altele. Aceste excepţii sunt diferite de întreruperi şi au loc în timpul execuţiei unei instrucţiuni, sistemul încercând reluarea acelei instrucţiuni, după tratarea excepţiei.

Sistemul UNIX foloseşte acelaşi mecanism atât la tratarea întreruperilor cât şi la tratarea excepţiilor.

6.6.6 Nivele de execuţie ale procesorului.

Nucleul, în anumite condiţii, trebuie să nu permită apariţia de întreruperi în timpul unei activităţi critice, care ar avea ca rezultat structuri de date corupte.

Nivelele tipice de întreruperi sunt : întreruperi software întreruperi de la terminale întreruperi de la dispozitive de reţea întreruperi de la discuri întreruperi de la ceasul de timp real întreruperi datorate erorilor hardware

6.6.7 Gestionarea memoriei.

Nucleul se află întotdeauna în memorie. Când se compilează un program, compilatorul generează un set de adrese pentru acel program care reprezintă adresele

- 93 -

Page 95: Curs So

Curs de SISTEME DE OPERARE

variabilelor şi structurilor de date. Aceste adrese sunt generate pentru o maşină virtuală, considerând că nici un alt program nu se va executa simultan pe aceeaşi maşină fizică. Când programul este rulat pe o maşină, nucleul va aloca spaţiu în memoria principală, dar adresele virtuale generate de compilator nu este necesar să fie identice cu adresele fizice pe care le ocupă acesta în maşină.

Nucleul în colaborare cu hardware-ul va iniţializa o translatera a adreselor virtuale în adrese fizice, astefl încât adresele generate de compilator vor indica adresele fizice de pe maşina respectivă.

- 94 -

Page 96: Curs So

Curs de SISTEME DE OPERARE

7. Arhitectura Sistemului de Operare UNIX

7.1 Introducere.

În UNIX există două concepte generale : fişierele şi procesele.

libraries

system call interface

FileSubsystem

buffer cache

interprocesscommunication

scheduler

memorymanagement

process

control

subsystemcharacter block

device drivers

hardware control

hardware

User level

Kernel level

Kernel level

Hardware level

User programstrap

Fig. 7.1-1

Fig. 1 arată o diagramă bloc a nucleului, ilustrând modulele şi relaţiile dintre acestea. În particular se reprezintă subsistemul de fişiere la stânga şi subsistemul pentru controlul proceselor în dreapta. Figura scoate în evidenţă 3 nivele : utilizator, kernel şi hardware.

Apelurile sistem şi interfaţa oferită de librării reprezintă graniţa dintre nivelele utilizator şi kernel. Figura partiţionează apelurile sistem în cele care interacţionează cu subsistemul de fişiere şi cele care interacţionează cu subsistemul de control al proceselor. Subsistemul de fişiere gestionează fişierele, alocând spaţiu acestora, administrând spaţiul liber, compunând accesele la fişiere şi regăsind datele pentru utilizator.

Procesele interacţionează cu subsistemul de fişiere printr-un set specific de apeluri sistem, ca şi open, close, read, write, stat(se citesc atributele unui fişier), chown, chmod.

- 95 -

Page 97: Curs So

Curs de SISTEME DE OPERARE

Subsistemul de fişiere accesează datele din fişiere folosind un mecanism cu buffere, care reglează fluxul de date dintre nucleu şi suporturile externe.

Mecanismul cu buffere interacţionează cu driverele de I/E pe bloc pentru a iniţia transferul de date spre sau dinspre nucleu. Driverele sunt module din nucleu care controlează funcţionarea dispozitivelor periferice. De asemenea există şi drivere de I/E orientate pe caractere pentru aşa numite raw devices.

Subsistemul de control al proceselor este responsabil pentru sincronizarea proceselor, comunicarea interprocese, gestionarea memoriei şi planificarea proceselor.

Cele două subsisteme interacţionează între ele de exemplu la încărcarea unui program pentru execuţie.

Câteva dintre apelurile sistem pentru controlul proceselor sunt : fork(crează un nou proces), exec(suprascrie un proces cu imaginea unui program), wait(aşteaptă terminarea unui proces fiu), brk(controlează dimensiunea memoriei alocate unui proces), signal(controlează răspunsul unui proces la un semnal).

Modulul de gestiune a memoriei controlează alocarea memoriei. Dacă la un anumit moment sistemul nu are destulă memorie fizică pentru toate procesele, nucleul va face transfer între memoria principală şi cea secundară, astfel încât toate procesele să se poată executa. Modulul planificator alocă CPU proceselor. El planifică un proces la execuţie, acesta se execută până când renunţă voluntar la CPU, ca urmare a unei aşteptări sau până când îi expiră cuanta de timp alocată, moment în care nucleul îi ia procesorul. Planificatorul în acest caz va alege pentru execu_ie procesul disponibil cu cea mai mare prioritate. Procesul original va fi planificat din nou la execuţie când va ajunge procesul disponibil cu cea mai mare prioritate.

Există o varietate de forme de comunicare interproces, de la semnalarea asincronă a unor evenimente şi până la transmiterea de mesaje între procese.

Modulul de control al hardware-ului este responsabil pentru tratarea întreruperilor şi pentru comunicarea cu maşina. Dispozitive ca discuri sau terminale pot întrerupe procesorul în timpul execuţiei unui proces. Nucleul poate relua execuţia procesului întrerupt după tratarea întraruperii. Întreruperile nu sunt tratate de procese speciale ci de funcţii speciale din nucleu, apelate în contextul procesului curent.

7.2 Subsistemul de fişiere.

Reprezentarea internă a unui fişier este dată printr-un aşa numit inode (index node), care conţine o descriere a aşezării fizice a fişierului pe disc şi alte informaţii, ca de exemplu : proprietarul, atributele de acces, momentul la care a fost accesat. Fiecare fişier are un singur inode, dar poate avea mai multe nume care toate sunt mapate (indică) la acelaşi inode. Fiecare nume este o aşa numită legătură (link). Când un proces crează un nou fişier, nucleul îi atribuie un inode neutilizat. Inodurile sunt în compoziţia sistemului de fişiere fizic, dar nucleul le citeşte în memorie pentru a avea un acces mai rapid la fişiere. Nucleul conţine în afara tabelului de inoduri, două alte structuri de date : tabela de fişiere şi tabela de descriptori pentru fişierele utilizator. Tabela de fişiere este o structură globală a nucleului, iar tabela de descriptori ai fişierelor utilizator este împărţită pe procese.

- 96 -

Page 98: Curs So

Curs de SISTEME DE OPERARE

User FileDescriptor Table

File Table Inode Table

Fig. 7.2-1

Când un proces deschide sau crează un fişier, nucleul alocă o intrare din fiecare tabelă corespunzătoare inodului fişierului. Intrările din cele 3 structuri de date conţin informaţii despre starea fişierului şi permit accesul la el. Tabela de fişiere de obicei con_ine deplasamentul în fişier unde va avea loc următoarea operaţiune de citire sau scriere, de asemenea mai conţine şi drepturile de acces admise procesului care a deschis fişierul. Tabela de descriptori pentru fişierele utilizator conţine date despre toate fişierele deschise de un anumit proces.

Un sistem de fişiere are următoarea structură :

bootblock

superblock

inode list data blocks

Fig. 7.2-2

Blocul de boot - ocupă începutul unui sistem de fişiere, de obicei primul sector şi poate con_ine codul de bootare necesar iniţializării sistemului de operare. Deşi doar un singur bloc de boot este necesar pentru a iniţializa un sistem, toate sistemele de fişiere au un bloc de boot.

Superblocul - descrie starea unui sistem de fişiere (dimensiune, câte fişiere poate conţine, unde se găseşte spaţiul liber, etc.)

Lista de inoduri - urmează superblocului şi dimensiunea acestei liste se specifică la configurarea sistemului. Nucleul face referire la inoduri prin indecşii acestora. Unul din aceste inoduri este inodul rădacină al sistemului de fişiere, adică este inodul prin care structura de directoare a sistemului de fişiere va fi accesibilă după execuţia apelului sistem mount.

Blocurile de date - de obicei încep la sfârşitul listei de inoduri şi conţin datele fişierelor şi date administrative. Un bloc alocat poate face parte dintr-un singur fişier din sistemul de fişiere.

Inodul - se află pe disc şi sunt citite într-o zonă de memorie. Conţin câmpurile : identificatorul proprietarului - proprietatea unui fişier e divizată între un singur

proprietar şi grupul proprietar şi defineşte setul de utilizatori care au acces la fişiere. Superutilizatorul are acces la orice fişier.

tipul fişierului fişiere regulare fişiere directoare

- 97 -

Page 99: Curs So

Curs de SISTEME DE OPERARE

fişiere speciale pe caracter fişiere speciale pe bloc fişiere FIFO

atributele de acces - sistemul protejează fişierele faţă de 3 clase : proprietarul grupul proprietarului alţii

Fiecare clasă poate avea drepturi de acces pentru citire, scriere şi execuţie; timpii de acces la fişier:

Timpul la care fişierul a fost ultima dată modificat.Timpul când a fost ultima oară accesat.Timpul când inodul a fost ultima dată modificat;

numărul de legături la un fişier - reprezintă numărul de nume pe care un fişier le are în ierarhia de directoare;

tabela de adrese pentru blocurile de date din fişier; dimensiunea fişierului;

Pentru o mai mare flexibilitate, nucleul alocă spaţiu pentru un fişier doar câte un bloc

până când se ajunge la spaţiul necesar, permiţând astfel ca datele dintr-un fişier să fie împrăştiate în sistemul de fişiere. Această schemă de alocare complică regăsirea datelor.

Tabela cu adresele blocurilor ar putea consta dintr-o listă de numere de blocuri aparţinând fişierului, dar manipularea unei liste de blocuri este destul de greoaie (consumă timp). Dacă un bloc logic conţine 1K atunci un fişier de 10K ar necesita un index având 10 numere de blocuri. Pentru a menţine structura unui inod destul de mică dar totuşi pentru a permite şi fişiere de dimensiuni mari, tabela de adrese dintr-un inod are forma :

Inode Data Blocks

23

1direct 0

4567

double indirect

direct 98

double indirect

triple indirect

single indirect

Fig. 7.2-3

- 98 -

Page 100: Curs So

Curs de SISTEME DE OPERARE

7.3 Subsistemul de procese

Un proces este defapt un program care se află în execuţie şi constă dintr-un şir de octeţi pe care CPU-ul le interpretează ca şi instrucţiuni maşină (numit “text”), date şi stivă. Mai multe procese sunt executate simultan, pe unele sisteme doar în aparenţă, ordinea execuţiei depinzând de planificarea acestora de către kernel. Deasemenea mai multe procese pot fi instanţe ale unui acelaşi program.

Un proces se execută urmând o secvenţă strictă de instrucţiuni, conţinută în proces, şi nu face salturi la secvenţele altor procese. El îşi citeşte şi scrie secţiunile de date şi stivă, dar nu poate citi sau scrie datele şi stiva altui proces. Procesele comunică cu alte procese şi cu lumea înconjurătoare doar prin apeluri sistem.

Practic un proces pe un sistem UNIX este o entitate care este creată prin apelul sistem fork. Orice proces, cu excepţia procesului 0 este creat când un alt proces execută acest apel sistem. Procesul care a apelat fork se numeşte proces părinte, iar procesul nou creat se numeşte procesul fiu. Fiecare proces are doar un singur proces părinte, dar poate avea mai multe procese fii. Nucleul identifică fiecare proces prin numărul de proces al acestuia, numit identificator de proces (PID).

Procesul 0 este un proces special care este creat când se iniţializează sistemul, după ce lansează un proces fiu (procesul 1), procesul 0 devine procesul swapper (cel care gestionează memoria virtuală). Procesul 1, cunoscut sub numele de init este "strămoşul" tuturor proceselor din sistem.

Nucleul, ca urmare a unui apel exec încarcă un fişier executabil în memorie. Procesul încărcat constă din cel puţin trei părţi, numite regiuni : text, date şi stivă. Regiunile text şi date corespund secţiunilor de text şi dată ale fişierului executabil, dar regiunea de stivă este creată automat şi dimensiunea acestuia este ajustată dinamic în timpul execuţiei.

Deoarece în sistemul UNIX un proces poate rula în două moduri, kernel sau utilizator, se folosesc stive separate pentru fiecare mod. Stiva utilizator conţine argumentele, variabilele locale şi alte date necesare funcţiilor care se execută în mod utilizator. Stiva kernel conţine datele necesare pentru funcţiile care se execută în mod kernel. Funcţiile şi datele din această stivă se referă la funcţii şi date din kernel şi nu din programul utilizator. Stiva kernel a unui proces este vidă când un proces rulează în mod utilizator.

Fiecare proces are alocată o intrare în tabela de procese a nucleului, deasemenea fiecărui proces îi este alocată o zonă utilizator (u area), care conţine date private manipulate doar de nucleu. Tabela de procese conţine un pointer spre o tabelă de regiuni ale procesului care conţine intrări care indică într-o altă tabelă de regiuni, globală, care la rândul lui indică adresele fizice din memoria fizică, corespunzătoare acelor regiuni. O regiune este o zonă continuă a spaţiului de adresare a unui proces (de ex. text, date şi stivă). Intrările în tabelele de regiuni descriu atributele regiunii, adică faptul că această regiune conţine text sau date, dacă este partajată sau privată şi dacă datele din regiune sunt în memoria principală sau nu. Cel de-al doilea nivel de indirectare (tabela de regiuni ale unui proces), permite proceselor independente să partajeze regiuni. Când un proces execută apelul sistem exec, nucleul alocă regiuni pentru text, date şi stivă după ce a eliberat vechile regiuni ale procesului.

Când un proces executâ apelul fork, nucleul duplică spaţiul de adrese al vechiului proces, permitând proceselor să partajeze regiunile când este posibil, altfel făcând o copie fizică. Când un proces apelează exit, nucleul desalocă regiunile pe care procesul le-a deţinut.

- 99 -

Page 101: Curs So

Curs de SISTEME DE OPERARE

Figura următoare ilustrează structurile de date relevante ale unui proces aflat în execuţie:

u areaper processregion table region table

process table

main memory

Fig. 7.3-1

Intrarea în tabela de procese şi zona numită u area conţin informaţii de control şi stare despre procese. Zona u area este o extensie a intrării în tabela de procese.

Câmpurile cele mai importante din tabela de procese sunt : câmp de stare, indicând starea procesului. intrarea în tabela de procese conţine câmpuri care permit nucleului localizarea

procesului şi a zonei sale u area, din memoria principală sau secundară. Nucleul foloseşte aceste informaţii pentru a putea face schimbarea de context, la acel proces, când acesta trece din starea Ready to Run In Memory în starea Kernel Running sau din starea Preempted în starea User Running. În plus, nucleul mai foloseşte aceste informaţii când transferă procesele din sau în memoria principală. Intrarea de tabelă mai conţine un câmp care dă dimensiunea procesului, astfel încât nucleul să ştie cât spaţiu să aloce procesului.

identificatori de utilizatori (UID-uri), care determină diferitele privilegii ale proceselor. De exemplu, aceste câmpuri determină setul de procese care pot trimite semnale unele la altele.

identificatori de procese (PID-uri), care specifică relaţiile dintre diferite procese. Aceste câmpuri sunt iniţializate când procesul intră în starea Created, în apelul sistem fork.

un descriptor de evenimente, setat când procesul este suspendat (starea de somn - sleep).

parametrii pentru planificatorul de procese, permit nucleului să determine ordinea în care procesele trec în stările Kernel Running şi User Running.

un câmp pentru semnale, care enumeră semnalele trimise procesului ăi care nu au fost încă tratate.

mai mulţi contori pentru păstrarea timpului de execuţie, utilizarea resurselor ăi altele, folosite pentru gestionarea ăi calcularea priorităţii de planificare. Există şi un câmp contor setabil de utilizator, folosit la transmiterea unui proces a unui semnal de alarmă.

- 100 -

Page 102: Curs So

Curs de SISTEME DE OPERARE

Zona u area conţine informaţii care descriu procesul, dar care trebuie să fie accesibile doar când procesul se execută efectiv. Câmpurile cele mai importante sunt :

un pointer către intrarea în tabela de procese a procesului. identificatorii reali şi efectivi de utilizator, care determină diferite privilegii acordate

procesului, cum ar fi drepturile de acces la fişiere. câmpuri contor care memorează timpul cât procesul şi descendenţii săi au petrecut în

mod utilizator respectiv în mod kernel. un tablou indicând modul de răspuns al procesului la diferite semnale. un câmp care identifică "terminalul de login" asociat cu procesul (dacă acesta există). câmp de eroare care reţine codurile de eroare dintimpul unui apel sistem. câmp care reţine valoarea de întoarcere dintr-un apel sistem. parametri de I/O care descriu cantitatea de date care urmează să fie transferate, adresa

tabloului sursă (sau destinaţie), din spaţiul utilizator, deplasamente de fişiere şi altele. directorul curent şi rădăcina curentă, descriu ambianţa sistemului de fişiere pentru

respectivul proces. tabela descriptorilor de fişier pentru fiecare fişier deschis. dimensiunile maxime ale unui proces şi a fişierelor pe care poate să le creeze. un câmp de mască de moduri de acces pentru fişierele care vor fi create de proces.

Implementarea oferă nucleului o cale uşoară de identificare a procesului curent, prin folosirea pointerului din zona u spre intrarea în tabela de procese.

7.3.1 Contextul unui proces

Contextul unui proces este starea acestuia, cum este ea definita de textul său, de valorile variabilelor utilizator globale şi structurilor de date, de valorile regiştrilor pe care le foloseste, de valorile din zona din tabela de procese care îi corespunde precum şi din zona u area şi conţinutul stivelor utilizator şi kernel. "Text"-ul sistemului de operare şi structurile sale de date globale, sunt partajate de toate procesele, dar ele nu constituie parte a contextului unui proces.

Când execută un proces, sistemul se spune că ruleaza în contextul procesului. Când nucleul decide că ar trebui să execute un alt proces, el face o aşa numită schimbare de context (context switch), astfel încât sistemul va rula în contextul noului proces. Nucleul permite o schimbare de context doar în anumite condiţii specifice. Când face o schimbare de context, nucleul salvează informaţie suficientă pentru a putea relua mai târziu procesul întrerurpt. La fel când se trece din modul utilizator în kernel, nucleul salvează suficientă informaţie, astfel încât mai tarziu să se poată întoarce în modul utilizator şi să continue execuţia din punctul în care a rămas. Schimbarea modului de execuţie din mod utilizator în kernel şi invers NU este o schimbare de context.

Nucleul tratează întreruperile în contextul procesului întrerupt, chiar dacă acesta nu a provocat apariţia întreruperii. Procesul întrerupt se putea găsi sau în mod utilizator sau în mod kernel. Nucleul salvează suficientă informaţie astfel încât mai târziu să poată relua execuţia procesului întrerupt, după care tratează întreruperea în mod kernel. Nucleul nu lansează sau planifică un proces special pentru tratarea întreruperilor.

- 101 -

Page 103: Curs So

Curs de SISTEME DE OPERARE

7.3.2 Stările şi tranziţiile unui proces

Timpul de viată al unui proces poate fi divizat într-un set de stări care descriu procesul. Un proces poate fi într-una din următoarele stări :

1) Procesul rulează în mod utilizator.2) Procesul rulează în mod kernel.3) Procesul nu rulează dar este pregătit pentru execuţie (atunci când nucleul îl

planifică).4) Procesul este adormit şi se află în memoria principală.5) Procesul este gata de execuţie, dar swapper-ul trebuie să îl aducă în memoria

principală înainte ca nucleul să îl poată planifica pentru execuţie.6) Procesul este adormit, şi swapper-ul a eliberat memoria ocupată de el transferându-l

în memoria secundară.7) Procesul este pe cale de a se întoarce din modul kernel în mod utilizator, dar nucleul

îl suspendă şi face o schimbare de context pentru a planifica un alt proces la execuţie.

8) Procesul este nou creat şi este într-o stare de tranziţie, procesul există, dar încă nu este gata de rulare, dar nu este nici adormit. Această stare este starea de start pentru toate procesele în afară de procesul 0.

9) Procesul a executat apelul de sistem exit şi este într-o stare de tranziţie. Procesul nu mai există, dar lasă o înregistrare conţinând codul de ieşire şi câteva statistici privitoare la timpii alocaţi pentru a fi colectate de procesul părinte. Această stare, cunoscută şi sub numele de starea zombie, este starea finala a unui proces.

- 102 -

Page 104: Curs So

Curs de SISTEME DE OPERARE

Următoarea diagramă prezintă diagrama de tranziţii dintre stările unui proces :

1

2

79

6 5

4 3

8

User Running

PreemptedZombie

Sleep, Swapped Ready to Run, Swapped

Created

AsleepIn Memory

Ready to RunIn Memory

KernelRunning

interrupt,interrupt return

sys call,interrupt return

returnto user

preemptexit

sleepreschedule

process

wakeup

wakeup

swapout

swapout

swapin

enough memory

not enough memory(swapping system only)

fork

Fig. 7.3-2

Pentru exemplificarea acestei diagrame vom considera evoluţia unui proces tipic. Starea iniţială a procesului este starea Created, când procesul părinte execută apelul sistem fork şi eventual trece într-o stare în care este pregătit pentru execuţie (3 sau 5). Pentru simplificare, presupunem că procesul intră în starea Ready to Run In Memory. Planificatorul de procese eventual va alege procesul pentru execuţie, astfel acesta intră în starea Kernel Running, unde îşi termină partea sa din apelul sistem fork.

Când procesul îşi termină apelul sistem, poate să treacă în starea User Running, unde se va executa în mod utilizator. După o perioadă de timp, ceasul sistem ar putea întrerupe procesorul şi procesul intră din nou în starea Kernel Running. După tratarea întreruperii de ceas, nucleul poate decide planificarea spre execuţie a unui alt proces, astfel încât procesul curent intră în starea Preempted şi în continuare va fi executat celălalt proces. Starea Preempted este defapt echivalentă cu starea Ready to Run In Memory, dar cele două stări au

- 103 -

Page 105: Curs So

Curs de SISTEME DE OPERARE

fost separate pentru a arăta că unui proces, care rulează în mod kernel, îi poate fi luat procesorul doar în momentul în care acesta este pe punctul de a se întoarce în mod utilizator. În continuare nucleul ar putea transfera procesul din starea Preempted în memoria secundară în starea Ready to Run Swapped, dacă este necesar. Eventual planificatorul l-ar putea alege spre execuţie, astfel procesul întorcându-se în starea User Running, deci executându-se din nou în starea utilizator.

Când un proces execută un apel sistem, el părăseşte starea User Running şi intră în starea Kernel Running. Presupunând că apelul sistem necesită operaţii de I/O cu discul, procesul este nevoit să aştepte pentru terminarea acestor operaţii. El va intra în starea Asleep In Memory, punându-se într-o stare de aşteptare până când este înştiinţat de faptul că operaţia de I/O s-a terminat. Când operaţia de I/O s-a terminat, hard-ul întrerupe CPU-ul şi rutina de tratare a întreruperii v-a trezi procesul, determinându-l să intre în starea Ready to Run In Memory.

Presupunând că sistemul execută mai multe procese care nu încap toate deodată în memoria principală ţi swapper-ul transferă din memorie procesul, pentru a face loc altui proces care se află în starea Ready to Run Swapped. Când un proces este transferat din memoria principală în memoria secundară, el trece în starea Ready to Run Swapped. Eventual swapper-ul alege procesul ca fiind cel mai potrivit pentru a fi adus în memoria principală, astfel procesul va intra din nou în starea Ready to Run In Memory. Planificatorul eventual va alege spre rulare procesul, el intrând în starea Kernel Running şi va continua execuţia. Când un proce se termină, el apelează apelul sistem exit, astfel intrând în starea Kernel Running şi în final în starea Zombie.

Un proces, la nivelul utilizatorului, are control doar asupra câtorva dintre stările de tranziţie. În primul rând un proces poate crea un alt proces. Dar starea în care ajunge din starea Created depinde în întregime de nucleu, procesul neavând controlul asupra acelor tranziţii. În al doilea rând, un proces poate executa apeluri sistem pentru a trece din starea User Running în starea Kernel Running şi astfel intrând din proprie iniţiativă în nucleu. Procesul nu are controlul asupra tranziţiilor la întoarcere din apelul sistem, evenimentele putând determina intrarea acestuia în starea Zombie. În final, un proces se poate termina de bună voie, executând apelul sistem exit. Toate celelalte tranziţii de stare urmăresc un algoritm înscris în nucleu, reacţionând la evenimente într-un fel predictibil.

- 104 -

Page 106: Curs So

Curs de SISTEME DE OPERARE

7.4 Controlul proceselor

Pentru controlul proceselor există câteva apeluri sistem, care vor fi explicate în continuare. În următoarele rânduri se prezintă succint apelurile sistem implicate în controlul proceselor, urmând ca ele să fie detaliate pe parcurs. Apelul sistem fork crează un nou proxes, apelul exit termină execuţia unui proces şi apelul wait permite procesului părinte să-şi sincronizeze execuţia cu terminarea unui proces fiu. Semnalele informează procesele despre evenimente asincrone. Apelul sistem exec permite proceselor lansarea în execuţie a unui nou program, suprascriindu-se spaţiul de adrese al procesului cu imaginea executabilă a unui fişier. Apelul sistem brk permite unui proces să aloce mai dinamic mai multă memorie, similar, sistemul permite şi creşterea dinamică a stivei utilizator.

7.4.1 Crearea proceselor.

Unicul mod în care se pot crea procese noi în sistemul de operare UNIX este prin apelul sistem fork. Procesul care a apelat fork este numit proces părinte, iar procesul nou creat este numit proces fiu. Sintaxa pentru apelul sistem fork este :

pid = fork();

La întoarcerea din apelul sistem fork, cele două procese au o copie identică a contextului lor de nivel utilizator, cu excepţia valorii de întoarcere pid. În procesul părinte, pid va avea valoarea corespunzătoare identificatorului procesului fiu, în procesul fiu, pid va avea valoarea 0.

Nucleul face următoarea secvenţă de acţiuni pentru fork :1. Alocă o intrare în tabela de procese noului proces.2. Alocă un identificator unic pentru noul proces.3. Face o copie logică a contextului procesului părinte. Deoarece unele porţinui ale

unui proces, ca şi regiunile de text, pot fi partajate între procese, nucleul câteodată poate să incrementeze contorul de referinţă la o regiune în loc să îl copieze într-un nou loc în memoria fizică.

4. Incrementează contorii din tabelele de fişiere şi inoduri, pentru fişierele asociate procesului.

5. Întoarce identificatorul procesului fiu, procesului părinte, şi valoarea 0, procesului fiu.

- 105 -

Page 107: Curs So

Curs de SISTEME DE OPERARE

În următoarea figură se ilustrează într-un mod grafic modul de creare a unui proces fiu.

SharedText

ParentData

ParentUserStack

Per ProcessRegion Table

U Area

Open Files

Current Directory

Changed Root

Kernel Stack

InodeTable

FileTable

Parent Process

ChildData

ChildUserStack

Per ProcessRegion Table

U Area

Open Files

Current Directory

Changed Root

Kernel Stack

Child Process

Fig. 7.4-1

EXEMPLU : Următorul program este un exemplu în care se ilustrează modul de partajare a

accesului la fişiere după apelul sistem fork. Programul se apelează cu doi parametri, numele unui fişier existent şi numele unui nou fişier care va fi creat. Procesul deschide fişierul existent, crează noul fişier şi crează un proces fiu prin apelul lui fork. Intern, nucleul efecuează copierea contextului procesului părinte pentru procesul fiu. Fiecare proces se execută în spaţii de adresare diferite şi fiecare poate accesa copiile private ale variabilelor globale fdrd, fdwt şi c şi copiile private ale variabilelor de pe stivă argc şi argv, dar niciuna nu poate accesa variabilele altui proces. Deoarece nucleul a copiat zona u area a procesului original, procesului fiu, în timpul apelului fork, procesul fiu moşteneşte accesul la fişierele părintelui (doar la acelea care erau deschise în momentul apelului fork), folosind aceeaşi descriptori de fişiere.

Procesele părinte şi fiu apelează funcţia rdwrt, independent, şi execută un ciclu, citind un bzte din fişierul sursă şi scriind-ul în fişierul destinaţie. Funcţia rdwrt se termină când apelul sistem read întâlneşte sfârşitul de fişier. Nucleul a incrementat contorul din tabela de fişiere a fişierelor sursă şi destinaţie şi descriptorii de fişiere din ambele procese se referă la aceleaşi intrări în tabela de fişiere. Adică descriptorii fdrd pentru ambele procese se referă la intrarea din tabela de fişiere pentru fişierul sursă, iar descriptorii fdwr

- 106 -

Page 108: Curs So

Curs de SISTEME DE OPERARE

pentru ambele procese se referă la intrarea din tabela de fişiere pentru fişierul destinaţie. Astfel, cele două procese nu vor citi sau scrie niciodată la aceleaşi valori de deplasament în cadrul fişierelor, deoarece nucleul incrementează deplasamentul după fiecare citire respectiv scriere. Deşi procesele aparent copiază fişierul sursă cu viteză dublă, deoarece îşi împart lucrul, conţinutul fişierului destinaţie va depinde de ordinea în care nucleul planifică spre execuţie procesele. Dacă planifică procesele astfel încât ei alternează execuţia apelurilor sistem, sau chiar dacă alternează execuţia perechilor de apeluri sistem read-write, conţinutul fişierului destinaţie ar fi identic cu cel al fişierului sursă. Dar se poate considera şi următorul scenariu, unde procesele sunt pe cale să citească următoarea secvenţă de două caractere "ab" din fişierul sursă. Presupunem că procesul părinte citeşte caracterul 'a' şi nucleul face o schimbare de context pentru a executa procesul fiu, înainte ca procesul părinte să poată scrie ce a citit. Dacă procesul fiu citeşte caracterul 'b' şi apucă să îl şi scrie în fişierul destinaţie înainte ca procesul părinte să fi fost replanificat, atunci fişierul destinaţie nu va conţine secvenţa "ab" ci secvenţa "ba". Nucleul nu garantează rata relativă de execuţie a proceselor.

#include <fcntl.h>

int fdrd, fdwt;char c;

main(int argc, char *argv[]){

if (argc != 3)exit(1);

if ((fdrd = open(argv[1], O_RDONLY)) == -1)exit(1);

if ((fdwt = creat(argv[2], 0666)) == -1)exit(1);

fork();/* ambele procese execută acelaşi cod */rdwrt();exit(0);

}

rdwrt(){

for(;;){

if (read(fdrd, &c, 1) != 1)return;

write(fdwt, &c, 1);}

}

- 107 -

Page 109: Curs So

Curs de SISTEME DE OPERARE

7.4.2 Semnale.

Semnalele informează procesele despre apariţia unor evenimente asincrone. Procesele pot să-şi transmită unele altora semnale cu ajutorul apelului sistem kill, sau nucleul poate transmite semnale intern.

Semnalele în general pot fi clasificate astfel : Semnale care au de a face cu terminarea unui proces, trimise când un proces se

termină sau când un proces execută apelul sistem signal cu parametrul death of child (distrugerea unui proces fiu);

Semnale care au de a face cu excepţiile produse de procese, cum ar fi accesarea de către un proces a unei adrese din afara spaţiului său virtual de adresare, când încearcă să scrie într-o zonă marcată ca read-only, sau când execută o instrucţiune privilegiată sau pentru diferite erori hard;

Semnale ce au de a face cu situaţii nerecuperabile din timpul unui apel sistem, cum ar fi consumarea tuturor resurselor sistemului în timpul unui apel exec, după ce spaţiul de adresare original a fost eliberat;

Semnale cauzate de o eroare neaşteptată în timpul unui apel sistem, cum ar fi apelul la o funcţie sistem inexistentă, scrierea într-o conductă care nu are un proces care să citească din ea sau utilizarea unor valori de referinţă ilegale pentru apelul sistem lseek;

Semnale care provin de la un proces în mod utilizator, cum ar fi când un proces ar dori să recepţioneze un semnal de alarmă, după o anumită perioadă sau când procesele trimit semnale arbitrare unele altora cu ajutorul apelului sistem kill;

Semnale care ţin de interacţionarea cu un terminal, cum ar fi întreruperea unui terminal de către un utilizator sau când un utilizator apasă tasta "break" sau "delete";

Semnale pentru urmărirea execuţiei unui proces.

Nucleul testează apariţia semnalelor când un proces este pe cale să revină din mod kernel în mod utilizator şi când intră sau părăseşte starea de asleep (adormit). Nucleul tratează semnalele doar când un proces revine din mod kernel în mod utilizator. Astfel, un semnal nu are un efect instantaneu asupra unui proces care rulează în mod kernel. Dacă un proces rulează în mod utilizator şi nucleul tratează o întrerupere care determină transmiterea unui semnal procesului, nucleul va recunoaşte şi va trata semnalul când se întoarce din tratarea întreruperii. Deci, un proces nu va executa niciodată în mod utilizator înainte de a trata semnalele rămase.

7.4.2.1 Tratarea semnalelor.

Nucleul tratează semnalele în contextul procesului care le-a recepţionat, deci un proces trebuie să se execute pentru a putea trata semnale. Există trei cazuri pentru tratarea semnalelor: procesul se termină la recepţionarea unui semnal, ignoră semnalul sau execută o funcţie particulară (utilizator) la recepţionarea unui semnal. Acţiunea implicită este apelul lui exit în mod kernel, dar un proces poate specifica execuţia unor acţiuni speciale la recepţionarea unor anumite semnale, cu ajutorul apelului sistem signal.

Sintaxa pentru apelul sistem signal este :

oldfunction = signal(signum, function);

- 108 -

Page 110: Curs So

Curs de SISTEME DE OPERARE

unde signum este numărul semnalului pentru care procesul specifică o anumită acţiune, function este adresa funcţiei utilizator pe care procesul vrea să îl execute la recepţionarea unui astfel de semnal, iar valoarea de întoarcere oldfunction era valoarea lui function din cel mai recent apel al lui signal pentru semnalul signum. Procesul în locul adresei funcţiei poate transmite valorile 1 sau 0. Dacă parametrul este 1, atunci procesul va ignora apariţiile ulterioare ale semnalului, iar dacă este 0, procesul va ieşi prin nucleu la apariţia acelui semnal (comportarea implicită).

Când un proces primeşte un semnal pe care a decis să îl ignore (printr-un apel anterior la signal cu parametrul, corespunzător adresei, 1), el îşi cpntinuă execuţia ca şi când nu s-ar fi întâmplat nimic. Deoarece nucleul nu resetează câmpul din zona u area care indică faptul că semnalul este ignorat, procesul va ignora semnalul ori de câte ori va mai apărea. Dacă un proces primeşte un semnal pe care a decis să îl trateze, el va executa funcţia specificată imediat când se reîntoarce în mod utilizator, după ce nucleul face următorii paşi :

1. Nucleul accesează contextul utilizator salvat, pentru găsirea valorii regiştrilor program counter şi stack pointer, pe care le-a salvat pentru întoarcerea la procesul utilizator.

2. Şterge câmpul care indică rutina de tratare a semnalului din zona u area, setându-l pe valoarea implicită.

3. Nucleul crează pe stiva utilizator un pseudo-apel la funcţia specificată, prin punerea în stivă a regiştrilor corespunzători, acest pseudo-apel va fi simulat în locul unde a fost făcut apelul sistem sau a apărut întreruperea.

4. Nucleul schimbă contextul salvat astfel : el resetează valoarea program counter-ului astfel încât să indice adresa funcţiei specificate şi setează valoarea stack pointer-ului astfel încât să reflecte creşterea corespunzătoare a stivei utilizator.

Deci după întoarcerea din mod kernel în mod utilizator, procesul va executa funcţia de tratare a semnalului; iar la întoarcerea din acea funcţie se va întoarce în locul în care a fost executat apelul sistem sau s-a recepţionat întreruperea, simulând întoarcerea dintr-o întrerupere.

Deoarece nucleul resetează câmpul care indică rutina de tratare a unui semnal s-ar putea ajunge la situaţii nedeterminate. Deoarece procesele rulează în mod utilizator, nucleul ar putea face o schimbare de context, apărând posibilitatea ca procesul să primească un semnal înainte de a putea să refacă legătura spre funcţia de tratare a semnalului.

EXEMPLU : Următorul program ilustrează această stare. Procesul apelează signal pentru a

specifica execuţia funcţiei sigcatcher la apariţia semnalului SIGINT. El crează un proces fiu, după care execută apelul sistem nice pentru a-şi micşora prioritatea, după care intră într-un ciclu infinit. Procesul fiu îşi suspendă execuţia pentru 5 secunde, pentru a da timp procesului părinte pentru aşi micşora prioritatea, după care procesul fiu intră într-un ciclu, în care trimite un semnal de întrerupere procesului părinte, prin apelul sistem kill. Dacă kill se întoarce cu un cod de eroare, probabil din cauză că procesul părinte nu mai există, procesul fiu se termină. Idea este că procesul părinte ar trebui să apeleze de fiecare dată funcţia de tratare a semnalului, care să tipărească un mesaj şi să apeleze din nou signal pentru a capta următoarea apariţie a unui semnal de întrerupere (SIGINT), astfel procesul părinte ar executa la infinit ciclul.

Dar este posibilă apariţia următoarei secvenţe de evenimente :1. Procesul fiu trimite un semnal de întrerupere procseului părinte.2. Procesul părinte prinde semnalul şi apelează funcţia de tratare, dar nucleul

întrerupe procesul şi face o schimbare de context, înainte ca acesta să fi executat din nou apelul sistem signal.

- 109 -

Page 111: Curs So

Curs de SISTEME DE OPERARE

3. Procesul fiu se execută din nou şi trimite un nou semnal de întrerupere procesului părinte.

4. Procesul părinte primeşte cel de-al doilea semnal de întrerupere, dar el nu a reuşit să specifice rutina de tratare pentru acesta, astfel încât se va apela la tratarea impicită, adică la reluarea execuţiei procesul părinte se va termina.

#include <signal.h>

sigcatcher(){

printf(“PID %d caught one.\n”, getpid()); /* print process id */signal(SIGINT, sigcatcher);

}

main(){

int ppid;

signal(SIGINT, sigcatcher);

if (fork() == 0){

/* give enough time for both processes to set up */sleep(5); /* library function to delay 5 seconds */ppid = getppid(); /* get parent id */for(;;)

if (kill(ppid, SIGINT) == -1)exit();

}

/* lower priority, greater chance of exhibiting race */nice(10);for(;;)

;}

7.4.2.2 Grupuri de procese.

Deşi procesele de pe un sistem UNIX sunt identificate printr-un identificator unic, sistemul câteodată trebuie să identifice procesele prin "grup". De exemplu, procesele cu un proces strămoş comun, care este un shell sunt în general legate unele de altele, de aceea toate aceste procese vor primi semnale când un utilizator apasă tasta "delete" sau "break" sau când terminalul nu mai este accesibil. Nucleul foloseşte identificatorul de grup al proceselor pentru a identifica grupurile de procese care trebuie să primească un semnal comun, pentru anumite evenimente. Procesele din acelaşi grup de procese au aceiaşi identificatori de grup.

Apelul sistem setpgrp iniţializează identificatorul de grup al unui proces şi îl setează egal cu valoarea identificatorului de proces al procesului care l-a apelat.

Sintaxa apelului este :

grp = setpgrp();

- 110 -

Page 112: Curs So

Curs de SISTEME DE OPERARE

unde grp este noul identificator de grup al procesului. Un proces fiu reţine identificatorul de grup al procesului părinte prin fork.

7.4.2.3 Trimiterea de semnale din procese.

Procesele folosesc apelul sistem kill pentru a trimite semnale. Sintaxa apelului este :

kill(pid, signum);

unde pid identifică setul de procese care vor primi semnalul, iar signum este numărul semnalului care se doreşte a fi transmis. Următoarea listă arată corespondenţa dintre valorile lui pid şi setul de procese :

Dacă pid este un întreg pozitiv, nucleul trimite semnalul la procesul cu identificatorul pid.

Dacă pid este 0, nucleul trimite semnalul la toate procesele din grupul procesului emiţător.

Dacă pid este -1, nucleul trimite semnalul tuturor proceselor al căror identificator real de utilizator corespunde cu identificatorul efectiv de utilizator al procesului emiţător. Dacă procesul emiţător are identificatorul efectiv de utilizator al superutilizatorului, atunci nucleul trimite semnalul tuturor proceselor cu excepţia procesului 0 şi 1.

Dacă pid este un întreg negativ, dar nu -1, nucleul trimite semnalul tuturor proceselor din grupul de procese al cărui identificator de grup este egal cu valoarea absolută a pid.

În toate cazurile, dacă procesul emiţător nu are identificatorul efectiv de utilizator al superutilizatorului, sau identificatorul său real sau efectiv nu se potrivesc cu identificatorul real sau efectiv al procesului destinaţie, apelul kill eşuează.

EXEMPLU : Următorul program exemplifică noţiunea de grup de procese, împreună cu folosirea

apelurilor de sistem menţionate.

#include <signal.h>main(){

register int i;setpgrp();for(i = 0; i < 10; i++){

if (fork() == 0){ /* proces fiu */

if (i & 1)setpgrp();

printf("pid = %d pgrp = %d\n", getpid(), getpgrp());pause(); /* apel sistem pentru suspendarea execuţiei */

}}kill(0, SIGINT);

- 111 -

Page 113: Curs So

Curs de SISTEME DE OPERARE

}

În precedentul program, procesul resetează identificatorul său de grup şi crează 10 procese fii. Când sunt create, fiecare proces fiu va avea acelaşi identificator de grup ca şi procesul părinte, dar procesele create în timpul iteraţiilor impare îşi resetează şi elel identificatorul de grup. Apelurile sistem getpid şi getpgrp întorc identificatorul de proces, respectiv identificatorul de grup al procesului aflat în execuţie, iar apelul sistem pause suspendă execuţia procesului până când recepţionează un semnal. În final, părintele execută apelul sistem kill şi trimite un semnal de întrerupere tuturor proceselor din grupul său. Nucleul trimite semnalul la cele 5 procese "pare", care nu şi-au resetat identificatorul de grup, dar celelalte 5 procese "impare" vor continua să ruleze.

7.4.3 Terminarea proceselor.

Procesele de pe un sistem UNIX se termină prin execuţia apelului sistem exit. Un proces pe cale de terminare intră în starea de Zombie, eliberând resursele deţinute, în afara intrării din tabela de procese. Sintaxa pentru apel este :

exit(status);

unde valoarea lui status este întoarsă procesului părinte pentru examinare. Procesele pot apela exit explicit sau implicit la sfârşitul programului, deoarece rutina de pornire linkeditată cu toate programele C apelează exit când programul revine din funcţia main, punctul de intrare al tuturor programelor. Deasemenea şi nucleul poate apela exit, intern, pentru un proces, ca răspuns la un semnal care nu a fost captat. Dacă este aşa atunci valoarea lui status indică numărul semnalului.

7.4.4 Aşteptarea terminării proceselor.

Un proces poate să-şi sincronizeze execuţia cu terminarea unui proces fiu prin executarea apelului sistem wait. Sintaxa apelului sistem este :

pid = wait(stat_addr);

unde pid este identificatorul de proces al unui fiu aflat în starea Zombie, iar stat_addr este adresa unui întreg (ret_code), care va conţine codul de ieşire pentru respectivul proces fiu.

EXEMPLU : Pentru exemplificare considerăm următorul program. Considerăm două cazuri,

primul, apelul programului fără parametri şi al doilea caz, apelul programului cu cel puţin un parametru. În primul caz procesul părinte crează 15 procese fii care eventual se termină cu valoarea de ieşire i, valoarea variabilei contor când procesul fiu a fost creat. Nucleul, executând wait pentru procesul părinte, găseşte un proces fiu în starea Zombie şi îi întoarce identificatorul de proces, este nedeterminat al cărui proces fiu va fi întors. Codul din librăria C, pentru apelul sistem exit plasează codul de ieşire în biţii 8 - 15 ai lui ret_code şi întoarce identificatorul de proces.

- 112 -

Page 114: Curs So

Curs de SISTEME DE OPERARE

În al doilea caz, procesul părinte apelează signal pentru a ignora semnalele datorate "morţii" proceselor fiu. Presupunând că procesul părinte adoarme înainte ca vreun proces fiu să se termine, când un proces fiu se termină, el trimite un semnal de "deces" procesului părinte, procesul părinte se trezeşte şi va fi planificat pentru execuţie. Când procesul părinte ajunge să se execute, el găseşte semnalul în aşteptare, dar deoarece el ignoră semnalele de "deces ale fiilor", nucleul îndepărtează intrarea corespunzătoare procesului fiu în starea Zombie din tabela de procese şi continuă execuţia lui wait ca şi cum nu s-ar fi recepţionat nici un semnal. Nucleul execută această procedură de fiecare dată când părintele primeşte un semnal de "deces al unui fiu", până când procesul părinte nu va mai avea fii. Atunci apelul sistem wait va întoarce -1, semnalând eroare, deoarece nu există nici un proces fiu după care să aştepte.

Diferenţa dintre cele două cazuri este că în primul caz procesul părinte aşteaptă după terminarea oricărui proces fiu, în timp ce în al doilea caz el aşteaptă pentru terminarea tuturor proceselor fiu.

#include <signal.h>

main(int argc, char *argv[]){

int i, re_val, ret_code;

if (argc >= 1)signal(SIGCLD, SIG_IGN); /* ignoră decesul fiilor */

for(i = 0; i < 15; i++)if (fork() == 0){ /* procesul fiu */

printf("child proc %x\n", getpid());exit(i);

}ret_val = wait(&ret_code);printf("wait ret_val %x ret_code %x\n", ret_val, ret_code);

}

7.4.5 Executarea altor programe.

Apelul sistem exec încarcă un alt program, suprascriind spaţiul de memorie al unui proces cu o copie a fişierului executabil. Sintaxa acestui apel sistem este :

execve(filename, argv, envp);

unde filename este numele fişierului executabil care va fi încărcat, argv este un pointer spre un tablou de pointeri spre şirurile de caractere care vor fi parametri programului executabil, iar envp este un pointer spre un tablou de pointeri spre şiruri de caractere care constituie ambianţa programului care va fi executat. Există mai multe funcţii de librărie, care apelează la exec, cum ar fi execl, execv, execle şi altele.

Când un program foloseşte parametrii din linia de comandă, ca în :

main(argc, argv)

- 113 -

Page 115: Curs So

Curs de SISTEME DE OPERARE

tabloul argv este o copie a parametrului argv comunicat lui exec. Şirurile de caractere din ambianţă au următoarea formă : "name=value" şi pot conţine informaţii utile. Procesele pot accesa ambianţa lor prin variabila globală environ, iniţializat de rutina C de start.

EXEMPLU : Următorul fragment de program ilustează folosirea acestui apel sistem :

main(){

int status;if (fork() == 0)

execl("/bin/date", "date", 0);wait(&status);

}

- 114 -