Corso di Sistemi Operativi
Laurea triennale in Ingegneria Informatica
Docente: Enzo Mumolo
Obiettivi formativi:
L'obiettivo del corso è di fornire una conoscenza dei meccanismi e delle politiche realizzate ad ogni
livello di un Sistema Operativo e le principali problematiche relative alla interazione dell’utente con il
sistema operativo UNIX/LINUX e della programmazione di sistema in Shell e Perl scripting.
Programma del corso:
Definizioni di base, servizi di un S.O., il S.O. come rete di code, come gestore risorse, come
macchina astratta. Cenni storici; classificazione secondo la organizzazione interna; sistemi monolitici,
stratificati, macchina virtuale, client/server. Nozioni di base: risorse, processi, PCB, thread, spooling,
stati di un processo, variabili d’ambiente, protezione delle risorse, processi demoni, file system.
Processi concorrenti in un ambiente a memoria condivisa.
Mutua esclusione, soluzioni software, algoritmo di Peterson, soluzioni hardware, sleep/wakeup,
semafori, soluzioni semaforiche di alcuni problemi tipici della concorrenza, alcun problemi codificati
in Java.
Sincronizzazione, alcun problemi codificati in Java.
Stallo, prevenzione, rilevamento e recupero, evitare lo stallo, algoritmo del banchiere, rilevare
lo stallo con piu’ risorse e piu’ istanze per risorsa.
Gestione dell’unita’ centrale: schedulazione ottima, processi CPU-bound e I/O bound,
predizione del tempo di elaborazione, schedulazione prioritaria, schedulazione Round Robin.
Gestione memoria contigua e gestione memoria paginata, memoria virtuale.
Gestione memoria di massa, alcuni file system.
Strutture di Unix: file mode, PID, GID, ID effettivo, ereditarieta’, redirezione, processi in
foregroud, background, struttura del file system, Inode, path, directory, protezione dei file, UFDT,
tabella dei file. Unix come macchina astratta: comandi utente, shell, editors, link hard e simbolici,
espressioni regolari, programmazione in shell, Perl, gestione file in Perl, generazione e gestione
processi in Perl, esempi di programmazione, esercitazioni pratiche.
Appunti di Sistemi Operativi
Enzo Mumolo
e-mail address :[email protected]
web address :www.units.it/mumolo
Indice
1 Introduzione
1.1
1
Struttura di un computer
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.1.1
Sistema operativo come macchina astratta . . . . . . . . . . . . . . . . . . . .
2
1.1.2
Sistema operativo come gestore di risorse
. . . . . . . . . . . . . . . . . . . .
2
1.1.3
Sistema operativo come architettura
. . . . . . . . . . . . . . . . . . . . . . .
2
1.2
Servizi e classicazione dei SO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.3
Storia e struttura dei sistemi operativi
4
Sistemi a strati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.4
Il kernel ed i processi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.3.1
1.5
1.6
. . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1
Macchine virtuali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
1.4.2
Modello client-server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
1.4.3
Sistemi monolitici
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
1.4.4
Il kernel di Unix
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
Le risorse
1.5.1
La protezione delle risorse . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
1.5.2
I thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
Le strutture fondamentali
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.6.1
PCB: Process Control Block . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.6.2
I le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
1.7
I processi e la Comunicazione tra processi (Inter Process Communicatons o IPC)
. .
16
1.8
Lo Spooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
i
Capitolo 1
Introduzione
1.1 Struttura di un computer
Figura 1.1 Struttura semplicata di un calcolatore
Esistono almeno due modi per poter denire e analizzare un moderno calcolatore:
il primo
dall'alto verso il basso, il secondo dal basso verso l'alto. Più precisamente:
dall'alto verso il basso, ovvero vederlo come macchina astratta (all'utente interessa utilizzare
consiste nel guardarlo
1.
la macchina senza occuparsi dell'implementazione che c'è sotto); da questo punto di vista viene
nascosta la complessità dei livelli sottostanti.
2.
dal basso verso l'alto, ovvero come gestore di risorse:
ci si pone dal punto di vista dell'hard-
ware, ovvero si guarda a come possono essere gestiti i vari dispositivi.
Fino ad alcuni anni fa dare una denizione di sistema operativo era tutto sommato facile: era
quel particolare strato di software che gestiva l'hardware. Al giorno d'oggi invece è dicile tracciare
rmware
un solco netto tra HW e SW; si pensi ad esempio al
(o microprogramma): esso è un
microcodice solitamente allocato in una ROM che serve ad interpretare un insieme di istruzioni ed
eseguirle attraverso una sequenza di passi elementari (l'insieme delle istruzioni interpretate denisce
il
linguaggio macchina):
ora questo strato può considerarsi parte integrante dell'hardware. Per-
tanto oggi si è più propensi a denire un sistema operativo come
un sistema che ore servizi
di
macchina astratta o di gestione delle risorse.
Esistono moltri altri punti di vista dai quali poter analizzare un computer: nel proseguio del
architettura.
corso verrà considerato anche una terza prospettiva: l'
Vediamo ora in dettaglio cosa vuol dire studiare un sistema da questi tre diversi punti di vista.
1
1.2 Servizi e classicazione dei SO
2
1.1.1 Sistema operativo come macchina astratta
Signica sostanzialmente studiare il modo in cui l'utente si approccia alla macchina: studiare la
shell e i servizi che questa ore, ad esempio:
- permette di spostare, copiare e rinominare le di varia natura;
√
creare applicazioni:
permette (e questo è un aspetto molto importante) di
ovvero il sistema
operativo crea, attraverso la macchina astratta, un ambiente per creare, eseguire e terminare
programmi (o applicazioni).
Qui dentro ci sono ad esempio i linguaggi compilati e quelli
interpretati (questi ultimi sono i più numerosi:
si pensi ad esempio ai linguaggi di shell,
l'HTML, il perl. . . )
1.1.2 Sistema operativo come gestore di risorse
Studiare il sistema come gestore di risorse può signicare migliorare le prestazioni della macchina:
- Facendo lo
scheduling della CPU: quest'ultima infatti deve essere continuamente suddivisa
tra i vari lavori. . .
- La memoria dev'essere sempre utilizzata al meglio: bisogna evitare il più possibile la frammentazione, bisogna garantire una buona allocazione dei dati. . .
- Bisogna gestire bene l'I\O in termini di tempi d'accesso e di adabilità. . .
- Bisogna gestire bene le risorse (e si badi che queste non sono solo HW, ma anche SW: si pensi
ad esempio ai processi). . .
1.1.3 Sistema operativo come architettura
Figura 1.2 Possibile rete di code d'attesa.
Dal punto di vista del progettista (ovvero colui che deve
operativo può essere visto come una rete di
code d'attesa:
dimensionare la macchina) il sistema
la gura a destra mostra una possibile
rappresentazione (estremamente semplicata) delle code che un processore deve essere in grado di
gestire in maniera eciente.
1.2 Servizi e classicazione dei SO
I servizi fondamentali di un Sistema Operativo sono i seguenti:
•
Creazione, esecuzione e terminazione dei programmi
1.2 Servizi e classicazione dei SO
•
Operazioni di Ingresso/uscita
•
Manipolazione di le
•
Gestione degli errori: Hardware, I/O, errori di utente
•
Allocazione delle risorse: CPU, memoria, le, I/O
•
statistiche nell'uso delle risorse
•
Protezione e Sicurezza
3
Un sistema operativo può essere classicato in base al suo utilizzo da parte dell'utente:
Generale:
Batch:
Uso secondo il quale non c'è una particolare utilizzazione prevista per i sistema.
In questo caso il sistema non ha interazioni con l'utente: ovvero le interazioni con l'utente
avvengono attraverso memorie di massa. Ogni processo parte da dati memorizzati esempio su
nastro e arriva a dei risultati memorizzati ad esempio su scheda perforata.
Interativo:
Dedicato:
È la
shell:
ovvero il sistema aspetta i comandi dell'utente.
Sistemi progettati per eseguire solo determinate applicazioni (rientrano in questo campo
i sistemi
embedded, ad esempio, dei cellulari).
Transazionali:
Sistemi progettati per gestire enormi quantità di dati.
Ogni sistema nasce quindi con delle modalità di utilizzo che hanno delle inuenze molto pesanti sul
tipo di struttura di cui sarà dotato: non esiste pertanto un sistema che possa soddisfare tutte le
diverse applicazioni.
1.3 Storia e struttura dei sistemi operativi
4
1.3 Storia e struttura dei sistemi operativi
Un modo per classicare i sistemi operativi è quello di farlo in base alla loro struttura interna.
1.3.1 Sistemi a strati
Il primo modo in cui si è iniziato a concepire un sistema operativo è stato mediante delle strutture
a livello.
Figura 1.3 Struttura onion skin.
Questo tipo di struttura è chiamata
onion skin (a buccia di cipolla):
in questi modelli il sistema
operativo è organizzato come una gerarchia a strati, ognuno costruito sopra il precedente; compito
di ogni strato è quello di fornire servizi allo strato superiore (per esempio la memoria utilizza servizi
che chiede al kernel).
Figura 1.4 Interazione ai conni del nucleo
Ogni strato interagisce col sottostante attraverso delle opportune interfacce (gura 1.4); questo
avviene ad ogni livello: se per esempio la shell ha bisogno del nucleo deve passare diversi conni.
Questo comporta che la struttura risulti molto pesante al ne delle prestazioni (infatti
l'attraversamento dei vari conni si traduce in elevati tempi di risposta).
In precedenza era stato sottolineato che il primo servizio di un sistema operativo è quello di
creare, eseguire e terminare processi: questo signica che il sistema operativo deve orire un ambiente per l'esecuzione delle applicazioni che dev'essere il più eciente possibile: pertanto risulta
immediato capire che le massime attenzioni saranno rivolte anché l'esecuzione sia più veloce possibile: tutto quello che si contrappone a questa esigenza è chiamato
sovraccarico.
1
Ogni sistema
operativo possiede un sovraccarico che deve tenere il più basso possibile . In una struttura del tipo
onion skin il sovraccarico è massimizzato.
Da questo discorso emergono due aspetti fondamentali della progettazione dei sistemi operativi:
1
Ed è anche il motivo per cui si cercano sempre algoritmi il più semplici possibile.
1.4 Il kernel ed i processi
L'ecienza
5
(ovvero il sovraccarico);
La protezione
del sistema: le strutture del sistema operativo devono essere robuste rispetto al-
l'esecuzione dei processi.
Stiamo parlando ovviamente del caso in cui non ci sia malizia
nell'esecuzione dei processi: ad esempio se viene fatto girare un programma bisogna assolutamente evitare che questo (per errori di programmazione) possa in alcun modo modicare
alcune strutture del sistema operativo.
Diverso è il caso della
sicurezza, caso in cui bisogna difendere il sistema operativo da intrusioni
esterne con scopi maliziosi.
La protezione del sistema si realizza costruendo questi conni in maniera molto precisa: in genere
vengono progettati in modo da poter essere attraversati solo con l'uso delle
trap);
trappole software (le
ovvero se mi trovo in un livello e voglio accedere a quello sottostante
devo volerlo fare
e
invoco le trappole: questo serve per evitare problemi accidentali. Ma cosa sono le trappole?
Le trappole rappresentano il meccanismo principale attraverso cui si cambia di livello: esse non
sono nient'altro che delle
interruzioni software che provocano:
a. il salvataggio sullo stack dello stato del processore (del program counter);
b. il cambiamento della
modalità di esecuzione del processore.
I processori hanno almeno due modalità di esecuzione:
user e system.
Non in tutte le modalità
si possono eseguire le stesse istruzioni: per esempio se il processore è in modalità user si hanno
delle restrizioni su alcune funzioni assembler. Per quanto riguarda la struttura onion skin, questa
prevede sei modalità di esecuzione come si può vedere dalla gura
?? e sono quelle consentite
dal processore (ogni processore infatti può orire o meno determinate modalità).
1.4 Il kernel ed i processi
Il compito fondamentale di ogni sistema operativo é quello di fornire un ambiente adatto per l'esecuzione dei programmi utente, e di fornire agli stessi tutte le caratteristiche richieste. I processi sono
descritti mediante strutture dati chiamate in generale PCB, che rappresentano tutte le informazioni
dei processi. Tali strutture dati sono accodate in una lista, come rappresentato nella seguente gura:
Figura 1.5 Lista dei descrittori dei processi
É compito del sistema operativo estrarre un descrittore attraverso gli algoritmi di schedulazione
e farli eseguire assegnando loro la CPU. In questo modo, la funzione di un sistema operativo - quella
di eseguire processi - puó essere riassunta dallo pseudocodice di g.1.2.
Secondo questo schema, il sistema é gestito da una serie di interruzioni che producono la esecuzione a divisione di tempo: ad ogni interruzione del timer lo schedulatore seleziona un descrittore
di processo al quale viene assegnata la CPU e che viene rimesso in coda una volta che l'esecuzione
é terminata. Questa esecuzione puó essere descritta nella gura 1.3.
interfaccia di libreria
L'interfaccia per le chiamate di sistema e l'
divisione tra i programmi utente ed applicativi ed il livello kernel.
rappresentano le linee di
L'interfaccia per le chiamate
di sistema si occupa di cambiare la modalitá di esecuzione di un processo da
modalita' utente
1.4 Il kernel ed i processi
6
Figura 1.6 Pseudocodice di un sistema operativo a divisione di tempo
Figura 1.7 Esecuzione dei processi a divisione di tempo
(running user mode) a
modalita' sistema
(running kernel mode) ogni volta che intercetta una
chiamata di sistema (system call).
Il meccanismo con il quale vengono attivate le chiamate di sistema é illustrato in g.1.2. Una
chiamata di sistema genera una interruzione che mette il processore in modalitá sistema (kernel
mode) nella quale vengono eseguite le chiamate di sistema.
essere di tio software o di tipo hardware.
In generale, le interruzioni possono
Entrambe sono gestite con il meccanismo illustrato in
g.1.2. In particolare, le chiamate di sistema sono prodotte dalle istruzioni 'trap' che producono
iterruzioni software.
Il kernel oltre a mettere a disposizione le interfacce per le chiamate di sistema possiede anche
tutto il software in grado di controllare direttamente l'hardware del calcolatore, la gestione dell'I/O,
la gestione del le system e la gestione dei processi. Il
sottoinsieme di gestione del le system
gestisce i le e la memoria secondaria, alloca lo spazio per i le, amministra lo spazio libero su
sottoinsieme di
controllo del hardware e' responsabile della gestione delle interruzioni (interrupt) e delle comunastro o disco, controlla l'accesso ai le e ricerca i dati per conto di ogni utente. Il
nicazioni con la macchina. I device di I/O a blocchi, cioe' i nastri ed i dischi, possono interrompere
la CPU durante l'esecuzione di un processo ed il kernel puo' riavviare il processo interrotto dopo
1.4 Il kernel ed i processi
7
Figura 1.8 Il meccanismo delle chiamate di sistema
aver gestito l'interruzione.
la
Il sottoinsieme di gestione del le system puo' accedere ai dati contenuti nei le utilizzando
buer cache cioe' un meccanismo di buering, che regola il usso dei dati tra il kernel ed i
device di I/O a blocchi, cioe' i nastri ed i dischi. Il meccanismo di buering interagisce infatti con
sottoinsieme
di gestione del le system puo' interagire anche direttamente con i device di I/O a caratteri,
i device di I/O a blocchi per avviare il trasferimento dei dati da e verso il kernel. Il
cioe' le stampanti, lo schermo video del terminale, la tastiera del terminale e i dispositivi di rete,
senza l'intervento di alcun meccanismo di buering. I device driver sono memorizzati, come gia'
osservato, sempre nel direttorio
/dev e quindi sono esterni al kernel.
Il
modulo dei processi di
I/O e' un'istanza dei device driver in esecuzione e quindi controlla l'operato dei device di I/O.
I processi interagiscono con il sottoinsieme di gestione del le system per mezzo di un
insieme di particolari chiamate di sistema, come open( ) che apre un le in lettura oppure in
scrittura, close( ) che chiude un le aperto, read( ) che legge da un le aperto, write( ) che
scrive in un le aperto, stat( ) che richiede gli attributi di un le, chown( ) che cambia l'utente
proprietario di un le e chmod( ) che cambia i permessi di accesso ad un le.
Il sottoinsieme del kernel di gestione dei processi risulta diviso in tre moduli. Il modulo
di schedulazione detto anche scheduler della CPU che decide a quali dei processi pronti in
memoria centrale bisogna assegnare il controllo della CPU. Lo scheduler della CPU gestisce quindi
la schedulazione dei processi in modo da eseguirli a turno nche' lasciano volontariamente libera
la CPU in attesa di una risorsa oppure il kernel decide che il tempo loro concesso e' gia' passato. Lo scheduler della CPU scegliera' allora il processo a priorita' piu' alta e lo fara' eseguire. Il
processo appena interrotto ripartira' invece quando tornera' ad essere il processo di priorita' piu'
alta.
L'algoritmo realizzato dallo scheduler della CPU e' comunque fortemente inuenzato dalle
tecniche di gestione della memoria. Il
modulo di comunicazione tra processi si occupa invece
della sincronizzazione dei processi, della comunicazione tra i processi e della comunicazione tra i
processi e la memoria centrale.
Ci sono diverse forme di comunicazione tra i processi che vanno
dalla segnalazione asincrona degli eventi alla trasmissione sincrona di messaggi tra i processi. Una
trasmissione asincrona non aspetta un messagio di conferma, mentre una trasmissione sincrona attende sempre un messagio di conferma.
Il
modulo della gestione della memoria
si occupa