SISTEMA OPERATIVO
È una piattaforma di sviluppo che gestisce le risorse hardware e software del computer,
fornendo servizi ai programmi applicativi e di sistema.
- Astrae le risorse hardware, presentando agli sviluppatori dei programmi applicativi una
visione delle risorse hardware più facile da usare e più potente rispetto alle risorse
hardware «native»
- Condivide le risorse hardware tra molti programmi contemporaneamente in esecuzione,
suddividendole tra questi in maniera equa ed efficiente e controllando che i programmi
le usino correttamente
- Mantiene ed organizza i nostri dati sotto forma di file e directory
Requisiti dei Sistemi Operativi
I requisiti dei sistemi operativi sono diversi in base allo scenario applicativo, per esempio i
server necessitano di massimizzare la performance e rendere equa la condivisione delle
risorse tra molti utenti, mentre invece i laptop, i PC o i tablet necessitano di massimizzare la
facilità d'uso e la produttività della singola persona che lo usa.
Struttura del SO
Un SO è formato da:
- Kernel: il programma che gestisce completamente l'hardware e offre ai programmi i
servizi per poterlo usare in maniera condivisa ed astratta.
- Middleware: servizi di alto livello che astraggono ulteriormente i servizi del kernel e
semplificano la programmazione di applicazioni (API, framework per grafica e per
suono ... )
- Programmi di sistema: offrono ulteriori funzionalità di supporto e di interazione
utente con il sistema (interfaccia utente per esempio)
Servizi del Sistema Operativo
- Controllo processi: permettono di caricare in memoria un programma, eseguirlo,
identificare e registrarne la condizione di terminazione
- Gestione file: permettono di leggere, scrivere, e manipolare files e directory
- Gestione dispositivi: permettono ai programmi di effettuare operazioni di
input/output
- Comunicazione tra processi: permettono ai programmi in esecuzione di scambiarsi
informazioni
- Protezione e sicurezza: permette ai proprietari delle informazioni in un sistema di
controllarne l'uso da parte di altri utenti e di difendere il sistema dagli accessi illegali
- Allocazione delle risorse: alloca le risorse hardware (CPU, memoria, dispositivi di
I/O) ai programmi in esecuzione in maniera equa ed efficiente
- Rilevamento errori
- Logging: mantiene traccia di quali programmi usano quali risorse, allo scopo di
contabilizzarle
Chiamate di sistema e API
Il kernel offre i propri servizi ai programmi sottoforma di chiamate di sistema, ossia di
funzioni invocabili in un determinato linguaggio di programmazione (C, C++ ... ).
I programmi però non utilizzano direttamente le chiamate di sistema, ma delle librerie di
middleware dette Application Program Interface (API) implementate invocando le chiamate
di sistema.
Le API sono esposte dal middleware, le chiamate di sistema dal kernel
Le API usano le chiamate di sistema nella loro implementazione
Le API sono standardizzate, le chiamate di sistema no (ogni kernel ha le sue)
Le API sono stabili, le chiamate di sistema possono variare al variare della versione del
sistema operativo
Le API offrono funzionalità più ad alto livello e più semplici da usare, le chiamate di
sistema offrono funzionalità più elementari e più complesse da usare.
Programmi di sistema
Gli utenti utilizzano i servizi del S.O attraverso i programmi di sistema.
Questi permettono agli utenti di avere un ambiente più conveniente per l'esecuzione dei
programmi, il loro sviluppo, e la gestione delle risorse del sistema.
I programmi di sistema sono implementati utilizzando le API, esattamente come i
programmi applicativi.
- Interfaccia utente: permette agli utenti di interagire con il sistema stesso; può essere
grafica (GUI) o a riga di comando (CLI);
- Gestione file: creazione, modifica, e cancellazione file e directory
- Modifica dei file: editor di testo, programmi per la manipolazione del contenuto dei
file
- Visualizzazione e modifica informazioni di stato: data, ora, memoria disponibile,
processi ... fino a informazioni complesse su prestazioni, accessi al sistema e debug.
Alcuni sistemi implementano un registry, ossia un database delle informazioni di
configurazione
- Caricamento ed esecuzione dei programmi: loader (legge un programma da disco
e lo carica in memoria), linker, debugger
- Ambianti di supporto alla programmazione: compilatori, assemblatori,
- Comunicazione: permettono di navigare il web, inviare posta elettronica ..
- Servizi in background: lanciati all'avvio del S.O, alcuni terminano, altri continuano
l'esecuzione fino allo shutdown. Forniscono servizi quali verifica dello stato dei
dischi ecc .. (es. demone temporale, "ogni sera a mezzanotte fare il backup", "ogni
mese fare il backup di tutto il disco")
Interprete dei comandi
L'interprete dei comandi permette agli utenti di impartire in maniera testuale delle istruzioni
al sistema operativo.
Modi per implementare un comando
- Built-in: l'interprete esegue direttamente il comando (tipico nell'interprete di
comandi di Windows)
- Il comando è un programma di sistema: l'interprete manda in esecuzione il
programma (tipico delle shell Unix e Unix-like)
I programmi di sistema sono implementati utilizzando le API, esattamente come i
programmi applicativi
PROCESSI
Programma -> entità passiva, insieme di istruzioni, uno stesso programma può dare origine
a diversi processi. I programmi rimangono sempre nella memoria del computer fino quando
non vengono eliminati.
Processo -> entità attiva astratta definita dal sistema operativo allo scopo di eseguire un
programma, è di fatto un programma in esecuzione o un esecutore di programmi. Programma
caricato in RAM soltanto per un tempo necessario.
Componenti di un Processo
È composto da diverse parti:
- Stato dei registri del processore che esegue il programma, in particolare il PC
- Stato dell'immagine del processo, ossia della regione di memoria centrale usata dai
programmi. Processi distinti hanno immagini distinte.
- Risorse del sistema operativo in uso al programma (files ... ) . Queste possono essere
condivise tra processi
- informazioni di contabilità (informazioni sullo stato del processo per il SO)
Immagine di un processo
Spazio di indirizzamento (address space) -> l'intervallo di indirizzi di memoria min ... max
in cui è contenuta l'immagine di un processo
L'immagine di un processo di norma contiene:
- text section, contenente il codice macchina del programma
- data section, contenente le variabili globali
- heap, contenente la memoria allocata dinamicamente durante
l'esecuzione
- stack delle chiamate, contenente parametri, variabili locali e
indirizzo di ritorno delle varie procedure che vengono invocate
durante l'esecuzione del programma.
Text e data section hanno dimensioni costanti per tutta la vita del
processo. Stack e heap invece crescono / decrescono durante la vita
del processo.
max
stack
heap
data
text
min
Operazioni sui processi
I sistemi operativi di solito forniscono delle API con le quali un processo può
creare/ terminare/ mettersi in attesa di altri processi.
Dal momento che solo un processo può creare un altro processo, all'avvio il kernel crea dei
processi «primordiali» dai quali tutti i processi utente e di sistema vengono
progressivamente creati. Di solito nei sistemi operativi i processi sono organizzati in
maniera gerarchica
Creazione di processi
Un processo (padre) può creare altri processi (figli). Questi a loro volta possono essere padri
di altri processi figli, creando un albero di processi.
La relazione padre/figlio è di norma importante per le politiche di condivisione risorse e di
coordinazione tra processi.
Possibili politiche di condivisione di risorse: padre e figlio condividono tutte le risorse o un
opportuno sottoinsieme o nessuna.
Possibili politiche di creazione spazio di indirizzi: il figlio è un duplicato del padre oppure
no, e bisogna specificare quale programma deve eseguire il figlio
Possibili politiche di coordinazione padre/figli: il padre è sospeso finché i figli non
terminano, oppure eseguono in maniera concorrente
Terminazione dei processi
Un processo per terminare di solito invoca esplicitamente un'API che annuncia la propria
terminazione al S.O. Un processo padre può attendere o meno la terminazione di un figlio
oppure può forzare la terminazione di un figlio.
In alcuni sistemi operativi il padre termina prima che il figlio termini, quindi il figlio viene
forzatamente ucciso. Questo tipo di terminazione viene detto a cascata (tutto il sottoalbero
del processo viene terminato).
API POSIX
- fork() crea un nuovo processo figlio;
- Il figlio è un duplicato del padre ed esegue concorrentemente ad esso (il padre non si
blocca in attesa del figlio).
- Ritorna al padre un PID del processo figlio con valore diverso da 0,
- Ritorna al figlio il PID 0
- exec() sostituisce il programma in esecuzione da un processo con un altro programma,
che viene eseguito dall'inizio; viene tipicamente usata dopo una fork() dal figlio per
iniziare ad eseguire un programma diverso da quello del padre
- wait() viene chiamata dal padre per attendere la terminazione del figlio, ritorna il PID
del figlio che è terminato e il codice di ritorno del figlio (passato come parametro alla
exit()).
- exit() fa terminare il processo che la invoca. Accetta come parametro un codice di
ritorno (numero). Il sistema operativo elimina il processo e recupera le sue risorse,
Quindi restituisce al processo padre il codice di ritorno (se ha invocato wait(), altrimenti
lo memorizza per quando l'invocherà)
- abort() fa terminare forzatamente un processo figlio
Se un processo termina ma suo padre non ha invocato wait() il processo è detto zombie: le
sue risorse non possono essere completamente deallocate (il padre potrebbe prima o poi
invocare wait()).
Se un processo padre termina prima di un suo figlio, non vi è terminazione a cascata: in tal
caso, i figli ancora attivi di un processo padre che ha terminato sono detti essere orfani.
Comunicazione interprocesso
Un'applicazione può essere composta da più processi.
Più processi possono essere indipendenti o cooperare. Un processo coopera con uno o più
altri processi se il suo comportamento «influenza» o «è influenzato da» il comportamento di
questi.
Per permettere ai processi di cooperare il sistema operativo deve mettere a disposizione
primitive di comunicazione interprocesso (IPC).
Tipi di Comunicazione Interprocesso
Ne esistono di 2 tipi:
- Memoria condivisa: Viene stabilita una zona di memoria condivisa tra i processi che
intendono comunicare. La sincronizzazione è controllata dai processi che comunicano,
non dal sistema operativo. Un processo non può leggere la memoria condivisa mentre
l'altro la sta scrivendo. Allo scopo i sistemi operativi mettono a disposizione ulteriori
primitive per la sincronizzazione.
- Message passing: i processi comunicano tra
di loro
senza condividere memoria,
shared memory
process B
attraverso la mediazione del sistema
process B
operativo. Questo mette a disposizione
un'operazione send(message) con la quale
un processo può inviare un messaggio ad un
altro
processo
e
un'operazione
kernel
kernel
receive(message) con la quale un processo
Memoria condivisa
può (mettersi in attesa fino a) ricevere un
messaggio da un altro processo. Per comunicare due processi devono stabilire un link di
comunicazione tra di loro e scambiarsi messaggi usando send e receive.
process A
process A
message queue
mo m1 m2 m3 ... mn
Message passing