SISTEMI OPERATIVI
PRIMO BLOCCO SLIDE (1-Intro)
INTRODUZIONE SISTEMI OPERATIVI
SISTEMA OPERATIVO: programma o insieme di programmi che agisce come intermediario tra utente
e hardware del computer (CPU, memoria centrale, memoria secondaria, dispositivi I/O, connessioni
di rete…) fornendo una visione astratta e semplificata di esso, gestendo in modo efficiente ed
efficace le risorse del sistema di calcolo e mettendo a disposizione un ambiente di esecuzione e
sviluppo per i programmi degli utenti.
Concorrenza: possibilità di avere più programmi che eseguono contemporaneamente.
(Fig. 1) Il sistema operativo è l’unica
entità in grado di gestire le risorse
hardware, se un programma a
livello più alto ha bisogno di
memoria (ad es. mallock) si rivolge
al sistema operativo come
intermediario. Gli utenti sono le
entità attive che lanciando
programmi determinano le attività
nel sistema.
Figura 1
Obiettivo primario mostrare una visione astratta delle risorse a disposizione aumentando quindi il
livello di astrazione. Importantissimi aspetti per un sistema operativo sono: Architettura,
Condivisione, Efficienza, Estendibilità, Protezione e Sicurezza (da intendersi come capacità di
limitare le interferenze tra utenti, risorse interne al sistema e attacchi provenienti dal mondo
esterno), Affidabilità e tolleranza ai guasti, Conformità a standard (a partire dalle prime versioni
stabili dei SO sono stati definiti standard che stabiliscono aspetti fondamentali delle interfacce dei
sistemi nei confronti dei programmi→standard posix).
I primi calcolatori risalgono al dopoguerra e sono caratterizzati da: tecnologia a valvole,
programmazione tramite linguaggio macchina, controllo manuale del sistema e assenza di SO
(l’operatore chiedeva al calcolatore l’esecuzione di operazioni in linguaggio macchina).
La seconda generazione di calcolatori prende il nome di sistemi batch semplici, caratterizzati da
architettura basata su transistor, input mediante schede perforate, utilizzo di linguaggi di alto livello.
Schede perforate: schede di cartone perforate da macchine perforatrici, tale scheda dava la
possibilità di codificare una singola istruzione di un programma. Un programma era dunque un
aggregato di schede perforate ognuna per ogni istruzione. Batch: pacco di schede che conteneva
codice e dati di una serie di programmi, per ogni job (=programma) comparivano alcune schede con
un comando che dava direttive al tema per eseguire certi compiti. Doveva essere inserita anche una
scheda che dicesse al sistema di caricare in memoria. C’era anche un comando per l’esecuzione.
Ogni programmatore scriveva il proprio programma, perforava le schede e si recava al centro di
calcolo, ai quali ci si rivolgeva per l’esecuzione dei propri elaborati. L’elaboratore aveva un
dispositivo di input per lettura ed esecuzione dei comandi sulle schede, ogni programma veniva
1
eseguito in maniera puramente ed esclusivamente sequenziale. Il compito del sistema operativo in
sistemi batch semplici era eseguire i pochi comandi (compile, load, run…) e occuparsi del
trasferimento di controllo da un job terminato al prossimo da eseguire. Tale SO era residente in
memoria (monitor), ma c’era totale assenza di interazione tra utente e job (consegna pacco di
schede al centro di calcolo e ritiro dell’elaborazione su fogli stampati. Se il codice fornito conteneva
errori esso poteva essere segnalato (se in compilazione) o verificato a occhio se presente in
esecuzione. Ciò portava a una reiterazione e ricompilazione con allungamento enorme dei tempi e
frequente aumento dei costi (spesso i costi del centro di calcolo andavano in base a una tariffa
oraria)), era scarsamente efficiente (ad ogni istante la CPU del sistema di elaborazione era dedicata
a un job, dunque durante l’input o l’output del job corrente la CPU rimaneva inattiva). La memoria
centrale dei sistemi batch semplici era tipicamente divisa in due parti: la parte dedicata al SO e la
parte dedicata al job corrente. Problemi dei sistemi batch semplici:
• Il job successivo non può iniziare l’esecuzione finché il job corrente non viene terminato
• Se un job si sospende in attesa di un evento la CPU, essendo ormai assegnata a tale job,
rimane inattiva
• Assenza di interazione tra sistema e utente
• Lentezza dei dispositivi I/O (molto maggiore rispetto a quanto “lecito”)
Per ovviare a questi problemi presto si introducono tecnologie Spooling (Simultaneous Peripheral
Operation On Line) che avevano l’obiettivo di svolgere contemporaneamente operazioni di input e
output con quelle di CPU (il disco veniva impiegato come un ampio buffer in cui memorizzare in
anticipo i programmi da seguire, leggere in anticipo i dati, memorizzare temporaneamente i risultati
in attesa che l’output sia pronto e caricare dati e codice del job successivo in modo da sovrapporre
I/O di un job con elaborazione del job successivo).
La maggior parte delle problematiche sopra esposte sono quindi risolte, ad eccezione dell’inattività
della CPU in caso di attesa di un evento, la soluzione a tale questione si trova nei sistemi batch
multiprogrammati. La multiprogrammazione consiste nel precaricamento su disco di un insieme di
job (detto pool), da cui il SO seleziona soltanto un sottoinsieme di job che viene caricato in memoria
centrale, a questo punto il SO sceglie uno dei job in memoria centrale e lo assegna alla CPU (job
corrente), nel momento in cui esso si pone in attesa di un evento il SO interviene e assegna l CPU ad
un altro job. In questo modo ad ogni istante il SO porta avanti l’esecuzione di più job
contemporaneamente (ma un solo job utilizza la CPU). Prende il nome di scheduling l’attività di
scelta attraverso la quale il SO seleziona il job a cui assegnare la CPU (scheduling dei job o long-term
scheduling è la scelta da parte del SO dei job da caricare in memoria, mentre lo scheduling della CPU
o short-term scheduling è la scelta del SO del job a cui assegnare la CPU), una volta fatto ciò il SO
effettua uno scambio tra il job in attesa dell’evento
e quello che può usare la CPU eseguendo il context
switch o cambio di contesto. La memoria dei
sistemi batch multiprogrammati si divide più parti:
una riservata al SO e tutte le altre riservate ai vari Figura 2
job caricati nella memoria centrale. È ovvio che una
suddivisione della memoria di questo genere necessiti di protezione adeguata soprattutto per
quanto riguarda l’area riservata al SO, ma anche per le altre zone.
Un particolare tipo di sistemi multiprogrammati sono i sistemi time-sharing (modello dei sistemi
odierni), nati dalla necessità di interattività (tra SO e utente) e di multiutenza (possibilità per più
2
utenti contemporaneamente di interagire col SO in modo tale che ad ognuno di essi il sistema
presenti una macchina virtuale dedicata in termini di utilizzo della CPU e di utilizzo di altre risorse).
In essi viene posto un limite temporale all’esecuzione della CPU da parte di un job (quanto di tempo
o time slice), se esso si esaurisce interviene il SO che blocca l’esecuzione e assegna alla CPU un altro
job. L’idea con i sistemi time-sharing è di dare all’utente l’idea di una memoria quasi illimitata adibita
all’esecuzione dei propri job (comincia a farsi strada l’idea di memoria virtuale).
Figura 4 - Utilizzo della CPU in sistemi time-sharing
Figura 3 - Utilizzo della CPU in sistemi batch multiprogrammati
(Fig. 3) in ascissa il tempo e in ordinata l’attività dei diversi job. Il piccolo intervallo fra fronte di salita
e l’istante di tempo è il tempo che impiega il SO ad assegnare alla CPU il job. Le fasi temporali in cui
la CPU non viene utilizzata sono ridotte al minimo.
(Fig. 4) supponiamo di avere 3 job caricati in memoria e uno scheduler che schedula per primo il job
1 all’sitante t0, esso va avanti ad usare la CPU fino al t1 quando il job si mette in attesa di un evento.
Interviene allora il SO che sceglie il job 2 e gli assegna la CPU. Supponiamo che esso vada avanti in
esecuzione fino all’esaurimento del quanto di tempo (valore molto piccolo nei sistemi di oggi), allora
interviene il SO e assegna la CPU al job 3. Quando il job esaurisce il suo quanto di tempo il SO
interrompe un job che potrebbe continuare la sua esecuzione ma semplicemente ha raggiunto il suo
limite.
RICHIAMI AL FUNZIONAMENTO HARDWARE DI UN SISTEMA DI ELABORAZIONE
L’architettura di un sistema di elaborazione può essere
schematizzata come in Figura 5. Si definisce controller
l’interfaccia hardware di tutte le periferiche e
dispositivi verso il bus di sistema, nel controller sono
contenuti tutti i registri direttamente indirizzabili dalla
CPU, ovvero il mezzo attraverso cui la CPU può
Figura 5 comunicare con le varie periferiche. L’interazione tra le
componenti dei sistemi di oggi si basa sulle interruzioni
asincrone (o interrupt), ognuna delle quali causata da uno specifico evento. Ad ogni interruzione è
associata una routine di servizio (o handler) per la gestione dello specifico evento. Ci sono due tipi
di interruzioni:
• Interruzioni hardware: i dispositivi esterni alla CPU inviano un segnale di interrupt vero e
proprio per notificare particolari eventi al SO
3
• Interruzioni software (trap): i programmi in esecuzione generano interruzioni quando
tentano di eseguire operazioni non lecite o richiedono al SO l’esecuzione di servizi (ad es.
divisione per zero, invio file a stampante…). La richiesta al SO di esecuzione di un servizio
viene detta system call
Quando avviene un’interruzione, che sia un’interruzione hardware (segnale) o un’interruzione
software (trap): (1)l’evento viene notificato al SO che interrompe l’attività in esecuzione nella CPU,
salva lo stato del job in esecuzione e (2) avvia la routine di servizio per la gestione dell’interruzione
(la specifica routine di servizio viene individuata attraverso il vettore delle interruzioni, nel quale ci
sono tutte le procedure necessarie a gestire ogni singolo evento, identificate da un intero. Il SO fa
riferimento al vettore, in particolare alla posizione correlata alla specifica interruzione che gli viene
notificata), (3) una volta completata tale routine viene ripristinato lo stato precedentemente salvato
in memoria.
Il controller di un dispositivo di I/O contiene necessariamente un registro dati (ove vengono
memorizzate temporaneamente informazioni da leggere o scrivere) e dei registri speciali (ove
vengono memorizzate le specifiche delle operazioni da eseguire (registro di controllo) e l’esito delle
operazioni eseguite (registro di stato)). Ogni volta che un job richiede un’operazione di I/O: (1) la
CPU scrive nei registri speciali del dispositivo la corrispondente sequenza di bit relativa
all’operazione da eseguire, (2) il controller esamina i registri e provvede ad eseguire l’operazione
richiesta, (3) la periferica notifica alla CPU il completamento dell’operazione attraverso l’invio di una
interruzione hardware, (4) l’interruzione viene gestita col passaggio di controllo al SO il quale esegue
l’operazione della routine di servizio. Ogni periferica è in grado di interpretare un proprio linguaggio
ma non esiste un SO che conosce tutta la gamma di linguaggi, è dunque necessaria l’introduzione
del driver del dispositivo: componente del SO che interagisce direttamente con la periferica
copiando nei registri del controller le informazioni relative all’operazione richiesta, la struttura di
tale componente dipende dal particolare dispositivo controllato (device-dependent) e consiste di
fatto nell’unica parte in grado di dialogare col dispositivo traducendo il linguaggio del sistema nel
suo specifico.
Uno dei compiti del SO è fornire strumenti e meccanismi per esercitare la protezione sulle risorse
(memoria, dispositivi di I/O e CPU). Il tema della protezione viene affrontato a livello hardware
solitamente, ovvero tutti i microprocessori di oggi hanno la possibilità di funzionare in varie modalità
→
(solitamente 2 architetture dual mode). Nel caso delle architetture dual mode ad ogni istante il
processore può funzionare in user mode o in kernel mode. Solitamente l’architettura della CPU
prevede almeno un bit di modo che rappresenta quello che è il modo di funzionamento corrente
(ad es. bit 0, la CPU lavora in modo kernel, al contrario bit 1, la CPU lavora in modo user). Le CPU
prevedono un set di istruzioni macchina (ISA), al cui interno vi è sempre un sottoinsieme di istruzioni
privilegiate (sono quelle potenzialmente più pericolose per il funzionamento del sistema, esse si
possono eseguire solo se il sistema è in kernel mode), esse sono ad esempio: accesso a dispositivi
I/O, gestione della memoria, disabilitazione di interruzioni, istruzioni di shutdown... L’unico modulo
software che esegue in kernel mode è il SO, tutti gli altri programmi utente eseguono in user mode
e l’unico modo per loro di eseguire operazioni privilegiate è effettuare una system call (il programma
delega il SO di eseguire per lui l’operazione. Il meccanismo della system call è particolare: (1)
invocazione system call, (2) invio di una trap al SO, (3) salvataggio dello stato, inteso come PC,
registri e bit di modo, del programma chiamante e trasferimento di controllo al SO, (4) esecuzione
del SO in kernel mode dell’operazione richiesta, (5) ripristino del programma interrotto con
4
conseguente ritorno alla user mode). Le system call sono disponibili per il programmatore
sottoforma di una libreria di funzioni.
Solitamente i modi di funzionamento per i microprocessori sono più di 2, consideriamo per esempio
la famiglia INTEL, la quale possiede 2 bit di protezione e conseguentemente 4 modi o ring: dl più
privilegiato a quello meno privilegiato si hanno Ring 0, Ring 1, Ring2, Ring 3. In realtà nonostante la
presenza di tutti e 4 i ring, nella maggior parte dei casi però ne vengono utilizzati soltanto due: Ring
0 (corrispondente al modo kernel) e Ring 3 (corrispondente al modo user). I 2 bit meno significativi
del registro CS rappresentano il livello di privilegio corrente (CPL: Current Privilege Level). Ad ogni
area di memoria, o segmento di memoria, viene assegnato un livello di privilegio richiesto per
l’accesso (PL), se il CPL è maggiore del livello di privilegio richiesto c’è una violazione (CPL>PL).
INTRODUZIONE ALL’ORGANIZZAZIONE DEI SISTEMI OPERATIVI
Il SO è molto complesso e si pone dunque il problema della soluzione migliore per la sua architettura
interna. Non c’è una soluzione standard, ma per ognuna ci sono pro e contro. Consideriamo come
riferimento i SO moderni (multiprogrammati e time-sharing). Le componenti tipiche sono:
• Gestione dei processi: preliminarmente va posta la differenziazione tra programma (entità
passiva costituita da un insieme di byte contenente le istruzioni da eseguire) e processo
(entità attiva costituente l’unità di lavoro ed esecuzione nel sistema, nonché l’istanza di un
programma in esecuzione. Definizione che pone dunque Processo = programma + contesto
di esecuzione). La componente della gestione dei processi è essenziale in un SO
multiprogrammato, dove possono essere presenti più processi simultanei in esecuzione,
essa deve avere specifici compiti di creazione/terminazione dei processi,
sospensione/ripristino dei processi, sincronizzazione/comunicazione dei processi e gestione
del blocco critico dei processi (deadlock: avviene se più processi contemporaneamente in
esecuzione sono in attesa di un evento che magari può dare soltanto uno di loro una volta
terminato)
• Gestione della memoria centrale: si occupa della gestione della RAM. Il SO deve:
allocare/deallocare memoria ai processi, separare nettamente gli spazi di indirizzi associati
ai processi (anche al fine di garantire i livelli di protezione), gestire la memoria virtuale
(ovvero spazi logici di indirizzi anche di dimensioni complessivamente superiori allo spazio
fisico), realizzare binding tra indirizzamento logico e fisico
• Gestione della memoria secondaria e del file system: la memoria secondaria è una
periferica occupante uno spazio a sé data la sua importanza. Essa alloca/dealloca spazio,
gestisce lo spazio libero, effettua lo scheduling delle operazioni su disco. È possibile accedere
alla memoria secondaria attraverso l’astrazione del file system. Il compito del SO è quindi di
fornire una visione logica uniforme della memoria secondaria (realizzando il concetto
astratto di file in quanto unità di memorizzazione logica e fornendo una struttura astratta
per l’organizzazione di tali file, ovvero il direttorio), creare/cancellare file e directory,
manipolare file e directory, associare file e dispositivi di memorizzazione secondaria. Spesso
qualunque risorsa che il sistema deve gestire è presente nel file system sottoforma di file
(idea di uniformità)
• Gestione dell’I/O: il compito del SO è dare all’utente un’interfaccia tra programmi e
dispositivi e, per ogni dispositivo, interagire col suo driver
• Protezione e sicurezza: come già detto un sistema multiprogrammato necessità di
protezione, ovvero di un controllo dell’accesso alle risorse (memoria, processi, file,
5
dispositivi) da parte di processi e utenti attraverso autorizzazioni e modalità di accesso.
Inoltre, se il sistema appartiene a una rete, vi è necessità di protezione dell’intero sistema
da parte di attacchi esterni malevoli
• Interfaccia utente e interfaccia programmatore (API): il SO presenta interfacce agli utenti
per permettere loro di eseguire certe operazioni: interprete comandi o shell (interazione tra
utente e SO tramite testo su linea di comando), interfaccia grafica o GUI (interazione tra
utente e SO tramite mouse ed elementi grafici su desktop). Per quanto riguarda la API, essa
è l&rsquo
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.
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