Sistemi operativi
Introduzione
Un sistema operativo è un insieme di programmi che gestiscono l'hardware del computer. Esso funge da intermediario tra l'utente e l'hardware del computer. Un sistema di calcolo si può suddividere in quattro componenti:
- L'hardware che fornisce le risorse di calcolo
- I programmi applicativi che definiscono il modo con cui usare le risorse
- Il SO che controlla e coordina l'uso dell'hardware da parte dei programmi applicativi
- Gli utenti
Definizioni del SO
Dal punto di vista del calcolatore, il SO ha diverse definizioni:
- Distributore di risorse, perché gestisce e distribuisce le risorse in caso di conflitti di richieste di risorse
- Programma di controllo, perché controlla l'esecuzione dei programmi utente e l'esecuzione dei dispositivi di I/O
- Kernel, perché è l'unico programma sempre in esecuzione
Sistemi mainframe
Sistemi a lotti
L'utente non interagiva con il sistema, ma preparava un job da eseguire, composto dal programma, i dati e le info sul tipo di lavoro e lo affidava al sistema. Questi tipi di SO trasferivano il controllo da un job al successivo. Lo svantaggio principale era la perenne inattività della CPU, perché molto più veloce dei dispositivi meccanici di I/O. Disponendo di un mezzo ad accesso diretto, il SO poteva organizzare la sequenza dei job, raggruppandoli in lotti (batch) con necessità simili, da far eseguire insieme, per velocizzare l'esecuzione.
Sistemi multiprogrammati
L'idea alla base di questo tipo di sistema è che il SO tiene contemporaneamente in memoria più processi e la CPU rivolge la sua attenzione ad uno di loro alla volta. La multiprogrammazione consente di aumentare l'uso della CPU organizzando i job in modo da tenerla sempre attiva. In questo modo, mentre un processo è in attesa di un evento, si esegue un altro processo. Se più processi sono pronti per essere caricati ed eseguiti, si dovrà effettuare:
- Job scheduling, per scegliere quali job caricare;
- CPU scheduling, per scegliere quali job eseguire.
Inoltre, è necessaria una gestione della memoria.
Sistemi time-sharing
Il time-sharing è un'estensione della multiprogrammazione, in cui si assegna ad ogni processo utente in memoria una porzione di tempo e alla scadenza la CPU viene allocata al processo dell'utente successivo. In questo modo, si dà all'utente l'impressione che il sistema sia totalmente dedicato ad ognuno di loro. Questo tipo di SO è interattivo poiché c'è uno scambio di informazioni tra utente e processo durante l'esecuzione.
Sistemi desktop
I PC sono computer rivolti al singolo utente. All'inizio le loro CPU non possedevano caratteristiche adeguate a proteggere un SO dai programmi. Sono vantaggiosi perché:
- Permettevano l'uso dei dispositivi di I/O
- Hanno una buona prontezza nella risposta
- Possono supportare diversi tipi di SO
Sistemi paralleli
I sistemi paralleli possiedono più processori in stretta comunicazione tra loro, condividendo i canali di comunicazione, il clock e la memoria. Sono conosciuti come sistemi multiprocessore e hanno tre vantaggi:
- Maggiore quantità di elaborazione effettuata
- Economia di scala, consentono di risparmiare perché condividono i dispositivi periferici e alimentatori elettrici
- Aumento di affidabilità, perché un guasto di un'unità non blocca il sistema, ma lo rallenta. La capacità di continuare, nonostante un guasto, si dice degradazione progressiva. Per questo motivo questi sistemi sono tolleranti ai guasti.
I sistemi più comuni impiegano un sistema multiprocessore simmetrico in cui:
- Ogni processore esegue una copia del SO
- Possono essere eseguiti contemporaneamente molti processi
- Vi è un problema di gestione del lavoro, perché un'unità potrebbe essere inattiva mentre un'altra è sovraccaricata.
Altri sistemi impiegano un sistema multiprocessore asimmetrico, in cui ad ogni processore ha assegnato uno specifico lavoro; mentre un processore principale (master) organizza e gestisce lavoro per i processori slave.
Sistemi distribuiti
I sistemi distribuiti sono sistemi in cui il calcolo viene distribuito tra i diversi processori fisicamente distinti. Vengono definiti sistemi debolmente accoppiati, in cui ogni processore possiede una propria memoria e comunicano tra loro tramite bus ad alta velocità o linee telefoniche. Questi sistemi possiedono molti vantaggi, tra cui: condivisione delle risorse, rapidità di calcolo e distribuzione del carico. Per poter funzionare necessitano di una infrastruttura di rete, che può essere locale (LAN) o geografica (WAN). Possono essere sistemi Client-Server o peer-to-peer. Il modello Client-Server più usato, modello master-slave.
Sistemi cluster
Il clustering permette a due o più sistemi di condividere periferiche. Questo tipo di soluzione si adotta per fornire un'elevata disponibilità. Se si presenta un malfunzionamento, il calcolatore che svolge il controllo si appropria dei mezzi di memorizzazione del calcolatore funzionante e riavvia le app in esecuzione. L'utente noterà solo una breve interruzione del servizio. Nei cluster asimmetrici, un server esegue un’app; mentre gli altri sono in hot-standby mode, pronti ad intervenire in caso di failure. Nei cluster simmetrici, tutti eseguono l'app e si controllano a vicenda.
Sistemi real-time
Sono sistemi molto usati quando si devono completare le operazioni in tempi prefissati. Si dividono in:
- Hard real-time, assicura che i compiti critici siano completati in un certo intervallo di tempo. I dati vengono memorizzati in una memoria a breve termine o di sola lettura (ROM). Questi tipi di sistemi tendono a separare l'utente dall’hardware, introducendo incertezza sui tempi di esecuzione. Inoltre, i requisiti di questi tipi di sistema sono in conflitto con i sistemi time sharing;
- Soft real-time, in cui si dà priorità massima ai processi critici, in modo da terminarli il prima possibile. Sono compatibili con i sistemi di time sharing, perché le attese nel nucleo devono essere limitate. Questo porta non poter rispettare i vincoli di tempo.
Sistemi palmari
Sono sistemi usati in dispositivi di ridotte dimensioni con hardware poco prestante, memoria limitata, processori lenti e ristrette disponibilità di alimentazione. Questo porta:
- Ad una gestione della memoria e della batteria;
- Ad una progettazione di SO e app tale da non gravare troppo sulla CPU;
- Accontentare le attività più comuni in schermi più piccoli.
Architettura del calcolatore
Un moderno calcolatore è composto da una CPU e dai controller dei dispositivi di I/O messi in comunicazione tramite i bus. Ogni controller gestisce una specifica periferica o set simili, e hanno una memoria temporanea locale, detta buffer. Il controller, informa la CPU di aver concluso un'operazione, generando un interrupt.
Gestione dell'interrupt
I moderni SO sono interrupt driven, gli eventi sono segnalati da un interrupt. Il vettore degli interrupt ha gli indirizzi di tutte le routine di gestione interrupt (interrupt handler), in cui sono definite le azioni da eseguire per gestire gli interrupt. Quando la CPU rileva un interrupt, avviene un cambio di contesto computazionale. Prima di lanciare la routine di gestione interrupt, si salva lo stato corrente e l'indirizzo dell'istruzione interrotta. Si effettua un’operazione detta polling, cioè si effettua una scansione dei dispositivi, interrogando ognuno e cercando una conferma su una eventuale richiesta di interrupt inviata. Quando il dispositivo in questione viene interrogato, invierà una conferma al processore e quest’ultimo avvierà la routine di gestione dell’interrupt relativa a tale dispositivo. La procedura di gestione interrupt determina le cause dell'interrupt, porta a termine le operazioni necessarie (recuperandole dal vettore degli interrupt), ricarica lo stato e riporta la CPU nello stato in cui si trovava prima dell'interrupt. Si definisce trap, un interrupt generato dal software a fronte di un errore o una richiesta utente.
Struttura dell'I/O
Per iniziare un'operazione di I/O, la CPU modifica i registri del controllore del dispositivo, comunicando l'operazione da eseguire. Il controller esamina il contenuto e completa il trasferimento. Al termine dell'operazione, informa la CPU tramite un interrupt di ritorno. La chiamata di I/O può essere:
- Sincrona o bloccante, si restituisce il controllo al processo utente solo dopo il completamento dell'operazione. Quindi, la CPU rimane inattiva e per poterlo fare alcuni calcolatori hanno un'istruzione di attesa; altri hanno un ciclo di attesa. Le chiamate sincrone possono essere eseguite una alla volta quindi il SO sa quale dispositivo richiede l’interrupt.
- Asincrona, eseguita tramite una chiamata di sistema che restituisce il controllo al processo senza aspettare il completamento dell'operazione. In questo caso, la CPU può svolgere altre operazioni durante l'attesa. Per avvisare il processo del completamento dell'operazione, si esegue un'altra chiamata di sistema. Per mantenere traccia delle richieste di I/O attive, il SO utilizza la device status table.
Device status table
A fronte di un maggior numero di richieste di I/O, è necessario gestire questo flusso. Per realizzare uno scheduling delle richieste, si tiene per ogni dispositivo una coda di richieste. Quando un’app richiede l’esecuzione di una chiamata di I/O bloccante, si aggiunge la richiesta alla coda. I kernel col il metodo I/O asincrono associano una tabella dello stato dei dispositivi alla coda dei processi in attesa. Gli elementi della tabella, uno per dispositivo, indicano il tipo, l’indirizzo e lo stato in cui si trova.
Accesso diretto alla memoria
Quando un dispositivo trasferisce grandi quantità di dati, l'uso della CPU per il controllo del bit di stato e per la scrittura dei dati nel registro del controllore, è uno spreco. Per evitare di sovraccaricare la CPU, si assegna una parte di questi compiti a un processore, detto Direct Access Memory (DMA). Grazie ad essa, si possono spostare blocchi dati senza l’intervento della CPU, che può eseguire nel frattempo altre operazioni. Un vantaggio legato all’uso della DMA è la generazione di un interrupt per blocco e non per byte.
Struttura della memoria
La memoria di un calcolatore viene divisa in:
- Memoria centrale: è un’unità di memorizzazione, cui la CPU può accedere direttamente via bus. È organizzata come un array di stringhe di bit, dette word. La CPU può accedere agli elementi della memoria centrale in tre modi:
- I/O mappato in memoria: i blocchi di indirizzi di memoria sono mappati in registri dati o registri indirizzi
- I/O programmato o sincrono: la CPU interroga un bit di controllo relativo a una data porta di I/O
- I/O interrupt driven: la CPU riceve un interrupt quando il dispositivo è pronto
- Memoria secondaria: è un’unità che si aggiunge a quella centrale. Rispetto ad essa, è una memoria non volatile. Il dispositivo più usato è il disco magnetico.
Dischi magnetici
I dischi magnetici sono suddivisi in tracce concentriche e settori, dove ogni settore è una fetta di disco. Le informazioni vengono lette e scritte da delle testine, che si posizionano in corrispondenza dell’indirizzo desiderato. Il tempo di accesso alle informazioni è dato dalla somma di tre tempi dovuti a:
- Spostamento della testina fino a raggiungere la traccia
- Attesa che il settore passi sotto la testina
- Tempo di lettura delle informazioni
Un problema correlato ai dischi magnetici è l’head crash. Si verifica quando la testina entra in contatto con il piatto rotante, scalfendo la superficie e danneggiando il supporto magnetico.
Gerarchia di memorizzazione
I sistemi di memorizzazione si possono organizzare a livello grafico in base a: velocità, tempo di esecuzione, costo, dimensioni e velocità. Scendendo nella gerarchia, il costo per bit diminuisce, ma aumenta il tempo di accesso. Nella struttura, gli elementi sopra i dischi RAM sono memorie volatili. Con il termine caching, si intende la copia temporanea dell'informazione in un sistema di memorizzazione più veloce. Inoltre, la memoria centrale può essere vista come cache veloce per dispositivi di memorizzazione secondari.
Caching
Di norma, le informazioni sono mantenute in memoria centrale e, al momento del loro uso, si copiano in una unità più veloce, la cache. Data la loro capacità limitata, è necessaria una politica di gestione della cache.
Protezioni hardware
La multiutenza, la multiprogrammazione e la condivisione di risorse implicano uno sfruttamento più efficiente del sistema, contrapposto all'insorgenza di problemi dovuti alla necessità di una protezione hardware. Esistono vari metodi per la protezione hardware, senza cui un sistema dovrebbe seguire un solo processo per volta.
Modalità differenziate
Per garantire il corretto funzionamento del sistema, è necessario proteggere il SO e gli altri programmi, da programmi malfunzionanti. Molti SO permettono di gestire differenti modi di utilizzo. Sono necessarie almeno due modi: modo utente e modo di sistema. Per indicare quale dei due sia attivo, si utilizza un bit di modalità. Il livello di protezione si ottiene definendo le istruzioni che possono causare danni allo stato del sistema. Esse vengono definite istruzioni privilegiate e possono essere eseguite solo in modalità di sistema. Se si tenta di seguirlo in modalità utente, la CPU non la esegue ma invia un segnale di eccezione al SO. Le istruzioni privilegiate consentono all'utente di interagire col SO, chiedendogli di eseguire compiti che solo lui può eseguire. Questa richiesta è nota come chiamata di sistema.
Protezione dell'I/O
Per evitare che i processi utente effettuino I/O non consentiti, tutte le istruzioni di I/O sono privilegiate. Affinché la protezione sia totale, un programma utente non deve mai poter ottenere il controllo della macchina in modalità di sistema.
Protezione della memoria
Per proteggere il SO dall'accesso degli altri programmi e proteggere i programmi gli uni dagli altri, si definisce un range di indirizzi legali a cui il programma può accedere. Questo avviene tramite due registri:
- Registro base, che contiene il più piccolo indirizzo legale della memoria fisica
- Registro limite, che contiene la dimensione del range degli indirizzi.
Qualsiasi tentativo, da parte di un programma in modalità utente, di accedere alle aree riservate, comporta l'invio di un segnale di eccezione.
Protezione della CPU
Per evitare che un programma trattenga la CPU per un tempo indefinito, si usa un timer, decrementato ad ogni colpo del clock. All'azzerarsi del timer, si genera un interrupt, passando il controllo al SO che decide se generare un errore o assegnare più tempo al programma.
Struttura dei SO
Un SO fornisce alcuni servizi:
- Gestione dei processi. Un processo si può considerare come un programma in esecuzione, che per essere eseguito, necessita di risorse che gli vengono allocate alla sua creazione o durante la sua esecuzione;
- Gestione della memoria centrale;
- Gestione dei file. Un file è un insieme di informazioni correlate definite dall'utente;
- Gestione dell’I/O;
- Protezione;
- Gestione della memoria di massa;
Interprete dei comandi
L'interprete dei comandi è un programma del SO che funge da interfaccia tra utente e SO. L'utente impartisce ordini tramite istruzioni di controllo che vengono lette e interpretate. Per questo motivo è anche detto interprete delle istruzioni di controllo o Shell. Un'interprete dei comandi può essere sia a caratteri che grafica.
Architettura di un SO
Una tipica suddivisione delle architetture dei SO è la seguente:
- Semplice: c'è una minima organizzazione gerarchica per garantire le massime funzionalità nel minimo spazio. Un esempio è MS-DOS, che non fu ben diviso in moduli ed era vulnerabile a programmi errati o maliziosi;
- Monolitica: composta da unico modulo che serve le richieste dei programmi utente singolarmente. Un esempio è UNIX. In un unico livello occorreva combinare molteplici funzioni, per questo, era difficile da modificare perché si generavano molti errori;
- A strati: composto da n livelli modulari, dove lo zero è l'hardware ed n l'interfaccia utente. Ogni strato ha funzioni ben determinate e può richiedere i servizi dei soli strati inferiori. Con questo tipo di sistema, gli errori sono più facili da individuare, perché ogni strato viene caricato uno alla volta. Di contro però, per servire una richiesta bisogna attraversare molteplici strati. Per risolvere questo problema, si cerca di creare meno livelli con più funzioni. Un esempio è OS/2.
- Microkernel: il nucleo ha solo funzioni strettamente necessarie, mentre tutto il resto viene realizzato come programmi a livello utente e di sistema. Il sistema ne risulta più sicuro, affidabile, portabile è facilmente estendibile. Purtroppo, possono soffrire di cali di funzione a causa del sovraccarico delle funzioni di sistema.
- Ibrida: suddiviso in ambiente applicativo e servizi, sotto cui c'è il kernel diviso in microkernel Mach e BSD.
- Modulare: il nucleo viene creato con una programmazione orientata agli oggetti. È simile a:
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
-
Sistemi operativi - Appunti
-
Appunti di Sistemi operativi
-
Appunti Sistemi Operativi - Seminari sistemi UAV , sistemi operativi NuttX-ROS
-
Sistemi operativi - Appunti