Tanenbaum_1_07eaf2110544e16848eca5e77c572966.pdf

Full Transcript

SISTEME DE OPERARE MODERNE Ediția a patra Andrew S. Tanenbaum Herbert Bos Pretince Hall PTR Upper Saddle River, New Jersey 07458 www.phptr.com 1 / 1. INTRODUCERE................................................................

SISTEME DE OPERARE MODERNE Ediția a patra Andrew S. Tanenbaum Herbert Bos Pretince Hall PTR Upper Saddle River, New Jersey 07458 www.phptr.com 1 / 1. INTRODUCERE............................................................................................................................................ 3 1.1 Ce este un sistem de operare?................................................................................................................... 5 1.1.1 Sistemul de operare ca mașină extinsă.................................................................................................. 5 1.1.2 Sistemul de operare ca administrator de resurse.................................................................................... 7 1.2 Istoria sistemelor de operare...................................................................................................................... 8 1.2.1 Prima generatie (1945 - 1955): tuburi cu vid........................................................................................... 8 1.2.2 A doua generație (1955 - 1965): tanzistoarele și tratarea pe loturi........................................................... 9 1.2.3 Generatia a treia (1965 - 1980): Circuite integrate si multiprogramare................................................... 11 1.2.4 Generatia a patra (1980 - până în prezent). Calculatoare personale..................................................... 15 1.2.5 Generația a cincea (din 1990 până în prezent): calculatoarele mobile................................................... 19 1.3 Notiuni din domeniul resurselor fizice ale calculatorului............................................................................ 19 1.3.1 Procesoarele........................................................................................................................................ 20 1.3.2 Cipuri multi-fire și multi-nuclee.............................................................................................................. 22 1.3.3 Memoria............................................................................................................................................... 24 1.3.4 Discurile............................................................................................................................................... 26 1.3.5 Dispozitivele de intrare/ieșire................................................................................................................ 28 1.3.6 Magistralele.......................................................................................................................................... 31 1.3.7 Pornirea computerului.......................................................................................................................... 33 1.4 Gradina zoologica a sistemelor de operare............................................................................................... 34 1.4.1 Sisteme de operare pentru masinile mari de calcul............................................................................... 34 1.4.2 Sisteme de operare pentru servere....................................................................................................... 35 1.4.3 Sisteme de operare multiprocesor........................................................................................................ 35 1.4.4 Sisteme de operare pentru calculatoare personale............................................................................... 35 1.4.5 Sisteme de operare în timp real............................................................................................................ 35 1.4.6 Sisteme de operare încorporate........................................................................................................... 36 1.4.7 Sisteme de operare pentru nodurile de senzori..................................................................................... 36 1.4.8 Sisteme de operare de timp real........................................................................................................... 36 1.4.9 Sisteme de operare pentru carduri inteligente....................................................................................... 37 1.5 Concepte din domeniul sistemelor de operare.......................................................................................... 37 1.5.1 Procese................................................................................................................................................ 38 1.5.2 Spații de adrese................................................................................................................................... 39 1.5.3 Fișierele............................................................................................................................................... 40 1.5.4 Intrări/Ieșiri........................................................................................................................................... 43 1.5.5 Protecția și securitatea......................................................................................................................... 43 1.5.6 Interpretorul de comenzi (shell)............................................................................................................ 43 1.6 APELURI DE SISTEM.............................................................................................................................. 44 1.6.1 Apeluri de sistem pentru administrarea proceselor................................................................................ 47 1.6.2 Apeluri de sistem pentru administrarea fisierelor................................................................................... 50 1.6.3 Apeluri de sistem pentru administrarea cataloagelor............................................................................. 50 1.6.4 Alte apeluri de sistem........................................................................................................................... 52 1.6.5 Interfața pentru programarea aplicațiilor Windows Win32 API............................................................... 52 1.7 STRUCTURA SISTEMELOR DE OPERARE............................................................................................ 54 1.7.1 Sisteme monolitice............................................................................................................................... 55 1.7.2 Sisteme structurate pe nivele................................................................................................................ 56 1.7.3 Modelul microkernel............................................................................................................................. 57 1.7.4 Modelul client-server............................................................................................................................ 58 1.7.5 Masini virtuale...................................................................................................................................... 59 1.7.6 Despre Exokernel................................................................................................................................. 62 1.8 DIN LUMEA LIMBAJULUI C..................................................................................................................... 62 1.8.1 Despre limbajul C................................................................................................................................. 63 1.8.2 Fișiere antet......................................................................................................................................... 63 1.8.3 Proiecte mari de programare................................................................................................................ 64 1.9 Cercetări în domeniul sistemelor de operare............................................................................................. 65 1.10 Rezumat.......................................................................................................................... 67 2 PREFAȚA Ediția a patra a acestei cărți este foarte diferită de a treia. Întrucât dezvoltarea sistemelor de operare nu rămâne pe loc, aducerea materialului într-o stare modernă a necesitat un număr mare de mici modificări. Capitolul despre sistemele de operare multimedia a fost mutat pe Internet, în principal pentru a face loc materialelor noi și pentru a împiedica cartea să crească până la o dimensiune absolut incontrolabilă. Capitolul Windows Vista a fost șters deoarece Vista nu a reușit să se ridice la nivelul așteptărilor companiei Microsoft. La fel și capitolul Symbian, deoarece sistemul este acum mult mai puțin răspândit. Vista a fost înlocuit cu Windows 8, iar Symbian cu Android. În plus, a fost inclus un capitol nou despre virtualizare. 1. INTRODUCERE Un computer modern este format dintr-unul sau mai multe procesoare, memoria operativă, memoria secundară, o imprimantă, o tastatură, un mouse, un display, echipamente de rețea și diverse dispozitive de intrare/ieșire. În consecință, este un sistem extrem de complex. Dacă un programator simplu ar fi obligat să înțeleagă complexitatea tuturor acestor dispozitive, atunci nu-i va mai rămâne timp pentru a scrie cod. Mai mult, gestionarea tuturor acestor componente și utilizarea lor optimă este o sarcină foarte dificilă. Din acest motiv, calculatoarele sunt echipate cu un software special numit Sistem de Operare, sarcina căruia este gestionarea programelor utilizatorului, precum și administrarea tuturor resurselor menționate anterior. Majoritatea cititorilor au deja experiență cu sisteme de operare, cum ar fi Windows, Linux, Unix FreeBSD sau Mac OS X, dar aspectul lor poate varia. Programele folosite de utilizatori pentru a interacționa cu calculatorul, de obicei numite shell, atunci când se bazează pe utilizarea textului sau interfața grafică de utilizator (GUI), nu fac parte din sistemul de operare, deși folosesc acest sistem. Schematic, principalele componente luate în considerare aici sunt prezentate în Fig. 1.1. Fig. 1.1. Locul sistemului de operare în cadrul resurselor program Partea inferioară a imaginii reprezintă resursele fizice (hardware). Include microcircuite, plăci, discuri, tastatură, monitor și alte componente fizice. Mai sus de hardware este software-ul. Majoritatea computerelor au două moduri de operare: modul kernel și modul utilizator. Sistemul 3 de operare este cea mai fundamentală piesă de software care funcționează în modul kernel (acest mod se mai numește și modul supervizor). În acest mod, sistemul are acces complet la toate componentele tehnice și poate folosi orice instrucțiune pe care calculatorul este capabil să o execute. Restul software-ului rulează în modul utilizator, în care este disponibil doar un subset de instrucțiuni ale mașinii. De exemplu, programelor care operează în modul utilizator sunt interzise să utilizeze instrucțiuni care controlează mașina sau să efectueze operațiuni de Intrare/Ieșire (I/O). Vom reveni de mai multe ori la diferențele dintre modurile kernel și utilizator. Aceste diferențe au o influență decisivă asupra sistemului de operare. Programele de interfață ale utilizatorului - shell-ul sau interfața grafică - se află la cel mai inferior nivel de software executat în modul utilizator și permit utilizatorului să ruleze alte programe, cum ar fi un browser web, un cititor de e-mail sau un player de muzică. Aceste programe de asemenea folosesc în mod activ sistemul de operare. Locul sistemului de operare este prezentat în Fig. 1.1. Acesta lucrează direct cu hardware-ul și reprezintă baza pentru restul software-ului. O diferență importantă între sistemul de operare și software-ul obișnuit (care operează în modul utilizator) este următoarea: dacă utilizatorul nu este mulțumit de un anumit cititor de e-mail, poate alege un alt program sau, dacă dorește, își poate scrie propriul program, dar nu poate scrie propriul program de gestionare a întreruperilor ceasului de sistem, care face parte din sistemul de operare și este protejat la nivel hardware de orice încercare de modificare din partea utilizatorului. Această distincție este uneori mai puțin pronunțată în sistemele încorporate (care pot să nu dispună de modul kernel) sau în sistemele interpretate (cum ar fi sistemele bazate pe limbajul Java, în care pentru separarea componentelor nu sunt utilizate resursele tehnice ci un interpretor). Multe sisteme au, de asemenea, programe care rulează în modul utilizator, dar care ajută sistemul de operare sau îndeplinească funcții speciale. De exemplu, programele care permit utilizatorilor să își schimbe parolele sunt destul de frecvente. Acestea nu fac parte din sistemul de operare și nu rulează în modul kernel, dar se înțelege că acestea îndeplinesc o funcție importantă și trebuie protejate în mod special. În unele sisteme, această idee este dusă la o formă extremă, iar acele zone care aparțineau în mod tradițional sistemului de operare (de exemplu, sistemul de fișiere) funcționează în spațiul utilizatorului. În aceste sisteme este dificil de trasat o graniță clară. Toate programele care rulează în modul kernel fac parte în mod clar din sistemul de operare, însă unele programe care rulează în afara acestui mod pot face parte din sistemul de operare sau cel puțin sunt strâns legate de el. Sistemele de operare diferă de programele de utilizator (adică de aplicații) nu numai prin locația lor. Caracteristic pentru ele sunt volumul relativ mare al codului, structura complexă și durata de viață lungă. Codul sursă al unui sistem de operare precum Linux sau Windows constă din aproximativ 5 milioane de linii. Pentru a ne imagina acest volum, să tipărim mental 5 milioane de linii în format carte de 50 de linii pe pagină și 1000 de pagini în fiecare volum (care este mai mare decât această carte). Ar fi nevoie de 100 de volume pentru a tipări această cantitate de cod, ceea ce înseamnă practic un întreg raft de cărți. Vă puteți imagina dacă vi s-ar da sarcina să asigurați mentenanța unui astfel de sistem și în prima zi șeful dumneavoastră v-ar duce la un raft de cărți și v-ar spune: "Asta e tot ce trebuie să înveți." Iar aceasta este doar pentru partea care rulează în modul kernel. Dacă includem și bibliotecile comune necesare, Windows are peste 70 de milioane de linii de cod (tipărite pe hârtie, acestea ar ocupa 10-20 de rafturi), fără a mai pune la socoteală principalele programe de aplicații (cum ar fi Windows Explorer, Windows Media Player etc.). 4 Acest lucru explică de ce sistemele de operare trăiesc atât de mult timp - sunt foarte greu de creat și, odată ce a fost creat unul, proprietarul este reticent să îl arunce și să înceapă să creeze unul nou. Acesta este motivul pentru care sistemele de operare evoluează pe o perioadă lungă de timp. Familia Windows 95/98/Me a fost în esență un singur sistem de operare, iar familia Windows NT/2000/XP/Vista/Windows 7 a fost un altul. Pentru utilizator, acestea semănau unul cu celălalt, deoarece Microsoft s-a asigurat că interfața de utilizator la Windows 2000/XP/Vista/Windows 7 era foarte asemănătoare cu cea a sistemului pe care îl înlocuia, care, de cele mai multe ori, era Windows 98. Cu toate acestea, Microsoft a avut câteva motive destul de întemeiate pentru a renunța la Windows 98, pe care le vom revedea atunci când vom intra într-un studiu detaliat al sistemului Windows în Capitolul 11. Un alt exemplu, folosit pe parcursul cărții, este sistemul de operare UNIX, variantele și clonele sale. Acesta a evoluat de-a lungul anilor, existând în versiuni bazate pe sistemul original, cum ar fi System V, Solaris și FreeBSD. Linux, pe de altă parte, are o nouă fundație software, deși modelul său se bazează mult pe UNIX și are un grad ridicat de compatibilitate cu acesta. Exemplele referitoare la UNIX vor fi folosite pe tot parcursul cărții, în timp ce Linux este tratat în detaliu în capitolul 10. Acest capitol abordează pe scurt unele dintre aspectele cheie ale sistemelor de operare, învățând ce sunt acestea, examinând istoria lor și tot ceea ce s-a întâmplat în jurul lor, analizând câteva concepte de bază ale sistemelor de operare și structura acestora. Multe subiecte importante vor fi abordate mai detaliat în capitolele următoare. 1.1 Ce este un sistem de operare? Este dificil să se dea o definiție precisă a unui sistem de operare (SO). Se poate spune că este un software care rulează în modul kernel, dar nici măcar această afirmație nu va fi întotdeauna adevărată. O parte a problemei constă în faptul că sistemele de operare îndeplinesc două funcții semnificativ diferite: ele (1) oferă programatorilor de aplicații (și, bineînțeles, aplicațiilor) un set de resurse abstracte ușor de înțeles, care înlocuiesc setul neordonat de resurse fizice și (2) gestionează aceste resurse abstracte. În funcție de persoana care vorbește, este posibil să auzim mai mult despre prima sau despre a doua dintre aceste funcții. Nouă ne revine sarcina să analizăm ambele funcții. 1.1.1 Sistemul de operare ca mașină extinsă Arhitectura majorității calculatoarelor (sistemul de instrucțiuni, organizarea memoriei, sistemul de intrare/ieșire și magistralele) la nivelul limbajului cod mașină este prea primitivă și incomodă pentru a fi utilizată în programe, în special în sistemele I/O. Pentru a pune discuția în context, să ne uităm la hard disk-urile moderne SATA (Serial ATA), care sunt utilizate în majoritatea computerelor. O carte publicată de Anderson Publishing în 2007, care descria interfața de disc pe care programatorii trebuiau să o învețe pentru a utiliza unitatea, conținea peste 450 de pagini. De atunci, interfața a fost revizuită de mai multe ori și a devenit chiar mai complexă decât era în 2007. Este clar că niciun programator sănătos la cap nu ar dori să se ocupe de o astfel de unitate la nivel hardware. În ajutorul programatorului, hardware-ul este gestionat de un software numit driver de disc, care oferă, fără alte precizări, o interfață pentru citirea și scrierea blocurilor de disc. SO conțin multe drivere pentru a controla dispozitivele de I/O. Dar, pentru majoritatea aplicațiilor, chiar și acest nivel este prea scăzut. Din această cauză toate sistemele de operare oferă un alt nivel (mai înalt) de abstractizare pentru utilizarea discului - fișierele. Utilizând această abstractizare, programele pot crea, scrie și citi fișiere, fără a intra în detaliile legate de modul în care funcționează de fapt hardware-ul. 5 Această abstractizare este cheia pentru gestionarea complexității. O bună abstractizare transformă o sarcină aproape imposibilă în două sarcini ușor de gestionat. Prima dintre aceste sarcini constă în definirea și implementarea abstracțiilor, iar cea de-a doua este utilizarea acestor abstracții pentru a rezolva problema curentă. O abstractizare pe care aproape orice utilizator de calculator o poate înțelege este fișierul menționat anterior. Acesta reprezintă un set de informații utile, de exemplu o fotografie digitală, un mesaj de e-mail salvat sau o pagină web. Fotografiile, e-mailurile și paginile web sunt mult mai ușor de utilizat decât discurile SATA (sau alte componente de disc). Sarcina unui sistem de operare este de a crea o abstractizare bună, iar apoi de a implementa și gestiona obiectele abstracte create în cadrul acestei abstractizări. În această carte, abstracțiunile vor avea o prioritate foarte mare, deoarece ele reprezintă una dintre cheile pentru înțelegerea sistemelor de operare. Având în vedere importanța acestui concept, merită să îl exprimăm în cuvinte ușor diferite. Cu tot respectul pentru proiectanții Macintosh, trebuie remarcat faptul că hardware-ul nu se evidențiază în mod deosebit prin finețe sau eleganță. Procesoarele, blocurile de memorie, discurile și alte componente din lumea reală sunt mult prea complexe, oferind interfețe dificile, incomode, incoerente și inconsistente pentru cei care trebuie să scrie cod pentru ele. Uneori, acest lucru se datorează necesității de a susține compatibilitatea retroactivă, alteori dorinței de a economisi bani, iar uneori, dezvoltatorii de hardware pur și simplu nu realizează (sau nu vor să realizeze) cât de multe probleme le creează dezvoltatorilor de software. Unul dintre obiectivele principale ale unui sistem de operare este de a ascunde hardware-ul și software-ul existent (și dezvoltatorii acestuia) sub abstracțiuni frumoase, elegante și neschimbătoare, care au fost create pentru a le înlocui și a funcționa corect. Sistemele de operare transformă urâțenia în frumusețe (figura 1.2). Fig. 1.2. Sistemul de operare transformă resursele tehnice urâte în abstracții frumoase Trebuie remarcat faptul că adevărații "beneficiari" ai sistemelor de operare sunt aplicațiile (desigur, nu fără ajutorul programatorilor de aplicații). Anume acestea sunt cei care lucrează direct cu sistemul de operare și cu abstracțiunile acestuia. Iar utilizatorii finali lucrează cu abstracțiunile oferite de interfața utilizatorului - fie o linie de comandă shell, fie o interfață grafică. Abstracțiunile interfeței utilizatorului pot fi similare abstracțiunilor furnizate de sistemul de operare, dar nu întotdeauna este cazul. Pentru a clarifica acest aspect, luați în considerare desktop-ul normal al SO Windows și linia de comandă. Ambele sunt programe care rulează pe sistemul de operare Windows și utilizează abstracțiile furnizate de acest sistem, dar oferă interfețe de utilizator semnificativ diferite. În mod similar, utilizatorii de Linux care rulează în 6 Gnome sau KDE văd o imagine total diferită decât utilizatorii de Linux care rulează pe X Window System, însă abstracțiunile care stau la baza SO sunt aceleași în ambele cazuri. În această carte vom studia în detaliu abstracțiunile disponibile pentru aplicații, dar nu ne vom aprofunda prea mult în interfețele cu utilizatorul. Acesta este un subiect complex și important, dar care are prea puțin de-a face cu sistemele de operare. 1.1.2 Sistemul de operare ca administrator de resurse Punctul de vedere conform căruia sistemul de operare oferă în principal abstracțiuni pentru programele de aplicații este o viziune de sus în jos (top down). Susținătorii punctului de vedere alternativ, de jos în sus (down-top), consideră că sistemul de operare există pentru a controla toate părțile unui sistem complex. Calculatoarele moderne sunt compuse din procesoare, memorie, cronometre, discuri, mouse-uri, interfețe de rețea, imprimante și o gamă largă de alte dispozitive. Susținătorii viziunii de jos în sus consideră că sarcina sistemului de operare este de a asigura o alocare ordonată și controlată a procesoarelor, memoriei și dispozitivelor de I/O între diversele programe care pretind să le utilizeze. Sistemele de operare moderne permit rularea simultană a mai multor programe. Imaginați-vă ce s-ar întâmpla dacă toate cele trei programe care rulează pe același computer ar încerca să tipărească simultan pe aceeași imprimantă. Primele câteva rânduri ale imprimării pot fi din programul nr. 1, următoarele câteva rânduri din programul nr. 2, apoi câteva rânduri din programul nr. 3 și așa mai departe. Rezultatul va fi un haos total. Sistemul de operare este conceput pentru a face ordine în haosul potențial prin stocarea pe disc a tuturor ieșirilor destinate imprimantei. Sistemul de operare dispune de o memorie tampon pe disc pentru toate datele de ieșire destinate imprimantei. Atunci când un program își termină activitatea sistemul de operare poate direcționa către imprimantă fișierul de pe disc în care au fost stocate datele programului și, în același timp, un alt program poate continua să genereze date către imprimantă fără să-și dea seama că ieșirea nu ajunge de fapt (pentru moment) la imprimantă. Atunci când mai mulți utilizatori lucrează cu un computer (sau o rețea) nevoile de gestionare și securizare a memoriei, intrărilor/ieșirilor și a altor resurse cresc dramatic. În caz contrar, utilizatorii vor interfera cu munca celorlalți. În plus, utilizatorii sunt adesea nevoiți să partajeze nu numai hardware-ul, dar și informațiile (fișiere, baze de date etc.). Pe scurt, susținătorii acestei viziuni asupre sistemului de operare consideră că sarcina principală a acestuia este de a ține evidența care program utilizează o resursă, pentru a satisface solicitările de resurse, fiind responsabil pentru utilizarea acestora și de a lua decizii cu privire la solicitările contradictorii din partea diferitor programe și utilizatori diferiți. Gestionarea resurselor implică multiplexarea (alocarea) resurselor în două moduri diferite: în timp și în spațiu. Atunci când o resursă este partajată în timp, diferite programe sau utilizatori o folosesc pe rând: mai întâi unul, apoi altul și așa mai departe. De exemplu, în cazul în care există un singur procesor și mai multe programe care încearcă să ruleze pe el, sistemul de operare alocă mai întâi procesorul unui program. După ce acesta a fost rulat suficient de mult timp, procesorul este alocat unui alt program, apoi unui al treilea program și tot așa. În cele din urmă, primul program poate primi din nou procesorul. Stabilirea exactă a modului în care resursa va fi alocată în timp - cine va fi următorul consumator și pentru cât timp - este sarcina sistemului de operare. Partajarea imprimantei reprezintă alt exemplu de multiplexare în timp. Atunci când în coada de așteptare a unei imprimante există mai multe lucrări de imprimare, trebuie să se decidă care va fi următoarea lucrare de tipărire. Un alt tip de partajare a resurselor este partajarea spațială. În loc să alterneze, fiecare client primește o parte din resursa partajată. De exemplu, memoria RAM este, de obicei, partajată 7 între mai multe programe în curs de execuție, astfel încât acestea să poată fi toate în memorie în orice moment (de exemplu, utilizând pe rând procesorul). Cu condiția să existe suficientă memorie pentru mai multe programe, este mai eficient să se aloce memoria mai multor programe simultan, decât să fie alocată toată memoria unui singur program, mai ales dacă acesta are nevoie doar de o mică parte din spațiul total. Desigur, în acest caz pot apărea probleme de partajare echitabilă, de securitate și așa mai departe, care trebuie rezolvate de sistemul de operare. O altă resursă partajată spațial este discul rigid. Mai multe sisteme permit stocarea fișierelor care aparțin diferitor utilizatori pe aceeași unitate în același timp. Alocarea spațiului pe disc și ținerea evidenței cine folosește care blocuri de disc este o sarcină tipică a unui sistem de operare. 1.2 Istoria sistemelor de operare Istoria sistemelor de operare datează de mulți ani. În următoarele compartimente ale acestei cărți vom discuta pe scurt câteva dintre principalele momente ale acestei evoluții. Deoarece sistemele de operare au apărut și au evoluat în procesul de creare a calculatoarelor, aceste evenimente sunt strâns legate din punct de vedere istoric. Din acest motiv, pentru a obține un tablou al dezvoltării sistemelor de operare, vom examina generațiile succesive de calculatoare. O atare schemă a relațiilor dintre generațiile de sisteme de operare și de calculatoare este foarte aproximativă, dar oferă o anumită structură fără de care ar fi complicat de înțeles ceva. Primul calculator digital adevărat a fost inventat de matematicianul englez Charles Babbage (1792-1871). Deși Babbage și-a petrecut cea mai mare parte a vieții construindu-și mașina analitică, acesta nu a reușit niciodată să o facă să funcționeze. Fiind o mașină pur mecanică, tehnologia din acea vreme nu era suficient de avansată pentru a realiza multe dintre piesele și mecanismele de mare precizie. Inutil să spunem că mașina sa nu avea un sistem de operare. Este un fapt istoric interesant că Babbage și-a dat seama că pentru o mașină analitică avea nevoie de software, așa că a angajat o tânără pe nume Ada Lovelace, fiica celebrului poet britanic George Byron. Dânsă a devenit primul programator din lume, iar limbajul de programare Ada®, creat în zilele noastre, a fost numit în cinstea ei. 1.2.1 Prima generatie (1945 - 1955): tuburi cu vid După eforturile nereușite ale lui Babbage, s-au înregistrat puține progrese în proiectarea calculatoarelor digitale până în timpul celui de-al Doilea Război Mondial, care a stimulat o explozie de lucrări în acest sens. Profesorul John Atanasoff și doctorandul său Clifford Berry au creat ceea ce este considerat în prezent primul calculator digital funcțional la Universitatea din Iowa. Acesta folosea 300 de tuburi electronice. Cam în aceeași perioadă, Konrad Zuse din Berlin a construit computerul Z3 bazat pe relee electromecanice. În 1944, un grup de oameni de știință (inclusiv Alan Turing) de la Bletchley Park din Marea Britanie a construit și programat “Colossus”, la Harvard Howard Aiken a construit ”Mark 1”, iar la Universitatea din Pennsylvania William Mauchley și doctorandul său John Presper Eckert au construit ”Eniac”. Unele dintre aceste mașini erau digitale, altele foloseau tuburi electronice, erau programabile dar destul de primitive și necesitau multe secunde pentru a produce chiar și cele mai simple calcule. La începuturile erei calculatoarelor, fiecare mașină era proiectată, construită, programată, operată și întreținută de același grup de persoane (de obicei ingineri). Toate programările se făceau exclusiv în limbajul mașinilor sau, chiar mai rău, prin asamblarea circuitelor electrice, iar mii de fire trebuiau conectate la panouri de conexiuni pentru a controla funcțiile de bază ale mașinilor. Limbajele de programare (chiar și cele de asamblare) nu erau încă cunoscute. Nimeni nu auzise niciodată de sisteme de operare. Modul de operare al programatorului era să 8 se înscrie pentru un anumit timp de lucru într-un registru special, apoi, cînd îi revine timpul, să coboare în camera de control, să-și conecteze panoul de patch-uri la computer și să petreacă următoarele câteva ore, sperând că niciunul dintre cele aproximativ 20 000 de tuburi electronice nu vor ieși din funcție în timpul procesului. În esență, toate sarcinile care trebuiau îndeplinite se reduceau la calcule matematice și numerice simple, cum ar fi precizrea tabelelor de sinusuri, cosinusuri și logaritmi sau calcularea traiectoriilor proiectilelor de artilerie. Când s-a propus folosirea cartelelor perforate, la începutul anilor 1950, situația s-a îmbunătățit oarecum. În loc să se folosească panouri de comutare, acum programele puteau fi scrise pe cartele și citite de pe acestea, dar în rest procedura de operare a rămas neschimbată. 1.2.2 A doua generație (1955 - 1965): tanzistoarele și tratarea pe loturi Inventarea tranzistoarelor în anul 1948 și introducerea lor în locul tuburilor cu vid (mijlocul anilor 1950) a schimbat radical situația. Calculatoarele au devenit suficient de fiabile pentru a putea fi fabricate ân scopuri comerciale, cu speranța că vor continua să funcționeze suficient de mult timp pentru a face o muncă utilă. Acuma se produce prima separare între proiectanți, constructori, operatori, programatori și personalul de întreținere. Aceste mașini, numite acum mainframe-uri, erau închise în săli mari speciale de calculatoare, cu aer condiționat, cu operatori profesioniști care să le gestioneze. Numai marile corporații, marile agenții guvernamentale sau universități își puteau permite să plătească prețul de mai multe milioane de dolari. Pentru a rula o lucrare (adică un program sau un set de programe), un programator scria mai întâi programul pe hârtie (în FORTRAN sau în limbaj de asamblare), îl transpunea pe cartele perforate, aducea pachetul de cartele în camera de introducere a datelor, îl înmâna unuia dintre operatori și se ducea să bea o cafea până când rezultatul era gata. Când execuția unei lucrări era încheiată, un operator se ducea la imprimantă, selecta listingul și îl ducea în camera de ieșire, astfel încât programatorul să-l poată prelua mai târziu. Apoi, operatorul lua unul dintre pachetele de cartele din camera de intrare și îl introducea. Dacă era nevoie de compilatorul FORTRAN, operatorul trebuia să îl ia dintr-un dulap de fișiere și să îl încarce în memoria calculatorului. Se pierdea mult timp cu calculatorul cu această plimbare a operatorilor prin sala de mașini. Având în vedere costul ridicat al echipamentului, nu este surprinzător faptul că oamenii au căutat rapid modalități de a reduce timpul pierdut. Soluția adoptată a fost tratarea pe loturi. Ideea era de a colecta o cutie plină de lucrări în camera de intrare și apoi de a le stoca pe o bandă magnetică folosind un calculator mic (relativ) ieftin, cum ar fi IBM 1401, care era destul de bun la citirea cartelelor, la copierea benzilor și la imprimarea rezultatelor, dar deloc bun la calcule numerice. Alte mașini mult mai scumpe, cum ar fi IBM 7094, erau fost folosite pentru calculul real. Această situație este prezentată în fig. 1-3. 9 Fig. 1-3. Tratarea pe loturi. (a) Programatorii aduc cartelele perforate la 1401. (b) 1401 citește lotul de lucrări pe bandă. (c) Operatorul duce banda de intrare la 7094. (d) 7094 efectuează calculul. (e) Operatorul duce banda de ieșire la 1401. (f) 1401 tipărește ieșirea. După aproximativ o oră de colectare a unui lot de lucrări, cardurile erau citite pe o bandă magnetică, care era transportată în sala mașinilor, unde era montată pe o unitate de bandă. Operatorul încărca apoi un program special (strămoșul sistemului de operare de astăzi), care citea prima lucrare de pe bandă și o executa. Rezultatul era scris pe o a doua bandă, în loc să fie tipărit. După ce o lucrare se termina, sistemul de operare citea automat următoarea lucrare de pe bandă și începea să o ruleze. Când întregul lot era gata, operatorul scotea benzile de intrare și de ieșire, înlocuia banda de intrare cu următorul lot și aducea banda de ieșire la un 1401 pentru imprimare off line (adică fără a fi conectată la calculatorul principal). Fig. 1.4. Structura unei lucrări în Fortran Monitor System (FMS) Structura unei sarcini de intrare (lucrări, job) tipice este prezentată în figura 1-4. Aceasta începe cu o cartelă $JOB, specificând timpul maxim de execuție în minute, numărul de cont care trebuie debitat și numele programatorului. Apoi venea o cartelă $FORTRAN, indicând sistemului de operare să încarce compilatorul FORTRAN de pe banda de sistem. Aceasta era urmată direct de programul care urma să fie compilat și apoi de o cartelă $LOAD, care indica sistemului de operare să încarce programul obiect tocmai compilat. (Programele compilate erau deseori scrise pe o bandă scratch1 și trebuiau să fie încărcate în mod explicit). Apoi venea cardul $RUN, care îi spunea sistemului de operare să ruleze programul cu datele care îl urmau. În cele din urmă, cardul $END marca sfârșitul lucrării. Aceste carduri de control primitive au fost precursorii shell-urilor moderne și ai interpretorilor de linii de comandă. 1 O bandă de scratch este o bandă magnetică care este utilizată pentru stocare temporară și care poate fi reutilizată sau ștearsă după finalizarea unei lucrări sau a unei execuții de procesare. 10 Computerele mari din a doua generație au fost utilizate în principal pentru calcule științifice și inginerești, cum ar fi rezolvarea ecuațiilor diferențiale parțiale care apar adesea în fizică și inginerie. Acestea erau în mare parte programate în FORTRAN și/sau în limbaj de asamblare. Sistemele de operare tipice erau FMS (Fortran Monitor System) și IBSYS, sistemul de operare al IBM pentru 7094. 1.2.3 Generatia a treia (1965 - 1980): Circuite integrate si multiprogramare La începutul anilor 1960 majoritatea producătorilor de calculatoare aveau două linii de produse distincte și incompatibile. Pe de o parte, existau computerele științifice de mari dimensiuni, orientate pe cuvinte, cum ar fi IBM 7094, care erau utilizate pentru calcule numerice de putere industrială în știință și inginerie. Pe de altă parte, erau computerele comerciale, orientate spre caractere, cum ar fi IBM 1401, utilizate pe scară largă pentru sortare și imprimare de către bănci și companii de asigurări. Dezvoltarea și întreținerea a două linii de produse complet diferite era o soluție costisitoare pentru producători. În plus, mulți clienți noi la început aveau nevoie de mașini mici, dar mai târziu doreau o mașină mai mare, care să le ruleze toate programele vechi, dar mai rapid. IBM a încercat să rezolve aceste două probleme dintr-o singură lovitură prin introducerea mașinilor System/360. Linia 360 era o serie de mașini compatibile cu software-ul de la modele 1401 până la unele mult mai mari, mai performante decât puternica 7094. Mașinile se deosebeau doar prin preț și performanță (capacitatea memoriei, viteza procesorului, numărul de dispozitive I/O permise și așa mai departe). Deoarece toate aveau aceeași arhitectură și același set de instrucțiuni, programele scrise pentru o mașină puteau rula pe toate celelalte - cel puțin în teorie. (Dar, așa cum se zice că a spus Yogi Berra: "În teorie, teoria și practica sunt la fel; în practică, nu sunt.") Deoarece System/360 a fost proiectat pentru a gestiona atât calculele științifice (numerice), cât și cele comerciale, o singură familie de mașini putea satisface nevoile tuturor clienților. În anii următori, IBM a scos pe piață succesori compatibili cu linia 360, folosind o tehnologie mai modernă, cunoscută sub numele de 370, 4300, 3080 și 3090. ZSeries este cel mai recent descendent al acestei linii, deși s-a îndepărtat considerabil de original. IBM 360 a fost prima linie majoră de calculatoare care a utilizat circuite integrate (de mici dimensiuni), oferind astfel un avantaj considerabil de preț/performanță față de mașinile din a doua generație, care erau construite din tranzistori individuali. A fost un succes imediat, iar ideea unei familii de computere compatibile a fost adoptată în scurt timp de toți ceilalți mari producători. Descendentele acestor mașini sunt utilizate și astăzi în centrele de calcul. În prezent, ele sunt adesea folosite pentru gestionarea unor baze de date uriașe (de exemplu, pentru sistemele de rezervare a companiilor aeriene) sau ca servere pentru site-urile World Wide Web care trebuie să proceseze mii de cereri pe secundă. Cel mai mare avantaj al ideii ''familiei unice'' a reprezentat în același timp și cea mai mare slăbiciune a acesteia. Intenția inițială era ca toate programele, inclusiv sistemul de operare, OS/360, să funcționeze pe toate modelele. Sistemul de operare trebuia să funcționeze pe sisteme mici, care adesea înlocuiau doar 1401 pentru copierea cartelelor perforate pe bandă și pe sisteme foarte mari, care înlocuiau 7094 pentru a face prognoze meteo și alte calcule grele, să funcționeze atât pe sisteme cu puține periferice, cât și pe sisteme cu multe periferice, să funcționeze în medii comerciale și în medii științifice. Plus la toate, trebuia să fie eficiente pentru toate aceste utilizări diferite. IBM (sau oricine altcineva, de altfel) nu avea cum să scrie un software care să îndeplinească toate aceste cerințe contradictorii. Rezultatul a fost un sistem de operare enorm și extraordinar de complex, probabil cu două-trei ordine de mărime mai mare decât FMS. Acesta era format 11 din milioane de linii de cod scrise de mii de programatori și conținea mii și mii de erori, care necesitau un flux continuu de noi versiuni în încercarea de a le corecta. Fiecare nouă versiune corecta unele erori și introducea altele noi, astfel încât numărul de erori rămânea probabil constant în timp. Unul dintre proiectanții OS/360, Fred Brooks, a scris ulterior o carte spirituală și incisivă (Brooks, 1995) în care descrie experiența proprie cu OS/360. Deși ar fi imposibil să rezumăm cartea aici, este suficient să spunem că pe copertă apare o turmă de animale preistorice blocate într-o groapă cu smoală. Coperta cărții lui Silberschatz et al. (2012) face o remarcă similară cu privire la faptul că sistemele de operare sunt dinozauri. În ciuda dimensiunii și a problemelor sale enorme, OS/360 și sistemele de operare similare din a treia generație produse de alți producători de calculatoare satisfăceau de fapt destul de bine majoritatea cerințelor clienților. Mai mult, aceste sisteme de operare au făcut populare mai multe tehnici-cheie absente în sistemele de operare din generația a doua. Probabil cea mai importantă dintre acestea a fost multiprogramarea. Pe mașina 7094, atunci când lucrarea curentă se întrerupea pentru a aștepta finalizarea intrării de pe o bandă sau a unei alte operațiuni de intrare/ieșire, unitatea centrală de procesare stătea pur și simplu inactivă până la terminarea operațiunii de intrare/ieșire. În cazul calculelor științifice puternic legate de procesor, I/O nu sunt frecvente, astfel încât acest timp pierdut nu este semnificativ. Însă, la prelucrarea datelor comerciale, timpul de așteptare pentru I/O poate reprezenta adesea 80 sau 90% din timpul total, așa că trebuia să se facă ceva pentru a evita ca procesorul (costisitor) să fie atât de mult timp inactiv. Soluția acestei probleme a fost de a împărți memoria în mai multe părți,numite partiții, cu o sarcină diferită în fiecare partiție, așa cum este prezentat în figura 1-5. Fig. 1.5. Sistem multitasking cu trei lucrări în memorie În timp ce o lucrare aștepta finalizarea I/O, o altă lucrare putea utiliza procesorul. Dacă în memoria principală se puteau afla simultan suficiente lucrări, procesorul central putea fi ținut ocupat aproape 100% din timp. Pentru a avea simultan mai multe lucrări în memorie erau necesare mecanisme hardware speciale care să asigure protecția reciprocă între lucrări. Calculatoarele din seria 360 și alte sisteme din generația a treia erau echipate cu astfel de mecanisme. O altă caracteristică importantă a sistemelor de operare din generația a treia era capacitatea de a citi lucrările de pe cartelele perforate pe disc imediat ce erau aduse în sala de calculatoare. Apoi, ori de câte ori o lucrare în curs de execuție se termina, sistemul de operare putea încărca o nouă lucrare de pe disc în partiția acum goală și o putea executa. Această tehnică se numește spooling (de la Simultaneous Peripheral Operation On Line) și era utilizată și pentru ieșire. Cu introducerea spooling-ului, nu mai era nevoie de mașina 1401 și a dispărut o mare parte din lucrul cu benzile. 12 Deși sistemele de operare din generația a treia erau potrivite pentru calcule științifice de mare anvergură și pentru execuții masive de procesare a datelor comerciale, acestea erau încă sisteme de tip batch. Mulți programatori tânjeau după zilele primei generații, când aveau mașina numai pentru ei timp de câteva ore, pentru a-și putea depana rapid programele. În cazul SO din generația a treia, timpul dintre trimiterea unei sarcini și obținerea rezultatelor era adesea de câteva ore, astfel încât o singură virgulă greșit plasată putea face ca o compilare să eșueze, iar programatorul să piardă jumătate de zi. Programatorilor nu le plăcea acest lucru. Această dorință de a avea un răspuns rapid a deschis calea pentru timesharing, o variantă de multiprogramare, în care fiecare utilizator are un terminal online. Într-un sistem de timesharing, dacă 20 de utilizatori sunt conectați și 17 dintre ei gândesc, vorbesc sau beau cafea, unitatea centrală poate fi alocată succesiv celor trei joburi care doresc să fie deservite. Deoarece oamenii care depanează programe emit de obicei comenzi scurte (de exemplu, compilați o procedură de cinci pagini2) mai degrabă decât comenzi lungi (de exemplu, sortați un fișier cu un milion de înregistrări), calculatorul poate oferi servicii rapide și interactive unui număr de utilizatori și, poate, de asemenea, să lucreze la sarcini mari de lucru pe loturi în fundal, atunci când procesorul este liber. Primul sistem de uz general cu partajarea timpului, CTSS (Compatible Time Sharing System), a fost dezvoltat la M.I.T. pe un 7094 special modificat (Corbato´ și al., 1962). Totuși timesharing-ul a devenit cu adevărat popular doar atunci când hardware-ul de protecție reciprocă necesar a fost implementat pe larg. După succesul sistemului CTSS, M.I.T., Bell Labs și General Electric (la acea vreme un important producător de calculatoare) au decis să se lanseze în dezvoltarea unui ''calculator utilitar'', adică a unei mașini care să suporte câteva sute de utilizatori simultani. Ei s-au inspirat din sistemul energetic - atunci când ai nevoie de energie electrică, nu trebuie decât să introduci ștekerul în priză și, în limitele rezonabile, va exista atâta energie cât ai nevoie. Proiectanții acestui sistem, cunoscut sub numele de MULTICS (MULTiplexed Information and Computing Service), au avut în vedere o mașină uriașă care să ofere putere de calcul pentru toți locuitorii din zona Boston. Ideea că mașinile de 10.000 de ori mai rapide decât mainframe-ul lor GE-645 vor fi vândute (pentru mult sub 1.000 de dolari) cu milioanele era pe atunci din domeniul science fiction, și va fi implementată doar 40 de ani mai târziu. Foarte asemănătoare cu ideea trenurilor supersonice subacvatice transatlantice. MULTICS a avut un succes discutabil. A fost conceput pentru a susține sute de utilizatori pe o mașină doar puțin mai puternică decât un PC cu Intel 386, deși avea o capacitate de I/O mult mai mare. Era o idee nu chiar trăsnită la vremea respectivă, deoarece oamenii de atunci erau capabili să creeze programe mici și eficiente, adică aveau o abilitate care s-a pierdut între timp. Au existat multe motive pentru care MULTICS nu a cucerit lumea, printre care nu ultimul fiind acela că a fost scris în limbajul de programare PL/I compilator pentru care a apărut doar peste câțiva ani, iar prima lui versiune poate fi numită funcțională doar cu mari rezerve. În plus, MULTICS a fost extrem de ambițios pentru epoca sa, la fel ca mașina analitică a lui Charles Babbage în secolul al XIX-lea. MULTICS a introdus multe idei fundamentale în informatică, dar transformarea sa într-un produs serios și într-un succes comercial major s-a dovedit a fi mult mai dificilă decât era de așteptat. Bell Labs a renunțat la proiect, iar General Electric a renunțat cu totul la afacerea cu calculatoare. Cu toate acestea, M.I.T. a persistat și a reușit să facă MULTICS să funcționeze. În cele din urmă acesta a fost vândut ca produs comercial unei companii (Honeywell), care a cumpărat afacerea cu calculatoarele de la General Electric și a instalat aproximativ 80 de copii 2 În această carte vom folosi termenii “procedură”, “subrutină” și “funcție” având același sens. 13 pe calculatoarele unor companii și universități importante din întreaga lume. Deși numărul de utilizatori MULTICS era mic, aceștia au dat dovadă de un angajament ferm față de sistem. De exemplu, General Motors, Ford și Agenția Națională de Securitate a SUA au renunțat la MULTICS abia la sfârșitul anilor '90, la 30 de ani de la lansare și după mai mulți ani în care au încercat să convingă Honeywell să actualizeze hardware-ul. Spre sfârșitul secolului XX, ideea de a crea un astfel de calculator utilitar s-a stins, dar s-ar putea să revină sub forma cloud computing, în care computere relativ mici (inclusiv smartphone-uri, tablete și altele asemenea) sunt conectate la servere din centre de date vaste și îndepărtate, unde se realizează toate calculele, computerul local ocupându-se doar de interfața cu utilizatorul. Motivația în acest caz este că majoritatea oamenilor nu doresc să administreze sisteme informatice tot mai complexe și mai pretențioase și preferă ca această muncă să fie efectuată de o echipă de profesioniști, de exemplu, persoane care lucrează pentru compania care administrează centrul de date. Comerțul electronic evoluează deja în această direcție, diverse companii rulează e-mailuri pe servere multiprocesor la care se conectează mașini client simple, în spiritul proiectului MULTICS. În ciuda lipsei de succes comercial, MULTICS a avut o influență uriașă asupra sistemelor de operare ulterioare (în special UNIX și derivatele sale, FreeBSD, Linux, iOS și Android). Acesta este descris în mai multe lucrări și într-o carte (Corbato´ et al., 1972; Corbato´ și Vyssotsky, 1965; Daley și Dennis, 1968; Organick, 1972; și Saltzer, 1974). Are, de asemenea, un site web activ, aflat la adresa www.multicians.org, cu informații despre sistem, proiectanți și utilizatori. O altă evoluție majoră în timpul celei de-a treia generații a fost creșterea fenomenală a minicalculatoarelor, începând cu DEC PDP-1 în 1961. PDP-1 avea doar 4K de cuvinte pe 18 biți, dar la 120.000 de dolari pentru o mașină (mai puțin de 5% din prețul unui 7094), s-a vândut ca pâinea caldă. Pentru anumite tipuri de lucrări nenumerice, era aproape la fel de rapid ca 7094 și a dat naștere unei noi industrii. A fost urmat rapid de o serie de alte PDP-uri (spre deosebire de familia IBM, toate incompatibile) culminând cu PDP-11. Unul dintre informaticienii de la Bell Labs care lucrase la proiectul MULTICS, Ken Thompson, a găsit ulterior un mic minicalculator PDP-7 pe care nu-l folosea nimeni și a început să scrie o versiune simplificată, pentru un singur utilizator, a sistemului MULTICS. Această lucrare s-a transformat mai târziu în sistemul de operare UNIX, care a devenit popular în lumea academică, în agențiile guvernamentale și în multe companii. Istoria dezvoltării SO UNIX a fost în repetate rânduri povestită în multe cărți (de exemplu, Salus, 1994). O parte din această poveste va fi prezentată în Cap. 10. Deocamdată, este suficient să spunem că, deoarece codul sursă era pe larg disponibil, diverse organizații și-au dezvoltat propriile versiuni (incompatibile), ceea ce a dus la un haos total. Au fost dezvoltate două versiuni de bază, System V, de la AT&T, și BSD (Berkeley Software Distribution) de la Universitatea California din Berkeley. Acestea au avut și unele variante minore. Pentru a face posibilă scrierea de programe care să ruleze pe orice sistem UNIX, Institutul Inginerilor Electrotehniști și Electroniști (IEEE) a dezvoltat un standard pentru UNIX, numit POSIX, pe care majoritatea versiunilor UNIX îl acceptă în prezent. POSIX definește o interfață minimă pentru apelurile de sistem pe care sistemele UNIX compatibile trebuie să o suporte. De fapt, în prezent și alte sisteme de operare suportă interfața POSIX. Ca o paranteză, merită menționat faptul că, în 1987, autorul acestei cărți a lansat o mică clonă de UNIX, numită MINIX, în scopuri educaționale. Din punct de vedere funcțional, MINIX este foarte asemănător cu UNIX, inclusiv respectă POSIX. De atunci, versiunea originală a evoluat în MINIX 3, care este foarte modular și are o fiabilitate foarte ridicată. Acesta are capacitatea de 14 a detecta și înlocui din mers modulele defecte sau chiar prăbușite (cum ar fi driverele de dispozitive I/O) fără repornire și fără a perturba programele în execuție. De asemenea, este disponibilă o carte care descrie funcționarea sa internă și listează codul sursă într-o anexă (Tanenbaum și Woodhull, 2006). Sistemul MINIX 3 este disponibil gratuit (inclusiv codul sursă) la adresa www.minix3.org. Dorința de a avea o versiune industrială gratuită (spre deosebire de cea educațională) a sistemului MINIX l-a determinat pe un student finlandez, Linus Torvalds, să scrie Linux. Acest sistem a fost inspirat direct din MINIX și dezvoltat pe baza acestuia, suportând inițial diverse caracteristici MINIX (de exemplu, sistemul de fișiere MINIX). De atunci, a fost extins în multe feluri de către multe persoane, dar a păstrat în continuare o anumită structură de bază comună cu MINIX și cu UNIX. Cititorii interesați de o istorie detaliată a SO Linux și a mișcării Open Source pot citi cartea lui Glyn Moody (2001). Cea mai mare parte din ceea ce se va spune despre UNIX aici se aplică la System V, MINIX, Linux și alte versiuni și clone de UNIX. 1.2.4 Generatia a patra (1980 - până în prezent). Calculatoare personale Următoarea perioadă în evoluția sistemelor de operare este asociată apariției circuitelor integrate mari (LSI, Large Scale Integration- Integrare pe scară largă) - cipuri de siliciu care conțin mii de tranzistori pe centimetru pătrat. Din punct de vedere al arhitecturii, calculatoarele personale (denumite inițial microcalculatoare) semănau foarte mult cu minicalculatoarele din clasa PDP-11, dar, bineînțeles, cu un preț diferit. În timp ce apariția minicalculatoarelor a permis departamentelor de companii și universități să dețină un calculator, apariția microprocesoarelor a oferit tuturor posibilitatea de a cumpăra un calculator personal. În 1974, la lansarea microprocesorului Intel 8080, prima unitate centrală de procesare pe 8 biți de uz general, Intel avea nevoie de un sistem de operare care să poată fi folosit pentru a-l testa. Intel l-a angajat pe unul dintre consultanții săi, Gary Kildall, pentru a proiecta și a scrie sistemul de operare necesar. Kildall cu un prieten au proiectat mai întâi un controler pentru o unitate de dischetă de 8 inchi recent lansată de Shugart Associates și au atașat unitatea la un procesor Intel 8080. Astfel s-a născut primul microcalculator cu unitate de disc. Kildall a creat apoi un sistem de operare pe disc numit CP/M (Control Program for Microcomputers). Atunci când Kildall și-a revendicat drepturile asupra CP/M, Intel i-a acceptat cererea deoarece nu credea că microcalculatoarele cu disc rigid au un viitor. Ulterior, Kildall a format Digital Research pentru a dezvolta și vinde CP/M. În 1977, Digital Research a reproiectat CP/M pentru a-l face potrivit pentru microcalculatoarele cu Intel 8080, Zilog Z80 și alte procesoare. Multe programe de aplicații au fost scrise pentru a rula pe CP/M, permițând sistemului să dețină poziția de top în lumea microcalculatoarelor timp de 5 ani. La începutul anilor 1980, IBM a dezvoltat IBM PC (Personal Computer – calculator personal)3 și a început să caute software pentru acesta. Personalul IBM l-a contactat pe Bill Gates pentru a obține o licență de utilizare a interpretorului său pentru limbajul BASIC. De asemenea, l-au întrebat dacă poate știe de un sistem de operare care să funcționeze pe un IBM PC. Gates i-a sfătuit să meargă la Digital Research, pe atunci principala companie de sisteme de operare. Dar Kildall a refuzat să se întâlnească cu IBM, trimițându-și în schimb subalternul. Pentru a înrăutăți lucrurile, avocatul său a refuzat chiar să semneze un acord de confidențialitate în ceea 3 Este important de reținut că, în acest caz, "IBM PC" este numele unui anumit model de calculator, în timp ce "PC" poate fi considerat ca o abreviere pentru "Personal Computer", o denumire a unei clase de calculatoare. Denumirea consacrată a acestui model ca fiind pur și simplu "PC" nu este corectă - în aceeași perioadă existau și alte calculatoare personale. 15 ce privește IBM PC-ul care urma să fie lansat, distrugând complet cazul. Corporația IBM i-a cerut din nou lui Gates să îi furnizeze un sistem de operare. După o a doua solicitare, Gates a aflat că un producător local de calculatoare, Seattle Computer Products, avea un sistem DOS (Disk Operating System). S-a dus la acea companie cu o ofertă de a cumpăra DOS (ar fi fost vorba de $50.000), pe care Seattle Computer Products a acceptat-o cu bucurie. Gates a creat apoi pachetul software DOS/BASIC, care a fost cumpărat de IBM. Când IBM a vrut să aducă unele îmbunătățiri la sistemul de operare, Bill Gates l-a invitat pe Tim Paterson, cel care a scris DOS și care a devenit primul angajat al Microsoft, compania nou înființată de Gates. Sistemul modificat a fost redenumit în MS-DOS (MicroSoft Disk Operating System) și a devenit rapid dominant pe piața PC-urilor IBM. Decisivă a fost decizia lui Gates (extrem de înțeleaptă) să vândă sistemul de operare MS-DOS companiilor de calculatoare pentru a fi instalat împreună cu hardware-ul lor, spre deosebire de încercarea lui Kildall de a vinde CP/M direct utilizatorilor finali (cel puțin la început). Atunci când în anul 1983 a apărut IBM PC/AT (o dezvoltare ulterioară a familiei IBM PC) cu un procesor Intel 80286, MS-DOS era deja bine stabilit, iar CP/M își ducea ultimele sale zile. Ulterior, MS-DOS a fost utilizat pe scară largă pe calculatoarele cu procesoarele 80386 și 80486. Deși versiunea originală a MS-DOS era mai degrabă primitivă, versiunile ulterioare erau mult mai avansate, multe dintre acestea fiind împrumutate de la UNIX. (Corporația Microsoft cunoștea foarte bine SO UNIX, în primii ani chiar a vândut o versiune UNIX pentru microcalculatoare - XENIX.) CP/M, MS-DOS și alte sisteme de operare pentru primele microcalculatoare erau bazate în întregime pe comenzi de la tastatură. Cu timpul, datorită cercetărilor efectuate în anii 1960 de Doug Engelbart de la Stanford Research Institute, această situație s-a schimbat. Engelbart a inventat interfața grafică cu utilizatorul (GUI) cu ferestre, pictograme, sisteme de meniuri și mouse-ul. Cercetătorii de la Xerox PARC au preluat această idee și au folosit-o în mașinile pe care le-au construit. Într-o zi, Steve Jobs, unul dintre autorii computerului Apple proiectat în garajul său, a vizitat PARC, unde a văzut GUI-ul și a realizat imediat potențialul pe care aceasta o deținea, potențial subestimat de conducerea Xerox. Jobs a demarat apoi crearea unui computer Apple echipat cu interfața grafică. Acest proiect a dus la crearea computerului Lisa, care a fost prea scump și nu a avut succes comercial. A doua încercare a lui Jobs, computerul Apple Macintosh, a fost un succes nu numai pentru că era mult mai ieftin decât Lisa, ci și pentru că avea o interfață de utilizator mai prietenoasă, concepută pentru utilizatorii care nu erau familiarizați cu computerele și care nu erau dornici să învețe nimic. Macintosh a cunoscut o susținere semnificativă în rândul persoanelor creative - designeri grafici, fotografi digitali profesioniști și companii profesionale de producție video digitală - care l-au adoptat. În 1999, Apple a împrumutat nucleul derivat din microkernelul Mach dezvoltat inițial de Universitatea Carnegie Mellon pentru a înlocui nucleul BSD UNIX. Prin urmare, Mac OS X este un sistem de operare bazat pe UNIX, deși cu o interfață foarte specială. Când Microsoft a decis să creeze un succesor pentru MS-DOS, a fost foarte impresionată de succesul lui Macintosh. Rezultatul a fost un sistem bazat pe o interfață grafică cu utilizatorul, numită Windows, care a fost inițial un add-on pentru MS-DOS (adică mai mult un shell decât un sistem de operare propriu-zis). Timp de aproximativ 10 ani, din 1985 până în 1995, Windows a fost doar un shell grafic peste MS-DOS. Dar, în 1995 a fost lansată o versiune independentă Windows - SO Windows 95. Acesta îndeplinea direct majoritatea funcțiilor sistemului de operare, folosind sistemul MS-DOS inclus doar pentru a porni și a rula programe vechi concepute pentru MS-DOS. În 1998, a fost lansată o versiune ușor modificată a sistemului, 16 numită Windows 98. Cu toate acestea, atât Windows 95, cât și Windows 98 conțineau încă o cantitate destul de mare de cod de asamblare scris pentru procesoarele Intel pe 16 biți. Celălalt sistem de operare Microsoft a fost Windows NT (NT înseamnă New Technology), care era, într-o anumită măsură, compatibil cu Windows 95. Windows NT a fost rescris și a devenit un sistem complet pe 32 de biți. Principalul dezvoltator al Windows NT a fost David Cutler, co- dezvoltătorul sistemului de operare VAX VMS, astfel încât unele idei din VMS sunt prezente în NT (atât de mult încât proprietarul VMS, DEC, a dat în judecată Microsoft. Conflictul a fost soluționat pe cale amiabilă pentru o sumă decentă). Microsoft se aștepta ca prima versiune să înlocuiască MS-DOS și toate celelalte versiuni de Windows, deoarece era mult superioară, dar așteptările nu au fost îndeplinite. Doar Windows NT 4.0 a reușit în cele din urmă să câștige o popularitate ridicată, în special în rețelele corporative. Cea de-a cincea versiune a Windows NT a fost redenumită Windows 2000 la începutul anului 1999. Aceasta a fost destinată să înlocuiască atât Windows 98, cât și Windows NT 4.0. Dar aceste planuri nu erau sortite să se împlinească în totalitate, așa că Microsoft a lansat o altă versiune de Windows 98, numită Windows Me (Millennium edition). În 2001 a fost lansată o versiune ușor actualizată a Windows 2000, numită Windows XP. Această versiune a fost lansată pentru o perioadă mult mai lungă, înlocuind practic toate versiunile anterioare de Windows. Cu toate acestea, noi versiuni au continuat să fie lansate. După Windows 2000, Microsoft a împărțit familia Windows într-o linie de produse pentru clienți și una pentru servere. Linia bazată pe client se baza pe XP și succesorii săi, în timp ce linia bazată pe server era formată din Windows Server 2003 și Windows 2008. Puțin mai târziu a apărut o a treia linie destinată lumii sistemelor de operare incorporate. Variațiile sub formă de service pack-uri au fost separate de toate aceste versiuni de Windows. Acest lucru a fost suficient pentru a-i liniști pe unii administratori (și pe autorii manualelor de sisteme de operare). Apoi, în ianuarie 2007, Microsoft a lansat o versiune finală a succesorului Windows XP, numită Vista. Avea o nouă interfață grafică, o securitate îmbunătățită și multe programe de utilizator noi sau actualizate. Microsoft a sperat că va înlocui complet Windows XP, dar nu a reușit. În schimb, a primit numeroase critici și articole de presă, în special din cauza cerințelor de sistem ridicate, a condițiilor restrictive de acordare a licențelor și a suportului pentru tehnologia de protecție a drepturilor de autor (tehnologie care îngreunează copierea de către utilizatori a materialelor protejate). Odată cu apariția lui Windows 7, un sistem de operare nou și mai puțin pretențios, mulți au decis să renunțe complet la Vista. Windows 7 nu a introdus multe caracteristici noi, dar a fost relativ mic și destul de stabil. Windows 7 a câștigat mai multă cotă de piață în mai puțin de trei săptămâni decât a câștigat Vista în șapte luni. În 2012, Microsoft a lansat succesorul lui Windows 7, Windows 8 - un sistem de operare cu un aspect complet nou, conceput pentru ecrane tactile. Compania a sperat că noul design va face din sistemul de operare o alegere dominantă pentru o gamă largă de dispozitive: desktop-uri, laptop-uri, tablete, telefoane și computere personale folosite ca home theater. Dar, până în prezent, pătrunderea sa pe piață a fost mult mai lentă decât în cazul Windows 7. Celălalt concurent principal din lumea PC-urilor este sistemul de operare UNIX (și diferitele sale derivate). UNIX are o poziție mai puternică pe serverele de rețea și industriale, dar devine din ce în ce mai răspândit și pe desktop-uri, laptop-uri, tablete și smartphone-uri. Pe computerele cu procesor Pentium, sistemul de operare Linux devine o alternativă populară la Windows pentru studenți și pentru un număr tot mai mare de utilizatori corporativi. 17 În această carte, termenul x86 va fi aplicat tuturor procesoarelor moderne bazate pe familia de arhitecturi cu seturi de instrucțiuni provenite de la procesorul 8086 creat în anii 1970. Companiile AMD și Intel au produs o mulțime de astfel de procesoare care, de multe ori, se deosebesc considerabil: procesoarele pot fi pe 32 sau 64 de biți, cu un număr mic sau mare de nuclee, cu o adâncime diferită a conveierilor etc. Totuși, ele sunt destul de asemănătoare pentru un programator și toate pot rula codul unui procesor 8086 scris acum 35 de ani. În cazul în care diferențele joacă un rol important, se vor face referiri la modele specifice, iar termenii x86-32 și x86-64 vor fi utilizați pentru a indica variantele pe 32 și 64 de biți. Sistemul de operare FreeBSD este, de asemenea, un derivat popular al SO UNIX, creat în cadrul proiectului BSD de la Berkeley. Toate computerele Macintosh moderne rulează o versiune modificată a FreeBSD (OS X). UNIX este, de asemenea, SO standard pe stațiile de lucru echipate cu procesoare RISC de înaltă performanță. Derivatele sale au fost utilizate pe scară largă pe dispozitivele mobile care rulează iOS 7 sau Android. În timp ce mulți utilizatori UNIX, în special programatori experimentați, preferă o interfață bazată pe linia de comandă, aproape toate sistemele UNIX acceptă sistemul X Window (sau X11), creat la Massachusetts Institute of Technology. Acest sistem efectuează operațiuni de bază de control al ferestrelor, permițând utilizatorilor să creeze, să șteargă, să mute și să redimensioneze ferestrele cu ajutorul mouse-ului. Adesea, o interfață grafică completă pentru utilizator, cum ar fi Gnome sau KDE, poate fi utilizată ca un add-on la X11, conferind UNIX un aspect și o senzație oarecum asemănătoare cu Macintosh sau Microsoft Windows. La mijlocul anilor 1980, a început să se dezvolte un fenomen interesant - creșterea rețelelor de calculatoare personale care rulează sisteme de operare de rețea și sisteme de operare distribuite (Tanenbaum și Van Steen, 2007). În sistemele de operare de rețea, utilizatorii sunt conștienți de existența mai multor calculatoare și se pot conecta la un calculator la distanță și pot copia fișiere de pe un calculator pe altul. Fiecare mașină rulează propriul sistem de operare local și are propriul utilizator(i) local(i). Sistemele de operare de rețea nu sunt semnificativ diferite de sistemele de operare cu un singur procesor. În mod evident, acestea au nevoie de un controler de interfață de rețea și de un software de nivel scăzut pentru a opera acest controler, precum și de programe pentru a se conecta la mașina de la distanță și a accesa fișiere de la distanță, dar aceste adăugiri nu schimbă structura de bază a sistemului de operare. În schimb, un sistem de operare distribuit se prezintă utilizatorilor săi ca un sistem tradițional cu un singur procesor, când, de fapt, este format din mai multe procesoare. Utilizatorii nu trebuie să știe unde rulează programele lor sau unde se află fișierele lor - toate acestea trebuie să fie gestionate automat și eficient de către sistemul de operare însuși. Adevăratele sisteme de operare distribuite necesită mult mai multe modificări decât simpla adăugare a unei cantități mici de cod la un sistem de operare cu un singur procesor, deoarece sistemele distribuite și cele centralizate sunt foarte diferite. De exemplu, sistemele distribuite permit adesea ca aplicațiile să ruleze simultan pe mai multe procesoare, ceea ce necesită algoritmi mai complecși pentru a distribui munca procesoarelor în vederea optimizării gradului de procesare paralelă a datelor. Prezența latenței (întârzierilor) în transmiterea datelor în rețea implică adesea faptul că acești (și alți) algoritmi trebuie să funcționeze în condiții de informații incomplete, depășite sau chiar incorecte. Această situație este fundamental diferită de cea a unui sistem cu un singur procesor. 18 1.2.5 Generația a cincea (din 1990 până în prezent): calculatoarele mobile Încă de pe timpurile benzilor desenate din anii 1940 când detectivul Dick Tracy a început să comunice folosind un radioemițător montat în ceasul de mână, oamenii au dorit un dispozitiv de comunicare pe care să-l poată purta cu ei oriunde mergeau. Primul telefon mobil adevărat a apărut în 1946 și cântărea aproximativ 40 de kilograme. Îl puteai lua cu tine oriunde te duceai, dacă aveai o mașină în care să îl transporți. Primul telefon portabil cu adevărat a apărut în anii 1970 și, cântărind aproximativ un kilogram, a fost acceptat relativ pozitiv. Era cunoscut cu afecțiune sub numele de "cărămidă". Curând, toată lumea și-a dorit unul. Astăzi, gradul de penetrare a telefoanelor mobile este de aproape 90% din populația globală. Putem efectua apeluri nu doar cu telefoanele noastre portabile și cu ceasurile de mână, ci în curând și cu ochelarii și alte obiecte portabile. În plus, partea cu telefonul nu mai este atât de interesantă. Primim e-mailuri, navigăm pe internet, trimitem mesaje text prietenilor noștri, ne jucăm în jocuri, și aflăm despre cât de aglomerat este traficul fără să ne mai mire toate astea. Deși ideea de a combina telefonul și calculatorul într-un singur dispozitiv exista încă din anii 1970, primul smartphone real a apărut abia la mijlocul anilor 1990, când Nokia a lansat N9000, care a combinat la propriu două dispozitive în mare parte separate: un telefon și un PDA (Personal Digital Assistant). În 1997, Ericsson a inventat termenul de smartphone pentru modelul său GS88 ''Penelope''. Acum, când smartphone-urile au devenit omniprezente, concurența dintre diferite sisteme de operare este acerbă, iar rezultatul este chiar mai puțin clar decât în lumea PC-urilor. Când sunt redactate aceste rânduri, Android de la Google este sistemul de operare dominant, iar iOS de la Apple este clar pe locul al doilea, dar nu a fost întotdeauna așa și s-ar putea ca totul să fie din nou diferit în doar câțiva ani. Dacă ceva este clar în lumea smartphone-urilor, este faptul că nu este ușor să rămâi regele muntelui pentru mult timp. Majoritatea smartphone-urilor din primul deceniu de la înființare rulau Symbian OS. Acesta a fost sistemul de operare ales de mărci populare precum Samsung, Sony Ericsson, Motorola și, mai ales, Nokia. Cu toate acestea, alte sisteme de operare precum Blackberry OS de la RIM (introdus pentru smartphone-uri în 2002) și iOS de la Apple (lansat pentru primul iPhone în 2007) au început să preia cota de piață de la Symbian. Mulți se așteptau ca RIM să domine piața de afaceri, în timp ce iOS va fi regele dispozitivelor de consum. Cota de piață a Symbian s-a prăbușit. În 2011, Nokia a renunțat la Symbian și a anunțat că se va concentra pe Windows Phone ca platformă principală. Pentru o perioadă, Apple și RIM au fost cele mai tari (deși nu la fel de dominante precum fusese Symbian), dar nu a durat foarte mult până când Android, un sistem de operare bazat pe Linux lansat de Google în 2008, să își depășească toți rivalii. Pentru producătorii de telefoane, Android avea avantajul de a fi open source și disponibil sub o licență permisivă. Prin urmare, aceștia puteau să îl modifice și să-l adapteze cu ușurință la propriul hardware. De asemenea, dispune de o comunitate uriașă de dezvoltatori care scriu aplicații, majoritatea în limbajul de programare Java, care le este familiar. Chiar și așa, ultimii ani au arătat că această dominație ar putea să nu dureze, iar concurenții Android sunt dornici să recupereze o parte din cota de piață. Vom analiza Android în detaliu în secțiunea 10.8. 1.3 Notiuni din domeniul resurselor fizice ale calculatorului Un sistem de operare este strâns legat de hardware-ul computerului pe care rulează. Acesta extinde setul de instrucțiuni al computerului și îi gestionează resursele. Pentru corecta funcționare sunt necesare cunoștințe adânci despre hardware, cel puțin despre modul în care 19 acesta apare în ochii programatorului. Din acest motiv, haideți să trecem în revistă pe scurt resurselor fizice ale calculatorului care intră în componența calculatoarelor personale moderne. După aceasta vom putea începe studiul detaliat a ceea ce fac și cum funcționează sistemele de operare. Din punct de vedere conceptual, un computer personal simplu poate fi abstractizat la un model asemănător cu cel din figura 1-6. Fig. 1.6. Componentele unui calculator personal Unitatea centrală, memoria și dispozitivele I/O sunt conectate cu ajutorul magistralei (bus) de sistem și comunică între ele prin intermediul acesteia. Calculatoarele personale moderne au o structură mai complicată, care implică mai multe magistrale, pe care le vom examina mai târziu. Deocamdată, acest model va fi suficient. În secțiunile următoare, vom trece în revistă pe scurt aceste componente și vom examina unele dintre problemele hardware care îi preocupă pe proiectanții de sisteme de operare. Inutil să mai spunem că acesta va fi un rezumat foarte compact. S-au scris multe cărți pe tema hardware-ului și a organizării calculatoarelor. Două dintre cele mai cunoscute sunt Tanenbaum și Austin (2012) și Patterson și Hennessy (2013). 1.3.1 Procesoarele Unitatea centrală de procesare (procesorul) este 'creierul'' calculatorului. Acesta preia instrucțiunile din memorie și le execută. Ciclul de bază al fiecărei unități centrale de procesare constă din (1) preluarea unei instrucțiuni din memorie, (2) decodificarea acesteea pentru a-i determina tipul și operanzii și (3) executarea. Ciclul se repetă pornind de la prima instrucțiune (punctul de intrare în program) până când programul se termină. În acest fel sunt executate programele. Fiecare unitate centrală de procesare are un set specific de instrucțiuni pe care le poate executa. Astfel, un x86 nu poate executa programe ARM, iar un procesor ARM nu poate executa programe x86. Deoarece accesarea memoriei pentru a obține o instrucțiune sau un cuvânt de date necesită mult mai mult timp decât executarea unei instrucțiuni, toate CPU-urile conțin unele registre în interior pentru a păstra variabilele cheie și rezultatele temporare. Astfel, setul de instrucțiuni conține, în general, instrucțiuni pentru a încărca un cuvânt din memorie într- un registru și pentru a stoca un cuvânt dintr-un registru în memorie. Alte instrucțiuni combină doi operanzi din registre, din memorie sau din ambele într-un rezultat, cum ar fi adunarea a două cuvinte și stocarea rezultatului într-un registru sau în memorie. În afară de registrele generale utilizate pentru a păstra variabilele și rezultatele temporare, majoritatea calculatoarelor dispun de mai multe registre speciale care sunt accesibile programatorului. Unul dintre acestea este contorul de instrucțiuni, care conține adresa de memorie a următoarei instrucțiuni care urmează să fie preluată. După ce instrucțiunea 20 respectivă a fost preluată, contorul de program este actualizat pentru a indica adresa următoarei instrucțiuni. Un alt registru, numit pointer de stivă, indică topul stivei curente din memorie. Stiva conține câte un cadru (zonă de memorie) pentru fiecare procedură în care programul a intratat, dar din care nu a ieșit încă. Cadrul de stivă (mediul procedurii curente) al unei proceduri conține parametrii de intrare, variabilele locale și variabilele temporare care nu sunt păstrate în registre. Un alt registru este PSW (Program Status Word). Acest registru conține biții de cod de stare, care sunt setați de instrucțiunile de comparare, biții pentru gestiunea priorității, modul (utilizator sau kernel) și diverși alți biți de control. Programele de utilizator pot citi, în mod normal, întregul PSW, dar, de obicei, pot scrie doar în unele dintre câmpurile acestuia. PSW joacă un rol important în apelurile de sistem și în operațiile de I/O. Sistemul de operare trebuie să cunoască totul despre toate registrele. La multiplexarea temporală a unității centrale, sistemul de operare va opri adesea programul în curs de execuție pentru a (re)porni un altul. De fiecare dată când oprește un program în execuție, sistemul de operare trebuie să salveze toate registrele, astfel încât să poată fi restaurate atunci când va fi reluată execuția programului. Pentru a îmbunătăți performanțele, proiectanții de unități centrale de procesare au abandonat de mult timp modelul simplu de preluare, decodificare și executare a câte unei instrucțiuni pe rând. Multe unități centrale de procesare moderne dispun de facilități pentru a executa mai mult de o instrucțiune în același timp. De exemplu, o unitate centrală poate avea unități separate de preluare, decodificare și execuție, astfel încât, în timp ce execută instrucțiunea n, ar putea, de asemenea, să decodifice instrucțiunea n + 1 și să preia instrucțiunea n + 2. O astfel de organizare se numește pipeline și este ilustrată în Fig. 1-7(a) pentru un pipeline cu trei etape. De obicei pipeline-urile sunt mai lungi. În cele mai multe modele de pipeline, odată ce o instrucțiune a fost preluată în pipeline, aceasta trebuie executată, chiar dacă instrucțiunea precedentă a fost o ramificare condiționată. Pipeline-urile dau mari bătăi de cap dezvoltatorilor de compilatoare și de sisteme de operare, deoarece aceștia sunt expuși complexității mașinii fizice și sunt obligați să rezolve problemele care apar aici. Fig. 1.7. (a) Pipeline cu trei etape. (b) Unitate centrală superscalară Procesorul superscalar, prezentat în figura 1.7, b, are un design mai avansat decât procesorul pipeline. Acesta are mai multe unități de execuție, de exemplu: una pentru aritmetica numerelor întregi, una pentru aritmetica în virgulă mobilă și una pentru operațiile logice. Două sau mai multe instrucțiuni sunt preluate în același timp, decodificate și plasate într-un buffer de stocare în așteptarea executării. De îndată ce unitatea de execuție devine disponibilă, aceasta caută în memoria tampon de stocare o instrucțiune pe care o poate executa și, dacă este disponibilă, o preia din memoria tampon și o execută. Ca urmare, comenzile programului adesea nu respect 21 ordinea de execuție. De asigurarea corectitudinii rezultatului final (că acesta va fi același cu cel care rezultă din respectarea ordinei de execuție) sunt reposnabile, de obicei, resursele tehnice. Însă, după cum vom vedea mai târziu, această abordare introduce complicații neplăcute în sistemul de operare. După cum s-a menționat, majoritatea procesoarelor, cu excepția celor mai simple utilizate în sistemele incorporate, au două moduri de funcționare: modul kernel și modul utilizator. De obicei, modul este controlat de un bit special din cuvântul de stare a programului, PSW. Atunci când funcționează în modul kernel, procesorul poate executa orice comandă din setul său de comenzi și poate utiliza orice posibilități ale resurselor fizice. Pe desktopuri și pe calculatoarele de tip server, sistemul de operare rulează de obicei în modul kernel, ceea ce îi oferă acces la toate capacitățile resurselor fizice. Pe majoritatea sistemelor incorporate, doar o mică parte a sistemului de operare rulează în modul kernel, restul sistemului de operare rulând în modul utilizator. Programele de utilizator rulează întotdeauna în modul utilizator, adică sunt executate doar instrucțiuni din cadrul unei submulțini de comenzi (numite nepriveligiate) și au acces la un subset de capacități ale hardware-ului. De regulă, toate comenzile referitoare la operațiunile de I/O și la protecția memoriei sunt interzise în modul utilizator. De asemenea, este bineînțeles interzisă setarea modului kernel prin modificarea valorii bitului PSW. Pentru a obține servicii de la sistemul de operare, programul utilizatorului trebuie să genereze un apel de sistem care este interceptat în kernel și care apelează sistemul de operare. Instrucțiunea de interceptare TRAP hook realizează comutarea din modul utilizator în modul kernel și pornește sistemul de operare. Când procesarea apelului este finalizată, controlul este returnat programului utilizator și se execută comanda care urmează apelului de sistem. Detaliile mecanismului de apelare a sistemului vor fi tratate mai târziu în acest capitol, dar pentru moment ar trebui să fie considerat un tip special de instrucțiune de apelare a procedurii care are proprietatea suplimentară de a trece din modul utilizator în modul kernel. De acum încolo, apelurile de sistem vor fi evidențiate cu același font ca în acest cuvânt: read. Desigur, calculatoarele au și alte întreruperi de sistem care nu sunt concepute pentru a intercepta instrucțiunea de apel de sistem. Dar majoritatea celorlalte întreruperi de sistem sunt declanșate de întreruperi pentru a avertiza asupra unor situații excepționale, cum ar fi încercările de împărțire la zero sau dispariția unui ordin în timpul unei operații în virgulă mobilă. În toate cazurile, controlul se transferă către sistemul de operare, care trebuie să decidă ce trebuie să facă în continuare. Uneori, programul trebuie să fie încheiat printr-un mesaj de eroare. În alte cazuri, eroarea poate fi ignorată (de exemplu, atunci când ordinul unui număr dispare, se poate presupune că acesta este zero). În sfârșit, atunci când programul a declarat în prealabil că va gestiona singur unele dintre situațiile posibile, controlul ar trebui să fie returnat programului pentru ca acesta să poată rezolva singur problema. 1.3.2 Cipuri multi-fire și multi-nuclee Legea lui Moore afirmă că numărul de tranzistori într-un cip se dublează la fiecare 18 luni. Această ''lege'' nu este un fel de lege a fizicii, cum ar fi conservarea impulsului, ci este o observație a cofondatorului Intel, Gordon Moore, cu privire la rapiditatea cu care inginerii de la companiile de semiconductori reușesc să micșoreze tranzistorii. Legea lui Moore este valabilă de peste trei decenii și se preconizează că va mai fi valabilă cel puțin încă unul. După aceea, numărul de atomi pe tranzistor va deveni prea mic, iar mecanica cuantică va începe să joace un rol important, împiedicând reducerea în continuare a dimensiunilor tranzistorului. 22 Abundența tranzistoarelor duce la o problemă: ce să facem cu toate acestea? Am văzut mai sus o abordare: arhitecturi superscalare, cu unități funcționale multiple. Dar, pe măsură ce numărul de tranzistori într-o unitate de volum crește, sunt posibile și mai multe unități funcționale. Un lucru evident de făcut este să punem memorii cache mai mari pe cipul procesorului. Aceasta se și întâmplă, dar, în cele din urmă, se va ajunge la punctul de descreștere a randamentului. Următorul pas evident este replicarea nu numai a unităților funcționale, ci și a unei părți din logica de control. Intel Pentium 4 a introdus această proprietate, numită multithreading sau hyperthreading (denumirea Intel), în procesorul x86, ca și în cazul altor câteva cipuri de procesor, inclusiv SPARC, Power5, Intel Xeon și familia Intel Core. Într-o primă aproximație, această tehnologie permite procesorului să păstreze starea a două fire diferite și să se comuteze între ele timp de câteva nanosecunde. (Un fir este un fel de proces ușor, care, la rândul său, este un program în curs de execuție; vom intra în detalii în cap. 2). De exemplu, dacă unul dintre procese trebuie să citească un cuvânt din memorie (ceea ce durează multe cicluri de ceas), un CPU cu mai multe fire poate pur și simplu să treacă la un alt fir. Multithreading-ul nu oferă un paralelism adevărat. Doar un singur proces la un moment dat rulează, dar timpul de comutare a firelor este redus la ordinul unor nanosecunde. Multithreading-ul are implicații pentru sistemul de operare, deoarece fiecare fir apare pentru sistemul de operare ca o unitate centrală de procesare separată. Să ne închipuim un sistem cu două procesoare reale, fiecare cu două fire de execuție. Sistemul de operare va vedea patru procesoare. Dacă există lucru doar pentru a menține ocupate două procesoare la un anumit moment de timp, acesta poate programa din greșeală două fire pe același processor fizic, iar celălalt processor să rămână complet inactiv. Această alegere este cu mult mai puțin eficientă decât utilizarea unui singur fir pe fiecare CPU. Dincolo de multithreading, multe cipuri CPU au acum patru, opt sau mai multe procesoare sau nuclee complete pe ele. Cipurile multicore din Fig. 1-8 conțin efectiv patru miniprocesoare, fiecare cu propriul CPU independent. (Despre cache vom explica mai jos.) Unele procesoare, cum ar fi Intel Xeon Phi și Tilera TilePro, au deja mai mult de 60 de nuclee pe un singur cristal. Folosirea unui astfel de procesor multicore va necesita cu siguranță un sistem de operare multiprocesor. Fig. 1.8. (a) Un cip cu patru nuclee cu o memorie cache L2 partajată. (b) Un cip patru nuclee cu memorii cache L2 separate De altfel, în ceea ce privește numărul absolut de nuclee, nimic nu întrece un GPU (unitate de procesare grafică) modern. Un GPU este un procesor cu, literalmente, mii de nuclee minuscule. Acestea sunt foarte bune pentru multe calcule mici efectuate în paralel, cum ar fi redarea 23 poligoanelor în aplicațiile grafice. Nu sunt la fel de bune pentru sarcini seriale. De asemenea, sunt greu de programat. În timp ce GPU-urile pot fi utile pentru sistemele de operare (de exemplu, criptarea sau procesarea traficului de rețea), este puțin probabil ca partea principală a sistemului de operare să ruleze pe astfel de procesoare. 1.3.3 Memoria A doua componentă principală a oricărui calculator este memoria. În mod ideal, memoria ar trebui să fie cât mai rapidă (mai rapidă decât execuția unei singure instrucțiuni, astfel încât procesorul să nu fie încetinit de accesarea memoriei), destul de mare și extrem de ieftină. Nici o tehnologie modernă nu poate îndeplini toate aceste cerințe, astfel încât se folosește o altă abordare. Sistemul de memorie este conceput ca o ierarhie de niveluri (figura 1.9). Fig. 1.9. Ierarhia unei memorii tipice. Valorile numerice sunt foarte aproximative. Nivelurile superioare au o viteză mai mare, o capacitate mai mică și un cost unitar de stocare a unui bit de informație mai mare decât nivelurile inferioare, uneori de miliarde de ori. Nivelul superior este format din registrele interne ale procesorului. Acestea sunt alcătuite din același material ca și procesorul și, prin urmare, sunt la fel de rapide. În consecință, nu există nicio întârziere în accesarea lor. Capacitatea de stocare disponibilă în ele este, de obicei, de 32 ×32 biți la un CPU pe 32 de biți și de 64×64 biți la un CPU pe 64 de biți. În ambele cazuri acest volum nu depășește vloarea de 1 KB. Programele singure pot să gestioneze registrele (adică să decidă ce să păstreze în ele) fără implicarea hardware-ului. Urmează memoria cache, care este în mare parte controlată de hardware. Memoria principală este împărțită în linii de memorie cache, de obicei câte 64 octeți, cu adresele 0 până la 63 în linia cache 0, 64 până la 127 în linia cache 1, și așa mai departe. Cele mai utilizate linii de cache sunt păstrate într-o memorie cache de mare viteză situată în interiorul sau foarte aproape de CPU. Atunci când programul trebuie să citească un cuvânt de memorie, hardware- ul cache-ului verifică dacă nu cumva linia necesară se află în memoria cache. Dacă da, ceea ce se numește "cache hit", cererea este satisfăcută din memoria cache și nu este trimisă nicio cerere de memorie pe magistrala către memoria principală. În mod normal, accesarea cache- ului durează aproximativ două cicluri de ceas. În cazul lipsei cuvântului necesar în linia cache, trebuie să se meargă la memorie operativă, ceea ce va însemna întârziere suplimentară substanțială în timp. Memoria cache este limitată ca dimensiune din cauza costul ridicat. Unele mașini au două sau chiar trei niveluri de memorie cache, fiecare mai lent și mai mare decât cel anterior. Memorizarea în cache joacă un rol esențial în multe domenii ale informaticii, nu doar pentru păstrarea șirurilor RAM. Caching-ul este utilizat frecvent pentru a îmbunătăți performanța atunci când există o resursă mare care poate fi împărțită în părți, dintre care unele sunt mult mai des utilizate decât altele. Sistemele de operare folosesc caching peste tot. De exemplu, majoritatea sistemelor de operare păstrează fișierele (sau părți de fișiere) foarte utilizate în memoria RAM, 24 evitând astfel să fie nevoie să le citească din nou în mod repetat de pe disc. Analogic, rezultatele conversiilor numelor lungi de fișiere, cum ar fi /home/ast/projects/minix3/src/kernel/clock.c, la adresa de disc unde se află fișierul pot fi stocate în memoria cache pentru a evita necesitatea unor căutări repetate. În cele din urmă, se poate stoca în memoria cache pentru utilizare ulterioară rezultatul conversiei dintre adresa unei pagini web (URL) și adresa de rețea (adresa IP). Există multe alte utilizări ale tehnologiei de stocare în memoria cache. În orice sistem de caching apar destul de repede o serie de probleme. 1. Când se plasează un element nou în memoria cache? 2. În ce zonă de memorie cache ar trebui plasat un nou element? 3. Ce intrare să fie eliminată (“victima”) din memoria cache atunci când dorim să obținem spațiu liber? 1. Unde anume va fi plasată “victima” (în memoria secundară)? Nu toate aceste întrebări au legătură cu memoria cache. De exemplu, în procesul de stocare șirurilor de caractere RAM în memoria cache a procesorului, un nou element va fi de obicei introdus în memoria cache de fiecare dată când accesarea memoriei cache a fost fără succes. Atunci când se calculează linia de memorie cache dorită pentru a plasa un nou element, de obicei sunt utilizați unii dintre biții superiori ai acelei adrese de memorie, la care se face referință. De exemplu, dacă există 4096 de linii de memorie cache de 64 de octeți și adrese de 32 de biți, biții de la 6 la 17 ar putea fi utilizați pentru a determina linia de memorie cache, iar biții de la 0 la 5 ar putea fi utilizați pentru a determina octetul din linia de memorie cache. În acest caz, elementul care urmează să fie șters este același cu cel care conține noile date, dar în alte sisteme este posibil ca această ordine să nu fie respectată. În sfârșit, atunci când o linie de memorie cache este suprascrisă în memoria RAM (dacă a fost modificată în timpul procesului de caching), locația de memorie în care urmează să fie suprascrisă este definită explicit prin adresa din cerere. Utilizarea memoriei cache s-a dovedit a fi atât de reușită încât multe procesoare moderne au două niveluri de memorie cache. Primul nivel, sau memoria cache L1, face întotdeauna parte din procesor și, de obicei, furnizează instrucțiuni decodate motorului de execuție a instrucțiunilor procesorului. Multe procesoare au o a doua memorie cache L1 pentru acele cuvinte de date care sunt foarte utilizate. În mod obișnuit, fiecare dintre memoriile cache L1 are o dimensiune de 16 Kbyte. În plus față de această memorie cache, procesoarele au adesea un al doilea nivel de memorie cache numit L2 cache, care conține câțiva megabytes de cuvinte de memorie utilizate recent. Diferența dintre memoria cache L1 și L2 este reprezentată de diagrama de sincronizare. Accesul la memoria cache de prim nivel nu are întârziere, în timp ce accesul la memoria cache de al doilea nivel necesită o întârziere de unul sau două cicluri de ceas. Atunci când proiectează procesoare multi-core, proiectanții trebuie să decidă unde să plaseze memoria cache. Figura 1.8 (a) prezintă o singură memorie cache L2 partajată de toate nucleele. Această abordare este utilizată în procesoarele multi-core de la Intel. Pentru comparație, figura 1.8 (b) arată că fiecare nucleu are propriul cache L2. Aceasta este abordarea utilizată de AMD. Fiecare abordare are propriile sale argumente pro și contra. De exemplu, memoria cache L2 partajată de la Intel necesită controler de cache mai complex, în timp ce calea aleasă de AMD face dificilă menținerea unei stări consecvente a memoriei cache L2 între nuclee. 25 Următorul în ierarhia prezentată în figura 1.9 este memoria operativă. Aceasta este principala zonă de lucru a sistemului de memorie al mașinii. Memoria operativă este adesea denumită memorie cu acces aleatoriu (Random Access Memory (RAM)). Veteranii o numesc uneori memorie cu miez, deoarece în anii 1950 și 1960, în memoria RAM se foloseau mici miezuri de ferită magnetizabile. Au trecut decenii, dar numele s-a păstrat. În zilele noastre, blocurile de memorie au volume diferite de la sute de megaocteți la mai mulți gigaocteți, iar acest volum crește rapid. Toate cererile procesorului care nu pot fi satisfăcute de memoria cache sunt direcționate către la RAM. Pe lângă memoria RAM, multe calculatoare sunt echipate cu o mică memorie cu acces aleatoriu, nevolatilă, numită Memorie numai pentru citire (ROM). Spre deosebire de RAM, ROM nu-și pierde conținutul atunci când se întrerupe alimentarea cu energie și, prin urmare, este nevolatilă. ROM-ul este programat din fabrică și nu poate fi modificat ulterior. Acest tip de memorie se caracterizează prin viteză mare și costuri reduse. Unele computere au un încărcător de pornire inițial în memoria ROM care este utilizat pentru a porni calculatorul. Unele controlere I/O au, de asemenea, acest tip de memorie pentru controlul de nivel scăzut al dispozitivului. Există și alte tipuri de memorie nevolatilă care pot fi șterse și rescrise, spre deosebire de ROM- uri: memoriile permanente programabile șterse electric (EEPROM), cunoscute și sub numele de (Electrically Erasable PROM) și memoria flash. Deoarece scrierea EEPROM-urilor durează cu câteva ordine de mărime mai mult decât a RAM-urilor, acestea sunt utilizate în același scop ca și ROM. De asemenea, acestea au și caracteristica suplimentară de a putea corecta erorile din programele pe care le conțin prin suprascrierea spațiului de memorie pe care îl ocupă. Memoria flash este utilizată în mod obișnuit ca suport de stocare pentru dispozitivele electronice portabile. Menționez doar două domenii de utlizare: servește drept "film (peliculă)" în aparatele foto digitale și "disc" în playerele muzicale portabile. în ceea ce privește performanța memoria flash se află la mijloc înttre RAM și disc. De asemenea, spre deosebire de un dispozitiv de stocare de tip "disc", dacă memoria flash este ștearsă sau suprascrisă de prea multe ori, aceasta devine vulnerabilă. Un alt tip de memorie este memoria CMOS, care este nevolatilă. Multe calculatoare folosesc memoria CMOS pentru a stoca data și ora curentă. Memoria CMOS și circuitele electronice de cronometrare a timpului sunt alimentate de o baterie miniaturală (sau de un pachet de baterii), astfel încât ora curentă este întotdeauna actualizată chiar și atunci când calculatorul este deconectat de la o sursă de alimentare externă. Memoria CMOS poate stoca, de asemenea, parametrii de configurare care să indice, de exemplu, de la ce unitate trebuie să pornească sistemul. Consumul de energie al memoriei CMOS este atât de redus încât utilizarea unei baterii instalată din fabrică durează adesea mai mulți ani. Însă, atunci când bateria începe să cedeze, computerul poate da semne de "Alzheimer" și poate "uita" lucruri pe care le ținea minte de ani de zile, cum ar fi de exemplu de pe care hard disk să pornească. 1.3.4 Discurile Următorul nivel al ierarhiei memoriei, după RAM, este discul magnetic (hard disk). O unitate de disc este de douzeci de ori mai ieftin decât memoria RAM în termeni de biți de informație, iar capacitatea de stocare este cu mult mai mare. Singura problema este că accesul la date este cu aproximativ trei ordine de mărime mai lent. Acest lucru se datorează faptului că este un dispozitiv mecanic a cărui construcție este prezentată în mod convențional în figura 1.10. 26 Fig. 1.10. Reprezentarea schematică a unui d

Use Quizgecko on...
Browser
Browser