ISTITUTO TECNICO E LICEO SCIENTIFICO TECNOLOGICO “ANGIOY” informaticangioy.altervista.org I SISTEMI OPERATIVI Prof. G. Ciaschetti 1. Introduzione Un Sistema Operativo (abbreviato in SO o OS a seconda che si usi l’italiano o l’inglese Operating System) è un insieme di programmi che gestiscono e rendono disponibile ad altri programmi le risorse del computer. Esso quindi costituisce il software di base del computer, al quale si appoggiano gli altri software, detti applicazioni, per accedere alle risorse hardware. La situazione è descritta nella seguente figura: Le applicazioni chiedono al Sistema Operativo l’uso delle risorse hardware, ed esso consente tale uso nei modi e nei tempi che ritiene più opportuni. Quando, ad esempio, scriviamo un’istruzione in un programma in linguaggio C (cioè un’applicazione) che richieda di accedere alla memoria RAM, o che debba leggere dati da un file, o ancora che richieda l’uso di dispositivi di input/output, o in tante altre situazioni, sarà il Sistema Operativo a occuparsi di soddisfare tale richiesta. La richiesta al Sistema Operativo non avviene in modo esplicito da parte del programmatore, ma avviene per mezzo del compilatore (ricordate? Un compilatore è quel software che permette di tradurre i nostri programmi scritti in C++ in linguaggio binario, per far sì che siano eseguibili), il quale sa come specificare l’istruzione per quel particolare Sistema Operativo che stiamo usando. Per questo motivo, ogni diverso Sistema Operativo ha il suo particolare compilatore (ad esempio, esiste un compilatore Dev-C++ per Windows, uno per il MAC-OS, uno per Linux, ecc.). Per fare un altro esempio, supponiamo che stiamo usando un programma di videoscrittura (come Word) e invochiamo la stampa del documento: l’applicazione (Word) richiederà la stampa al Sistema Operativo, il quale apre la cartella delle stampanti permettendo di selezionarne una, oltre alle varie opzioni di stampa, quindi invia il file da stampare alla stampante (l’hardware). Un altro modo possibile di vedere il Sistema Operativo è dal punto di vista degli utenti: esso rappresenta l’interfaccia tra l’utente e il computer: una volta acceso il computer, il Sistema Operativo mette a disposizione un ambiente nel quale è possibile eseguire tutta una serie di informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 operazioni (esecuzione di programmi, visualizzazione dei file e delle cartelle, ecc.), cioè quello che noi chiamiamo “usare il computer”. Un Sistema Operativo è organizzato in moduli stratificati tra loro. Ogni modulo comunica con i moduli immediatamente adiacenti mediante delle funzioni dette primitive. Il principio è un po’ quello dell’incapsulamento nella programmazione orientata agli oggetti: un modulo conosce cosa sa fare un modulo adiacente (conosce, cioè, la definizione delle primitive e come vanno usate), ma non come lo fa (cioè, come esse sono implementate). Le primitive del modulo più esterno, quelle usate dalle applicazioni, sono chiamate API (Application Programming Interface). Lo schema della figura precedente, allora, possiamo vederlo più in dettaglio come segue: Prima di iniziare a vedere in dettaglio come funziona un sistema operativo, torniamo un secondo alla prima definizione che abbiamo dato, il SO come gestore delle risorse del computer: ma quali sono le risorse che il SO gestisce? Possiamo racchiuderle in quattro grandi categorie: memoria RAM tempo di utilizzo della CPU dispositivi periferici (stampanti, mouse, tastiera, video, CD-ROM, ecc.) files Vedremo come i diversi moduli del SO si occupano di gestire ognuna di queste quattro categorie di risorse. 2. Storia I sistemi batch I primi computer riuscivano a eseguire una sola sequenza di istruzioni (da qui batch, letteralmente lotto di istruzioni) per volta. Di conseguenza, i primi sistemi operativi servivano solo per permettere l’immissione nel computer (tramite schede perforate) dei dati e del programma da svolgere. informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Nessuna interazione tra l’uomo e la macchina era permessa durante l’elaborazione. Inoltre, era possibile avere dei report sul risultato dell’elaborazione e sullo stato della macchina. I sistemi multiprogrammati A partire dagli anni 60, si è cominciato a usare il computer in modo più massiccio, con conseguente aumento delle richieste di calcolo. Nasceva l’esigenza di eseguire, con lo stesso computer, più programmi contemporaneamente. E’ in questo momento che è nato UNIX, il primo vero sistema operativo, capace di gestire la multiprogrammazione e tutte le problematiche ad essa connessa, effettuando lo scheduling di lungo termine (che prendono il nome di lavori, da cui il termine job scheduling), ossia la scelta di quali lavori caricare in memoria dal disco, e lo scheduling della CPU (cpu scheduling), o di breve termine ossia la scelta di come ripartire la CPU tra i vari lavori presenti in memoria. La logica di questi sistemi è sostanzialmente quella dei sistemi batch, con la sola differenza che stavolta possono essere mantenuti in memoria ed eseguiti più programmi per volta, ed è il SO che organizza la memoria RAM e il lavoro della CPU tra i diversi programmi. I sistemi multitasking Agli inizi degli anni 70, l’uso del computer era ormai diventato molto diffuso, e iniziavano a nascere i primi computer dipartimentali collegati a più terminali, ognuno dei quali usato da un diverso operatore. Si tratta dei sistemi di tipo client-server (il terminale è il client, il computer centrale o mainframe è il server), in cui occorre gestire oltre che più programmi, anche più utenti contemporaneamente. Si tratta di una successiva evoluzione del sistema UNIX, in cui ogni lavoro di ogni utente è chiamato compito (o task in inglese, da cui il termine multitasking). Questo tipo di SO doveva provvedere a gestire un elevato e frequente numero di accessi alla memoria, introducendo anche dei meccanismi di protezione dei dati tra i diversi utenti. Inoltre, ogni utente doveva avere l’impressione di avere a disposizione “per sé” le risorse di elaborazione, senza dover aspettare il completamento degli altri compiti degli altri utenti. Nasce così il concetto di time-sharing, cioè della divisione del tempo di CPU in slot temporali di durata piccolissima: viene assegnato a ogni slot un diverso compito dei vari utenti, i quali così non fanno in tempo a rendersi conto di aspettare tra uno slot e l’altro. I sistemi user-friendly Nel 1977 nasce il primo personal computer: l’Apple II. Esso segna l’inizio di una nuova era per l’informatica, poiché si passa dall’uso lavorativo all’uso domestico del computer, abbracciando una moltitudine di nuovi utilizzatori. Nasce così l’esigenza di rendere “agevole” la macchina calcolatrice anche ai non esperti: i sistemi operativi che nascono in questo periodo si concentrano soprattutto nello sviluppo dell’interfaccia uomo-macchina, utilizzando sistemi di comando per il SO più agevoli della semplice tastiera. E’ nel 1984 che, con l’Apple McIntosh, Steve Jobs e Steve Wozniak inventano il primo sistema operativo con interfaccia WIMP (Windows, Icons, Mouse and Pointer). Successivamente, tale interfaccia sarà ripresa anche da altri sistemi operativi, come lo stesso UNIX, Windows, e la versione gratuita e open source di Unix, Linux). I sistemi distribuiti e multiprocessore Con la nascita negli anni 80 delle reti di computer di tipo peer-to-peer, in cui più computer di uguali caratteristiche sono collegati tra loro per condividere alcune risorse, quali stampanti e file, nasce la possibilità di utilizzare più processori contemporaneamente per eseguire uno stesso insieme di elaborazioni: uno stesso programma viene eseguito su più computer “paralleli” per sfruttare informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 maggiori risorse di calcolo, e quindi terminare prima (si pensi a programmi che richiedono giorni o mesi di elaborazione, come quelli per la cifratura di codici o per la soluzione di problemi complessi). I sistemi operativi si specializzano allora nella gestione di più processori contemporaneamente, inizialmente dislocati su diversi computer in rete, attualmente comunemente montati su uno stesso computer (si pensi al processore Intel Core Duo, ad esempio, due processori in uno). I sistemi mobili A partire dagli anni 90, con l’avvento dei telefoni cellulari, sempre più ricchi di utility e di applicazioni per lo svago, e dei computer palmari (PDA, Personal Digital Assistant), nasce l’esigenza per i SO di avere buone prestazioni a costi contenuti, e soprattutto di risparmiare energia. Nascono così sistemi operativi più leggeri che ottimizzano l’uso delle risorse da un punto di vista energetico, come Windows Mobile, Symbian o Palm OS. 3. Il nucleo Il modulo più importante di un SO è quello che si occupa della gestione dei processi: il nucleo o kernel. Ricordiamo che un processo è un programma in esecuzione (un programma è un’entità statica, mentre un processo è un’entità dinamica). Per ogni processo in esecuzione, il nucleo del SO mantiene un insieme di informazioni relative al processo in un PCB (Process Control Block), che memorizza: il numero del processo (ogni processo viene contraddistinto da un numero progressivo dal SO) lo stato del processo il program counter (a che punto si trova la sua esecuzione, cioè qual è la prossima istruzione da eseguire) lo stato dei registri della CPU le informazioni relative allo scheduling del processo (priorità, ecc.) le informazioni relative alla memoria dedicata al processo (indirizzi, ecc.) la lista dei file aperti usati dal processo (in scrittura e in lettura). I processi possono essere single thread o multi thread, cioè avere un solo canale di esecuzione o più canali di esecuzione (un esempio di processo single thread è il Paint di Windows: è possibile fare un solo disegno per volta; un esempio di processo multi thread è Word, che permette di avere più documenti aperti nello stesso programma). Anche nel caso di processi multi thread, comunque, si ha un solo PCB e non uno per ogni thread. I processi tra loro possono essere concorrenti (che si contendono le risorse), cooperanti (che hanno un obiettivo comune, dunque non importa se le risorse vengono assegnate a uno oppure a un altro, va bene comunque), oppure indipendenti (assenza di conflitto di risorse). In ognuno di questi casi, il SO gestisce la ripartizione delle risorse tra i diversi processi. In particolare, nel caso di processi cooperanti, il SO mette a disposizione un meccanismo semaforico per la loro sincronizzazione e le primitive send e receive per lo scambio di messaggi. Inoltre, mediante la informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 primitiva RPC (Remote Procedure Call) un processo può richiedere al SO l’esecuzione di un altro processo. Ciclo di vita di un processo Abbiamo visto che essendo le risorse di un computer “scarse”, cioè limitate, esse devono essere opportunamente ripartite tra i diversi processi in esecuzione. Di conseguenza, un processo può trovarsi in diversi stati, a seconda che esso sia stato o meno caricato in memoria RAM, che abbia o no disponibilità della CPU per l’elaborazione, o che sia in attesa di qualche operazione di input/output. Nella seguente figura sono mostrati i possibili stati in cui un processo può trovarsi, e le transizioni da uno stato all’altro. Nel momento in cui si fa doppio click su un file eseguibile (un programma), il processo è creato. Solo quando verrà caricato nella memoria dal Long Term Scheduler, (un software del nucleo che realizza lo scheduling di lungo termine), esso passa dallo stato creato allo stato pronto. Deve, però, competere con gli altri processi per la risorsa CPU, per poter essere eseguito. Questo conflitto è risolto dallo Short Term Scheduler (un altro software del nucleo), il quale ripartisce il tempo di CPU tra i diversi processi secondo determinate strategie di scheduling. Se selezionato, il processo passa dallo stato pronto allo stato in esecuzione, viene caricato il suo PCB, e quando invece deselezionato ritorna allo stato pronto. Il cambiamento del PCB del processo attualmente in esecuzione viene chiamato context-switch. Mentre il processo è in esecuzione, può accadere che esso richieda un’operazione di input/output, che interessi cioè un dispositivo periferico (come abbiamo già accennato, è il SO a occuparsi anche di questo, ma con un altro modulo, non il nucleo), la quale richiede molto tempo rispetto alla velocità del processore, circa 1 milione di volte più lenta. Mentre aspetta che si compia l’operazione, esso viene posto nello stato in attesa per poi essere nuovamente posto nello stato pronto quando il dispositivo periferico comunica al SO di aver terminato l’operazione mandando un segnale di interrupt (interruzione: “hey, io ho finito, fermati un attimo, prestami attenzione!”). informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Il processo è posto nello stato in attesa anche in caso di chiamate al sistema (come l’istruzione system(“pause”), per intenderci) che generano una trap, ossia l’esecuzione di speciali routine di priorità assoluta. Non appena terminata trap, il processo torna ad essere pronto per essere di nuovo schedulato. Gestione degli eventi (interrupt/trap) Allo scopo sapere da quale dispositivo periferico (mouse, tastiera, disco, video, ecc.) arriva la richiesta di interruzione, o IRQ (Interrupt ReQuest), o se si tratta di una chiamata di sistema, il nucleo del SO mantiene un vettore degli interrupt, un vettore di bit (1 = interruzione, 0 = nessuna interruzione) in cui ogni posizione corrisponde a un diverso dispositivo periferico. Alcune posizioni sono quindi riservate al sistema. Il vettore viene continuamente monitorato dal SO, che fa partire immediatamente la routine di gestione dell’interruzione o la trap, avviando un context-switch. CPU scheduling Ogni diversa scelta dello scheduler dà luogo a diverse prestazioni del sistema. E’ opportuno allora che l’algoritmo faccia le migliori scelte possibili. Ogni possibile soluzione può essere rappresentata su un diagramma di Gantt, in cui si riporta una linea per ogni processore, che rappresenta l’asse dei tempi, e un rettangolo di altezza fissa e lunghezza pari alla durata del processo, ossia il tempo di CPU che esso richiede per la sua esecuzione, come nella figura che segue: Diversi indicatori di prestazione dell’algoritmo di scheduling di breve termine possono essere usati: - percentuale di utilizzo della CPU: si schedulano i processi per massimizzare il tempo in cui la CPU o le CPU, se più di una, lavorano. Equivale a minimizzare il numero di context-switch. - troughput: si massimizza il numero di processi terminati nell’unità di tempo. - Cmax: indicando con Ci l’istante di completamento dell’i-esimo processo, e con Cmax il massimo di questi tempi, si minimizza quest’ultimo, il che equivale a minimizzare l’istante in cui si terminano tutti i processi. E’ anche un indicatore di bilanciamento dei lavori nei sistemi multiprocessore: infatti, minore è il tempo per completare tutti i lavori, più equa è la ripartizione di essi. - media dei tempi di completamento iCi/N: si miminizza il tempo medio di completamento dei diversi processi: questo indicatore è molto usato nei diversi benchmark dei processori. informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Per raggiungere questi obiettivi, l’algoritmo di scheduling può funzionare in modo FCFS (First Come First Served): i processi sono gestiti in coda, quindi in modo FIFO. SPT (Shortest Processing Time first): viene schedulato prima il processo che dura meno. Questo algoritmo minimizza il tempo medio di completamento dei processi. Priorità: può essere statica o dinamica. Nel primo caso, riguarda l’importanza del processo, nel secondo può crescere all’aumentare del tempo d’attesa del processo. Round Robin: si assegna a rotazione la CPU ai diversi processi, suddividendo il tempo in slot temporali. 4. La gestione della memoria Un altro importante modulo del SO si occupa di gestire la memoria del computer. Soprattutto, parliamo di gestione della memoria di lavoro, la RAM, dove devono risiedere i programmi per essere eseguiti. Ricordiamo che è il Long Term Scheduler che assegna la memoria ai diversi processi. Questo può non essere un problema, (al giorno d’oggi un normale PC ha una memoria RAM da 2 a 4 GigaByte, spesso sufficienti per i pochi programmi per volta che eseguiamo quotidianamente), ma diventa di fondamentale importanza quando il numero di processi simultanei tende a crescere. L’operazione di caricamento/scaricamento dalla RAM di un processo, da parte dello scheduler di lungo termine, è chiamata swapping (scambio: un processo torna sul disco mentre uno viene caricato in memoria). Quando scriviamo un programma, in linguaggio C o in un altro linguaggio di programmazione, molte istruzioni fanno riferimento alla memoria: ad esempio, l’istruzione N = N + 1; richiede di prelevare in memoria, all’indirizzo della variabile N, il valore di tale variabile, quindi sommare 1, e successivamente di memorizzare nello stesso indirizzo il risultato. Il fatto è che al momento della scrittura del programma non è noto l’indirizzo di N. E non sarà noto finché il programma non diventerà un processo, cioè creato (quando si fa doppio click) e posto in memoria (stato di pronto). Quello che accade in realtà è che al momento della compilazione di un programma, viene generato dal compilatore un codice rilocabile, fatto di indirizzi logici (a partire dall’inizio del programma, ecc., ), che diventeranno indirizzi fisici veri e propri solo quando esso sarà effettivamente caricato in ram per la sua esecuzione. La traduzione degli indirizzi da logici a fisici viene fatta mediante un dispositivo hardware chiamato MMU (Memory Management Unit), sulla base di una tabella di corrispondenza mantenuta dal modulo di gestione della memoria del SO. Un meccanismo molto importante gestito da questo modulo è quello della memoria virtuale: quando la memoria RAM a disposizione non basta per caricare tutti i processi, viene usata una parte del disco rigido come fosse la RAM, pur sapendo che l’operazione di trasferimento da/verso il disco è mille volte più lenta di quella della RAM (che è circa 100-1000 volte più lenta del processore). Questo evita di far si che si verifichino errori per riferimento a istruzioni non presenti in memoria. Il modulo di gestione della memoria del SO si occupa, oltre che dell’allocazione della RAM per lo scheduling di lungo termine, anche della gestione della memoria Cache, che viene indirizzata allo stesso modo della memoria RAM. informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Strategie di allocazione della RAM Gli obiettivi del Long Term Scheduler sono quelli dell’ottimizzazione della memoria, cioè farci stare il maggior numero possibile di processi, e la protezione dei dati: è di fondamentale importanza fare in modo che un processo non possa modificare, magari accidentalmente, dati di un altro processo. Diverse strategie di allocazione sono state proposte: Partizionamento: in questo schema di allocazione la memoria risulta partizionata in più parti (che impropriamente in informatica vengono chiamate partizioni), e viene assegnata una diversa parte a ogni diverso processo. I processi che non trovano spazio restano sul disco (memoria virtuale). Il SO mantiene una tabella delle partizioni in cui è specificato, per ogni processo, l’indirizzo iniziale della partizione, e la sua dimensione in byte. processo1 partizione1 dimensione1 processo2 partizione2 dimensione 2 … … … Con il partizionamento della memoria, le possibili strategie di allocazione della RAM sono first fit (scegli la prima partizione libera sufficientemente grande), best fit (scegli la partizione più adatta per dimensioni), e worst fit (scegli la partizione meno adatta). Nel primo caso si produce il fenomeno della frammentazione della memoria: lo spazio di una partizione che avanza, non necessaria al processo corrispondente, non è ulteriormente utilizzabile. Nel secondo caso, il problema della frammentazione viene parzialmente risolto. Il terzo caso, sebbene sembri poco vantaggioso, ha una sua utilità quando insieme ai programmi occorre includere nella partizione anche i dati che essi utilizzano: lasciare parecchio spazio nella partizione può avere senso per evitare di accedere ai dati su disco ogni volta, o di dover suddividere opportunamente lo spazio dei dati (qualora essi siano memorizzati separatamente dai programi). Paginazione: in questo schema lo spazio degli indirizzi logici è suddiviso in aree della stessa dimensione chiamate pagine di circa 4Kbyte. Corrispondentemente, lo spazio degli indirizzi fisici risulta suddiviso in settori. A ogni processo vengono assegnate più pagine, non necessariamente contigue, e dunque più settori della RAM. In questo modo, si crea meno frammentazione della memoria. Gli indirizzi logici sono formati da un indirizzo base più un offset: il primo rappresenta il numero di pagina, il secondo il numero di byte all’interno della pagina. Mediante una tabella di paginazione, il SO mantiene la corrispondenza tra pagine e settori, e mediante una tabella dei settori identifica l’indirizzo fisico di ogni settore. informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Il meccanismo della paginazione agevola, inoltre, il meccanismo della memoria virtuale: alcune pagine di un processo possono essere effettivamente caricate in RAM, mentre altre risiedere ancora sul disco. Se il processo richiede una pagina non presente in tabella (cioè, si trova sul disco), si ha un page fault e viene avviata una routine sistema di gestione del fault, che carica in tabella (e in RAM) la pagina necessaria a scapito di qualche altra pagina (swapping). Il problema principale della paginazione è legato alla gestione di processi cooperanti mediante buffer condiviso: un buffer suddiviso in più pagine risulta molto più difficile da gestire a livello di programmazione. Inoltre, resta il problema della frammentazione interna alle pagine, sebbene minore rispetto alla frammentazione causata dal partizionamento. Segmentazione: in questo schema, la memoria RAM risulta suddivisa in segmenti di lunghezza variabile, ognuno dei quali contiene un elemento ben definito del programma (ad esempio, una funzione, una variabile, una stringa, ecc.). Per ogni segmento, il SO mantiene in una tabella di segmentazione l’indirizzo base e la dimensione del segmento. segmento 1 base1 dimensione1 segmento 2 base2 dimensione2 … … … Di nuovo, la traduzione degli indirizzi da logici a fisici è fatta sommando l’indirizzo base più l’offset dell’istruzione, come nel caso della paginazione. Il vantaggio principale di questo schema è quello di eliminare completamente il fenomeno della frammentazione. Attualmente, i moderni SO utilizzano una tecnica mista di allocazione della memoria fatta di pagine e segmenti. 5. Il File System Il terzo modulo del SO di cui ci occupiamo è quello relativo alla gestione dei file. Ricordiamo che un file è un insieme di informazioni binarie (quindi, bit) memorizzate in modo persistente. A ogni file il SO associa un insieme di attributi, che ne indicano: - il numero progressivo (nella lista dei file aperti); - il nome del file e l’estensione (es. pippo.txt, prova.cpp, mioprogramma.exe). L’estensione si usa solo nei sistemi Windows, mentre per i sistemi Unix-like (Linux, MAC OS) non è prevista: il SO riconosce il tipo di file in base a un codice (una stringa) posto all’inizio del file; - la sua collocazione (il percorso nella struttura logica dei file); - la sua dimensione; - i privilegi (protezione): quale utente può fare quale operazione sul file (ad esempio, creazione, apertura, lettura/scrittura, eliminazione, esecuzione, ecc.); - la data di creazione e di ultima modifica (solo ultima modifica in Windows). informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Il File System del SO mantiene in una tabella la lista di file aperti, in cui sono indicati il numero progressivo del file, un handler (puntatore) che ne specifica la posizione sul disco, l’utente che ha aperto il file e l’applicazione che ha eseguito l’apertura. Se un nuovo utente apre un altro file, qualora autorizzato, viene creato un nuovo handler e inserito in tabella. id1 handler1 user1 application1 id2 handler2 user2 application2 … … … Struttura del file system I percorsi logici dei file sono organizzati dal file system in una struttura ad albero. Un albero è un grafo connesso aciclico, in cui un nodo rappresenta la radice dell’albero, e i nodi che non hanno successori sono chiamati foglie (si pensi a un albero genealogico). La radice dell’albero corrisponde a un’unità logica di un dispositivo di memorizzazione di massa, i nodi intermedi corrispondo alle directory (o cartelle), e le foglie corrispondono ai file. In Windows è possibile avere tante unità logiche (ad esempio, si può partizionare l’hard disk in più unità C, D, ecc., e poi avere altre unità logiche come E per il CD-ROM, F per la pendrive, ecc.), a ognuna delle quali corrisponde un diverso albero. Il file di questo documento, ad esempio, si trova nel percorso d:\documents and settings\tchasqui\didattica\opsis.doc (a partire dalla radice, unità logica D, scendi nella cartella documents and settings, poi nella cartella tchasqui, poi ancora nella cartella didattica e lì si trova il file opsis.doc). Si noti come il simbolo \ rappresenta la discesa di un livello nella struttura. Nei sistemi Unix-like esiste invece un’unica radice, cioè una sola struttura ad albero per tutti i dispositivi. Allorché si debba utilizzare un altro dispositivo di memorizzazione, come il floppy disk o la pendrive, occorre “montare” (mounting) nell’unico albero la struttura del file system del dispositivo, come in figura seguente: informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Mentre nei sistemi Windows le unità logiche si chiamano C: , D: , E: ecc., in Unix la sola unità logica alla radice è indicata con il simbolo /, che è anche il simbolo che si usa per scendere di livello. Ad esempio, il percorso del file prova.cpp che si trova nella directory bin è indicato con /bin/prova.cpp. In entrambi i tipi di sistemi, sia Windows che Unix, l’operatore .. può essere usato per risalire la struttura di un livello nei percorsi relativi (a partire da un nodo intermedio). Ad ogni nodo dell’albero (o degli alberi, in Windows), sia che si tratti di un nodo intermedio (directory) sia che si tratti di una foglia (file), il SO associa un Access Control List (ACL) che definisce i privilegi degli utenti per quel nodo. In Unix, l’ACL è composto di una lettera per specificare se si tratta di un file o una directory, e poi da tre gruppi di tre lettere che indicano i privilegi di lettura/scrittura/esecuzione a livello utente, gruppo o generale. Ad esempio, d rw_ r_ _ _ rwx rw_ r_ _ _ __ directory con privilegi di lettura e scrittura per l’utente, solo lettura per il gruppo e per tutti gli altri file con privilegi di lettura, scrittura ed esecuzione a livello utente, lettura e scrittura a livello gruppo, e nessuna operazione per tutti gli altri In Windows esistono due tipi di file system: FAT (File Allocation Table) e NTFS (New Technology File System). Il primo è il più vecchio dei due (usato solo fino a Win95), e non prevede informazioni ACL (infatti, tutti i SO di casa Microsoft fino a Win95 non prevedono la multiutenza). Questo è il motivo per cui se abbiamo nel nostro computer due sistemi operativi come Windows e Linux, riusciamo a vedere in Linux i file di Windows solo se abbiamo usato il sistema NTFS. Allocazione fisica dei file Finora abbiamo parlato di percorsi logici dei file: sono quelli che vedono gli utenti e i programmi che a questi file devono accedere. In realtà, la situazione a livello fisico è molto diversa: il disco rigido è formato da tanti dischi magnetici montati su un unico perno centrale, ognuno dei quali risulta suddiviso in tracce e settori. L’intersezione tra una traccia e un settore si chiama blocco e ha di solito la dimensione di 64Kbyte; più blocchi allineati sui vari dischi danno luogo a un cilindro. informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 Ogni file è memorizzato su uno o più blocchi, ed è il SO che mantiene la corrispondenza tra i percorsi logici dei file, più agevoli per gli utenti, e i percorsi fisici veri e propri (quale disco, quale cilindro, quale blocco). Ma in che modo il SO assegna i blocchi ai diversi file? Esistono diverse strategie di allocazione del disco: 1) allocazione contigua: vengono assegnati al file blocchi adiacenti tra loro. Questa strategia minimizza i tempi di trasferimento dei file, in quanto rende minimo il movimento meccanico necessario per posizionarsi sui byte di interesse. I blocchi adiacenti possono trovarsi sullo stesso cilindro (nessun movimento), oppure sulla stessa traccia (movimento di rotazione del disco) oppure sullo stesso settore (spostamento delle testine). 2) allocazione collegata: i blocchi vengono collegati tra loro memorizzando su ogni blocco l’indirizzo del blocco successivo, creando così una lista lineare del tipo in questo tipo di allocazione, qualunque blocco può essere utilizzato per ogni file, e non si verifica così il problema della frammentazione del disco che, invece, si ha nell’allocazione contigua. Tuttavia, richiede parecchi movimenti (rotazione del disco e spostamento delle testine) per passare da un blocco a un altro, con conseguente perdita di velocità di trasferimento dei dati. 3) allocazione indicizzata: il primo blocco viene utilizzato come indice per memorizzare gli indirizzi fisici dei blocchi che costituiscono il file. E’ più facile da gestire rispetto all’allocazione collegata, ma presenta gli stessi problemi di velocità di trasferimento. informaticangioy.altervista.org Sistemi Operativi A.S. 2009/2010 I comandi per il file system Anche se i nostri moderni sistemi operativi, essendo user-friendly, ci mettono a disposizione l’interfaccia WIMP per la gestione dei file (gestione risorse, doppio click su una cartella per vedere il suo contenuto, ecc.), esiste una serie di comandi che è possibile dare al SO per lavorare con il file system. In Windows, occorre aprire una finestra DOS per dare questi comandi (menu avvio esegui cmd oppure menu avvio programmi accessori prompt di MS DOS), mentre in Linux o MAC bisogna aprire una shell (finestra di comando: la più usata è bash). Riportiamo, a titolo di esempio, alcuni dei comandi di principali, per la sintassi e le modalità di utilizzo dei quali rimandiamo a manuali specifici. WINDOWS UNIX CD CD Change directory DIR LS Directory listing COPY CP File copy MOVE MV Move file/directory DEL/RMDIR RM Remove file/directory MKDIR MD Make directory HELP HELP Help commands TREE LS View subtree ATTRIB CHMOD View/change file attributes