:: Riassunto Capitolo 3 - Struttura dei SO ::
Torna alla pagina di Sistemi Operativi
Diversi punti di vista per considerare un SO:
Processo = programma in esecuzione => chiamate di sistema per permettere ai processi di creare sottoprocessi da eseguire in modo concorrente.
OCIO: programma != processo: programma = passivo processo = attivo
Processo: esecuzione sequenziale => contatore di programma che dice qual'è la prossima istruzione da eseguire.
In relazione ai processi, il SO deve:
Durante la fase di fetch la CPU preleva istruzioni dalla memoria. La fase di data-fetch invece legge e scrive sulla memoria.
Multiprogrammazione => occorre gestire la memoria centrale:
Uso comodo del computer => visione logica di memorizzazione delle info => file = unità logica di memorizzazione.
File = insieme di info correlate dal creatore del file. Organizzati in directory per facilitarne l'uso.
Operazioni che il SO fa riguardo ai files:
Sottosistema di I/O = nasconde le caratteristiche dei dispositivi I/O al resto del SO.
Il sottosistema I/O è fatto di:
Dicevamo che la memoria centrale è troppo piccola per contenere tutto, e soprattutto è volatile => occorre avere un'unità di memorizzazione secondaria che supplisca, e da cui e verso cui copiare dati e programmi che man mano servono
Le unità di memorizzazione secondarie vanno ben gestite:
Sistema distribuito = insieme di processori che non condivide memoria, periferiche o orologio => collegati con una rete di comunicazione
HW per realizzare la rete + SW per gestirla = rete informatica
Processi separati protetti l'un l'altro
Protezione = insieme dei meccanismi per il controllo dell'accesso alle risorse da parte dei processi o degli utenti dei computer.
Interprete dei comandi = uno dei programmi di sistema più importanti = interfaccia tra utente e SO.
SO = differenti in base all'amichevolezza dell'interprete dei comandi, che può esere una shell testuale o una GUI (graphical user interface).
Comandi accessibili tramite interprete = tutti, eg gestire processi, I/O etc.
Ogni SO fornisce servizi diversi ma si possono raggruppare in categorie comuni
Gruppo di funzioni che servono ad assicurare un uso efficiente del sistema:
Chiamata di sistema = interfaccia tra processo e SO => accessibili in assembly o anche in linguaggi di alto livello => in questo caso assomigliano a chiamate di funzioni normali.
Dettagli di tale interfaccia = nascosti al programmatore.
Passare parametri al SO: tre metodi
Gli ultimi 2 metodi non impongono limitazioni al numero di parametri.
Chiamate di sistema = raggruppabili in 5 categorie:
Processo:
load = caricare un altro programma. execute = eseguire l'altro programma. => i nuovi programmi possono essere eseguiti in sequenza (A crea B, lo esegue, B finisce e il controllo torna ad A) oppure in modo concorrente (A crea B e ognuno va per la sua strada).
Patria potestà sui processi generati:
Debug: dump della memoria per vedere eventuali errori; trace per seguire le istruzioni passo passo => alcune CPU hanno la modalità single step in HW, in cui dopo ogni istruzione si esegue una TRAP.
Tracciamento = con trace e temporizzatore vedo quali porzioni di codice sono più usate dal mio processo => utile per i programmatori.
Esempi: MSDOS: SO a processo singolo => carico un programma e questo sostituisce una parte dell'interprete dei comandi. Quando termina, ricarica l'interprete dei comandi. TSR = terminate and stay resident = intercetta interrupt, viene eseguito e termina, ma non viene tolto dalla memoria => l'interprete gli riserva dello spazio non sovrascrivibile.
FreeBSD: multitasking. Un utente lancia un comando dalla shell => la shell fa una fork e poi nella copia ottenuta viene chiamata la exec, che sostituisce il codice della shell con quello del programma invocato. Si può scegliere di attenderne l'esecuzione, o di eseguirlo in parallelo.
Generare, cancellare, read, write, reposition, close. Idem per le directory. Occorre anche saper leggere e impostare gli attributi dei files.
File = si possono vedere come dispositivi astratti => le chiamate di sistema per i files vanno bene anche per i dispositivi.
Infatti molti SO (eg UNIX) mappano i dispositivi nel filesystem.
Ora, data, numero di utenti, versione del SO, RAM libera, disco utilizzato; info per ogni processo (chi lo ha eseguito, da quanto, quanta RAM occupa etc. => Capitolo 4.1.3)
2 modelli:
Message passing = il SO permette la creazione di un collegamento fra processi.
Shared memory = si elimina consensualmente tra processi la protezione della memoria, così che più processi possano accedervi.
Programmi di sistema = ambiente opportuno per sviluppo ed esecuzione di programmi.
Ci sono anche i programmi applicativi.
Programma di sistema più importante = interprete dei comandi.
2 modi per implementare i comandi dell'interprete:
UNIX usa il metodo 2:
L'utente vede il SO tramite i programmi di sistema, non tramite le chiamate di sistema.
OCIO: il SO non fa distinzione tra processi applicativi e processi di sistema: per lui sono tutti processi.
Dopo aver visto le componenti, ora vediamo come metterle insieme in un kernel = nucleo.
Sistemi che non sono divisi in moduli, per vari motivi progettuali o storici.
Interfaccia dei programmi applicativi = API = chiamate di sistema. Interfaccia utente = gruppo di programmi di sistema disponibili, che usano le chiamate di sistema.
=> Top-down: dall'utente all'hardware => le interfacce esterne possono rimanere identiche anche se quelle interne cambiano.
SO = diviso in layer (strati). Il più basso è l'hw. Quello più alto è l'interfaccia utente.
Vantaggi:
Difficoltà:
Microkernel = tutto ciò che non è indispensabile è levato dal kernel. Fondamentalmente rimangono i meccanismi di comunicazione tra processi.
Tutto il resto è implementato come programmi di sistema.
Pro:
Contro:
C'è un kernel centrale, e intorno, allo stesso livello, sono creati diversi moduli, raggruppabili in 7 categorie:
In questo modo, il kernel offre le funzioni base, gli altri moduli forniscono il resto, e i vari moduli possono comunicare direttamente tra loro senza passare per gli strati.
Virtualizzazione = dare al processo l'illusione di avere una macchina tutta per sé.
Sopra l'HW c'è l'implementazione di una macchina virtuale => la macchina virtuale riproduce una copia esatta dell HW sottostante => su ogni macchina gira un kernel diverso.
I processi girano quindi dentro il loro SO privato.
Pro:
Implementazione: prima dicevamo che c'è una modalità utente, e una modalità di sistema (monitor) => qui le cose si complicano perché c'è la modalità utente virtuale e la modalità monitor virtuale.
Le macchine virtuali (VM) sono processi che, rispetto al SO vero e proprio sottostante (quello che offre una copia dell'HW), sono dei processi utente.
Un processo su una VM gira in modalità utente virtuale. Quando fa chiamate di sistema, queste vengono eseguite in modalità monitor virtuale.
=> una chiamata I/O fa questa strada: utente virtuale => monitor virtuale => utente fisico => monitor fisico; poi c'è il ritorno => può metterci molto tempo.
Java = è una tecnologia, non un semplice linguaggio, perché fornisce un sacco di cose in più rispetto ad un semplice linguaggio:
Unisce l'idea di macchina virtuale, realizzata come processo utente su di un SO => i concetti visti nei paragrafi sopra non sono mutuamente esclusivi.
Orientato agli oggetti, indipendente dall'architettura, distribuito, multithread.
Le classi sono compilate in bytecode, a sua volta eseguito dalla macchina virtuale (realizzata in SW o anche in HW, volendo).
Applet = programmi con accesso limitato alle risorse eseguibili direttamente in un browser web.
Garbage collection = l'allocazione e la deallocazione della memoria è a carico di Java e non dell'utente.
Nel testo ci si concentra sulle API standard.
Java Virtual Machine = JVM => caricatore di classi ed interprete che esegue i bytecode.
Bytecode = formato in cui sono compilate le classi => è indipendente dall'architettura HW => un programma Java funziona su qualsiasi JVM su qualsiasi sistema operativo.
Interprete = esegue i comandi uno alla volta, o li compila in tempo reale (JIT = just in time) in linguaggio nativo del computer ospite.
Piattaforma Java = astrazione dalla macchina fisica => permette la portabilità.
Ambiente di compilazione e di run-time. Ambiente di compilazione = trasforma una classe in bytecode Run-time = la JVM su cui viene eseguito il codice
È basato sul linguaggio => tutto funziona nello stesso spazio di indirizzamento => la protezione della memoria è affidata al linguaggio e non al SO.
Primo problema = definire obiettivi e specifiche.
Alto livello:
Obiettivi dell'utente:
Obiettivi del programmatore:
=> In conclusione, sono tutti obiettivi vaghi e non c'è accordo su come realizzarli => creatività ed esperienza.
Ci sono però principi generali, che vediamo qui sotto.
Meccanismo = come fare qualcosa. Politica = che cosa fare, e quando
Desiderabile avere meccanismi slegati dalle politiche:
=> posso provare e sperimentare diverse politiche e meccanismi
Dopo la progettazione, devo realizzare il SO.
Tradizonalmente = assembly o linguaggio macchina.
Ora = linguaggi a più alto livello (in genere C).
Vantaggi dell'utilizzo di linguaggi ad alto livello:
Svantaggi:
Però:
=> uso l'ASM per le parti critiche, dopo aver identificato i colli di bottiglia (trace e debug, vedi sopra).
Posso scrivere SO specifici per una certa macchina.
Ma in generale sono più versatili (girano su più HW etc.) => il procedimento chiamato SYSGEN (system generation) configura il SO in base ai parametri:
Queste scelte possono essere prese una volta, oppure organizzate in tabelle => all'avvio, il SO legge dalle tabelle e si autoconfigura.
L'avvio del sistema operativo avviene nella fase di boot.
Bootstrap: all'avvio o al reset, viene caricato il program counter con una locazione di memoria prestabilita => l'esecuzione parte da lì.
Il programma di bootstrap di solito è in ROM. Può fare tutto quello che vuole (diagnostica etc.). Alcuni SO hanno tutto in ROM (eg i palmari) => EPROM riscrivibili etc.
Sistemi operativi grandi: